HTML_QuickForm2
[ class tree: HTML_QuickForm2 ] [ index: HTML_QuickForm2 ] [ all elements ]

Source for file Rule.php

Documentation is available at Rule.php

  1. <?php
  2. /**
  3.  * Base class for HTML_QuickForm2 rules
  4.  *
  5.  * PHP version 5
  6.  *
  7.  * LICENSE:
  8.  *
  9.  * Copyright (c) 2006-2012, Alexey Borzov <avb@php.net>,
  10.  *                          Bertrand Mansion <golgote@mamasam.com>
  11.  * All rights reserved.
  12.  *
  13.  * Redistribution and use in source and binary forms, with or without
  14.  * modification, are permitted provided that the following conditions
  15.  * are met:
  16.  *
  17.  *    * Redistributions of source code must retain the above copyright
  18.  *      notice, this list of conditions and the following disclaimer.
  19.  *    * Redistributions in binary form must reproduce the above copyright
  20.  *      notice, this list of conditions and the following disclaimer in the
  21.  *      documentation and/or other materials provided with the distribution.
  22.  *    * The names of the authors may not be used to endorse or promote products
  23.  *      derived from this software without specific prior written permission.
  24.  *
  25.  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  26.  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  27.  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  28.  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  29.  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  30.  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  31.  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  32.  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
  33.  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  34.  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  35.  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  36.  *
  37.  * @category HTML
  38.  * @package  HTML_QuickForm2
  39.  * @author   Alexey Borzov <avb@php.net>
  40.  * @author   Bertrand Mansion <golgote@mamasam.com>
  41.  * @license  http://opensource.org/licenses/bsd-license.php New BSD License
  42.  * @version  SVN: $Id: Rule.php 325773 2012-05-22 14:45:59Z avb $
  43.  * @link     http://pear.php.net/package/HTML_QuickForm2
  44.  */
  45.  
  46. /**
  47.  * Abstract base class for HTML_QuickForm2 rules
  48.  *
  49.  * This class provides methods that allow chaining several rules together.
  50.  * Its validate() method executes the whole rule chain starting from this rule.
  51.  *
  52.  * @category HTML
  53.  * @package  HTML_QuickForm2
  54.  * @author   Alexey Borzov <avb@php.net>
  55.  * @author   Bertrand Mansion <golgote@mamasam.com>
  56.  * @license  http://opensource.org/licenses/bsd-license.php New BSD License
  57.  * @version  Release: 2.0.0
  58.  * @link     http://pear.php.net/package/HTML_QuickForm2
  59.  */
  60. abstract class HTML_QuickForm2_Rule
  61. {
  62.    /**
  63.     * Constant showing that validation should be run server-side
  64.     * @see  HTML_QuickForm2_Node::addRule()
  65.     */
  66.     const SERVER = 1;
  67.  
  68.    /**
  69.     * Constant showing that validation should be run client-side (on form submit)
  70.     * @see  HTML_QuickForm2_Node::addRule()
  71.     */
  72.     const CLIENT = 2;
  73.  
  74.    /**
  75.     * Constant showing that validation should be run client-side (on form submit and on leaving the field)
  76.     * @see  HTML_QuickForm2_Node::addRule()
  77.     */
  78.     const ONBLUR_CLIENT = 6;
  79.  
  80.    /**
  81.     * A combination of SERVER and CLIENT constants
  82.     * @see  HTML_QuickForm2_Node::addRule()
  83.     */
  84.     const CLIENT_SERVER = 3;
  85.  
  86.    /**
  87.     * A combination of SERVER and ONBLUR_CLIENT constants
  88.     * @see  HTML_QuickForm2_Node::addRule()
  89.     */
  90.     const ONBLUR_CLIENT_SERVER = 7;
  91.  
  92.    /**
  93.     * An element whose value will be validated by this rule
  94.     * @var  HTML_QuickForm2_Node 
  95.     */
  96.     protected $owner;
  97.  
  98.    /**
  99.     * An error message to display if validation fails
  100.     * @var  string 
  101.     */
  102.     protected $message;
  103.  
  104.    /**
  105.     * Configuration data for the rule
  106.     * @var  mixed 
  107.     */
  108.     protected $config;
  109.  
  110.    /**
  111.     * Rules chained to this one via "and" and "or" operators
  112.     *
  113.     * The contents can be described as "disjunctive normal form", where an outer
  114.     * array represents a disjunction of conjunctive clauses represented by inner
  115.     * arrays.
  116.     *
  117.     * @var  array 
  118.     */
  119.     protected $chainedRules = array(array());
  120.  
  121.  
  122.    /**
  123.     * Class constructor
  124.     *
  125.     * @param HTML_QuickForm2_Node $owner   Element to validate
  126.     * @param string               $message Error message to display if validation fails
  127.     * @param mixed                $config  Configuration data for the rule
  128.     */
  129.     public function __construct(HTML_QuickForm2_Node $owner$message ''$config = null)
  130.     {
  131.         $this->setOwner($owner);
  132.         $this->setMessage($message);
  133.         $this->setConfig($config);
  134.     }
  135.  
  136.    /**
  137.     * Merges local configuration with that provided for registerRule()
  138.     *
  139.     * Default behaviour is for global config to override local one, different
  140.     * Rules may implement more complex merging behaviours.
  141.     *
  142.     * @param mixed $localConfig  Local configuration
  143.     * @param mixed $globalConfig Global configuration, usually provided to {@link HTML_QuickForm2_Factory::registerRule()}
  144.     *
  145.     * @return   mixed   Merged configuration
  146.     */
  147.     public static function mergeConfig($localConfig$globalConfig)
  148.     {
  149.         return is_null($globalConfig)$localConfig$globalConfig;
  150.     }
  151.  
  152.    /**
  153.     * Sets configuration data for the rule
  154.     *
  155.     * @param mixed $config Rule configuration data (specific for a Rule)
  156.     *
  157.     * @return   HTML_QuickForm2_Rule 
  158.     * @throws   HTML_QuickForm2_InvalidArgumentException    in case of invalid
  159.     *                configuration data
  160.     */
  161.     public function setConfig($config)
  162.     {
  163.         $this->config = $config;
  164.         return $this;
  165.     }
  166.  
  167.    /**
  168.     * Returns the rule's configuration data
  169.     *
  170.     * @return   mixed   Configuration data (specific for a Rule)
  171.     */
  172.     public function getConfig()
  173.     {
  174.         return $this->config;
  175.     }
  176.  
  177.    /**
  178.     * Sets the error message output by the rule
  179.     *
  180.     * @param string $message Error message to display if validation fails
  181.     *
  182.     * @return   HTML_QuickForm2_Rule 
  183.     * @throws HTML_QuickForm2_InvalidArgumentException if trying to validate
  184.     *        HTML_QuickForm2_Element_InputHidden with a non-empty error message
  185.     *        (e.g. not in Rule chain)
  186.     */
  187.     public function setMessage($message)
  188.     {
  189.         if ($this->owner instanceof HTML_QuickForm2_Element_InputHidden
  190.             && strlen($message)
  191.         {
  192.             throw new HTML_QuickForm2_InvalidArgumentException(
  193.                 "Hidden elements cannot have validation errors"
  194.             );
  195.         }
  196.         $this->message = (string)$message;
  197.         return $this;
  198.     }
  199.  
  200.    /**
  201.     * Returns the error message output by the rule
  202.     *
  203.     * @return   string  Error message
  204.     */
  205.     public function getMessage()
  206.     {
  207.         return $this->message;
  208.     }
  209.  
  210.    /**
  211.     * Sets the element that will be validated by this rule
  212.     *
  213.     * @param HTML_QuickForm2_Node $owner Element to validate
  214.     *
  215.     * @throws   HTML_QuickForm2_InvalidArgumentException    if trying to set
  216.     *        an instance of HTML_QuickForm2_Element_Static as rule owner; if
  217.     *        trying to validate HTML_QuickForm2_Element_InputHidden with a
  218.     *        non-empty error message (e.g. not in Rule chain)
  219.     */
  220.     public function setOwner(HTML_QuickForm2_Node $owner)
  221.     {
  222.         // Very little sense to validate static elements as they're, well, static.
  223.         // If someone comes up with a validation rule for these, he can override
  224.         // setOwner() there...
  225.         if ($owner instanceof HTML_QuickForm2_Element_Static{
  226.             throw new HTML_QuickForm2_InvalidArgumentException(
  227.                 get_class($this' cannot validate Static elements'
  228.             );
  229.         }
  230.         if ($owner instanceof HTML_QuickForm2_Element_InputHidden
  231.             && strlen($this->getMessage())
  232.         {
  233.             throw new HTML_QuickForm2_InvalidArgumentException(
  234.                 "Hidden elements cannot have validation errors"
  235.             );
  236.         }
  237.         if (null !== $this->owner{
  238.             $this->owner->removeRule($this);
  239.         }
  240.         $this->owner = $owner;
  241.     }
  242.  
  243.    /**
  244.     * Adds a rule to the chain with an "and" operator
  245.     *
  246.     * Evaluation is short-circuited, next rule will not be evaluated if the
  247.     * previous one returns false. The method is named this way because "and" is
  248.     * a reserved word in PHP.
  249.     *
  250.     * @param HTML_QuickForm2_Rule $next 
  251.     *
  252.     * @return   HTML_QuickForm2_Rule    first rule in the chain (i.e. $this)
  253.     * @throws   HTML_QuickForm2_InvalidArgumentException    when trying to add
  254.     *            a "required" rule to the chain
  255.     */
  256.     public function and_(HTML_QuickForm2_Rule $next)
  257.     {
  258.         if ($next instanceof HTML_QuickForm2_Rule_Required{
  259.             throw new HTML_QuickForm2_InvalidArgumentException(
  260.                 'and_(): Cannot add a "required" rule'
  261.             );
  262.         }
  263.         $this->chainedRules[count($this->chainedRules- 1][$next;
  264.         return $this;
  265.     }
  266.  
  267.    /**
  268.     * Adds a rule to the chain with an "or" operator
  269.     *
  270.     * Evaluation is short-circuited, next rule will not be evaluated if the
  271.     * previous one returns true. The method is named this way because "or" is
  272.     * a reserved word in PHP.
  273.     *
  274.     * @param HTML_QuickForm2_Rule $next 
  275.     *
  276.     * @return   HTML_QuickForm2_Rule    first rule in the chain (i.e. $this)
  277.     * @throws   HTML_QuickForm2_InvalidArgumentException    when trying to add
  278.     *            a "required" rule to the chain
  279.     */
  280.     public function or_(HTML_QuickForm2_Rule $next)
  281.     {
  282.         if ($next instanceof HTML_QuickForm2_Rule_Required{
  283.             throw new HTML_QuickForm2_InvalidArgumentException(
  284.                 'or_(): Cannot add a "required" rule'
  285.             );
  286.         }
  287.         $this->chainedRules[= array($next);
  288.         return $this;
  289.     }
  290.  
  291.    /**
  292.     * Performs validation
  293.     *
  294.     * The whole rule chain is executed. Note that the side effect of this
  295.     * method is setting the error message on element if validation fails
  296.     *
  297.     * @return   boolean     Whether the element is valid
  298.     */
  299.     public function validate()
  300.     {
  301.         $globalValid = false;
  302.         $localValid  $this->validateOwner();
  303.         foreach ($this->chainedRules as $item{
  304.             /* @var $multiplier HTML_QuickForm2_Rule */
  305.             foreach ($item as $multiplier{
  306.                 if (!($localValid $localValid && $multiplier->validate())) {
  307.                     break;
  308.                 }
  309.             }
  310.             if ($globalValid $globalValid || $localValid{
  311.                 break;
  312.             }
  313.             $localValid = true;
  314.         }
  315.         $globalValid or $this->setOwnerError();
  316.         return $globalValid;
  317.     }
  318.  
  319.    /**
  320.     * Validates the owner element
  321.     *
  322.     * @return   bool    Whether owner element is valid according to the rule
  323.     */
  324.     abstract protected function validateOwner();
  325.  
  326.    /**
  327.     * Sets the error message on the owner element
  328.     */
  329.     protected function setOwnerError()
  330.     {
  331.         if (strlen($this->getMessage()) && !$this->owner->getError()) {
  332.             $this->owner->setError($this->getMessage());
  333.         }
  334.     }
  335.  
  336.    /**
  337.     * Returns the client-side validation callback
  338.     *
  339.     * This essentially builds a Javascript version of validateOwner() method,
  340.     * with element ID and Rule configuration hardcoded.
  341.     *
  342.     * @return   string    Javascript function to validate the element's value
  343.     * @throws   HTML_QuickForm2_Exception   if Rule can only be run server-side
  344.     */
  345.     protected function getJavascriptCallback()
  346.     {
  347.         throw new HTML_QuickForm2_Exception(
  348.             get_class($this' does not implement javascript validation'
  349.         );
  350.     }
  351.  
  352.    /**
  353.     * Returns IDs of form fields that should trigger "live" Javascript validation
  354.     *
  355.     * This returns IDs that are linked to the rule itself.
  356.     *
  357.     * @return array 
  358.     */
  359.     protected function getOwnJavascriptTriggers()
  360.     {
  361.         return $this->owner->getJavascriptTriggers();
  362.     }
  363.  
  364.    /**
  365.     * Returns IDs of form fields that should trigger "live" Javascript validation
  366.     *
  367.     * This returns IDs that are linked to the rule itself and its chained
  368.     * rules. Live validation will be be triggered by 'blur' or 'change' event
  369.     * on any of the elements whose IDs are returned by this method.
  370.     *
  371.     * @return array 
  372.     */
  373.     protected function getJavascriptTriggers()
  374.     {
  375.         $triggers array_flip($this->getOwnJavascriptTriggers());
  376.         foreach ($this->chainedRules as $item{
  377.             /* @var $multiplier HTML_QuickForm2_Rule */
  378.             foreach ($item as $multiplier{
  379.                 foreach ($multiplier->getJavascriptTriggers(as $trigger{
  380.                     $triggers[$trigger= true;
  381.                 }
  382.             }
  383.         }
  384.         return array_keys($triggers);
  385.     }
  386.  
  387.    /**
  388.     * Returns the client-side representation of the Rule
  389.     *
  390.     * This creates an instance of either qf.Rule or qf.LiveRule (depends on
  391.     * $outputTriggers) with initialization parameters:
  392.     *  - callback: {@see getJavascriptCallback()}
  393.     *  - element ID to set error for if validation fails
  394.     *  - error message to set if validation fails
  395.     *  - triggers: {@see getJavascriptTriggers()} (only for
  396.     *    qf.LiveRule when $outputTriggers is true)
  397.     *  - chained rules, array of arrays like in $chainedRules property
  398.     *
  399.     * @param bool $outputTriggers Whether the Rule will be run onblur / onchange
  400.     *
  401.     * @return   string 
  402.     * @throws   HTML_QuickForm2_Exception   if Rule or its chained Rules can only
  403.     *                                        be run server-side
  404.     */
  405.     public function getJavascript($outputTriggers = true)
  406.     {
  407.         HTML_QuickForm2_Loader::loadClass('HTML_QuickForm2_JavascriptBuilder');
  408.  
  409.         $js $this->getJavascriptCallback(",\n\t'" $this->owner->getId()
  410.               . "', " HTML_QuickForm2_JavascriptBuilder::encode($this->getMessage());
  411.  
  412.         $js $outputTriggers && count($triggers $this->getJavascriptTriggers())
  413.               ? 'new qf.LiveRule(' $js ', ' HTML_QuickForm2_JavascriptBuilder::encode($triggers)
  414.               : 'new qf.Rule(' $js;
  415.  
  416.         if (count($this->chainedRules> 1 || count($this->chainedRules[0]> 0{
  417.             $chained = array();
  418.             foreach ($this->chainedRules as $item{
  419.                 $multipliers = array();
  420.                 /* @var $multiplier HTML_QuickForm2_Rule */
  421.                 foreach ($item as $multiplier{
  422.                     $multipliers[$multiplier->getJavascript(false);
  423.                 }
  424.                 $chained['[' implode(",\n"$multipliers']';
  425.             }
  426.             $js .= ",\n\t [" implode(",\n"$chained"]";
  427.         }
  428.         return $js ')';
  429.     }
  430. }
  431. ?>

Documentation generated on Tue, 26 Jun 2012 15:30:28 +0000 by phpDocumentor 1.4.3. PEAR Logo Copyright © PHP Group 2004.