PageRenderTime 60ms CodeModel.GetById 3ms app.highlight 43ms RepoModel.GetById 1ms app.codeStats 1ms

/inc/patForms.php

https://github.com/chregu/fluxcms
PHP | 2819 lines | 1530 code | 301 blank | 988 comment | 211 complexity | cb9862037ff4832c2e8b6578c1e06cc5 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1<?php
   2/**
   3 * patForms form manager class - serialize form elements into any given output format
   4 * using element classes, and build the output via renderer classes.
   5 *
   6 * $Id$
   7 *
   8 * @package		patForms
   9 * @author		Sebastian Mordziol <argh@php-tools.net>
  10 * @author		gERD Schaufelberger <gerd@php-tools.net>
  11 * @author		Stephan Schmidt <schst@php-tools.net>
  12 * @copyright	2003-2004 PHP Application Tools
  13 * @license		LGPL
  14 * @link		http://www.php-tools.net
  15 */
  16
  17/**
  18 * set the include path
  19 */
  20if( !defined( 'PATFORMS_INCLUDE_PATH' ) ) {
  21	define( 'PATFORMS_INCLUDE_PATH', dirname( __FILE__ ). '/patForms' );
  22}
  23
  24
  25
  26/**
  27 * location of global javascripts
  28 */
  29define('PATFORMS_SCRIPT_PATH', PATFORMS_INCLUDE_PATH . '/Scripts');
  30
  31/**
  32 * needs helper methods of patForms_Element
  33 */
  34include_once PATFORMS_INCLUDE_PATH . "/Element.php";
  35 
  36/**
  37 * error definition: renderer base class file (renderers/_base.php) could not 
  38 * be found.
  39 *
  40 * @see	patForms::_createModule()
  41 */									
  42define( "PATFORMS_ERROR_NO_MODULE_BASE_FILE", 1001 );
  43
  44/**
  45 * error definition: the specified renderer could not be found.
  46 *
  47 * @see	patForms::_createModule()
  48 */									
  49define( "PATFORMS_ERROR_MODULE_NOT_FOUND", 1002 );
  50
  51/**
  52 * error definition: the element added via the {@link patForms::addElement()}
  53 * is not an object. Use the {@link patForms::createElement()} method to
  54 * create an element object.
  55 *
  56 * @see	patForms::addElement()
  57 * @see	patForms::createElement()
  58 */									
  59define( "PATFORMS_ERROR_ELEMENT_IS_NO_OBJECT", 1003 );
  60
  61/**
  62 * error definition: generic unexpected error.
  63 */									
  64define( "PATFORMS_ERROR_UNEXPECTED_ERROR", 1004 );
  65
  66/**
  67 * element does not exist
  68 */									
  69define( "PATFORMS_ERROR_ELEMENT_NOT_FOUND", 1012 );
  70
  71/**
  72 * renderer object has not been set - if you want to render the form, you have to
  73 * set a renderer object via the {@link patForms::setRenderer()} method. To create
  74 * a renderer, use the {@link patForms::createRenderer()} method.
  75 *
  76 * @see	patForms::setRenderer()
  77 * @see	patForms::createRenderer()
  78 */									
  79define( "PATFORMS_ERROR_NO_RENDERER_SET", 1013 );
  80
  81/**
  82 * invalid renderer
  83 *
  84 * @see	createRenderer()
  85 */									
  86define( "PATFORMS_ERROR_INVALID_RENDERER", 1014 );
  87
  88/**
  89 * invalid method
  90 *
  91 * @see	setMethod()
  92 */									
  93define( "PATFORMS_ERROR_INVALID_METHOD", 1015 );
  94
  95/**
  96 * Given parameter is not a boolean value
  97 */									
  98define( "PATFORMS_ERROR_PARAMETER_NO_BOOL", 1016 );
  99
 100/**
 101 * Given Static property does not exist
 102 */
 103define( "PATFORMS_ERROR_NO_STATIC_PROPERTY", 1017 );
 104
 105/**
 106 * Unknown event
 107 */
 108define( "PATFORMS_ERROR_UNKNOWN_EVENT", 1018 );
 109
 110/**
 111 * Invalid event handler
 112 */
 113define( "PATFORMS_ERROR_INVALID_HANDLER", 1019 );
 114
 115/**
 116 * Event exists
 117 */
 118define( 'PATFORMS_NOTICE_EVENT_ALREADY_REGISTERED', 1020 );
 119
 120/**
 121 * Invalid storage container
 122 */
 123define( 'PATFORMS_ERROR_INVALID_STORAGE', 1021 );
 124
 125define( 'PATFORMS_NOTICE_ARRAY_EXPECTED', 1022 );
 126
 127define( 'PATFORMS_NOTICE_ATTRIBUTE_NOT_SUPPORTED', 1023 );
 128
 129define( 'PATFORMS_NOTICE_INVALID_OPTION', 1024 );
 130
 131define( 'PATFORMS_ERROR_ATTRIBUTE_REQUIRED', 1025 );
 132
 133define( 'PATFORMS_ERROR_CAN_NOT_VERIFY_FORMAT', 1026 );
 134
 135define( 'PATFORMS_ERROR_METHOD_FOR_MODE_NOT_AVAILABLE', 1027 );
 136
 137
 138/**
 139 * errors apply on translating errors matching current locale settings
 140 */
 141define( 'PATFORMS_NOTICE_VALIDATOR_ERROR_LOCALE_UNDEFINED', 1028 );
 142define( 'PATFORMS_WARNING_VALIDATOR_ERROR_UNDEFINED', 1029 );
 143
 144/**
 145 * Script file could not be loaded
 146 */
 147define( 'PATFORMS_WARNING_SCRIPTFILE_NOT_FOUND', 1040 );
 148
 149/**
 150 * apply the rule before the built-in validation
 151 */
 152define( 'PATFORMS_RULE_BEFORE_VALIDATION', 1 );
 153 
 154/**
 155 * apply the rule after the built-in validation
 156 */
 157define( 'PATFORMS_RULE_AFTER_VALIDATION', 2 );
 158
 159/**
 160 * apply the rule before AND after the built-in validation
 161 */
 162define( 'PATFORMS_RULE_BOTH', 3 );
 163    
 164/**
 165 * attach the observer to the elements
 166 */
 167define( 'PATFORMS_OBSERVER_ATTACH_TO_ELEMENTS', 1 );
 168
 169/**
 170 * attach the observer to the form
 171 */
 172define( 'PATFORMS_OBSERVER_ATTACH_TO_FORM', 2 );
 173
 174/**
 175 * attach the observer to the form and the elements
 176 */
 177define( 'PATFORMS_OBSERVER_ATTACH_TO_BOTH', 3 );
 178
 179/**
 180 * group values should stay nested
 181 */
 182define('PATFORMS_VALUES_NESTED', 0);
 183
 184/**
 185 * group values should be flattened
 186 */
 187define('PATFORMS_VALUES_FLATTENED', 1);
 188
 189/**
 190 * group values should be prefixed
 191 */
 192define('PATFORMS_VALUES_PREFIXED', 2);
 193
 194/**
 195 * Static patForms properties - used to emulate pre-PHP5 static properties.
 196 * 
 197 * @see	setStaticProperty()
 198 * @see	getStaticProperty()
 199 */
 200$GLOBALS['_patForms']	=	array(
 201	'format'			=>	'html',
 202	'locale'			=>	'C',
 203	'customLocales'		=>	array(),
 204	'autoFinalize'		=>	true,
 205	'defaultAttributes'	=>	array(),
 206	'elementCounter'	=>	0,
 207);
 208
 209/**
 210 * patForms form manager class - serialize form elements into any given output format
 211 * using element classes, and build the output via renderer classes.
 212 *
 213 * @package		patForms
 214 * @author		Sebastian Mordziol <argh@php-tools.net>
 215 * @author		gERD Schaufelberger <gerd@php-tools.net>
 216 * @author		Stephan Schmidt <schst@php-tools.net>
 217 * @copyright	2003-2004 PHP Application Tools
 218 * @license		LGPL
 219 * @link		http://www.php-tools.net
 220 * @version		1.0
 221 * @todo		check the clientside functionality, as that can lead to broken pages
 222 */
 223class patForms
 224{
 225   /**
 226	* javascript that will displayed only once
 227	*
 228	* @access	private
 229	* @var		array
 230	*/
 231	var $globalJavascript	=	array();
 232
 233   /**
 234	* javascript that will be displayed once per instance
 235	*
 236	* @access	private
 237	* @var		array
 238	*/
 239	var $instanceJavascript	=	array();
 240
 241   /**
 242	* stores the mode for the form. It defaults to 'default', and is only overwritten if
 243	* set specifically. It is passed on to any elements you create.
 244	*
 245	* @access	private
 246	* @see		setMode()
 247	*/
 248	var $mode	=	'default';
 249	
 250   /**
 251	* XML entities
 252	*
 253	* @access	private
 254	* @see		toXML()
 255	* @todo		This is redundant to the Element's xmlEntities property - find a way to keep this in one place
 256	*/
 257	var $xmlEntities = array(
 258		"<"	=>	"&lt;",
 259		">"	=>	"&gt;",
 260		"&"	=>	"&amp;",
 261		"'"	=>	"&apos;",
 262		'"'	=>	"&quot;"
 263	);
 264
 265   /**
 266	* stores the format for the element. It defaults to 'html', and is only overwritten if
 267	* set specifically. It is passed on to any elements you create.
 268	*
 269	* @access	private
 270	* @see		setFormat()
 271	*/
 272	var $format	=	'html';
 273	
 274   /**
 275	* stores the flag telling the form whether it has been submitted - this is passed on to any
 276	* elements you create.
 277	*
 278	* @access	private
 279	* @see		setSubmitted()
 280	*/
 281	var $submitted	=	false;
 282
 283   /**
 284	* stores the element objects of this form.
 285	* @access	private
 286	* @see		addElement()
 287	*/
 288	var $elements	=	array();
 289	
 290   /**
 291	* stores a renderer
 292	* @access	private
 293	* @see		setRenderer(), renderForm()
 294	*/
 295	var $renderer		=	null;
 296	
 297   /**
 298	* stores the locale to use when adding validation errors for the whole form.
 299	*
 300	* @access	private
 301	* @var		string	$locale
 302	* @see		setLocale()
 303	*/
 304	var	$locale		=	'C';
 305	
 306   /**
 307	* stores custom locale
 308	*
 309	* @access	private
 310	* @var		array
 311	* @see		setLocale()
 312	*/
 313	var	$customLocales = array();
 314
 315   /**
 316	* stores the element name
 317	* @access	private
 318	* @see		getElementName()
 319	*/
 320	var $elementName = 'Form';
 321	
 322   /**
 323	* flag to indicate, whether form should be validated automatically
 324	* by renderForm()
 325	*
 326	* @access	private
 327	* @var		string
 328	* @see		setAutoValidate(), renderForm()
 329	*/
 330	var	$autoValidate	=	false;
 331	
 332   /**
 333	* name of the variable that indicates, whether the form has
 334	* been submitted.
 335	*
 336	* @access	private
 337	* @var		string
 338	* @see		setAutoValidate()
 339	*/
 340	var	$submitVar	=	null;
 341	
 342   /**
 343	* event handlers
 344	*
 345	* @access	private
 346	* @var		array
 347	* @see		registerEventHandler()
 348	* @see		registerEvent()
 349	*/
 350	var	$_eventHandler	=	array();
 351	
 352   /**
 353	* events that can be triggered
 354	*
 355	* @access	private
 356	* @var		array
 357	* @see		registerEventHandler()
 358	* @see		triggerEvent()
 359	* @see		registerEvent()
 360	*/
 361	var	$_validEvents	=	array( 'onInit', 'onSubmit', 'onError', 'onSuccess' );
 362	
 363   /**
 364	* Stores whether the current form has been validated
 365	*
 366	* @access	private
 367	*/
 368	var $validated	=	false;
 369	
 370   /**
 371	* Stores whether the current form is valid or not (after the 
 372	* validation process)
 373	*
 374	* @access	private
 375	*/
 376	var $valid	=	null;
 377	
 378   /**
 379	* Stores the names of all static properties that patForms will use as defaults
 380	* for the properties with the same name on startup.
 381	*
 382	* @access	private
 383	*/
 384	var $staticProperties	=	array(
 385		'format'		=>	'setFormat',
 386		'autoFinalize'	=>	'setAutoFinalize',
 387		'locale'		=>	'setLocale',
 388	);
 389	
 390   /**
 391	* Stores the flag for the autoFinalize feature
 392	*
 393	* @access	private
 394	*/
 395	var $autoFinalize	=	true;
 396
 397   /**
 398	* custom validation rules
 399	* 
 400	* @access	private
 401	* @var		array
 402	*/
 403	var $_rules			=	array();
 404	
 405   /**
 406	* define error codes an messages for the form
 407	*
 408	* Will be set by validation rules that have been
 409	* added to the form.
 410	*
 411	* @access private
 412	* @var	array	$validatorErrorCodes
 413	*/
 414	var	$validatorErrorCodes  =   array();
 415
 416   /**
 417	* stores any validation errors that can occurr during the
 418	* form's validation process.
 419	*
 420	* @access	private
 421	* @var		array	$validationErrors
 422	*/
 423	var	$validationErrors  =   array();
 424	
 425   /**
 426	* next error offset for rules
 427	* @access	private
 428	* @var		integer
 429	*/
 430	var $nextErrorOffset	=	1000;
 431
 432   /**
 433	* Attributes of the form - needed to generate the form tag
 434	*
 435	* @access	private
 436	* @var		array	$attributes
 437	* @see		setAttribute()
 438	*/
 439	var	$attributes	=	array();
 440	
 441   /**
 442	* Attribute definition for the form - defines which attribute the form
 443	* itself supports.
 444	*
 445	* @access	public
 446	*/
 447	var	$attributeDefinition	=	array(	
 448			
 449		'id' =>	array(	
 450			'required'		=>	false,
 451			'format'		=>	'string',
 452			'outputFormats'	=>	array( 'html' ),
 453		),
 454		
 455		'name' => array(	
 456			'required'		=>	true,
 457			'format'		=>	'string',
 458			'outputFormats'	=>	array( 'html' ),
 459		),
 460		
 461		'method' => array(	
 462			'required'		=>	true,
 463			'format'		=>	'string',
 464			'default'		=>	'post',
 465			'outputFormats'	=>	array( 'html' ),
 466		),
 467
 468		'action' => array(	
 469			'required'		=>	true,
 470			'format'		=>	'string',
 471			'outputFormats'	=>	array( 'html' ),
 472		),
 473
 474		'accept' => array(	
 475			'required'		=>	false,
 476			'format'		=>	'string',
 477			'outputFormats'	=>	array( 'html' ),
 478		),
 479
 480		'accept-charset' => array(	
 481			'required'		=>	false,
 482			'format'		=>	'string',
 483			'outputFormats'	=>	array( 'html' ),
 484		),
 485
 486		'enctype' => array(	
 487			'required'		=>	false,
 488			'format'		=>	'string',
 489			'outputFormats'	=>	array( 'html' ),
 490		),
 491
 492		'onreset' => array(	
 493			'required'		=>	false,
 494			'format'		=>	'string',
 495			'outputFormats'	=>	array( 'html' ),
 496		),
 497
 498		'onsubmit' => array(	
 499			'required'		=>	false,
 500			'format'		=>	'string',
 501			'outputFormats'	=>	array( 'html' ),
 502		),
 503
 504		'target' => array(	
 505			'required'		=>	false,
 506			'format'		=>	'string',
 507			'outputFormats'	=>	array( 'html' ),
 508		),
 509	);
 510	
 511   /**
 512	* Stores all available patForms options - these are inherited by all elements
 513	* and their dependencies, like rules.
 514	*
 515	* Short option overview:
 516	*
 517	* - scripts: enable client script integration
 518	*
 519	* @access	public
 520	*/
 521	var $options	=	array(
 522
 523		'scripts'	=>	array(
 524			'enabled'	=>	false,
 525			'params'	=>	array(
 526									'folder'    => PATFORMS_SCRIPT_PATH,
 527									'jsInclude' => false
 528								),
 529		),
 530
 531	);
 532	
 533   /**
 534	* observers of the form
 535	*
 536	* @access	private
 537	* @var		array
 538	*/
 539	var	$observers = array();
 540
 541   /**
 542	* Sets the default attributes that will be inherited by any elements you add to the form.
 543	*
 544	* <b>Note:</b> You have to call this method statically before creating a new form if you use 
 545	* patForm's automatic element creation feature via the {@link createForm()} method, as the
 546	* default attributes cannot be set after an element has been created.
 547	*
 548	* @static
 549	* @access	public
 550	* @param	array	$attributes	The list of attributes to set with key => value pairs.
 551	*/
 552	function setDefaultAttributes( $attributes )
 553	{
 554		patForms::setStaticProperty( 'defaultAttributes', $attributes );
 555	}
 556	
 557   /**
 558	* sets the locale (language) to use for the validation error messages of all elements
 559	* in the form.
 560	*
 561	* @access	public
 562	* @param	string		language code
 563	* @param	string		optional language file
 564	* @return	bool		True on success
 565	*/
 566	function setLocale( $locale, $languageFile = null )
 567	{
 568		if (!is_null($languageFile)) {
 569			$languageData   = patForms::parseLocaleFile($languageFile);
 570
 571			$customLocales = patForms::getStaticProperty('customLocales');
 572			$customLocales[$locale] = $languageData;
 573			patForms::setStaticProperty('customLocales', $customLocales);
 574		}
 575
 576		if( isset( $this ) && is_a( $this, 'patForms' ) ) {
 577			$this->locale = $locale;
 578		
 579			if( !empty( $this->elements ) ) {
 580				$cnt	=	count( $this->elements );
 581				for( $i=0; $i < $cnt; $i++ ) {
 582					$this->elements[$i]->setLocale( $locale );
 583				}
 584			}
 585		} else {
 586			patForms::setStaticProperty('locale', $locale);
 587		}
 588		
 589		return true;
 590	}
 591
 592   /**
 593	* checks, whether a locale is a custom locale
 594	*
 595	* @static
 596	* @access	public
 597	* @param	string		locale name
 598	* @return	boolean
 599	*/
 600	function isCustomLocale($locale)
 601	{
 602		$customLocales = patForms::getStaticProperty('customLocales');
 603		if (isset($customLocales[$locale])) {
 604			return true;
 605		}
 606		return false;
 607	}
 608
 609   /**
 610	* get the custom locale for an element or a rule
 611	*
 612	* @static
 613	* @access	public
 614	* @param	string		locale
 615	* @param	string		key
 616	* @return	array
 617	*/
 618	function getCustomLocale($locale, $key)
 619	{
 620		$customLocales = patForms::getStaticProperty('customLocales');
 621		if (!isset($customLocales[$locale])) {
 622			return false;
 623		}
 624		if (!isset($customLocales[$locale][$key])) {
 625			return false;
 626		}
 627		return $customLocales[$locale][$key];
 628	}
 629	
 630   /**
 631	* parses a locale file
 632	*
 633	* @access	private
 634	* @param	string		filename
 635	* @return	array		locale information
 636	* @todo		add some file checks
 637	*/
 638	function parseLocaleFile($filename)
 639	{
 640		return parse_ini_file($filename, true);
 641	}
 642	
 643   /**
 644	* sets the format of the element - this will be passed on to any elements you create. If you
 645	* have already added some elements when you call this method, it will be passed on to them too.
 646	*
 647	* @access	public
 648	* @param	string	$format	The name of the format you have implemented in your element(s).
 649	* @return	bool	$result	True on success
 650	* @see		setMode()
 651	* @see		format
 652	* @see		serialize()
 653	*/
 654	function setFormat( $format )
 655	{
 656		if( isset( $this ) && is_a( $this, 'patForms' ) )
 657		{
 658			$this->format	=	strtolower( $format );
 659			
 660			if( !empty( $this->elements ) )
 661			{
 662				$cnt	=	count( $this->elements );
 663				for( $i=0; $i < $cnt; $i++ )
 664				{
 665					$this->elements[$i]->setFormat( $format );
 666				}
 667			}
 668		}
 669		else
 670		{
 671			patForms::setStaticProperty( 'format', $format );
 672		}
 673		
 674		return true;
 675	}
 676	
 677   /**
 678	* sets the mode of the form - If you have already added some elements when you call this 
 679	* method, it will be passed on to them too.
 680	*
 681	* @access	public
 682	* @param	string	$mode	The mode to set the form to: default|readonly or any other mode you have implemented in your element class(es). Default is 'default'.
 683	* @see		setMode()
 684	* @see		mode
 685	* @see		serialize()
 686	*/
 687	function setMode( $mode )
 688	{
 689		$this->mode	=	strtolower( $mode );
 690
 691		if( !empty( $this->elements ) )
 692		{
 693			$cnt	=	count( $this->elements );
 694			for( $i=0; $i < $cnt; $i++ )
 695			{
 696				$this->elements[$i]->setMode( $mode );
 697			}
 698		}
 699	}
 700
 701   /**
 702	* sets the current submitted state of the form. Set this to true if you want the form
 703	* to pick up its submitted data. It will pass on this information to all elements that 
 704	* have been added so far, and new ones inherit it too.
 705	*
 706	* @access	public
 707	* @param	bool	$state	True if it has been submitted, false otherwise (default).
 708	* @see		isSubmitted()
 709	* @see		submitted
 710	*/
 711	function setSubmitted( $state )
 712	{
 713		if( $state == true )
 714		{
 715			$eventState	=	$this->triggerEvent( 'Submit' );
 716			if( $eventState === false )
 717				return	false;
 718		}
 719
 720		$this->submitted	=	$state;
 721
 722		if( !empty( $this->elements ) )
 723		{
 724			$cnt	=	count( $this->elements );
 725			for( $i=0; $i < $cnt; $i++ )
 726			{
 727				$this->elements[$i]->setSubmitted( $state );
 728			}
 729		}
 730		
 731		return $state;
 732	}
 733
 734   /**
 735	* sets the method for the request
 736	*
 737	* @access	public
 738	* @param	string	$method		GET or POST
 739	* @see		method
 740	* @uses		setAttribute()
 741	*/
 742	function setMethod( $method )
 743	{
 744		$method	=	strtolower( $method );
 745
 746		if( $method != 'get' && $method != 'post' )
 747		{
 748			return patErrorManager::raiseError( 
 749				PATFORMS_ERROR_INVALID_METHOD, 
 750				'Unknown method "'.$method.'". Currently only GET and POST are supported as patForms methods.'
 751			);
 752		}
 753		$this->setAttribute( 'method', $method );
 754		return	true;
 755	}
 756	
 757   /**
 758	* sets the action for the form
 759	*
 760	* This is a only a wrapper for setAttribute()
 761	*
 762	* @access	public
 763	* @param	string	$action
 764	* @see		setAttribute()
 765	*/
 766	function setAction( $action )
 767	{
 768		return $this->setAttribute( 'action', $action );
 769	}
 770
 771   /**
 772	* Sets the AutoFinalize mode for the form. The AutoFinalize mode will tell patForms to
 773	* finalize all elements after the form has been validated successfully.
 774	*
 775	* @access	public
 776	* @param	boolean	$mode		Whether to activate the AutoFinalize mode (true) or not (false).
 777	* @return	boolean	$success	True if okay, a patError object otherwise.
 778	* @see		finalizeForm()
 779	*/
 780	function setAutoFinalize( $mode )
 781	{
 782		if( !is_bool( $mode ) )
 783		{
 784			return patErrorManager::raiseError(
 785				PATFORMS_ERROR_PARAMETER_NO_BOOL,
 786				'The setAutoFinalize() method requires a boolean value ( true or false ) as parameter.'
 787			);
 788		}
 789	
 790		if( isset( $this ) && is_a( $this, 'patForms' ) )
 791		{
 792			$this->autoFinalize	=	$mode;
 793		}
 794		else
 795		{
 796			patForms::setStaticProperty( 'autoFinalize', $mode );
 797		}
 798
 799		return true;
 800	}
 801	
 802   /**
 803	* Wrapper method that adds a filter to all elements
 804	* of the form at once instead of having to do it for
 805	* each element.
 806	*
 807	* @access	public
 808	* @param	object	&$filter	The filter object to apply
 809	* @see		patForms_Element::applyFilter()
 810	* @todo		add error management and docs once the element's applyFilter method has too
 811	*/
 812	function applyFilter( &$filter )
 813	{
 814		if( empty( $this->elements ) )
 815			return true;
 816			
 817		$cnt = count( $this->elements );
 818
 819		for( $i = 0; $i < $cnt; $i++ )
 820		{
 821			$this->elements[$i]->applyFilter( $filter );
 822		}
 823	}
 824	
 825   /**
 826	* creates a new patForms object and returns it; this method is made to be called statically
 827	* to be able to create a new patForms object from anywhere.
 828	*
 829	* @access	public
 830	* @param	array	$formDefinition		Optional form definition for elements that will be added to the form
 831	* @param	array	$attributes			The attributes to set for the form itself
 832	* @return	object patForms	$form	The new patForms object.
 833	* @todo		it should be possible to pass Rule definitions, so they can be loaded and added	automatically.
 834	*/
 835	function &createForm( $formDefinition = null, $attributes = null )
 836	{
 837		$form	=	&new patForms();
 838		
 839		if( $attributes != null )
 840		{
 841			$form->setAttributes( $attributes );
 842		}
 843		
 844		if( $formDefinition === null )
 845			return	$form;
 846
 847		foreach( $formDefinition as $name => $element )
 848		{
 849			if( !isset( $element["filters"] ) )
 850			{
 851				$element["filters"]	=	null;
 852			}
 853			if( !isset( $element["children"] ) )
 854			{
 855				$element["children"]	=	null;
 856			}
 857			
 858			$el	= &$form->createElement( $name, $element["type"], $element["attributes"], $element["filters"], $element["children"] );
 859			
 860			if( isset( $element["renderer"] ) ) {
 861				$el->setRenderer( $element["renderer"] );
 862			}
 863			
 864			$result		=	$form->addElement( $el );
 865			if (patErrorManager::isError( $result )) {
 866				return	$result;
 867			}
 868		}
 869		return $form;
 870	}
 871
 872   /**
 873	* add a custom validation rule
 874	*
 875	* @access	public
 876	* @param	object patForms_Rule	validation rule
 877	* @param	integer					time to apply rule (before or after built-in validation)
 878	* @param	boolean					apply the rule, even if the form is invalid
 879	* @param	boolean					should form get revalidated (not implemented yet)
 880	* @return	boolean					currently always true
 881	*/
 882	function addRule( &$rule, $time = PATFORMS_RULE_AFTER_VALIDATION, $invalid = false, $revalidate = false )
 883	{
 884		$rule->prepareRule( $this );
 885
 886		$this->_rules[]	=	 array(
 887									'rule'			=>	&$rule,
 888									'time'			=>	$time,
 889									'invalid'		=>	$invalid,
 890									'revalidate'	=>	$revalidate
 891								 );
 892	}
 893	
 894   /**
 895	* patForms PHP5 constructor - processes some intitialization tasks like merging the currently
 896	* set static properties with the internal properties.
 897	*
 898	* @access	public
 899	*/
 900	function __construct()
 901	{
 902		foreach( $this->staticProperties as $staticProperty => $setMethod )
 903		{
 904			$propValue	=	patForms::getStaticProperty( $staticProperty );
 905			if( patErrorManager::isError( $propValue ) )
 906				continue;
 907			
 908			$this->$setMethod( $propValue );
 909		}
 910		
 911		// initialize patForms internal attribute collection
 912		$this->loadAttributeDefaults();
 913	}
 914	
 915   /**
 916	* patForms pre-PHP5 constructor - does nothing for the moment except being a wrapper
 917	* for the PHP5 contructor for older PHP versions support.
 918	*
 919	* @access	public
 920	*/
 921	function patForms()
 922	{
 923		patForms::__construct();
 924	}
 925
 926   /**
 927    * sets a renderer object that will be used to render
 928	* the form.
 929	*
 930	* @access	public
 931	* @param	object		&$renderer	The renderer object
 932	* @return	mixed		$success	True on success, patError object otherwise.
 933	* @see		createRenderer()
 934	* @see		renderForm()
 935	*/
 936	function setRenderer( &$renderer, $args = array() )
 937	{
 938		if( !is_object( $renderer ) )
 939		{
 940			return patErrorManager::raiseError( 
 941				PATFORMS_ERROR_INVALID_RENDERER, 
 942				'You can only set a patForms_Renderer object with the setRenderer() method, "'.gettype( $renderer ).'" given.'
 943			);
 944		}
 945
 946		$this->renderer	=	&$renderer;
 947		
 948		if( isset( $args['includeElements'] ) && $args['includeElements'] === true )
 949		{
 950			// check all elements - there may be some that need
 951			// renderers too, so we give them the same renderer if
 952			// they don't already have one.
 953			$cnt = count( $this->elements );
 954			for( $i = 0; $i < $cnt; $i++ )
 955			{
 956				if( $this->elements[$i]->usesRenderer && !is_object( $this->elements[$i]->renderer ) )
 957				{
 958					$this->elements[$i]->setRenderer( $renderer );
 959				}
 960			}
 961		}
 962		
 963		return true;
 964	}
 965	
 966   /**
 967    * sets a storage container object that will be used to store data
 968	*
 969	* @access	public
 970	* @param	object patForms_Storage
 971	* @see		createStorage()
 972	*/
 973	function setStorage( &$storage )
 974	{
 975		if( !is_object( $storage ) )
 976		{
 977			return patErrorManager::raiseError( 
 978				PATFORMS_ERROR_INVALID_STORAGE, 
 979				'You can only set a patForms_Storage object with the setStorage() method, "'.gettype( $storage ).'" given.'
 980			);
 981		}
 982
 983		$this->registerEventHandlerObject( $storage,
 984											array(
 985													'onInit'	=>	'loadEntry',
 986													'onSuccess'	=>	'storeEntry'
 987												)
 988										);
 989	}
 990
 991   /**
 992	* renders the form with the renderer that was set via the {@link setRenderer()}
 993	* method.
 994	*
 995	* WARNING: This is still in alpha state!
 996	*
 997	* Should this method return a reference??
 998	* The return value could contain large blocks of HTML or large arrays!
 999	* Do we want to copy these?
1000	*
1001	* @access	public
1002	* @param	mixed	$args		arguments that will be passed to the renderer
1003	* @return	mixed	$form		The rendered form, or false if failed.
1004	*/
1005	function renderForm( $args = null )
1006	{
1007		if( $this->renderer === null )
1008		{
1009			return patErrorManager::raiseError( 
1010				PATFORMS_ERROR_NO_RENDERER_SET, 
1011				'Form cannot be rendered, you have to set a renderer first via the setRenderer() method.'
1012			);
1013		}
1014
1015		// form is not submitted, or auto-validation is disabled => render it
1016		if( !$this->isSubmitted() || $this->autoValidate !== true )
1017		{
1018			$this->triggerEvent( 'Init' );
1019			return $this->renderer->render( $this, $args );
1020		}
1021
1022		$this->validateForm();
1023
1024		return $this->renderer->render( $this, $args );
1025	}
1026	
1027   /**
1028	* Validates all elements of the form.
1029	*
1030	* @access	public
1031    * @param    boolean     Flag to indicate, whether form should be validated again, if it already has been validated.
1032	* @return	boolean	    True if all elements could be validated, false otherwise.
1033	* @see		finishForm()
1034	*/
1035	function validateForm( $revalidate = false )
1036	{
1037		if( $this->validated && !$revalidate )
1038			return $this->valid;
1039
1040		$valid	=	true;
1041	
1042		/**
1043		 * validate custom rules
1044		 */
1045		if( !$this->_applyRules( PATFORMS_RULE_BEFORE_VALIDATION ) )
1046		{
1047			$valid	=	false;
1048		}
1049
1050		/**
1051		 * validate elements
1052		 */
1053		if( $valid === true )
1054		{
1055			$cnt	=	count( $this->elements );
1056			for( $i = 0; $i < $cnt; ++$i )
1057			{
1058				if( !$this->elements[$i]->validate() )
1059				{
1060					$valid	=	false;
1061				}
1062			}
1063		}
1064
1065		/**
1066		 * validate custom rules
1067		 */
1068		if( !$this->_applyRules( PATFORMS_RULE_AFTER_VALIDATION, $valid ) )
1069		{
1070			$valid	=	false;
1071		}
1072		
1073		if( $valid === true && $this->autoFinalize === true )
1074			$this->finalizeForm();
1075		
1076		$this->valid	=	$valid;
1077		
1078		$this->validated = true;
1079
1080		if( $valid === true )
1081		{
1082			$this->_announce( 'status', 'validated' );
1083			$event	=	'Success';
1084		}
1085		else
1086		{
1087			$this->_announce( 'status', 'error' );
1088			$event	=	'Error';
1089		}
1090
1091		$this->triggerEvent( $event );
1092		
1093		return $this->valid;
1094	}
1095
1096   /**
1097	* apply rules
1098	*
1099	* @access	private
1100	* @param	integer		time of validation
1101	* @param	boolean		form is valid
1102	* @return	boolean		rules are valid or not
1103	* @todo		add documentation
1104	*/
1105	function _applyRules( $time, $isValid = true )
1106	{
1107		$valid = true;
1108		
1109		$cnt = count( $this->_rules );
1110		for ($i = 0; $i < $cnt; $i++) {
1111			
1112			// wrong time
1113			if (( $this->_rules[$i]['time'] & $time ) != $time) {
1114				continue;
1115			}
1116			if (!$isValid && !$this->_rules[$i]['invalid']) {
1117				continue;
1118			}
1119
1120			$result	=	$this->_rules[$i]['rule']->applyRule( $this, PATFORMS_RULE_AFTER_VALIDATION );
1121			if( $result === false ) {
1122				$valid	=	false;
1123			}
1124		}
1125		return	$valid;
1126	}
1127	
1128   /**
1129	* Finalizes the form by telling each fom element to finalize - finalizing means to
1130	* process any tasks that need to be done after the form has been validated, like
1131	* deleting any temporary files or whatever an element needs to do at that point.
1132	*
1133	* @access	public
1134	* @return	bool	$success	Wether all elements could be finalized
1135	* @see		validateForm()
1136	*/
1137	function finalizeForm()
1138	{
1139		$success	=	true;
1140	
1141		$cnt	=	count( $this->elements );
1142		for( $i = 0; $i < $cnt; ++$i )
1143		{
1144			if( !$this->elements[$i]->finalize() )
1145			{
1146				patErrorManager::raiseWarning(
1147					PATFORMS_ERROR_ELEMENT_NOT_FINALIZED,
1148					'Element "'.$this->elements[$i]->elementName.'" could not be finalized. See the element error messages for more details.'
1149				);
1150				
1151				$success	=	false;
1152			}
1153		}
1154		
1155		return $success;
1156	}
1157	
1158   /**
1159	* creates a new renderer from the patForms renderer collection and returns it.
1160	*
1161	* @access	public
1162	* @param	string						The name of the renderer to create - have a look at the Renderer/ subfolder for a list of available renderers.
1163	* @return	object patForms_Renderer	The renderer object, or error object
1164	*/
1165	function &createRenderer( $name )
1166	{
1167		return	patForms::_createModule( 'Renderer', $name );
1168	}
1169
1170   /**
1171	* creates a new storage container and returns it.
1172	*
1173	* @access	public
1174	* @param	string						The name of the storage to create - have a look at the Storage/ subfolder for a list of available storage containers.
1175	* @return	object patForms_Storage		The storage container, or error object
1176	*/
1177	function &createStorage( $name )
1178	{
1179		return	patForms::_createModule( 'Storage', $name );
1180	}
1181
1182   /**
1183	* Creates a new filter and returns it.
1184	*
1185	* You may pass an array as second parameter that contains
1186	* parameters for the filter. patForms will check for setter methods
1187	* for all keys and set the corresponding values.
1188	*
1189	* This eases the creating of simple filter objects.
1190	*
1191	* @access	public
1192	* @param	string						The name of the filter to create - have a look at the Filter/ subfolder for a list of available filters.
1193	* @param	array						Optional parameters for the filter, if you provide a parameter, make sure the filter implements a set[Paramname]() method.
1194	*										This will be automated with interceptors in the PHP5 version of patForms
1195	* @return	object patForms_Filter		The filter, or error object
1196	*/
1197	function &createFilter( $name, $params = null )
1198	{
1199		$filter	=	&patForms::_createModule( 'Filter', $name );
1200		
1201		if( !is_array( $params ) )
1202		{
1203			return	$filter;
1204		}
1205		
1206		foreach( $params as $param => $value )
1207		{
1208			$setter		=	'set' . ucfirst( $param );
1209			if( method_exists( $filter, $setter ) )
1210			{
1211				$filter->$setter( $value );
1212			}
1213		}
1214		return	$filter;
1215	}
1216
1217   /**
1218	* creates a new rule from the patForms rule collection and returns it.
1219	*
1220	* If your rules are not located in patForms/Rule you have to load and
1221	* instantiate them on your own.
1222	*
1223	* @access	public
1224	* @param	string					The name of the rule to create - have a look at the Rule/ subfolder for a list of available rules.
1225	* @param	string					The id of the rule, needed if the rule uses client side actions.
1226	* @return	object patForms_Rule	The rule object, or error object
1227	*/
1228	static function &createRule( $name, $id = null )
1229	{
1230		$rule	=	&patForms::_createModule( 'Rule', $name );
1231		if( $id != null )
1232		{
1233			$rule->setId( $id );
1234		}
1235		return $rule;
1236	}
1237
1238   /**
1239	* creates a new observer from the patForms observer collection and returns it.
1240	*
1241	* If your observers are not located in patForms/Observer you have to load and
1242	* instantiate them on your own.
1243	*
1244	* @access	public
1245	* @param	string						The name of the observer to create - have a look at the Observer/ subfolder for a list of available observers.
1246	* @return	object patForms_Observer	The observer object, or error object
1247	*/
1248	function &createObserver( $name )
1249	{
1250		$observer = &patForms::_createModule( 'Observer', $name );
1251
1252		return $observer;
1253	}
1254
1255   /**
1256	* creates a new module for patForms
1257	*
1258	* @access	private
1259	* @param	string	$type		type of the module. Possible values are 'Renderer', 'Rule'
1260	* @param	string	$name		The name of the renderer to create - have a look at the renderers/ subfolder for a list of available renderers.
1261	* @return	object	$module		The module object, or an error object
1262	*/
1263	function &_createModule( $type, $name )
1264	{
1265		$baseFile		=	PATFORMS_INCLUDE_PATH . '/'.$type.'.php';
1266		$baseClass	=	'patForms_'.$type;
1267
1268		// if there is an underscore in the module name, we want
1269		// to load the module from a subfolder, so we transform
1270		// all underscores to slashes.
1271		$pathName	=	$name;
1272		if( strstr( $pathName, '_' ) )
1273		{
1274			$pathName	=	str_replace( '_', '/', $name );
1275		}
1276		
1277		$moduleFile		=	PATFORMS_INCLUDE_PATH . '/'.$type.'/'.$pathName.'.php';
1278		$moduleClass	=	'patForms_'.$type.'_'.$name;
1279        if( !class_exists( $baseClass, FALSE ) )
1280		{
1281			if( !file_exists( $baseFile ) )
1282			{
1283				return patErrorManager::raiseError( 
1284					PATFORMS_ERROR_NO_MODULE_BASE_FILE, 
1285					$type .' base file could not be found',
1286					'Tried to load base file in path "'.$baseFile.'"' 
1287				);
1288			}
1289			
1290			include_once $baseFile;
1291		}
1292		
1293		if( !class_exists( $moduleClass, true ) )
1294		{
1295			if( !file_exists( $moduleFile ) )
1296			{
1297				if (defined('PATFORMS_LOCAL_INCLUDE_PATH')) {
1298                    $localModuleClass = PATFORMS_LOCAL_INCLUDE_PATH."/".$type."/".$pathName.".php";   
1299                    if (file_exists($localModuleClass)) {
1300                        include_once $localModuleClass;    
1301                        $module = new $moduleClass();
1302                        return $module;
1303                    }
1304                }
1305                
1306                return patErrorManager::raiseError( 
1307					PATFORMS_ERROR_MODULE_NOT_FOUND, 
1308					$type.' "'.$name.'" file "'.$moduleFile. '" could not be found.'
1309				);
1310			}
1311			include_once $moduleFile;
1312		}
1313
1314		$module	= new $moduleClass();
1315		
1316		return $module;
1317	}
1318
1319   /**
1320	* adds an element to the form - has to be a patForms_Element object. Use the {@link createElement()}
1321	* method to create a new element object. Also takes care of passing on the form's configuration
1322	* including the mode, format and submitted flags to the element.
1323	*
1324	* @access	public
1325	* @param	object	&$element	The patForms_Element object to add to this form.
1326	* @return	bool	$success	True if everything went well, false otherwise.
1327	* @see		patForms_Element
1328	* @see		createElement()
1329	*/
1330	function addElement( &$element )
1331	{
1332		if( !is_object( $element ) )
1333		{
1334			return patErrorManager::raiseError( 
1335				PATFORMS_ERROR_ELEMENT_IS_NO_OBJECT, 
1336				'The addElement() method expects an element object, "'.gettype( $element ).'" given.'
1337			);
1338		}
1339		
1340		if( patErrorManager::isError( $element ) )
1341		{
1342			return patErrorManager::raiseError( 
1343				PATFORMS_ERROR_UNEXPECTED_ERROR, 
1344				'The element you are trying to add is a patError object, and not a patForms element object.'
1345			);
1346		}
1347
1348		if( !$element->getId() ) {
1349			$element->setId( $this->getElementId() );
1350		}
1351		$element->setMode( $this->getMode() );
1352		$element->setFormat( $this->getFormat() );
1353		$element->setSubmitted( $this->isSubmitted() );
1354		$element->setLocale( $this->getLocale() );
1355
1356		$this->elements[]	=&	$element;		
1357		
1358		return true;
1359	}
1360
1361   /**
1362	* replaces an element in the form
1363	*
1364	* @access	public
1365	* @param	object	$element	The patForms_Element object to be replaced
1366	* @param	object	&$replace	The element that will replace the old element
1367	* @return	bool	$success	True if everything went well, false otherwise.
1368	* @see		patForms_Element
1369	* @see		addElement()
1370	*/
1371	function replaceElement( $element, &$replace )
1372	{
1373		if( !is_object( $replace ) ) {
1374			return patErrorManager::raiseError( 
1375				PATFORMS_ERROR_ELEMENT_IS_NO_OBJECT, 
1376				'The addElement() method expects an element object, "'.gettype( $replace ).'" given.'
1377			);
1378		}
1379		
1380		if( patErrorManager::isError( $replace ) ) {
1381			return patErrorManager::raiseError( 
1382				PATFORMS_ERROR_UNEXPECTED_ERROR, 
1383				'The element you are trying to add is a patError object, and not a patForms element object.'
1384			);
1385		}
1386		
1387		if (is_object($element)) {
1388			$element = $element->getId();
1389		}
1390		
1391		$cnt = count($this->elements);
1392		for ($i = 0; $i < $cnt; $i++) {
1393			if ($this->elements[$i]->getId() === $element) {
1394
1395				if( !$replace->getId() ) {
1396					$replace->setId( $this->getElementId() );
1397				}
1398				$replace->setMode( $this->getMode() );
1399				$replace->setFormat( $this->getFormat() );
1400				$replace->setSubmitted( $this->isSubmitted() );
1401				$replace->setLocale( $this->getLocale() );
1402	
1403				$this->elements[$i] = &$replace;
1404				return true;
1405			}
1406			
1407			// the current element is a container
1408			if (method_exists($this->elements[$i], 'replaceElement')) {
1409				$result = $this->elements[$i]->replaceElement($element, $replace);
1410				if ($result === true) {
1411					return $result;
1412				}
1413			}
1414		}
1415		
1416		return false;
1417	}
1418
1419   /**
1420	* Get an element by its name.
1421	*
1422	* @access	public
1423	* @param	string	$name	name of the element
1424	* @return	object			patForms element
1425	* @deprecated	please use patForms::getElementByName() instead
1426	*/
1427	function &getElement( $name )
1428	{
1429		return $this->getElementByName( $name );
1430	}
1431
1432   /**
1433	* Get an element by its name.
1434	*
1435	* @access	public
1436	* @param	string	$name	name of the element
1437	* @return	mixed			either a patForms element or an array containing patForms elements
1438	* @see		getElementById()
1439	*/
1440	function &getElementByName( $name )
1441	{
1442		if( $name == '__form' ) {
1443			return $this;
1444		}
1445		
1446		$elements = array();
1447		$cnt      = count( $this->elements );
1448		for ($i = 0; $i < $cnt; $i++) {
1449			if ($this->elements[$i]->getName() == $name) {
1450				$elements[]	= &$this->elements[$i];
1451				continue;
1452			}
1453			if (method_exists($this->elements[$i], 'getElementById')) {
1454				patErrorManager::pushExpect(PATFORMS_ERROR_ELEMENT_NOT_FOUND);
1455				$result = &$this->elements[$i]->getElementByName($name);
1456				patErrorManager::popExpect();
1457				if (!patErrorManager::isError($result)) {
1458					if (is_array($result)) {
1459						$cnt2 = count( $result );
1460						for ($j = 0; $j < $cnt2; $j++) {
1461							$elements[]	= &$result[$j];
1462						}
1463					} else {
1464						$elements[]	= &$result;
1465					}
1466				}
1467			}
1468		}
1469		
1470		switch( count( $elements ) )
1471		{
1472			case	0:
1473                $r = patErrorManager::raiseError( 
1474					PATFORMS_ERROR_ELEMENT_NOT_FOUND, 
1475					'Element '.$name.' could not be found.'
1476				);
1477				return $r; 
1478				break;
1479			case	1:
1480				return	$elements[0];
1481				break;
1482			default:
1483				return	$elements;
1484				break;
1485		}
1486	}
1487
1488   /**
1489	* Get an element by its id.
1490	*
1491	* @access	public
1492	* @param	string	$id		id of the element
1493	* @return	object			patForms element
1494	*/
1495	function &getElementById( $id )
1496	{
1497		$cnt	=	count( $this->elements );
1498		for( $i = 0; $i < $cnt; $i++ )
1499		{
1500			if( $this->elements[$i]->getId() == $id ) {
1501				return $this->elements[$i];
1502			}
1503			if (method_exists($this->elements[$i], 'getElementById')) {
1504				patErrorManager::pushExpect(PATFORMS_ERROR_ELEMENT_NOT_FOUND);
1505				$result = &$this->elements[$i]->getElementById($id);
1506				patErrorManager::popExpect();
1507				if (!patErrorManager::isError($result)) {
1508					return $result;
1509				}
1510			}
1511		}
1512		return patErrorManager::raiseError( 
1513			PATFORMS_ERROR_ELEMENT_NOT_FOUND, 
1514			'Element '.$name.' could not be found.'
1515		);
1516	}
1517
1518   /**
1519	* Get all elements of the form
1520	*
1521	* @access	public
1522	* @return	array	all elements of the form
1523	*/
1524	function &getElements()
1525	{
1526		return	$this->elements;
1527	}
1528
1529   /**
1530	* Creates a new form element and returns a reference to it.
1531	*
1532	* The optional $filters array has to be in the following format:
1533	*
1534	* <pre>
1535	* array(
1536	*       array(
1537	*              'filter' => 'Multiplier',
1538	*              'params' => array( 'multiplier' => 6 )
1539	*            )
1540	*	   )
1541	* </pre>
1542	*
1543	* @access	public
1544	* @param	string	$name		The name of the element
1545	* @param	string	$type		The type of the element; for a list of possible elements, have a look at the elements/ subfolder of the patForms package.
1546	* @param	array	$attributes	Attributes for the element
1547	* @param	array	$filters	Optional filters that will be applied
1548	* @return	object patForms_Element	$element	The element object, or patError if failed.
1549	*/
1550	function &createElement( $name, $type, $attributes, $filters = null, $children = null )
1551	{
1552		$element =& patForms::_createModule( 'Element', $type );
1553		if( patErrorManager::isError( $element ) )
1554		{
1555			return	$element;
1556		}
1557
1558		$attributes['name']	=	$name;
1559		if( !isset( $attributes['id'] ) ) {
1560			$attributes['id'] = patForms::getElementId();
1561		}
1562		
1563		// add default attributes - do this the 'silent' way be checking whether
1564		// the element supports the given attribute, as the element throws a notice
1565		// if it does not support it - this is not expected from default attributes.
1566		foreach( patForms::getStaticProperty( 'defaultAttributes' ) as $attributeName => $attributeValue ) 
1567		{
1568			if( !$element->hasAttribute( $attributeName ) )
1569			{
1570				continue;
1571			}
1572			
1573			$element->setAttribute( $attributeName, $attributeValue );
1574		}
1575	
1576		// set the given attributes normally
1577		$success = $element->setAttributes( $attributes );
1578		if( patErrorManager::isError( $success ) )
1579		{
1580			return $success;
1581		}
1582
1583		if (is_array($children)) {
1584			foreach ($children as $child) {
1585				$childName = $child['attributes']['name'];
1586				
1587				$childEl = &patForms::createElement($childName, $child['type'], $child['attributes']);
1588				if( isset( $child["renderer"] ) ) {
1589					$childEl->setRenderer( $child["renderer"] );
1590				}
1591				
1592				$element->addElement($childEl);
1593			}
1594		}
1595		
1596		$success = $element->_init();
1597		if( patErrorManager::isError( $success ) ) {
1598			return $success;
1599		}
1600		
1601		// if we don't have any filters to add, we're done
1602		if( !is_array( $filters ) )
1603		{
1604			return $element;
1605		}
1606		
1607		$cnt	=	count( $filters );
1608		for( $i = 0; $i < $cnt; $i++ )
1609		{
1610			$params =	isset( $filters[$i]['params'] ) ? $filters[$i]['params'] : null;
1611			$filter	=	&patForms::createFilter( $filters[$i]['filter'], $params );
1612			if( patErrorManager::isError( $filter ) )
1613			{
1614				continue;
1615			}
1616			$element->applyFilter( $filter );
1617		}
1618		
1619		return $element;
1620	}
1621	
1622   /**
1623	* retrieves the validation errors from all elements in the form. Use this if the validateForm()
1624	* method returned false.
1625	*
1626	* @access	public
1627	* q
1628	* @return	array	$errors	Array containing an array with validation errors for each element in the form.
1629	* @todo		replace	__form with the name of the form, once attributes are implemented
1630	*/
1631	function getValidationErrors($withElements = true)
1632	{
1633		$found	=	false;
1634		$errors	=	array();
1635		
1636		if( !empty( $this->validationErrors ) )
1637		{
1638			$errors['__form']	=	$this->validationErrors;
1639			$found = true;
1640		}
1641		
1642		if ($withElements === false) {
1643			return $errors;
1644		}
1645		
1646		$cnt = count( $this->elements );
1647		for( $i = 0; $i < $cnt; ++$i )
1648		{
1649			$name	=	$this->elements[$i]->getAttribute( 'name' );
1650			if( $name === false )
1651			{
1652				continue;
1653			}
1654			
1655			$elementErrors = $this->elements[$i]->getValidationErrors();
1656			
1657			if( empty( $elementErrors ) )
1658				continue;
1659				
1660			$errors[$name]	=	$elementErrors;
1661			$found = true;
1662		}
1663		
1664		if( $found )
1665			return $errors;
1666			
1667		return false;
1668	}
1669	
1670   /**
1671	* retrieves the values for all elements in the form.
1672	*
1673	* @access	public
1674	* @param	array		desired fields
1675	* @param	integer		Mode that should be used to return values in groups
1676	* @return	array		The values for all elements, as elementname => elementvalue.
1677	*
1678	* @todo		remove the ugly Group check and replace with something better
1679	* @todo		implement something similar for getValidation errors
1680	*/
1681	function getValues( $fields = null, $type = PATFORMS_VALUES_NESTED )
1682	{
1683		$values	=	array();
1684		
1685		$cnt = count( $this->elements );
1686		for( $i = 0; $i < $cnt; ++$i )
1687		{
1688			$name	=	$this->elements[$i]->getAttribute( 'name' );
1689			if( $name === false ) {
1690				continue;
1691			}
1692			
1693			if( is_array( $fields ) && !in_array( $name, $fields ) ) {
1694				continue;
1695			}
1696
1697			$tmpVal = $this->elements[$i]->getValue();
1698			if (!is_array($tmpVal) || $this->elements[$i]->elementName != 'Group') {
1699				$values[$name] = $tmpVal;
1700				continue;			
1701			}
1702			
1703			switch ($type) {
1704				case PATFORMS_VALUES_FLATTENED:
1705					$values = array_merge($values, $tmpVal);
1706					break;
1707				case PATFORMS_VALUES_PREFIXED:
1708					foreach ($tmpVal as $key => $val) {
1709						$values[$name.'_'.$key] = $val;
1710					}
1711					break;
1712				case PATFORMS_VALUES_NESTED:
1713				default:
1714					$values[$name] = $tmpVal;
1715					break;
1716
1717			}
1718		}
1719		return $values;
1720	}
1721	
1722   /**
1723	* sets the values for all elements in the form. Use this to fill your form with external
1724	* data, like a db query. Caution: if you do this and set the form to submitted, the values
1725	* will be overwritten by any values present in the $_GET or $_POST variables.
1726	*
1727	* @access	public
1728	* @param	array	$values	The values for all elements, as elementname => elementvalue.
1729	*/
1730	function setValues( $values, $overrideUserInput = false )
1731	{
1732		patErrorManager::pushExpect(PATFORMS_ERROR_ELEMENT_NOT_FOUND);
1733        if(is_array($values)) {
1734            foreach ($values as $elName => $value) {
1735                $el = &$this->getElementByName($elName);
1736                if (patErrorManager::isError($el)) {
1737                    continue;
1738                }
1739                if ($overrideUserInput === true) {
1740                    $el->setValue($value);
1741                } else {
1742                    $el->setDefaultValue($value);
1743                }
1744            }
1745        }
1746		patErrorManager::popExpect();
1747		return true;
1748	}
1749	
1750   /**
1751	* retrieves the current mode of the form
1752	*
1753	* @access	public
1754	* @return	string	$mode	The current form mode
1755	* @see		setMode()
1756	* @see		$mode
1757	*/
1758	function getMode()
1759	{
1760		return $this->mode;
1761	}
1762	
1763   /**
1764	* returns the locale that is currently set for the form.
1765	*
1766	* @access	public
1767	* @return	string	$locale	The locale.
1768	* @see		setLocale()
1769	* @see		$locale
1770	*/
1771	function getLocale()
1772	{
1773		return $this->locale;
1774	}
1775	
1776   /**
1777	* retrieves the current format of the form
1778	*
1779	* @access	public
1780	* @return	string	$format	The current form format
1781	* @see		setFormat()
1782	* @see		format
1783	*/
1784	function getFormat()
1785	{
1786		return $this->format;
1787	}
1788	
1789   /**
1790	* retrieves the current method of the form
1791	*
1792	* @access	public
1793	* @return	string	$method	The request method
1794	* @see		setMethod()
1795	*/
1796	function getMethod()
1797	{
1798		return $this->getAttribute( 'method' );
1799	}
1800	
1801   /**
1802	* retrieves the current action of the form
1803	*
1804	* @access	public
1805	* @return	string	$action		Action of the form
1806	* @see		setAction()
1807	*/
1808	function getAction()
1809	{
1810		$action = $this->getAttribute( 'action' );
1811		if( !empty( $action ) )
1812			return $action;
1813		return	$_SERVER['PHP_SELF'];
1814	}
1815	
1816   /**
1817	* adds an atribute to the form's attribute collection. If the attribute
1818	* already exists, it is overwritten.
1819	*
1820	* @access	public
1821	* @param	string	$attributeName	The name of the attribute to add
1822	* @param	string	$atributeValue	The value of the attribute
1823	*/
1824	function setAttribute( $attributeName, $attributeValue )
1825	{
1826		if( !isset( $this->attributeDefinition[$attributeName] ) )
1827		{
1828			patErrorManager::raiseNotice( 
1829				PATFORMS_NOTICE_ATTRIBUTE_NOT_SUPPORTED, 
1830				"The attribute '".$attributeName."' is not supported by the form, skipped it. [".get_class( $this )."]" 
1831			);
1832			return true;
1833		}
1834		
1835		$this->attributes[$attributeName]	=	$attributeValue;
1836		
1837		return true;
1838	}
1839	
1840   /**
1841	* adds several attributes at once to the form's attribute collection.
1842	* Any existing attributes will be overwritten.
1843	*
1844	* @access	public
1845	* @param	array	$attributes	The attributes to add
1846	* @see		setAttribute()
1847	*/
1848	function setAttributes( $attributes )
1849	{
1850		if( !is_array( $attributes ) )
1851		{
1852			return patErrorManager::raiseError( 
1853				PATFORMS_NOTICE_ARRAY_EXPECTED, 
1854				"setAttributes: array expected"
1855			);
1856		}
1857	
1858		foreach( $attributes as $attributeName => $attributeValue )
1859		{
1860			$this->setAttribute( $attributeName, $attributeValue );
1861		}
1862		
1863		return true;
1864	}
1865
1866   /**
1867	* retrieves the value of a form attribute.
1868	*
1869	* @access	public
1870	* @param	string	$attribute	The name of the attribute to retrieve
1871	* @return	mixed	$attributeValue	The value of the attribute, or false if it does not exist in the attributes collection.
1872	* @see		setAttribute()
1873	*/
1874	function getAttribute( $attribute )
1875	{
1876		if( !isset( $this->attributes[$attribute] ) )
1877		{
1878			return false;
1879		}
1880		
1881		return $this->attributes[$attribute];
1882	}
1883	
1884   /**
1885	* retrieves all attributes of the form, or only the specified attributes.
1886	*
1887	* @access	public
1888	* @param	array	$attributes	Optional: The names of the attributes to retrieve. Only the attributes that exist will be returned.
1889	* @return	array	$result		The attributes
1890	* @see		getAttribute()
1891	*/
1892	function getAttributes( $attributes = array() )
1893	{
1894		if( empty( $attributes ) )
1895		{
1896			return $this->attributes;
1897		}
1898		
1899		$result	=	array();
1900		foreach( $attributes as $attribute )
1901		{
1902			if( $attributeValue = $this->getAttribute( $attribute ) )
1903			{
1904				$result[$attribute]	=	$attributeValue;
1905			}
1906		}
1907		
1908		return $result;
1909	}
1910	
1911   /**
1912	* Loads the default attribute values into the attributes collection. Done directly
1913	* on startup (in the consructor).
1914	*
1915	* The action defaults to the path of the current script, with session
1916	* ID appended automatically, if SID has been defined.
1917	*
1918	* @access	public
1919	* @return	bool	$success	Always returns true.
1920	* @see		$attributeDefaults
1921	*/
1922	function loadAttributeDefaults()
1923	{
1924		foreach( $this->attributeDefinition as $attributeName => $attributeDef )
1925		{
1926			if( isset( $attributeDef['default'] ) )
1927			{
1928				$this->attributes[$attributeName]	=	$attributeDef['default'];
1929			}
1930			
1931			if( $attributeName == 'action' )
1932			{
1933				$this->attributes[$attributeName]	=	$_SERVER['PHP_SELF'];
1934				/**
1935				 * session has been started, append session ID
1936				 */
1937				if( defined( 'SID' ) )
1938					$this->attributes[$attributeName] .= '?' . SID;
1939			}
1940		}
1941		
1942		return true;
1943	}
1944
1945   /**
1946	* retrieves the form's current submitted state.
1947	*
1948	* If autoValidate is used, it will check for the submitVar and
1949	* set the submitted flag accordingly
1950	*
1951	* @access	public
1952	* @return	bool	$state	True if it has been submitted, false otherwise.
1953	* @see		setSubmitted(), setAutoValidate()
1954	* @see		submitted
1955	*/
1956	function isSubmitted()
1957	{
1958		if( $this->submitted === true )
1959		{
1960			return true;
1961		}
1962		
1963		if( !isset( $this->submitVar ) )
1964		{
1965			return	false;
1966		}
1967
1968		if( !$this->autoValidate )
1969		{
1970			return	false;
1971		} 
1972
1973		if( isset( $_GET[$this->submitVar] ) || isset( $_POST[$this->submitVar] ) )
1974		{
1975			$this->setSubmitted( true );
1976		}
1977		
1978		return $this->submitted;
1979	}
1980	
1981   /**
1982	* Creates a new patForms_Creator object
1983	*
1984	* @static
1985	* @access	public
1986	* @return	object	$creator	The creator object, or a patError object on failure
1987	*/
1988	function createCreator( $type )
1989	{
1990		return patForms::_createModule( 'Creator', $type );
1991	}
1992	
1993   /**
1994	* get the element name of the form
1995	*
1996	* @access	public
1997	* @return	string	name of the form
1998	*/
1999	function getElementName()
2000	{
2001		return $this->elementName;
2002	}
2003
2004   /**
2005	* get next error offset
2006	*
2007	* @access	public
2008	* @return	integer
2009	*/
2010	function getErrorOffset( $requiredCodes = 100 )
2011	{
2012		$offset					=	$this->nextErrorOffset;
2013		$this->nextErrorOffset	=	$this->nextErrorOffset + $requiredCodes;
2014		return	 $offset;
2015	}
2016	
2017   /**
2018	* add error codes and messages for validator method
2019	*
2020	* @access	public
2021	* @param	array	defintions
2022	* @param	integer	offset for the error codes
2023	*/
2024	function addValidatorErrorCodes( $defs, $offset = 1000 )
2025	{
2026		foreach( $defs as $lang => $codes )
2027		{
2028			if( !isset( $this->validatorErrorCodes[$lang] ) )
2029			{
2030				$this->validatorErrorCodes[$lang]	=	array();
2031			}
2032			
2033			foreach( $codes as $code => $message )
2034			{
2035				$this->validatorErrorCodes[$lang][($offset+$code)]	=	$message;
2036			}
2037		}
2038	}
2039
2040   /**
2041	* add a validation error to the whole form
2042	*
2043	* This can be achieved by adding a validation rule to the form.
2044	*
2045	* @access	public
2046	* @param	integer	$code
2047	* @param	array	$vars	fill named placeholder with values
2048	* @return 	boolean $result	true on success
2049	* @see		addRule()
2050	*/
2051    function addValidationError( $code, $vars = array() )
2052    {
2053		$error		=	false;
2054		$lang		=	$this->locale;
2055		$element	=	$this->getElementName();
2056		
2057		// find error message for selected language
2058		while( true )
2059		{
2060			// error message matches language code
2061			if( isset( $this->validatorErrorCodes[$lang][$code] ) )
2062			{
2063				$error	=	array( "element" => $element, "code" => $code, "message" => $this->validatorErrorCodeā€¦

Large files files are truncated, but you can click here to view the full file