PageRenderTime 68ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/propel_14/vendor/propel/contrib/pat/patForms.php

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