PageRenderTime 128ms CodeModel.GetById 55ms app.highlight 64ms RepoModel.GetById 1ms app.codeStats 0ms

/Library/Kumbia/Controller/StandardForm/StandardFormController.php

http://kumbia-enterprise.googlecode.com/
PHP | 1536 lines | 876 code | 158 blank | 502 comment | 206 complexity | 679018f95a4b4d3d39c69efd09b079ab MD5 | raw file
   1<?php
   2
   3/**
   4 * Kumbia Enterprise Framework
   5 *
   6 * LICENSE
   7 *
   8 * This source file is subject to the New BSD License that is bundled
   9 * with this package in the file docs/LICENSE.txt.
  10 *
  11 * If you did not receive a copy of the license and are unable to
  12 * obtain it through the world-wide-web, please send an email
  13 * to license@loudertechnology.com so we can send you a copy immediately.
  14 *
  15 * @category	Kumbia
  16 * @package		Controller
  17 * @subpackage	StandardForm
  18 * @copyright	Copyright (c) 2008-2010 Louder Technology COL. (http://www.loudertechnology.com)
  19 * @copyright	Copyright (c) 2005-2008 Andres Felipe Gutierrez (gutierrezandresfelipe at gmail.com)
  20 * @license		New BSD License
  21 * @version 	$Id: StandardFormController.php 150 2010-09-24 16:20:10Z gutierrezandresfelipe $
  22 */
  23
  24/**
  25 * StandardFormController
  26 *
  27 * La Clase StandardForm es la base principal para la generacin de formularios
  28 * de tipo Standard
  29 *
  30 * Notas de Version:
  31 * Desde Kumbia-0.4.7, StandardForm mantiene los valores de la entrada
  32 * cuando los metodos before_ o validation devuelven false;
  33 *
  34 * @category	Kumbia
  35 * @package		Controller
  36 * @subpackage	StandardForm
  37 * @copyright	Copyright (c) 2008-2010 Louder Technology COL. (http://www.loudertechnology.com)
  38 * @copyright	Copyright (c) 2005-2008 Andres Felipe Gutierrez (gutierrezandresfelipe at gmail.com)
  39 * @license		New BSD License
  40 */
  41abstract class StandardForm extends Controller {
  42
  43	/**
  44	 * Tabla con la que trabaja el formulario
  45	 *
  46	 * @var string
  47	 */
  48	protected $source;
  49
  50	/**
  51	 * Lista de campos a ignorar en la generacion
  52	 *
  53	 * @var array
  54	 */
  55	protected $ignoreList = array();
  56
  57	/**
  58	 * Array que contiene los meta-datos internos
  59	 * para generar el formulario
  60	 *
  61	 * @var string
  62	 */
  63	protected $form = array();
  64
  65	/**
  66	 * Hace que el formulario no sea persistente
  67	 *
  68	 * @var boolean
  69	 * @staticvar
  70	 */
  71	static public $force = false;
  72
  73	/**
  74	 * Numero de Minutos que el layout ser? cacheado
  75	 *
  76	 * @var integer
  77	 */
  78	protected $cacheLayout = 0;
  79
  80	/**
  81	 * Numero de Minutos que la vista ser? cacheada
  82	 *
  83	 * @var integer
  84	 */
  85	public $cache_view = 0;
  86
  87	/**
  88	 * Indica si se deben leer los datos de la base
  89	 * de datos para generar el formulario
  90	 *
  91	 * @var boolean
  92	 */
  93	public $scaffold = false;
  94
  95	/**
  96	 * Indica el tipo de respuesta que será generado
  97	 *
  98	 * @var string
  99	 */
 100	public $view;
 101
 102	/**
 103	 * Indica si se debe mantener los valores del
 104	 * formulario o no
 105	 *
 106	 * @var boolean
 107	 */
 108	public $keep_action = true;
 109
 110	/**
 111	 * Último fetch realizado en la consulta
 112	 *
 113	 * @var int
 114	 */
 115	private $_lastFetch = 0;
 116
 117	/**
 118	 * Mensaje de exito al insertar
 119	 *
 120	 * @var string
 121	 */
 122	public $successInsertMessage = '';
 123
 124	/**
 125	 * Mensaje de Fallo al insertar
 126	 *
 127	 * @var string
 128	 */
 129	public $failureInsertMessage = '';
 130
 131	/**
 132	 * Mensaje de Suceso al Actualizar
 133	 *
 134	 * @var string
 135	 */
 136	public $successUpdateMessage = "";
 137
 138	/**
 139	 * Mensaje de Fallo al Actualizar
 140	 *
 141	 * @var string
 142	 */
 143	public $failureUpdateMessage = "";
 144
 145	/**
 146	 * Mensaje de Exito al Borrar
 147	 *
 148	 * @var string
 149	 */
 150	public $successDeleteMessage = "";
 151
 152	/**
 153	 * Mensaje de fallo al borrar
 154	 *
 155	 * @var string
 156	 */
 157	public $failureDeleteMessage = "";
 158
 159	/**
 160	 * SQL que contiene la ultima consulta efectuada
 161	 *
 162	 * @var string
 163	 */
 164	protected $query;
 165
 166	/**
 167	 * Constructor de la clase
 168	 *
 169	 */
 170	public function __construct(){
 171		$this->setPersistance(true);
 172		if(method_exists($this, 'initialize')){
 173			$this->initialize();
 174		}
 175	}
 176
 177	/**
 178	 * Emula la acción Report llamando a show
 179	 *
 180	 * @access public
 181	 */
 182	public function reportAction(){
 183		$this->view = 'index';
 184		$modelName = EntityManager::getEntityName($this->getSource());
 185		if(!EntityManager::isEntity($modelName)){
 186			throw new StandardFormException('No hay un modelo "'.$modelName.'" para hacer la operación de reporte');
 187			return $this->routeTo(array('action' => 'index'));
 188		}
 189		if(!$this->{$modelName}->isDumped()){
 190			$this->{$modelName}->dumpModel();
 191		}
 192		foreach($this->{$modelName}->getAttributesNames() as $field_name){
 193			if(isset($_REQUEST["fl_$field_name"])){
 194				$this->{$modelName}->$field_name = $_REQUEST["fl_$field_name"];
 195			}
 196		}
 197
 198		/**
 199		 * Busca si existe un método o un llamado variable al método
 200		 * beforeReport, si este método devuelve false termina la ejecución
 201		 * de la acción
 202		 */
 203		if(method_exists($this, 'beforeReport')){
 204			if($this->beforeReport()===false){
 205				return null;
 206			}
 207			if(Router::getRouted()){
 208				return null;
 209			}
 210		} else {
 211			if(isset($this->beforeReport)){
 212				if($this->{$this->beforeReport}()===false){
 213					return null;
 214				}
 215				if(Router::getRouted()){
 216					return null;
 217				}
 218			}
 219		}
 220
 221		Generator::scaffold($this->form, $this->scaffold);
 222		GeneratorReport::generate($this->form);
 223
 224		/**
 225		 * Busca si existe un método o un llamado variable al método
 226		 * afterInsert, si este método devuelve false termina la ejecución
 227		 * de la acción
 228		 */
 229		if(method_exists($this, 'afterReport')){
 230			if($this->afterReport()===false){
 231				return null;
 232			}
 233			if(Router::getRouted()){
 234				return null;
 235			}
 236		} else {
 237			if(isset($this->afterReport)){
 238				if($this->{$this->afterReport}()===false){
 239					return null;
 240				}
 241				if(Router::getRouted()){
 242					return null;
 243				}
 244			}
 245		}
 246		return $this->routeTo(array('action' => 'index'));
 247	}
 248
 249	/**
 250	 * Devuelve el source
 251	 *
 252	 * @return string
 253	 */
 254	public function getSource(){
 255		if($this->source==''){
 256			$controller = Router::getController();
 257			ActiveRecordUtils::sqlSanizite($controller);
 258			$this->source = $controller;
 259		}
 260		return $this->source;
 261	}
 262
 263	/**
 264	 * Metodo Insert por defecto del Formulario
 265	 *
 266	 */
 267	public function insertAction(){
 268
 269
 270		$controllerRequest = ControllerRequest::getInstance();
 271		if($controllerRequest->isPost()){
 272
 273			$this->view = 'index';
 274			$this->keep_action = '';
 275
 276			Generator::scaffold($this->form, $this->scaffold);
 277
 278			$modelName = EntityManager::getEntityName($this->getSource());
 279			if(!EntityManager::isEntity($modelName)){
 280				throw new StandardFormException('No hay un modelo "'.$modelName.'" para hacer la operación de inserción');
 281				return $this->routeTo(array('action' => 'index'));
 282			}
 283
 284			if(!$this->{$modelName}->isDumped()){
 285				$this->{$modelName}->dumpModel();
 286			}
 287
 288			foreach($this->{$modelName}->getAttributesNames() as $field_name){
 289				if(isset($_REQUEST["fl_$field_name"])){
 290					$this->{$modelName}->$field_name = $_REQUEST["fl_$field_name"];
 291				}
 292			}
 293
 294			/**
 295			 * Busca si existe un método o un llamado variable al método
 296			 * validation, si este método devuelve false termina la ejecución
 297			 * de la acción
 298			 */
 299			if(method_exists($this, 'validation')){
 300				if($this->validation()===false){
 301					$this->keep_action = 'insert';
 302					if(!Router::getRouted()){
 303						return $this->routeTo(array('action' => 'index'));
 304					}
 305				}
 306				if(Router::getRouted()){
 307					return;
 308				}
 309			} else {
 310				if(isset($this->validation)){
 311					if($this->{$this->validation}()===false){
 312						$this->keep_action = 'insert';
 313						if(!Router::getRouted()){
 314							return $this->routeTo(array('action' => 'index'));
 315						}
 316					}
 317					if(Router::getRouted()){
 318						return;
 319					}
 320				}
 321			}
 322
 323			/**
 324			 * Busca si existe un método o un llamado variable al método
 325			 * beforeInsert, si este método devuelve false termina la ejecucin
 326			 * de la acción
 327			 */
 328			if(method_exists($this, 'beforeInsert')){
 329				if($this->beforeInsert()===false){
 330					$this->keep_action = 'insert';
 331					if(!Router::getRouted()){
 332						return $this->routeTo(array('action' => 'index'));
 333					}
 334				}
 335				if(Router::getRouted()){
 336					return;
 337				}
 338			} else {
 339				if(isset($this->beforeInsert)){
 340					if($this->{$this->beforeInsert}()===false){
 341						$this->keep_action = 'insert';
 342						if(!Router::getRouted()){
 343							return $this->routeTo(array('action' => 'index'));
 344						}
 345					}
 346					if(Router::getRouted()){
 347						return;
 348					}
 349
 350				}
 351			}
 352
 353			/**
 354			 * Subimos los archivos de Imagenes del Formulario
 355			 */
 356			foreach($this->form['components'] as $fkey => $rrow){
 357				if($this->form['components'][$fkey]['type']=='image'){
 358					if(isset($_FILES['fl_'.$fkey])){
 359						move_uploaded_file($_FILES['fl_'.$fkey]['tmp_name'], htmlspecialchars('public/img/upload/'.$_FILES['fl_'.$fkey]['name']));
 360						$this->{$modelName}->$fkey = urlencode(htmlspecialchars('upload/'.$_FILES['fl_'.$fkey]['name']));
 361					}
 362				}
 363			}
 364
 365			/**
 366			 * Utilizamos el modelo ActiveRecord para insertar el registro
 367			 * por lo tanto los
 368			 */
 369			$attributes = $this->$modelName->getPrimaryKeyAttributes();
 370			foreach($attributes as $attribute){
 371				if($attribute=='id'){
 372					$this->{$modelName}->id = null;
 373				}
 374			}
 375
 376			if($this->{$modelName}->create()==true){
 377				if($this->successInsertMessage){
 378					Flash::success($this->successInsertMessage);
 379				} else {
 380					Flash::success("Se insertó correctamente el registro");
 381				}
 382			} else {
 383				foreach($this->{$modelName}->getMessages() as $message){
 384					Flash::error($message->getMessage());
 385				}
 386				if(isset($this->failuresInsertMessage)&&$this->failuresInsertMessage!=""){
 387					Flash::error($this->failureInsertMessage);
 388				} else {
 389					Flash::error("Hubo un error al insertar el registro");
 390					$this->keep_action = 'insert';
 391					if(Router::getRouted()==false){
 392						return $this->routeTo(array('action' => 'index'));
 393					}
 394				}
 395			}
 396
 397			foreach($this->{$modelName}->getAttributesNames() as $fieldName){
 398				if(isset($_REQUEST['fl_'.$fieldName])){
 399					$_REQUEST['fl_'.$fieldName] = $this->{$modelName}->readAttribute($fieldName);
 400				}
 401			}
 402
 403			/**
 404			 * Busca si existe un método o un llamado variable al método
 405			 * after_insert
 406			 */
 407			if(method_exists($this, 'afterInsert')){
 408				$this->afterInsert();
 409				if(Router::getRouted()){
 410					return;
 411				}
 412			} else {
 413				if(isset($this->afterInsert)){
 414					$this->{$this->afterInsert}();
 415				}
 416				if(Router::getRouted()){
 417					return;
 418				}
 419			}
 420		} else {
 421			Flash::error('Debe volver a digitar los datos del formulario');
 422		}
 423
 424		// Muestra el Formulario en la accion show
 425		return $this->routeTo(array('action' => 'index'));
 426
 427	}
 428
 429	/**
 430	 * Emula la acción Update llamando a show
 431	 *
 432	 * @access public
 433	 */
 434	public function updateAction(){
 435
 436		$this->view = 'index';
 437		$this->keep_action = '';
 438
 439		Generator::scaffold($this->form, $this->scaffold);
 440
 441		$modelName = EntityManager::getEntityName($this->getSource());
 442		if(!EntityManager::isEntity($modelName)){
 443			throw new StandardFormException('No hay un modelo "'.$this->getSource().'" para hacer la operación de actualización');
 444			return $this->routeTo(array('action' => 'index'));
 445		}
 446
 447		if($this->{$modelName}->isDumped()==false){
 448			$this->{$modelName}->dumpModel();
 449		}
 450
 451		/**
 452		 * Subimos los archivos de Imágenes del Formulario
 453		 */
 454		foreach($this->form['components'] as $fkey => $rrow){
 455			if($this->form['components'][$fkey]['type']=='image'){
 456				if(isset($_FILES['fl_'.$fkey])){
 457					move_uploaded_file($_FILES['fl_'.$fkey]['tmp_name'], htmlspecialchars('public/img/upload/'.$_FILES['fl_'.$fkey]['name']));
 458					$this->{$modelName}->$fkey = urlencode(htmlspecialchars('upload/'.$_FILES['fl_'.$fkey]['name']));
 459				}
 460			}
 461		}
 462
 463		$primaryKey = array();
 464		foreach($this->form['components'] as $fkey => $rrow){
 465			if(isset($rrow['primary'])&&$rrow['primary']==1){
 466				if(isset($_REQUEST["fl_$fkey"])){
 467					$primaryKey[] = "$fkey = '".$_REQUEST["fl_$fkey"]."'";
 468				} else {
 469					Flash::error('Datos incorrectos de actualización');
 470					return $this->routeTo('action: index');
 471				}
 472			}
 473		}
 474
 475		if(count($primaryKey)){
 476			$this->{$modelName}->findFirst(join(' AND ', $primaryKey));
 477		}
 478
 479		foreach($this->{$modelName}->getAttributes() as $fieldName){
 480			if(isset($_REQUEST["fl_$fieldName"])){
 481				$this->{$modelName}->writeAttribute($fieldName, $_REQUEST["fl_$fieldName"]);
 482			}
 483		}
 484
 485		/**
 486		 * Busca si existe un método o un llamado variable al método
 487		 * validation, si este método devuelve false termina la ejecución
 488		 * de la acción
 489		 */
 490		if(method_exists($this, 'validation')){
 491			if($this->validation()===false){
 492				$this->keep_action = 'update';
 493				if(!Router::getRouted()){
 494					return $this->routeTo(array('action' => 'index'));
 495				}
 496			}
 497			if(Router::getRouted()){
 498				return;
 499			}
 500		} else {
 501			if(isset($this->validation)){
 502				if($this->{$this->validation}()===false){
 503					$this->keep_action = 'update';
 504					if(!Router::getRouted()){
 505						return $this->routeTo(array('action' => 'index'));
 506					}
 507				}
 508				if(Router::getRouted()){
 509					return;
 510				}
 511			}
 512		}
 513
 514		/**
 515		 * Busca si existe un metodo o un llamado variable al metodo
 516		 * before_update, si este metodo devuelve false termina la ejecucion
 517		 * de la accion
 518		 */
 519		if(method_exists($this, 'beforeUdate')){
 520			if($this->beforeUpdate()===false){
 521				$this->keep_action = 'update';
 522				if(!Router::getRouted()){
 523					return $this->routeTo(array('action' => 'index'));
 524				}
 525			}
 526			if(Router::getRouted()){
 527				return null;
 528			}
 529		} else {
 530			if(isset($this->beforeUpdate)){
 531				if($this->{$this->beforeUpdate}()===false){
 532					$this->keep_action = 'update';
 533					if(!Router::getRouted()){
 534						return $this->routeTo(array('action' => 'index'));
 535					}
 536				}
 537				if(Router::getRouted()){
 538					return null;
 539				}
 540			}
 541		}
 542
 543		/**
 544		 * Utilizamos el modelo ActiveRecord para actualizar el registro
 545		 */
 546		if($this->{$modelName}->update()==true){
 547			if($this->successUpdateMessage){
 548				Flash::success($this->successUpdateMessage);
 549			} else {
 550				Flash::success('Se actualizó correctamente el registro');
 551			}
 552		} else {
 553			$this->keep_action = 'update';
 554			foreach($this->{$modelName}->getMessages() as $message){
 555				Flash::error($message->getMessage());
 556			}
 557			if($this->failureUpdateMessage){
 558				Flash::error($this->failureUpdateMessage);
 559			} else {
 560				Flash::error('Hubo un error al actualizar el registro');
 561			}
 562			$_REQUEST['queryStatus'] = 1;
 563			$_REQUEST['id'] = $this->{$modelName}->readAttribute('id');
 564			return $this->routeTo(array('action' => 'index'));
 565		}
 566
 567		foreach($this->{$modelName}->getAttributes() as $fieldName){
 568			$_REQUEST['fl_'.$fieldName] = $this->{$modelName}->readAttribute($fieldName);
 569		}
 570
 571		/**
 572		 * Busca si existe un método o un llamado variable al método
 573		 * afterUpdate
 574		 */
 575		if(method_exists($this, 'afterUpdate')){
 576			$this->afterUpdate();
 577			if(Router::getRouted()){
 578				return;
 579			}
 580		} else {
 581			if(isset($this->afterUpdate)){
 582				$this->{$this->afterUpdate}();
 583				if(Router::getRouted()){
 584					return;
 585				}
 586			}
 587		}
 588
 589		// Muestra el Formulario en la accion index
 590		return $this->routeTo(array('action' => 'index'));
 591
 592	}
 593
 594	/**
 595	 * Esta acción se emplea al generarse un error de validación al actualizar
 596	 *
 597	 * @access public
 598	 */
 599	public function checkAction(){
 600		$_REQUEST['queryStatus'] = true;
 601	}
 602
 603	/**
 604	 * Permite mostrar/ocultar los asteriscos al lado
 605	 * de los componentes del formulario
 606	 *
 607	 * @access public
 608	 * @param boolean $option
 609	 */
 610	public function showNotNulls($option = true){
 611		$this->form['show_not_nulls'] = $option;
 612	}
 613
 614	/**
 615	 * Emula la accion Delete llamando a show
 616	 *
 617	 * @access public
 618	 */
 619	public function deleteAction(){
 620
 621		$this->view = 'index';
 622
 623		Generator::scaffold($this->form, $this->scaffold);
 624
 625		$modelName = EntityManager::getEntityName($this->getSource());
 626		if(!EntityManager::isEntity($modelName)){
 627			throw new StandardFormException('No hay un modelo "'.$this->getSource().'" para hacer la operación de actualización');
 628			return $this->routeTo(array('action' => 'index'));
 629		}
 630
 631		if(!$this->{$modelName}->isDumped()){
 632			$this->{$modelName}->dumpModel();
 633		}
 634
 635		foreach($this->{$modelName}->getAttributesNames() as $fieldName){
 636			if(isset($_REQUEST["fl_$fieldName"])){
 637				$this->{$modelName}->$fieldName = $_REQUEST["fl_$fieldName"];
 638			} else {
 639				$this->{$modelName}->$fieldName = "";
 640			}
 641		}
 642
 643		/**
 644		 * Busca si existe un método o un llamado variable al método
 645		 * before_delete, si este método devuelve false termina la ejecución
 646		 * de la acción
 647		 */
 648		if(method_exists($this, "beforeDelete")){
 649			if($this->beforeDelete()===false){
 650				if(!Router::getRouted()){
 651					return $this->routeTo(array('action' => 'index'));
 652				}
 653			}
 654			if(Router::getRouted()){
 655				return null;
 656			}
 657		} else {
 658			if(isset($this->beforeDelete)){
 659				if($this->{$this->beforeDelete}()===false){
 660					if(!Router::getRouted()){
 661						return $this->routeTo(array('action' => 'index'));
 662					}
 663				}
 664				if(Router::getRouted()){
 665					return null;
 666				}
 667			}
 668		}
 669
 670
 671		/**
 672		 * Utilizamos el modelo ActiveRecord para eliminar el registro
 673		 */
 674		if($this->{$modelName}->delete()){
 675			if($this->successDeleteMessage!=''){
 676				Flash::success($this->successDeleteMessage);
 677			} else {
 678				Flash::success("Se eliminó correctamente el registro");
 679			}
 680		} else {
 681			if($this->failureDeleteMessage!=''){
 682				Flash::error($this->failureDeleteMessage);
 683			} else {
 684				Flash::error("Hubo un error al eliminar el registro");
 685			}
 686		}
 687		foreach($this->{$modelName}->getAttributesNames() as $fieldName){
 688			$_REQUEST["fl_$fieldName"] = $this->{$modelName}->readAttribute($fieldName);
 689		}
 690
 691		/**
 692		 * Busca si existe un método o un llamado variable al método
 693		 * after_delete
 694		 */
 695		if(method_exists($this, "afterDelete")){
 696			$this->afterDelete();
 697			if(Router::getRouted()){
 698				return;
 699			}
 700		} else {
 701			if(isset($this->afterDelete)){
 702				$this->{$this->afterDelete}();
 703				if(Router::getRouted()){
 704					return;
 705				}
 706			}
 707		}
 708
 709		// Muestra el Formulario en la accion index
 710		return $this->routeTo(array('action' => 'index'));
 711	}
 712
 713	/**
 714	 * Emula la acción Query llamando a show
 715	 */
 716	public function queryAction(){
 717
 718		$this->view = 'index';
 719
 720		Generator::scaffold($this->form, $this->scaffold);
 721
 722		$modelName = EntityManager::getEntityName($this->getSource());
 723		if(!EntityManager::isEntity($modelName)){
 724			throw new StandardFormException('No hay un modelo "'.$modelName.'" para hacer la operación de consulta');
 725			return $this->routeTo(array('action' => 'index'));
 726		}
 727
 728		if(isset($this->form['dataFilter'])) {
 729			if($this->form['dataFilter']){
 730				$dataFilter = $form['dataFilter'];
 731			} else {
 732				$dataFilter = "1=1";
 733			}
 734		} else {
 735			$dataFilter = "1=1";
 736		}
 737
 738		if(!isset($this->form['joinTables'])) {
 739			$this->form['joinTables'] = "";
 740			$tables = "";
 741		} else {
 742			if($this->form['joinTables']) {
 743				$tables = ",".$this->form['joinTables'];
 744			} else {
 745				$tables = "";
 746			}
 747		}
 748		if(isset($this->form['joinConditions'])){
 749			$joinConditions = " AND ".$this->form['joinConditions'];
 750		} else {
 751			$joinConditions = '';
 752		}
 753
 754		$modelName = EntityManager::getEntityName($this->getSource());
 755		$model = $this->{$modelName};
 756
 757		if($model->isDumped()==false){
 758			$model->dumpModel();
 759		}
 760
 761		$primaryKeys = $model->getPrimaryKeyAttributes();
 762		$query =  "SELECT ".join(',', $primaryKeys)." FROM ".$this->form['source']."$tables WHERE $dataFilter $joinConditions ";
 763		$source = $this->form['source'];
 764
 765		$form = $this->form;
 766		$config = CoreConfig::readEnviroment();
 767		foreach($this->{$modelName}->getAttributesNames() as $fkey){
 768			if(!isset($_REQUEST["fl_".$fkey])){
 769				$_REQUEST["fl_".$fkey] = "";
 770			}
 771			if(trim($_REQUEST["fl_".$fkey])&&$_REQUEST["fl_".$fkey]!='@'){
 772				if(!isset($form['components'][$fkey]['valueType'])){
 773					$form['components'][$fkey]['valueType'] = "";
 774				}
 775				if($form['components'][$fkey]['valueType']=='numeric'||$form['components'][$fkey]['valueType']=='date'){
 776					if($config->database->type!='oracle'){
 777						$query.=" and $source.$fkey = '".$_REQUEST["fl_".$fkey]."'";
 778					} else {
 779						if($form['components'][$fkey]['valueType']=='date'){
 780							$query.=" and $source.$fkey = TO_DATE('".$_REQUEST["fl_".$fkey]."', 'YYYY-MM-DD')";
 781						} else {
 782							$query.=" and $source.$fkey = '".$_REQUEST["fl_".$fkey]."'";
 783						}
 784					}
 785				} else {
 786					if($form['components'][$fkey]['type']=='hidden'){
 787						$query.=" and $source.$fkey = '".$_REQUEST["fl_".$fkey]."'";
 788					} else {
 789						if($form['components'][$fkey]['type']=='check'){
 790							if($_REQUEST["fl_".$fkey]==$form['components'][$fkey]['checkedValue']){
 791								$query.=" and $source.$fkey = '".$_REQUEST["fl_".$fkey]."'";
 792							}
 793						} else {
 794							if($form['components'][$fkey]['type']=='time'){
 795								if($_REQUEST["fl_".$fkey]!='00:00'){
 796									$query.=" and $source.$fkey = '".$_REQUEST["fl_".$fkey]."'";
 797								}
 798							} else {
 799								if(isset($form['components'][$fkey]['primary'])&&$form['components'][$fkey]['primary']){
 800									$query.=" and $source.$fkey = '".$_REQUEST["fl_".$fkey]."'";
 801								} else {
 802									$query.=" and $source.$fkey LIKE '%".$_REQUEST["fl_".$fkey]."%'";
 803								}
 804							}
 805						}
 806					}
 807				}
 808			}
 809		}
 810
 811		$this->query = $query;
 812
 813		$_REQUEST['queryStatus'] = true;
 814		$_REQUEST['id'] = 0;
 815
 816		$this->fetchAction(0);
 817
 818	}
 819
 820	/**
 821	 * Emula la acción Fetch llamando a show
 822	 *
 823	 * @access	public
 824	 * @param	integer $id
 825	 */
 826	public function fetchAction($id=0){
 827
 828		$this->view = 'index';
 829		$db = DbBase::rawConnect();
 830		if(!$this->query){
 831			return $this->routeTo(array('action' => 'index'));
 832		}
 833
 834		if($id!=='last'){
 835			$id = $this->filter($id, "int");
 836			if($id==0){
 837				$id = 0;
 838			}
 839		}
 840
 841		$this->_lastFetch = $id;
 842
 843		$db->setFetchMode(DbBase::DB_ASSOC);
 844		$rows = $db->fetchAll($this->query);
 845		if(!isset($id)) {
 846			$id = 0;
 847		} else {
 848			$num = $id;
 849		}
 850
 851		//Hubo resultados en el select?
 852		if(!count($rows)){
 853			Flash::notice("No se encontraron resultados en la búsqueda");
 854			foreach($this->form['components'] as $fkey => $rrow){
 855				unset($_REQUEST["fl_".$fkey]);
 856			}
 857			unset($_REQUEST['queryStatus']);
 858			return $this->routeTo(array('action' => 'index'));
 859		}
 860
 861		if($id>=count($rows)){
 862			$num = count($rows)-1;
 863		}
 864		if($num<0){
 865			$num = 0;
 866		}
 867
 868		if($id==='last'){
 869			$num = count($rows)-1;
 870		}
 871
 872		$_REQUEST['id'] = $num;
 873
 874		/**
 875		 * Busca si existe un método o un llamado variable al método
 876		 * beforeFetch, si este método devuelve false termina la ejecución
 877		 * de la acción
 878		 */
 879		if(method_exists($this, 'beforeFetch')){
 880			if($this->beforeFetch()===false){
 881				return null;
 882			}
 883			if(Router::getRouted()){
 884				return null;
 885			}
 886		} else {
 887			if(isset($this->beforeFetch)){
 888				if($this->{$this->beforeFetch}()===false){
 889					return null;
 890				}
 891				if(Router::getRouted()){
 892					return null;
 893				}
 894			}
 895		}
 896
 897		Flash::notice("Visualizando ".($num+1)." de ".count($rows)." registros");
 898
 899		$modelName = EntityManager::getEntityName($this->getSource());
 900		$model = $this->{$modelName};
 901
 902		//especifica el registro que quiero mostrar
 903		$row = $rows[$num];
 904		$conditions = array();
 905		foreach($row as $key => $value){
 906			$conditions[] = $key.' = \''.$value.'\'';
 907		}
 908
 909		$record = $model->findFirst(join(' AND ', $conditions));
 910		foreach($record->getAttributes() as $attribute){
 911			$_REQUEST['fl_'.$attribute] = $record->readAttribute($attribute);
 912		}
 913		$_REQUEST['id'] = $num;
 914
 915		/**
 916		 * Busca si existe un método o un llamado variable al métodp afterDelete
 917		 */
 918		if(method_exists($this, 'afterFetch')){
 919			$this->afterFetch();
 920			if(Router::getRouted()){
 921				return;
 922			}
 923		} else {
 924			if(isset($this->afterFetch)){
 925				$this->{$this->afterFetch}();
 926			}
 927			if(Router::getRouted()){
 928				return;
 929			}
 930		}
 931
 932		return $this->routeTo(array('action' => 'index'));
 933
 934	}
 935
 936	/**
 937	 * Cambia la vista de browse a la vista index
 938	 *
 939	 * @access public
 940	 * @return boolean
 941	 */
 942	public function backAction(){
 943		$this->view = 'index';
 944		$this->keep_action = "";
 945		return $this->routeTo(array('action' => 'index'));
 946	}
 947
 948	/**
 949	 * Emula la acción Browse llamando a show
 950	 *
 951	 * @access public
 952	 */
 953	public function browseAction(){
 954		$this->view = 'browse';
 955		$this->keep_action = "";
 956		return $this->routeTo(array('action' => 'index'));
 957	}
 958
 959	/**
 960	 * Es el metodo principal de StandarForm y es llamado implicitamente
 961	 * para mostrar el formulario y su accion asociada.
 962	 * La propiedad $this->getSource() indica la tabla con la que se va a generar
 963	 * el formulario
 964	 *
 965	 * @access public
 966	 */
 967	public function indexAction(){
 968
 969		if($this->scaffold==true){
 970			$this->form["source"] = $this->getSource();
 971			foreach($this->ignoreList as $ignore){
 972				$this->form['components'][$ignore]['ignore'] = true;
 973			}
 974			Generator::buildForm($this->form, true);
 975		} else {
 976			if(count($this->form)){
 977				$this->form["source"] = $this->getSource();
 978				foreach($this->ignoreList as $ignore){
 979					$this->form['components'][$ignore]['ignore'] = true;
 980				}
 981				Generator::buildForm($this->form);
 982			} else {
 983				throw new StandardFormException('Debe especificar las propiedades del formulario a crear en $this->form ó coloque public $scaffold = true para generar dinámicamente el formulario.');
 984				$this->resetRorm();
 985			}
 986		}
 987	}
 988
 989	/**
 990	 * Elimina los meta-datos del formulario
 991	 *
 992	 * @access public
 993	 */
 994	protected function resetForm(){
 995		$appController = $_REQUEST['controller']."Controller";
 996		$instanceName = Core::getInstanceName();
 997		unset($_SESSION['KUMBIA_CONTROLLERS'][$instanceName][$appController]);
 998	}
 999
1000	/**
1001	 * Guarda un nuevo valor para una relacion detalle del
1002	 * controlador actual
1003	 *
1004	 * @access public
1005	 */
1006	public function _save_helperAction(){
1007
1008		$this->set_response('view');
1009		$db = DbBase::rawConnect();
1010		Generator::scaffold($this->form, $this->scaffold);
1011
1012		$field = $this->form['components'][$this->request('name')];
1013		ActiveRecord::sql_item_sanizite($field['foreignTable']);
1014		ActiveRecord::sql_item_sanizite($field['detailField']);
1015		$db->query("insert into {$field['foreignTable']} ({$field['detailField']})
1016		values ('{$this->request('valor')}')");
1017	}
1018
1019	/**
1020	 * Devuelve los valores actualizados de
1021	 *
1022	 * @access public
1023	 */
1024	public function _get_detailAction(){
1025
1026		$this->set_response('xml');
1027		$db = DbBase::rawConnect();
1028		Generator::scaffold($this->form, $this->scaffold);
1029
1030		$name = $this->request('name');
1031		$com = $this->form['components'][$this->request('name')];
1032
1033		if($com['extraTables']){
1034			ActiveRecord::sql_item_sanizite($com['extraTables']);
1035			$com['extraTables']=','.$com['extraTables'];
1036		}
1037
1038		ActiveRecordUtils::sqlSanizite($com['orderBy']);
1039
1040		if(!$com['orderBy']){
1041			$ordb = $name;
1042		} else {
1043			$ordb = $com['orderBy'];
1044		}
1045		if($com['whereCondition']){
1046			$where = 'where '.$com['whereCondition'];
1047		} else {
1048			$where = '';
1049		}
1050
1051		ActiveRecord::sql_item_sanizite($name);
1052		ActiveRecord::sql_item_sanizite($com['detailField']);
1053		ActiveRecord::sql_item_sanizite($com['foreignTable']);
1054
1055		if($com['column_relation']){
1056			$com['column_relation'] = str_replace(";", "", $com['column_relation']);
1057			$query = "select ".$com['foreignTable'].".".$com['column_relation']." as $name,
1058					".$com['detailField']." from
1059					".$com['foreignTable'].$com['extraTables']." $where order by $ordb";
1060			$db->query($query);
1061		} else {
1062			$query = "select ".$com['foreignTable'].".$name,
1063					  ".$com['detailField']." from ".$com['foreignTable'].$com['extraTables']." $where order by $ordb";
1064			$db->query($query);
1065		}
1066		$xml = new simpleXMLResponse();
1067		while($row = $db->fetchArray()){
1068			if($this->request('valor')==$row[1]){
1069				$xml->add_node(array("value" => $row[0], "text" => $row[1], "selected" => "1"));
1070			} else {
1071				$xml->add_node(array("value" => $row[0], "text" => $row[1], "selected" => "0"));
1072			}
1073		}
1074		$xml->out_response();
1075	}
1076
1077	/**
1078	 * Metodo de ayuda para el componente helpText
1079	 *
1080	 */
1081	public function __autocompleteAction(){
1082
1083	}
1084
1085	/**
1086	 * Metodo de ayuda para el componente helpText
1087	 *
1088	 * @access public
1089	 */
1090	public function __check_value_inAction(){
1091		$this->set_response('xml');
1092		$db = DbBase::rawConnect();
1093		$_REQUEST['condition'] = str_replace(";", "", urldecode($_REQUEST['condition']));
1094		ActiveRecord::sql_item_sanizite($_REQUEST['ftable']);
1095		ActiveRecord::sql_item_sanizite($_REQUEST['dfield']);
1096		ActiveRecord::sql_item_sanizite($_REQUEST['name']);
1097		ActiveRecord::sql_item_sanizite($_REQUEST['crelation']);
1098		$_REQUEST['ftable'] = str_replace(";", "", $_REQUEST['ftable']);
1099		$_REQUEST['dfield'] = str_replace(";", "", $_REQUEST['dfield']);
1100		$_REQUEST['name'] = str_replace(";", "", $_REQUEST['name']);
1101		if($_REQUEST["crelation"]){
1102			$db->query("select ".$_REQUEST["dfield"]." from ".$_REQUEST['ftable']. " where ".$_REQUEST['crelation']." = '".$_REQUEST['value']."'");
1103		} else {
1104			$db->query("select ".$_REQUEST["dfield"]." from ".$_REQUEST['ftable']. " where ".$_REQUEST['name']." = '".$_REQUEST['value']."'");
1105		}
1106		echo "<?xml version='1.0' encoding='iso8859-1'?>\r\n<response>\r\n";
1107		$row = $db->fetchArray();
1108		echo "\t<row num='", $db->numRows(), "' detail='", htmlspecialchars($row[0]), "'/>\r\n";
1109		$db->close();
1110		echo "</response>";
1111	}
1112
1113	/**
1114	 * Indica que un campo tendró un helper de ayuda
1115	 *
1116	 * @access	public
1117	 * @param	string $field
1118	 * @param	string $helper
1119	 */
1120	protected function useHelper($field, $helper=''){
1121		if(!$helper){
1122			$helper = $field;
1123		}
1124		$this->form['components'][$field."_id"]['use_helper'] = $helper;
1125	}
1126
1127	/**
1128	 * Establece el Titulo del Formulario
1129	 *
1130	 * @param string $caption
1131	 */
1132	protected function setFormCaption($caption){
1133		$this->form['caption'] = $caption;
1134	}
1135
1136	/**
1137	 * Indica que un campo seró de tipo imagen
1138	 *
1139	 * @access public
1140	 * @param string $what
1141	 */
1142	protected function setTypeImage($what){
1143		$this->form['components'][$what]['type'] = 'image';
1144	}
1145
1146	/**
1147	 * Indica que un campo seró de tipo numerico
1148	 *
1149	 * @access public
1150	 * @param string $what
1151	 */
1152	protected function setTypeNumeric($what){
1153		$this->form['components'][$what]['type'] = 'text';
1154		$this->form['components'][$what]['valueType'] = 'numeric';
1155	}
1156
1157	/**
1158	 * Indica que un campo seró de tipo Time
1159	 *
1160	 * @access public
1161	 * @param string $what
1162	 */
1163	protected function setTypeTime($what){
1164		$this->form['components'][$what]['type'] = 'time';
1165	}
1166
1167	/**
1168	 * Indica que un campo seró de tipo fecha
1169	 *
1170	 * @access public
1171	 * @param string $what
1172	 */
1173	protected function setTypeDate($what){
1174		$this->form['components'][$what]['type'] = 'text';
1175		$this->form['components'][$what]['valueType'] = 'date';
1176	}
1177
1178	/**
1179	 * Indica que un campo seró de tipo password
1180	 *
1181	 * @access public
1182	 * @param string $what
1183	 */
1184	protected function setTypePassword($what){
1185		$this->form['components'][$what]['type'] = 'password';
1186	}
1187
1188	/**
1189	 * Indica que un campo seró de tipo textarea
1190	 *
1191	 * @access public
1192	 * @param string $what
1193	 */
1194	protected function setTypeTextarea($what){
1195		$this->form['components'][$what]['type'] = 'textarea';
1196	}
1197
1198	/**
1199	 * Indica una lista de campos recibirón entrada solo en mayósculas
1200	 *
1201	 */
1202	protected function setTextUpper(){
1203		if(func_num_args()){
1204			foreach(func_get_args() as $what){
1205				$this->form['components'][$what]['type'] = 'text';
1206				$this->form['components'][$what]['valueType'] = 'textUpper';
1207			}
1208		}
1209	}
1210
1211	/**
1212	 * Crea un combo estótico
1213	 *
1214	 * @param string $what
1215	 * @param string $arr
1216	 */
1217	protected function setComboStatic($what, $arr){
1218		$this->form['components'][$what]['type'] = 'combo';
1219		$this->form['components'][$what]['class'] = 'static';
1220		$this->form['components'][$what]['items'] = $arr;
1221	}
1222
1223	/**
1224	 * Crea un combo Dinamico
1225	 *
1226	 * @access public
1227	 * @param string $what
1228	 */
1229	protected function setComboDynamic($what){
1230		$numberArguments = func_num_args();
1231		$opt = Utils::getParams(func_get_args(), $numberArguments);
1232		$opt['field'] = $opt['field'] ? $opt['field'] : $opt[0];
1233		$opt['relation'] = $opt['relation'] ? $opt['relation'] : $opt[1];
1234		$opt['detail_field'] = $opt['detail_field'] ? $opt['detail_field'] : $opt[2];
1235		$this->form['components'][$opt['field']]['type'] = 'combo';
1236		$this->form['components'][$opt['field']]['class'] = 'dynamic';
1237		$this->form['components'][$opt['field']]['foreignTable'] = $opt['relation'];
1238		$this->form['components'][$opt['field']]['detailField'] = $opt['detail_field'];
1239		if(isset($opt['conditions'])&&$opt['conditions']){
1240			$this->form['components'][$opt['field']]['whereCondition'] = $opt['conditions'];
1241		}
1242		if($opt['column_relation']){
1243			$this->form['components'][$opt['field']]['column_relation'] = $opt['column_relation'];
1244		}
1245		if($opt['column_relation']){
1246			$this->form['components'][$opt['field']]['column_relation'] = $opt['column_relation'];
1247		} else {
1248			$this->form['components'][$opt['field']]['column_relation'] = $opt['id'];
1249		}
1250		if(isset($opt['force_charset'])){
1251			$this->form['components'][$opt['field']]['force_charset'] = $opt['force_charset'];
1252		}
1253	}
1254
1255	/**
1256	 * Crea un Texto de Ayuda de Contexto
1257	 *
1258	 * @access public
1259	 * @param string $what
1260	 */
1261	protected function setHelpContext($what){
1262		$numberArguments = func_num_args();
1263		$opt = Utils::getParams(func_get_args(), $numberArguments);
1264		$field = $opt['field'];
1265		$this->form['components'][$field]['type'] = 'helpContext';
1266	}
1267
1268	/**
1269	 * Especifica que un campo es de tipo E-Mail
1270	 *
1271	 * @access public
1272	 * @param array $fields
1273	 */
1274	protected function setTypeEmail($fields){
1275		if(func_num_args()){
1276			foreach(func_get_args() as $field){
1277				$this->form['components'][$field]['type'] = 'text';
1278				$this->form['components'][$field]['valueType'] = "email";
1279			}
1280		}
1281	}
1282
1283	/**
1284	 * Recibe una lista de campos que no van a ser incluidos en
1285	 * la generación del formulario
1286	 *
1287	 * @access protected
1288	 */
1289	protected function ignore(){
1290		if(func_num_args()){
1291			foreach(func_get_args() as $what){
1292				$this->form['components'][$what]['ignore'] = true;
1293				if(!in_array($what, $this->ignoreList)){
1294					$this->ignoreList[] = $what;
1295				}
1296			}
1297		}
1298	}
1299
1300	/**
1301	 * Permite cambiar el tamaóo (size) de un campo $what a $size
1302	 *
1303	 * @access protected
1304	 * @param string $what
1305	 * @param integer $size
1306	 */
1307	protected function setSize($what, $size){
1308		$this->form['components'][$what]['attributes']['size'] = $size;
1309	}
1310
1311	/**
1312	 * Permite cambiar el tamaóo móximo de caracteres que se puedan
1313	 * digitar en un campo texto
1314	 *
1315	 * @access protected
1316	 * @param string $what
1317	 * @param integer $size
1318	 */
1319	protected function setMaxlength($what, $size){
1320		$this->form['components'][$what]['attributes']['maxlength'] = $size;
1321	}
1322
1323	/**
1324	 * Hace que un campo aparezca en la pantalla de visualización
1325	 *
1326	 * @access protected
1327	 */
1328	protected function notBrowse(){
1329		if(func_num_args()){
1330			foreach(func_get_args() as $what){
1331				$this->form['components'][$what]['notBrowse'] = true;
1332			}
1333		}
1334	}
1335
1336	/**
1337	 * Hace que un campo no aparezca en el reporte PDF
1338	 *
1339	 * @access protected
1340	 * @param string $what
1341	 */
1342	protected function notReport($what){
1343		if(func_num_args()){
1344			foreach(func_get_args() as $what){
1345				$this->form['components'][$what]['notReport'] = true;
1346			}
1347		}
1348	}
1349
1350	/**
1351	 * Cambia la imagen del Formulario. $im es una imagen en img/
1352	 *
1353	 * @access protected
1354	 * @param string $im
1355	 */
1356	protected function setTitleImage($im){
1357		$this->form['titleImage'] = $im;
1358	}
1359
1360	/**
1361	 * Cambia el numero de campos que aparezcan por fila
1362	 * cuando se genere el formulario
1363	 *
1364	 * @access protected
1365	 * @param integer $number
1366	 */
1367	protected function fieldsPerRow($number){
1368		$this->form['fieldsPerRow'] = $number;
1369	}
1370
1371	/**
1372	 * Inhabilita el formulario para insertar
1373	 *
1374	 * @access protected
1375	 */
1376	protected function unableInsert(){
1377		$this->form['unableInsert'] = true;
1378	}
1379
1380	/**
1381	 * Inhabilita el formulario para borrar
1382	 *
1383	 * @access protected
1384	 */
1385	protected function unableDelete(){
1386		$this->form['unableDelete'] = true;
1387	}
1388
1389	/**
1390	 * Inhabilita el formulario para actualizar
1391	 *
1392	 * @access protected
1393	 */
1394	protected function unableUpdate(){
1395		$this->form['unableUpdate'] = true;
1396	}
1397
1398	/**
1399	 * Inhabilita el formulario para consultar
1400	 *
1401	 * @access protected
1402	 */
1403	protected function unableQuery(){
1404		$this->form['unableQuery'] = true;
1405	}
1406
1407	/**
1408	 * Inhabilita el formulario para visualizar
1409	 *
1410	 * @access protected
1411	 */
1412	protected function unableBrowse(){
1413		$this->form['unableBrowse'] = true;
1414	}
1415
1416	/**
1417	 * Inhabilita el formulario para generar reporte
1418	 *
1419	 * @access protected
1420	 */
1421	protected function unableReport(){
1422		$this->form['unableReport'] = true;
1423	}
1424
1425	/**
1426	 * Indica que un campo seró de tipo Hidden
1427	 *
1428	 * @access protected
1429	 * @param array $fields
1430	 */
1431	protected function setHidden($fields){
1432		if(func_num_args()){
1433			foreach(func_get_args() as $field){
1434				$this->form['components'][$field]['type'] = 'hidden';
1435			}
1436		}
1437	}
1438
1439	/**
1440	 * Cambia el Texto Caption de un campo en especial
1441	 *
1442	 * @access protected
1443	 * @param string $fieldName
1444	 * @param string $caption
1445	 */
1446	protected function setCaption($fieldName, $caption){
1447		$this->form['components'][$fieldName]['caption'] = $caption;
1448	}
1449
1450	/**
1451	 * Hace que un campo sea de solo lectura
1452	 *
1453	 * @access protected
1454	 * @param string $fields
1455	 */
1456	protected function setQueryOnly($fields){
1457		if(func_num_args()){
1458			foreach(func_get_args() as $field){
1459				$this->form['components'][$field]['queryOnly'] = true;
1460			}
1461		}
1462	}
1463
1464	/**
1465	 * Cambia el texto de los botones para los formularios
1466	 * estandar setActionCaption('insert', 'Agregar')
1467	 *
1468	 * @access protected
1469	 * @param string $action
1470	 * @param string $caption
1471	 */
1472	protected function setActionCaption($action, $caption){
1473		$this->form['buttons'][$action] = $caption;
1474	}
1475
1476	/**
1477	 * Asigna un atributo a un campo del formulario
1478	 * setAttribute('campo', 'rows', 'valor')
1479	 *
1480	 * @access protected
1481	 * @param string $field
1482	 * @param string $name
1483	 * @param mixed $value
1484	 */
1485	protected function setAttribute($field, $name, $value){
1486		$this->form['components'][$field]['attributes'][$name] = $value;
1487	}
1488
1489
1490	/**
1491	 * Asigna un atributo a un campo del formulario
1492	 * setAttribute('campo', 'rows', 'valor')
1493	 *
1494	 * @access protected
1495	 * @param string $field
1496	 * @param string $event
1497	 * @param string $value
1498	 */
1499	protected function setEvent($field, $event, $value){
1500		$this->form['components'][$field]['attributes']["on".$event] = $value;
1501	}
1502
1503	/**
1504	 * Ejecuta el inicializador para tomar los cambios sin reiniciar el navegador
1505	 *
1506	 * @access public
1507	 */
1508	public function __wakeup(){
1509		if(method_exists($this, "initialize")){
1510			$this->initialize();
1511		}
1512		$this->setPersistance(true);
1513		parent::__wakeup();
1514	}
1515
1516	/**
1517	 * Trata de recuperarse de errores ocurridos en la base de datos
1518	 *
1519	 * @access public
1520	 * @param Exception $e
1521	 */
1522	public function onException($e){
1523		if(is_subclass_of($e, 'DbException')){
1524			if($e instanceof DbConstraintViolationException){
1525				Flash::error('No se puede efectuar la operación ya que el registro se esta usando en otras partes del sistema');
1526				$action = Router::getAction();
1527				$this->RouteTo('action: index');
1528			} else {
1529				throw $e;
1530			}
1531		} else {
1532			throw $e;
1533		}
1534	}
1535
1536}