web/lib/Zend/Form.php
changeset 64 162c1de6545a
parent 19 1c2f13fd785c
child 68 ecaf28ffe26e
equal deleted inserted replaced
63:5b37998e522e 64:162c1de6545a
       
     1 <?php
       
     2 /**
       
     3  * Zend Framework
       
     4  *
       
     5  * LICENSE
       
     6  *
       
     7  * This source file is subject to the new BSD license that is bundled
       
     8  * with this package in the file LICENSE.txt.
       
     9  * It is also available through the world-wide-web at this URL:
       
    10  * http://framework.zend.com/license/new-bsd
       
    11  * If you did not receive a copy of the license and are unable to
       
    12  * obtain it through the world-wide-web, please send an email
       
    13  * to license@zend.com so we can send you a copy immediately.
       
    14  *
       
    15  * @category   Zend
       
    16  * @package    Zend_Form
       
    17  * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
       
    18  * @license    http://framework.zend.com/license/new-bsd     New BSD License
       
    19  */
       
    20 
       
    21 /** @see Zend_Validate_Interface */
       
    22 require_once 'Zend/Validate/Interface.php';
       
    23 
       
    24 /**
       
    25  * Zend_Form
       
    26  *
       
    27  * @category   Zend
       
    28  * @package    Zend_Form
       
    29  * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
       
    30  * @license    http://framework.zend.com/license/new-bsd     New BSD License
       
    31  * @version    $Id: Form.php 23429 2010-11-22 23:06:46Z bittarman $
       
    32  */
       
    33 class Zend_Form implements Iterator, Countable, Zend_Validate_Interface
       
    34 {
       
    35     /**#@+
       
    36      * Plugin loader type constants
       
    37      */
       
    38     const DECORATOR = 'DECORATOR';
       
    39     const ELEMENT = 'ELEMENT';
       
    40     /**#@-*/
       
    41 
       
    42     /**#@+
       
    43      * Method type constants
       
    44      */
       
    45     const METHOD_DELETE = 'delete';
       
    46     const METHOD_GET    = 'get';
       
    47     const METHOD_POST   = 'post';
       
    48     const METHOD_PUT    = 'put';
       
    49     /**#@-*/
       
    50 
       
    51     /**#@+
       
    52      * Encoding type constants
       
    53      */
       
    54     const ENCTYPE_URLENCODED = 'application/x-www-form-urlencoded';
       
    55     const ENCTYPE_MULTIPART  = 'multipart/form-data';
       
    56     /**#@-*/
       
    57 
       
    58     /**
       
    59      * Form metadata and attributes
       
    60      * @var array
       
    61      */
       
    62     protected $_attribs = array();
       
    63 
       
    64     /**
       
    65      * Decorators for rendering
       
    66      * @var array
       
    67      */
       
    68     protected $_decorators = array();
       
    69 
       
    70     /**
       
    71      * Default display group class
       
    72      * @var string
       
    73      */
       
    74     protected $_defaultDisplayGroupClass = 'Zend_Form_DisplayGroup';
       
    75 
       
    76     /**
       
    77      * Form description
       
    78      * @var string
       
    79      */
       
    80     protected $_description;
       
    81 
       
    82     /**
       
    83      * Should we disable loading the default decorators?
       
    84      * @var bool
       
    85      */
       
    86     protected $_disableLoadDefaultDecorators = false;
       
    87 
       
    88     /**
       
    89      * Display group prefix paths
       
    90      * @var array
       
    91      */
       
    92     protected $_displayGroupPrefixPaths = array();
       
    93 
       
    94     /**
       
    95      * Groups of elements grouped for display purposes
       
    96      * @var array
       
    97      */
       
    98     protected $_displayGroups = array();
       
    99 
       
   100     /**
       
   101      * Global decorators to apply to all elements
       
   102      * @var null|array
       
   103      */
       
   104     protected $_elementDecorators;
       
   105 
       
   106     /**
       
   107      * Prefix paths to use when creating elements
       
   108      * @var array
       
   109      */
       
   110     protected $_elementPrefixPaths = array();
       
   111 
       
   112     /**
       
   113      * Form elements
       
   114      * @var array
       
   115      */
       
   116     protected $_elements = array();
       
   117 
       
   118     /**
       
   119      * Array to which elements belong (if any)
       
   120      * @var string
       
   121      */
       
   122     protected $_elementsBelongTo;
       
   123 
       
   124     /**
       
   125      * Custom form-level error messages
       
   126      * @var array
       
   127      */
       
   128     protected $_errorMessages = array();
       
   129 
       
   130     /**
       
   131      * Are there errors in the form?
       
   132      * @var bool
       
   133      */
       
   134     protected $_errorsExist = false;
       
   135 
       
   136     /**
       
   137      * Has the form been manually flagged as an error?
       
   138      * @var bool
       
   139      */
       
   140     protected $_errorsForced = false;
       
   141 
       
   142     /**
       
   143      * Form order
       
   144      * @var int|null
       
   145      */
       
   146     protected $_formOrder;
       
   147 
       
   148     /**
       
   149      * Whether or not form elements are members of an array
       
   150      * @var bool
       
   151      */
       
   152     protected $_isArray = false;
       
   153 
       
   154     /**
       
   155      * Form legend
       
   156      * @var string
       
   157      */
       
   158     protected $_legend;
       
   159 
       
   160     /**
       
   161      * Plugin loaders
       
   162      * @var array
       
   163      */
       
   164     protected $_loaders = array();
       
   165 
       
   166     /**
       
   167      * Allowed form methods
       
   168      * @var array
       
   169      */
       
   170     protected $_methods = array('delete', 'get', 'post', 'put');
       
   171 
       
   172     /**
       
   173      * Order in which to display and iterate elements
       
   174      * @var array
       
   175      */
       
   176     protected $_order = array();
       
   177 
       
   178     /**
       
   179      * Whether internal order has been updated or not
       
   180      * @var bool
       
   181      */
       
   182     protected $_orderUpdated = false;
       
   183 
       
   184     /**
       
   185      * Sub form prefix paths
       
   186      * @var array
       
   187      */
       
   188     protected $_subFormPrefixPaths = array();
       
   189 
       
   190     /**
       
   191      * Sub forms
       
   192      * @var array
       
   193      */
       
   194     protected $_subForms = array();
       
   195 
       
   196     /**
       
   197      * @var Zend_Translate
       
   198      */
       
   199     protected $_translator;
       
   200 
       
   201     /**
       
   202      * Global default translation adapter
       
   203      * @var Zend_Translate
       
   204      */
       
   205     protected static $_translatorDefault;
       
   206 
       
   207     /**
       
   208      * is the translator disabled?
       
   209      * @var bool
       
   210      */
       
   211     protected $_translatorDisabled = false;
       
   212 
       
   213     /**
       
   214      * @var Zend_View_Interface
       
   215      */
       
   216     protected $_view;
       
   217 
       
   218     /**
       
   219      * @var bool
       
   220      */
       
   221     protected $_isRendered = false;
       
   222 
       
   223     /**
       
   224      * Constructor
       
   225      *
       
   226      * Registers form view helper as decorator
       
   227      *
       
   228      * @param mixed $options
       
   229      * @return void
       
   230      */
       
   231     public function __construct($options = null)
       
   232     {
       
   233         if (is_array($options)) {
       
   234             $this->setOptions($options);
       
   235         } elseif ($options instanceof Zend_Config) {
       
   236             $this->setConfig($options);
       
   237         }
       
   238 
       
   239         // Extensions...
       
   240         $this->init();
       
   241 
       
   242         $this->loadDefaultDecorators();
       
   243     }
       
   244 
       
   245     /**
       
   246      * Clone form object and all children
       
   247      *
       
   248      * @return void
       
   249      */
       
   250     public function __clone()
       
   251     {
       
   252         $elements = array();
       
   253         foreach ($this->getElements() as $name => $element) {
       
   254             $elements[] = clone $element;
       
   255         }
       
   256         $this->setElements($elements);
       
   257 
       
   258         $subForms = array();
       
   259         foreach ($this->getSubForms() as $name => $subForm) {
       
   260             $subForms[$name] = clone $subForm;
       
   261         }
       
   262         $this->setSubForms($subForms);
       
   263 
       
   264         $displayGroups = array();
       
   265         foreach ($this->_displayGroups as $group)  {
       
   266             $clone    = clone $group;
       
   267             $elements = array();
       
   268             foreach ($clone->getElements() as $name => $e) {
       
   269                 $elements[] = $this->getElement($name);
       
   270             }
       
   271             $clone->setElements($elements);
       
   272             $displayGroups[] = $clone;
       
   273         }
       
   274         $this->setDisplayGroups($displayGroups);
       
   275     }
       
   276 
       
   277     /**
       
   278      * Reset values of form
       
   279      *
       
   280      * @return Zend_Form
       
   281      */
       
   282     public function reset()
       
   283     {
       
   284         foreach ($this->getElements() as $element) {
       
   285             $element->setValue(null);
       
   286         }
       
   287         foreach ($this->getSubForms() as $subForm) {
       
   288             $subForm->reset();
       
   289         }
       
   290 
       
   291         return $this;
       
   292     }
       
   293 
       
   294     /**
       
   295      * Initialize form (used by extending classes)
       
   296      *
       
   297      * @return void
       
   298      */
       
   299     public function init()
       
   300     {
       
   301     }
       
   302 
       
   303     /**
       
   304      * Set form state from options array
       
   305      *
       
   306      * @param  array $options
       
   307      * @return Zend_Form
       
   308      */
       
   309     public function setOptions(array $options)
       
   310     {
       
   311         if (isset($options['prefixPath'])) {
       
   312             $this->addPrefixPaths($options['prefixPath']);
       
   313             unset($options['prefixPath']);
       
   314         }
       
   315 
       
   316         if (isset($options['elementPrefixPath'])) {
       
   317             $this->addElementPrefixPaths($options['elementPrefixPath']);
       
   318             unset($options['elementPrefixPath']);
       
   319         }
       
   320 
       
   321         if (isset($options['displayGroupPrefixPath'])) {
       
   322             $this->addDisplayGroupPrefixPaths($options['displayGroupPrefixPath']);
       
   323             unset($options['displayGroupPrefixPath']);
       
   324         }
       
   325 
       
   326         if (isset($options['elementDecorators'])) {
       
   327             $this->_elementDecorators = $options['elementDecorators'];
       
   328             unset($options['elementDecorators']);
       
   329         }
       
   330 
       
   331         if (isset($options['elements'])) {
       
   332             $this->setElements($options['elements']);
       
   333             unset($options['elements']);
       
   334         }
       
   335 
       
   336         if (isset($options['defaultDisplayGroupClass'])) {
       
   337             $this->setDefaultDisplayGroupClass($options['defaultDisplayGroupClass']);
       
   338             unset($options['defaultDisplayGroupClass']);
       
   339         }
       
   340 
       
   341         if (isset($options['displayGroupDecorators'])) {
       
   342             $displayGroupDecorators = $options['displayGroupDecorators'];
       
   343             unset($options['displayGroupDecorators']);
       
   344         }
       
   345 
       
   346         if (isset($options['elementsBelongTo'])) {
       
   347             $elementsBelongTo = $options['elementsBelongTo'];
       
   348             unset($options['elementsBelongTo']);
       
   349         }
       
   350 
       
   351         if (isset($options['attribs'])) {
       
   352             $this->addAttribs($options['attribs']);
       
   353             unset($options['attribs']);
       
   354         }
       
   355 
       
   356         $forbidden = array(
       
   357             'Options', 'Config', 'PluginLoader', 'SubForms', 'Translator',
       
   358             'Attrib', 'Default',
       
   359         );
       
   360 
       
   361         foreach ($options as $key => $value) {
       
   362             $normalized = ucfirst($key);
       
   363             if (in_array($normalized, $forbidden)) {
       
   364                 continue;
       
   365             }
       
   366 
       
   367             $method = 'set' . $normalized;
       
   368             if (method_exists($this, $method)) {
       
   369                 if($normalized == 'View' && !($value instanceof Zend_View_Interface)) {
       
   370                     continue;
       
   371                 }
       
   372                 $this->$method($value);
       
   373             } else {
       
   374                 $this->setAttrib($key, $value);
       
   375             }
       
   376         }
       
   377 
       
   378         if (isset($displayGroupDecorators)) {
       
   379             $this->setDisplayGroupDecorators($displayGroupDecorators);
       
   380         }
       
   381 
       
   382         if (isset($elementsBelongTo)) {
       
   383             $this->setElementsBelongTo($elementsBelongTo);
       
   384         }
       
   385 
       
   386         return $this;
       
   387     }
       
   388 
       
   389     /**
       
   390      * Set form state from config object
       
   391      *
       
   392      * @param  Zend_Config $config
       
   393      * @return Zend_Form
       
   394      */
       
   395     public function setConfig(Zend_Config $config)
       
   396     {
       
   397         return $this->setOptions($config->toArray());
       
   398     }
       
   399 
       
   400 
       
   401     // Loaders
       
   402 
       
   403     /**
       
   404      * Set plugin loaders for use with decorators and elements
       
   405      *
       
   406      * @param  Zend_Loader_PluginLoader_Interface $loader
       
   407      * @param  string $type 'decorator' or 'element'
       
   408      * @return Zend_Form
       
   409      * @throws Zend_Form_Exception on invalid type
       
   410      */
       
   411     public function setPluginLoader(Zend_Loader_PluginLoader_Interface $loader, $type = null)
       
   412     {
       
   413         $type = strtoupper($type);
       
   414         switch ($type) {
       
   415             case self::DECORATOR:
       
   416             case self::ELEMENT:
       
   417                 $this->_loaders[$type] = $loader;
       
   418                 return $this;
       
   419             default:
       
   420                 require_once 'Zend/Form/Exception.php';
       
   421                 throw new Zend_Form_Exception(sprintf('Invalid type "%s" provided to setPluginLoader()', $type));
       
   422         }
       
   423     }
       
   424 
       
   425     /**
       
   426      * Retrieve plugin loader for given type
       
   427      *
       
   428      * $type may be one of:
       
   429      * - decorator
       
   430      * - element
       
   431      *
       
   432      * If a plugin loader does not exist for the given type, defaults are
       
   433      * created.
       
   434      *
       
   435      * @param  string $type
       
   436      * @return Zend_Loader_PluginLoader_Interface
       
   437      */
       
   438     public function getPluginLoader($type = null)
       
   439     {
       
   440         $type = strtoupper($type);
       
   441         if (!isset($this->_loaders[$type])) {
       
   442             switch ($type) {
       
   443                 case self::DECORATOR:
       
   444                     $prefixSegment = 'Form_Decorator';
       
   445                     $pathSegment   = 'Form/Decorator';
       
   446                     break;
       
   447                 case self::ELEMENT:
       
   448                     $prefixSegment = 'Form_Element';
       
   449                     $pathSegment   = 'Form/Element';
       
   450                     break;
       
   451                 default:
       
   452                     require_once 'Zend/Form/Exception.php';
       
   453                     throw new Zend_Form_Exception(sprintf('Invalid type "%s" provided to getPluginLoader()', $type));
       
   454             }
       
   455 
       
   456             require_once 'Zend/Loader/PluginLoader.php';
       
   457             $this->_loaders[$type] = new Zend_Loader_PluginLoader(
       
   458                 array('Zend_' . $prefixSegment . '_' => 'Zend/' . $pathSegment . '/')
       
   459             );
       
   460         }
       
   461 
       
   462         return $this->_loaders[$type];
       
   463     }
       
   464 
       
   465     /**
       
   466      * Add prefix path for plugin loader
       
   467      *
       
   468      * If no $type specified, assumes it is a base path for both filters and
       
   469      * validators, and sets each according to the following rules:
       
   470      * - decorators: $prefix = $prefix . '_Decorator'
       
   471      * - elements: $prefix = $prefix . '_Element'
       
   472      *
       
   473      * Otherwise, the path prefix is set on the appropriate plugin loader.
       
   474      *
       
   475      * If $type is 'decorator', sets the path in the decorator plugin loader
       
   476      * for all elements. Additionally, if no $type is provided,
       
   477      * the prefix and path is added to both decorator and element
       
   478      * plugin loader with following settings:
       
   479      * $prefix . '_Decorator', $path . '/Decorator/'
       
   480      * $prefix . '_Element', $path . '/Element/'
       
   481      *
       
   482      * @param  string $prefix
       
   483      * @param  string $path
       
   484      * @param  string $type
       
   485      * @return Zend_Form
       
   486      * @throws Zend_Form_Exception for invalid type
       
   487      */
       
   488     public function addPrefixPath($prefix, $path, $type = null)
       
   489     {
       
   490         $type = strtoupper($type);
       
   491         switch ($type) {
       
   492             case self::DECORATOR:
       
   493             case self::ELEMENT:
       
   494                 $loader = $this->getPluginLoader($type);
       
   495                 $loader->addPrefixPath($prefix, $path);
       
   496                 return $this;
       
   497             case null:
       
   498                 $prefix = rtrim($prefix, '_');
       
   499                 $path   = rtrim($path, DIRECTORY_SEPARATOR);
       
   500                 foreach (array(self::DECORATOR, self::ELEMENT) as $type) {
       
   501                     $cType        = ucfirst(strtolower($type));
       
   502                     $pluginPath   = $path . DIRECTORY_SEPARATOR . $cType . DIRECTORY_SEPARATOR;
       
   503                     $pluginPrefix = $prefix . '_' . $cType;
       
   504                     $loader       = $this->getPluginLoader($type);
       
   505                     $loader->addPrefixPath($pluginPrefix, $pluginPath);
       
   506                 }
       
   507                 return $this;
       
   508             default:
       
   509                 require_once 'Zend/Form/Exception.php';
       
   510                 throw new Zend_Form_Exception(sprintf('Invalid type "%s" provided to getPluginLoader()', $type));
       
   511         }
       
   512     }
       
   513 
       
   514     /**
       
   515      * Add many prefix paths at once
       
   516      *
       
   517      * @param  array $spec
       
   518      * @return Zend_Form
       
   519      */
       
   520     public function addPrefixPaths(array $spec)
       
   521     {
       
   522         if (isset($spec['prefix']) && isset($spec['path'])) {
       
   523             return $this->addPrefixPath($spec['prefix'], $spec['path']);
       
   524         }
       
   525         foreach ($spec as $type => $paths) {
       
   526             if (is_numeric($type) && is_array($paths)) {
       
   527                 $type = null;
       
   528                 if (isset($paths['prefix']) && isset($paths['path'])) {
       
   529                     if (isset($paths['type'])) {
       
   530                         $type = $paths['type'];
       
   531                     }
       
   532                     $this->addPrefixPath($paths['prefix'], $paths['path'], $type);
       
   533                 }
       
   534             } elseif (!is_numeric($type)) {
       
   535                 if (!isset($paths['prefix']) || !isset($paths['path'])) {
       
   536                     continue;
       
   537                 }
       
   538                 $this->addPrefixPath($paths['prefix'], $paths['path'], $type);
       
   539             }
       
   540         }
       
   541         return $this;
       
   542     }
       
   543 
       
   544     /**
       
   545      * Add prefix path for all elements
       
   546      *
       
   547      * @param  string $prefix
       
   548      * @param  string $path
       
   549      * @param  string $type
       
   550      * @return Zend_Form
       
   551      */
       
   552     public function addElementPrefixPath($prefix, $path, $type = null)
       
   553     {
       
   554         $this->_elementPrefixPaths[] = array(
       
   555             'prefix' => $prefix,
       
   556             'path'   => $path,
       
   557             'type'   => $type,
       
   558         );
       
   559 
       
   560         foreach ($this->getElements() as $element) {
       
   561             $element->addPrefixPath($prefix, $path, $type);
       
   562         }
       
   563 
       
   564         foreach ($this->getSubForms() as $subForm) {
       
   565             $subForm->addElementPrefixPath($prefix, $path, $type);
       
   566         }
       
   567 
       
   568         return $this;
       
   569     }
       
   570 
       
   571     /**
       
   572      * Add prefix paths for all elements
       
   573      *
       
   574      * @param  array $spec
       
   575      * @return Zend_Form
       
   576      */
       
   577     public function addElementPrefixPaths(array $spec)
       
   578     {
       
   579         $this->_elementPrefixPaths = $this->_elementPrefixPaths + $spec;
       
   580 
       
   581         foreach ($this->getElements() as $element) {
       
   582             $element->addPrefixPaths($spec);
       
   583         }
       
   584 
       
   585         return $this;
       
   586     }
       
   587 
       
   588     /**
       
   589      * Add prefix path for all display groups
       
   590      *
       
   591      * @param  string $prefix
       
   592      * @param  string $path
       
   593      * @return Zend_Form
       
   594      */
       
   595     public function addDisplayGroupPrefixPath($prefix, $path)
       
   596     {
       
   597         $this->_displayGroupPrefixPaths[] = array(
       
   598             'prefix' => $prefix,
       
   599             'path'   => $path,
       
   600         );
       
   601 
       
   602         foreach ($this->getDisplayGroups() as $group) {
       
   603             $group->addPrefixPath($prefix, $path);
       
   604         }
       
   605 
       
   606         return $this;
       
   607     }
       
   608 
       
   609     /**
       
   610      * Add multiple display group prefix paths at once
       
   611      *
       
   612      * @param  array $spec
       
   613      * @return Zend_Form
       
   614      */
       
   615     public function addDisplayGroupPrefixPaths(array $spec)
       
   616     {
       
   617         foreach ($spec as $key => $value) {
       
   618             if (is_string($value) && !is_numeric($key)) {
       
   619                 $this->addDisplayGroupPrefixPath($key, $value);
       
   620                 continue;
       
   621             }
       
   622 
       
   623             if (is_string($value) && is_numeric($key)) {
       
   624                 continue;
       
   625             }
       
   626 
       
   627             if (is_array($value)) {
       
   628                 $count = count($value);
       
   629                 if (array_keys($value) === range(0, $count - 1)) {
       
   630                     if ($count < 2) {
       
   631                         continue;
       
   632                     }
       
   633                     $prefix = array_shift($value);
       
   634                     $path   = array_shift($value);
       
   635                     $this->addDisplayGroupPrefixPath($prefix, $path);
       
   636                     continue;
       
   637                 }
       
   638                 if (array_key_exists('prefix', $value) && array_key_exists('path', $value)) {
       
   639                     $this->addDisplayGroupPrefixPath($value['prefix'], $value['path']);
       
   640                 }
       
   641             }
       
   642         }
       
   643         return $this;
       
   644     }
       
   645 
       
   646     // Form metadata:
       
   647 
       
   648     /**
       
   649      * Set form attribute
       
   650      *
       
   651      * @param  string $key
       
   652      * @param  mixed $value
       
   653      * @return Zend_Form
       
   654      */
       
   655     public function setAttrib($key, $value)
       
   656     {
       
   657         $key = (string) $key;
       
   658         $this->_attribs[$key] = $value;
       
   659         return $this;
       
   660     }
       
   661 
       
   662     /**
       
   663      * Add multiple form attributes at once
       
   664      *
       
   665      * @param  array $attribs
       
   666      * @return Zend_Form
       
   667      */
       
   668     public function addAttribs(array $attribs)
       
   669     {
       
   670         foreach ($attribs as $key => $value) {
       
   671             $this->setAttrib($key, $value);
       
   672         }
       
   673         return $this;
       
   674     }
       
   675 
       
   676     /**
       
   677      * Set multiple form attributes at once
       
   678      *
       
   679      * Overwrites any previously set attributes.
       
   680      *
       
   681      * @param  array $attribs
       
   682      * @return Zend_Form
       
   683      */
       
   684     public function setAttribs(array $attribs)
       
   685     {
       
   686         $this->clearAttribs();
       
   687         return $this->addAttribs($attribs);
       
   688     }
       
   689 
       
   690     /**
       
   691      * Retrieve a single form attribute
       
   692      *
       
   693      * @param  string $key
       
   694      * @return mixed
       
   695      */
       
   696     public function getAttrib($key)
       
   697     {
       
   698         $key = (string) $key;
       
   699         if (!isset($this->_attribs[$key])) {
       
   700             return null;
       
   701         }
       
   702 
       
   703         return $this->_attribs[$key];
       
   704     }
       
   705 
       
   706     /**
       
   707      * Retrieve all form attributes/metadata
       
   708      *
       
   709      * @return array
       
   710      */
       
   711     public function getAttribs()
       
   712     {
       
   713         return $this->_attribs;
       
   714     }
       
   715 
       
   716     /**
       
   717      * Remove attribute
       
   718      *
       
   719      * @param  string $key
       
   720      * @return bool
       
   721      */
       
   722     public function removeAttrib($key)
       
   723     {
       
   724         if (isset($this->_attribs[$key])) {
       
   725             unset($this->_attribs[$key]);
       
   726             return true;
       
   727         }
       
   728 
       
   729         return false;
       
   730     }
       
   731 
       
   732     /**
       
   733      * Clear all form attributes
       
   734      *
       
   735      * @return Zend_Form
       
   736      */
       
   737     public function clearAttribs()
       
   738     {
       
   739         $this->_attribs = array();
       
   740         return $this;
       
   741     }
       
   742 
       
   743     /**
       
   744      * Set form action
       
   745      *
       
   746      * @param  string $action
       
   747      * @return Zend_Form
       
   748      */
       
   749     public function setAction($action)
       
   750     {
       
   751         return $this->setAttrib('action', (string) $action);
       
   752     }
       
   753 
       
   754     /**
       
   755      * Get form action
       
   756      *
       
   757      * Sets default to '' if not set.
       
   758      *
       
   759      * @return string
       
   760      */
       
   761     public function getAction()
       
   762     {
       
   763         $action = $this->getAttrib('action');
       
   764         if (null === $action) {
       
   765             $action = '';
       
   766             $this->setAction($action);
       
   767         }
       
   768         return $action;
       
   769     }
       
   770 
       
   771     /**
       
   772      * Set form method
       
   773      *
       
   774      * Only values in {@link $_methods()} allowed
       
   775      *
       
   776      * @param  string $method
       
   777      * @return Zend_Form
       
   778      * @throws Zend_Form_Exception
       
   779      */
       
   780     public function setMethod($method)
       
   781     {
       
   782         $method = strtolower($method);
       
   783         if (!in_array($method, $this->_methods)) {
       
   784             require_once 'Zend/Form/Exception.php';
       
   785             throw new Zend_Form_Exception(sprintf('"%s" is an invalid form method', $method));
       
   786         }
       
   787         $this->setAttrib('method', $method);
       
   788         return $this;
       
   789     }
       
   790 
       
   791     /**
       
   792      * Retrieve form method
       
   793      *
       
   794      * @return string
       
   795      */
       
   796     public function getMethod()
       
   797     {
       
   798         if (null === ($method = $this->getAttrib('method'))) {
       
   799             $method = self::METHOD_POST;
       
   800             $this->setAttrib('method', $method);
       
   801         }
       
   802         return strtolower($method);
       
   803     }
       
   804 
       
   805     /**
       
   806      * Set encoding type
       
   807      *
       
   808      * @param  string $value
       
   809      * @return Zend_Form
       
   810      */
       
   811     public function setEnctype($value)
       
   812     {
       
   813         $this->setAttrib('enctype', $value);
       
   814         return $this;
       
   815     }
       
   816 
       
   817     /**
       
   818      * Get encoding type
       
   819      *
       
   820      * @return string
       
   821      */
       
   822     public function getEnctype()
       
   823     {
       
   824         if (null === ($enctype = $this->getAttrib('enctype'))) {
       
   825             $enctype = self::ENCTYPE_URLENCODED;
       
   826             $this->setAttrib('enctype', $enctype);
       
   827         }
       
   828         return $this->getAttrib('enctype');
       
   829     }
       
   830 
       
   831     /**
       
   832      * Filter a name to only allow valid variable characters
       
   833      *
       
   834      * @param  string $value
       
   835      * @param  bool $allowBrackets
       
   836      * @return string
       
   837      */
       
   838     public function filterName($value, $allowBrackets = false)
       
   839     {
       
   840         $charset = '^a-zA-Z0-9_\x7f-\xff';
       
   841         if ($allowBrackets) {
       
   842             $charset .= '\[\]';
       
   843         }
       
   844         return preg_replace('/[' . $charset . ']/', '', (string) $value);
       
   845     }
       
   846 
       
   847     /**
       
   848      * Set form name
       
   849      *
       
   850      * @param  string $name
       
   851      * @return Zend_Form
       
   852      */
       
   853     public function setName($name)
       
   854     {
       
   855         $name = $this->filterName($name);
       
   856         if ('' === (string)$name) {
       
   857             require_once 'Zend/Form/Exception.php';
       
   858             throw new Zend_Form_Exception('Invalid name provided; must contain only valid variable characters and be non-empty');
       
   859         }
       
   860 
       
   861         return $this->setAttrib('name', $name);
       
   862     }
       
   863 
       
   864     /**
       
   865      * Get name attribute
       
   866      *
       
   867      * @return null|string
       
   868      */
       
   869     public function getName()
       
   870     {
       
   871         return $this->getAttrib('name');
       
   872     }
       
   873 
       
   874     /**
       
   875      * Get fully qualified name
       
   876      *
       
   877      * Places name as subitem of array and/or appends brackets.
       
   878      *
       
   879      * @return string
       
   880      */
       
   881     public function getFullyQualifiedName()
       
   882     {
       
   883         return $this->getName();
       
   884     }
       
   885 
       
   886     /**
       
   887      * Get element id
       
   888      *
       
   889      * @return string
       
   890      */
       
   891     public function getId()
       
   892     {
       
   893         if (null !== ($id = $this->getAttrib('id'))) {
       
   894             return $id;
       
   895         }
       
   896 
       
   897         $id = $this->getFullyQualifiedName();
       
   898 
       
   899         // Bail early if no array notation detected
       
   900         if (!strstr($id, '[')) {
       
   901             return $id;
       
   902         }
       
   903 
       
   904         // Strip array notation
       
   905         if ('[]' == substr($id, -2)) {
       
   906             $id = substr($id, 0, strlen($id) - 2);
       
   907         }
       
   908         $id = str_replace('][', '-', $id);
       
   909         $id = str_replace(array(']', '['), '-', $id);
       
   910         $id = trim($id, '-');
       
   911 
       
   912         return $id;
       
   913     }
       
   914 
       
   915     /**
       
   916      * Set form legend
       
   917      *
       
   918      * @param  string $value
       
   919      * @return Zend_Form
       
   920      */
       
   921     public function setLegend($value)
       
   922     {
       
   923         $this->_legend = (string) $value;
       
   924         return $this;
       
   925     }
       
   926 
       
   927     /**
       
   928      * Get form legend
       
   929      *
       
   930      * @return string
       
   931      */
       
   932     public function getLegend()
       
   933     {
       
   934         return $this->_legend;
       
   935     }
       
   936 
       
   937     /**
       
   938      * Set form description
       
   939      *
       
   940      * @param  string $value
       
   941      * @return Zend_Form
       
   942      */
       
   943     public function setDescription($value)
       
   944     {
       
   945         $this->_description = (string) $value;
       
   946         return $this;
       
   947     }
       
   948 
       
   949     /**
       
   950      * Retrieve form description
       
   951      *
       
   952      * @return string
       
   953      */
       
   954     public function getDescription()
       
   955     {
       
   956         return $this->_description;
       
   957     }
       
   958 
       
   959     /**
       
   960      * Set form order
       
   961      *
       
   962      * @param  int $index
       
   963      * @return Zend_Form
       
   964      */
       
   965     public function setOrder($index)
       
   966     {
       
   967         $this->_formOrder = (int) $index;
       
   968         return $this;
       
   969     }
       
   970 
       
   971     /**
       
   972      * Get form order
       
   973      *
       
   974      * @return int|null
       
   975      */
       
   976     public function getOrder()
       
   977     {
       
   978         return $this->_formOrder;
       
   979     }
       
   980 
       
   981     /**
       
   982      * When calling renderFormElements or render this method
       
   983      * is used to set $_isRendered member to prevent repeatedly
       
   984      * merging belongsTo setting
       
   985      */
       
   986     protected function _setIsRendered()
       
   987     {
       
   988         $this->_isRendered = true;
       
   989         return $this;
       
   990     }
       
   991 
       
   992     /**
       
   993      * Get the value of $_isRendered member
       
   994      */
       
   995     protected function _getIsRendered()
       
   996     {
       
   997         return (bool)$this->_isRendered;
       
   998     }
       
   999 
       
  1000     // Element interaction:
       
  1001 
       
  1002     /**
       
  1003      * Add a new element
       
  1004      *
       
  1005      * $element may be either a string element type, or an object of type
       
  1006      * Zend_Form_Element. If a string element type is provided, $name must be
       
  1007      * provided, and $options may be optionally provided for configuring the
       
  1008      * element.
       
  1009      *
       
  1010      * If a Zend_Form_Element is provided, $name may be optionally provided,
       
  1011      * and any provided $options will be ignored.
       
  1012      *
       
  1013      * @param  string|Zend_Form_Element $element
       
  1014      * @param  string $name
       
  1015      * @param  array|Zend_Config $options
       
  1016      * @return Zend_Form
       
  1017      */
       
  1018     public function addElement($element, $name = null, $options = null)
       
  1019     {
       
  1020         if (is_string($element)) {
       
  1021             if (null === $name) {
       
  1022                 require_once 'Zend/Form/Exception.php';
       
  1023                 throw new Zend_Form_Exception('Elements specified by string must have an accompanying name');
       
  1024             }
       
  1025 
       
  1026             if (is_array($this->_elementDecorators)) {
       
  1027                 if (null === $options) {
       
  1028                     $options = array('decorators' => $this->_elementDecorators);
       
  1029                 } elseif ($options instanceof Zend_Config) {
       
  1030                     $options = $options->toArray();
       
  1031                 }
       
  1032                 if (is_array($options)
       
  1033                     && !array_key_exists('decorators', $options)
       
  1034                 ) {
       
  1035                     $options['decorators'] = $this->_elementDecorators;
       
  1036                 }
       
  1037             }
       
  1038 
       
  1039             $this->_elements[$name] = $this->createElement($element, $name, $options);
       
  1040         } elseif ($element instanceof Zend_Form_Element) {
       
  1041             $prefixPaths              = array();
       
  1042             $prefixPaths['decorator'] = $this->getPluginLoader('decorator')->getPaths();
       
  1043             if (!empty($this->_elementPrefixPaths)) {
       
  1044                 $prefixPaths = array_merge($prefixPaths, $this->_elementPrefixPaths);
       
  1045             }
       
  1046 
       
  1047             if (null === $name) {
       
  1048                 $name = $element->getName();
       
  1049             }
       
  1050 
       
  1051             $this->_elements[$name] = $element;
       
  1052             $this->_elements[$name]->addPrefixPaths($prefixPaths);
       
  1053         }
       
  1054 
       
  1055         $this->_order[$name] = $this->_elements[$name]->getOrder();
       
  1056         $this->_orderUpdated = true;
       
  1057         $this->_setElementsBelongTo($name);
       
  1058 
       
  1059         return $this;
       
  1060     }
       
  1061 
       
  1062     /**
       
  1063      * Create an element
       
  1064      *
       
  1065      * Acts as a factory for creating elements. Elements created with this
       
  1066      * method will not be attached to the form, but will contain element
       
  1067      * settings as specified in the form object (including plugin loader
       
  1068      * prefix paths, default decorators, etc.).
       
  1069      *
       
  1070      * @param  string $type
       
  1071      * @param  string $name
       
  1072      * @param  array|Zend_Config $options
       
  1073      * @return Zend_Form_Element
       
  1074      */
       
  1075     public function createElement($type, $name, $options = null)
       
  1076     {
       
  1077         if (!is_string($type)) {
       
  1078             require_once 'Zend/Form/Exception.php';
       
  1079             throw new Zend_Form_Exception('Element type must be a string indicating type');
       
  1080         }
       
  1081 
       
  1082         if (!is_string($name)) {
       
  1083             require_once 'Zend/Form/Exception.php';
       
  1084             throw new Zend_Form_Exception('Element name must be a string');
       
  1085         }
       
  1086 
       
  1087         $prefixPaths              = array();
       
  1088         $prefixPaths['decorator'] = $this->getPluginLoader('decorator')->getPaths();
       
  1089         if (!empty($this->_elementPrefixPaths)) {
       
  1090             $prefixPaths = array_merge($prefixPaths, $this->_elementPrefixPaths);
       
  1091         }
       
  1092 
       
  1093         if ($options instanceof Zend_Config) {
       
  1094             $options = $options->toArray();
       
  1095         }
       
  1096 
       
  1097         if ((null === $options) || !is_array($options)) {
       
  1098             $options = array('prefixPath' => $prefixPaths);
       
  1099         } elseif (is_array($options)) {
       
  1100             if (array_key_exists('prefixPath', $options)) {
       
  1101                 $options['prefixPath'] = array_merge($prefixPaths, $options['prefixPath']);
       
  1102             } else {
       
  1103                 $options['prefixPath'] = $prefixPaths;
       
  1104             }
       
  1105         }
       
  1106 
       
  1107         $class = $this->getPluginLoader(self::ELEMENT)->load($type);
       
  1108         $element = new $class($name, $options);
       
  1109 
       
  1110         return $element;
       
  1111     }
       
  1112 
       
  1113     /**
       
  1114      * Add multiple elements at once
       
  1115      *
       
  1116      * @param  array $elements
       
  1117      * @return Zend_Form
       
  1118      */
       
  1119     public function addElements(array $elements)
       
  1120     {
       
  1121         foreach ($elements as $key => $spec) {
       
  1122             $name = null;
       
  1123             if (!is_numeric($key)) {
       
  1124                 $name = $key;
       
  1125             }
       
  1126 
       
  1127             if (is_string($spec) || ($spec instanceof Zend_Form_Element)) {
       
  1128                 $this->addElement($spec, $name);
       
  1129                 continue;
       
  1130             }
       
  1131 
       
  1132             if (is_array($spec)) {
       
  1133                 $argc = count($spec);
       
  1134                 $options = array();
       
  1135                 if (isset($spec['type'])) {
       
  1136                     $type = $spec['type'];
       
  1137                     if (isset($spec['name'])) {
       
  1138                         $name = $spec['name'];
       
  1139                     }
       
  1140                     if (isset($spec['options'])) {
       
  1141                         $options = $spec['options'];
       
  1142                     }
       
  1143                     $this->addElement($type, $name, $options);
       
  1144                 } else {
       
  1145                     switch ($argc) {
       
  1146                         case 0:
       
  1147                             continue;
       
  1148                         case (1 <= $argc):
       
  1149                             $type = array_shift($spec);
       
  1150                         case (2 <= $argc):
       
  1151                             if (null === $name) {
       
  1152                                 $name = array_shift($spec);
       
  1153                             } else {
       
  1154                                 $options = array_shift($spec);
       
  1155                             }
       
  1156                         case (3 <= $argc):
       
  1157                             if (empty($options)) {
       
  1158                                 $options = array_shift($spec);
       
  1159                             }
       
  1160                         default:
       
  1161                             $this->addElement($type, $name, $options);
       
  1162                     }
       
  1163                 }
       
  1164             }
       
  1165         }
       
  1166         return $this;
       
  1167     }
       
  1168 
       
  1169     /**
       
  1170      * Set form elements (overwrites existing elements)
       
  1171      *
       
  1172      * @param  array $elements
       
  1173      * @return Zend_Form
       
  1174      */
       
  1175     public function setElements(array $elements)
       
  1176     {
       
  1177         $this->clearElements();
       
  1178         return $this->addElements($elements);
       
  1179     }
       
  1180 
       
  1181     /**
       
  1182      * Retrieve a single element
       
  1183      *
       
  1184      * @param  string $name
       
  1185      * @return Zend_Form_Element|null
       
  1186      */
       
  1187     public function getElement($name)
       
  1188     {
       
  1189         if (array_key_exists($name, $this->_elements)) {
       
  1190             return $this->_elements[$name];
       
  1191         }
       
  1192         return null;
       
  1193     }
       
  1194 
       
  1195     /**
       
  1196      * Retrieve all elements
       
  1197      *
       
  1198      * @return array
       
  1199      */
       
  1200     public function getElements()
       
  1201     {
       
  1202         return $this->_elements;
       
  1203     }
       
  1204 
       
  1205     /**
       
  1206      * Remove element
       
  1207      *
       
  1208      * @param  string $name
       
  1209      * @return boolean
       
  1210      */
       
  1211     public function removeElement($name)
       
  1212     {
       
  1213         $name = (string) $name;
       
  1214         if (isset($this->_elements[$name])) {
       
  1215             unset($this->_elements[$name]);
       
  1216             if (array_key_exists($name, $this->_order)) {
       
  1217                 unset($this->_order[$name]);
       
  1218                 $this->_orderUpdated = true;
       
  1219             } else {
       
  1220                 foreach ($this->_displayGroups as $group) {
       
  1221                     if (null !== $group->getElement($name)) {
       
  1222                         $group->removeElement($name);
       
  1223                     }
       
  1224                 }
       
  1225             }
       
  1226             return true;
       
  1227         }
       
  1228 
       
  1229         return false;
       
  1230     }
       
  1231 
       
  1232     /**
       
  1233      * Remove all form elements
       
  1234      *
       
  1235      * @return Zend_Form
       
  1236      */
       
  1237     public function clearElements()
       
  1238     {
       
  1239         foreach (array_keys($this->_elements) as $key) {
       
  1240             if (array_key_exists($key, $this->_order)) {
       
  1241                 unset($this->_order[$key]);
       
  1242             }
       
  1243         }
       
  1244         $this->_elements     = array();
       
  1245         $this->_orderUpdated = true;
       
  1246         return $this;
       
  1247     }
       
  1248 
       
  1249     /**
       
  1250      * Set default values for elements
       
  1251      *
       
  1252      * Sets values for all elements specified in the array of $defaults.
       
  1253      *
       
  1254      * @param  array $defaults
       
  1255      * @return Zend_Form
       
  1256      */
       
  1257     public function setDefaults(array $defaults)
       
  1258     {
       
  1259         $eBelongTo = null;
       
  1260 
       
  1261         if ($this->isArray()) {
       
  1262             $eBelongTo = $this->getElementsBelongTo();
       
  1263             $defaults = $this->_dissolveArrayValue($defaults, $eBelongTo);
       
  1264         }
       
  1265         foreach ($this->getElements() as $name => $element) {
       
  1266             $check = $defaults;
       
  1267             if (($belongsTo = $element->getBelongsTo()) !== $eBelongTo) {
       
  1268                 $check = $this->_dissolveArrayValue($defaults, $belongsTo);
       
  1269             }
       
  1270             if (array_key_exists($name, $check)) {
       
  1271                 $this->setDefault($name, $check[$name]);
       
  1272                 $defaults = $this->_dissolveArrayUnsetKey($defaults, $belongsTo, $name);
       
  1273             }
       
  1274         }
       
  1275         foreach ($this->getSubForms() as $name => $form) {
       
  1276             if (!$form->isArray() && array_key_exists($name, $defaults)) {
       
  1277                 $form->setDefaults($defaults[$name]);
       
  1278             } else {
       
  1279                 $form->setDefaults($defaults);
       
  1280             }
       
  1281         }
       
  1282         return $this;
       
  1283     }
       
  1284 
       
  1285     /**
       
  1286      * Set default value for an element
       
  1287      *
       
  1288      * @param  string $name
       
  1289      * @param  mixed $value
       
  1290      * @return Zend_Form
       
  1291      */
       
  1292     public function setDefault($name, $value)
       
  1293     {
       
  1294         $name = (string) $name;
       
  1295         if ($element = $this->getElement($name)) {
       
  1296             $element->setValue($value);
       
  1297         } else {
       
  1298             if (is_scalar($value)) {
       
  1299                 foreach ($this->getSubForms() as $subForm) {
       
  1300                     $subForm->setDefault($name, $value);
       
  1301                 }
       
  1302             } elseif (is_array($value) && ($subForm = $this->getSubForm($name))) {
       
  1303                 $subForm->setDefaults($value);
       
  1304             }
       
  1305         }
       
  1306         return $this;
       
  1307     }
       
  1308 
       
  1309     /**
       
  1310      * Retrieve value for single element
       
  1311      *
       
  1312      * @param  string $name
       
  1313      * @return mixed
       
  1314      */
       
  1315     public function getValue($name)
       
  1316     {
       
  1317         if ($element = $this->getElement($name)) {
       
  1318             return $element->getValue();
       
  1319         }
       
  1320 
       
  1321         if ($subForm = $this->getSubForm($name)) {
       
  1322             return $subForm->getValues(true);
       
  1323         }
       
  1324 
       
  1325         foreach ($this->getSubForms() as $subForm) {
       
  1326             if ($name == $subForm->getElementsBelongTo()) {
       
  1327                 return $subForm->getValues(true);
       
  1328             }
       
  1329         }
       
  1330         return null;
       
  1331     }
       
  1332 
       
  1333     /**
       
  1334      * Retrieve all form element values
       
  1335      *
       
  1336      * @param  bool $suppressArrayNotation
       
  1337      * @return array
       
  1338      */
       
  1339     public function getValues($suppressArrayNotation = false)
       
  1340     {
       
  1341         $values = array();
       
  1342         $eBelongTo = null;
       
  1343         
       
  1344         if ($this->isArray()) {
       
  1345             $eBelongTo = $this->getElementsBelongTo();
       
  1346         }
       
  1347         
       
  1348         foreach ($this->getElements() as $key => $element) {
       
  1349             if (!$element->getIgnore()) {
       
  1350                 $merge = array();
       
  1351                 if (($belongsTo = $element->getBelongsTo()) !== $eBelongTo) {
       
  1352                     if ('' !== (string)$belongsTo) {
       
  1353                         $key = $belongsTo . '[' . $key . ']';
       
  1354                     }
       
  1355                 }
       
  1356                 $merge = $this->_attachToArray($element->getValue(), $key);
       
  1357                 $values = $this->_array_replace_recursive($values, $merge);
       
  1358             }
       
  1359         }
       
  1360         foreach ($this->getSubForms() as $key => $subForm) {
       
  1361             $merge = array();
       
  1362             if (!$subForm->isArray()) {
       
  1363                 $merge[$key] = $subForm->getValues();
       
  1364             } else {
       
  1365                 $merge = $this->_attachToArray($subForm->getValues(true),
       
  1366                                                $subForm->getElementsBelongTo());
       
  1367             }
       
  1368             $values = $this->_array_replace_recursive($values, $merge);
       
  1369         }
       
  1370 
       
  1371         if (!$suppressArrayNotation &&
       
  1372             $this->isArray() &&
       
  1373             !$this->_getIsRendered()) {
       
  1374             $values = $this->_attachToArray($values, $this->getElementsBelongTo());
       
  1375         }
       
  1376 
       
  1377         return $values;
       
  1378     }
       
  1379 
       
  1380     /**
       
  1381      * Returns only the valid values from the given form input.
       
  1382      *
       
  1383      * For models that can be saved in a partially valid state, for example when following the builder,
       
  1384      * prototype or state patterns it is particularly interessting to retrieve all the current valid
       
  1385      * values to persist them.
       
  1386      *
       
  1387      * @param  array $data
       
  1388      * @param  bool $suppressArrayNotation
       
  1389      * @return array
       
  1390      */
       
  1391     public function getValidValues($data, $suppressArrayNotation = false)
       
  1392     {
       
  1393         $values = array();
       
  1394         $eBelongTo = null;
       
  1395 
       
  1396         if ($this->isArray()) {
       
  1397             $eBelongTo = $this->getElementsBelongTo();
       
  1398             $data = $this->_dissolveArrayValue($data, $eBelongTo);
       
  1399         }
       
  1400         $context = $data;
       
  1401         foreach ($this->getElements() as $key => $element) {
       
  1402             if (!$element->getIgnore()) {
       
  1403                 $check = $data;
       
  1404                 if (($belongsTo = $element->getBelongsTo()) !== $eBelongTo) {
       
  1405                     $check = $this->_dissolveArrayValue($data, $belongsTo);
       
  1406                 }
       
  1407                 if (isset($check[$key])) {
       
  1408                     if($element->isValid($check[$key], $context)) {
       
  1409                         $merge = array();
       
  1410                         if ($belongsTo !== $eBelongTo && '' !== (string)$belongsTo) {
       
  1411                             $key = $belongsTo . '[' . $key . ']';
       
  1412                         }
       
  1413                         $merge = $this->_attachToArray($element->getValue(), $key);
       
  1414                         $values = $this->_array_replace_recursive($values, $merge);
       
  1415                     }
       
  1416                     $data = $this->_dissolveArrayUnsetKey($data, $belongsTo, $key);
       
  1417                 }
       
  1418             }
       
  1419         }
       
  1420         foreach ($this->getSubForms() as $key => $form) {
       
  1421             $merge = array();
       
  1422             if (isset($data[$key]) && !$form->isArray()) {
       
  1423                 $tmp = $form->getValidValues($data[$key]);
       
  1424                 if (!empty($tmp)) {
       
  1425                     $merge[$key] = $tmp;
       
  1426                 }
       
  1427             } else {
       
  1428                 $tmp = $form->getValidValues($data, true);
       
  1429                 if (!empty($tmp)) {
       
  1430                     $merge = $this->_attachToArray($tmp, $form->getElementsBelongTo());
       
  1431                 }
       
  1432             }
       
  1433             $values = $this->_array_replace_recursive($values, $merge);
       
  1434         }
       
  1435         if (!$suppressArrayNotation &&
       
  1436             $this->isArray() &&
       
  1437             !empty($values) &&
       
  1438             !$this->_getIsRendered()) {
       
  1439             $values = $this->_attachToArray($values, $this->getElementsBelongTo());
       
  1440         }
       
  1441 
       
  1442         return $values;
       
  1443     }
       
  1444 
       
  1445     /**
       
  1446      * Get unfiltered element value
       
  1447      *
       
  1448      * @param  string $name
       
  1449      * @return mixed
       
  1450      */
       
  1451     public function getUnfilteredValue($name)
       
  1452     {
       
  1453         if ($element = $this->getElement($name)) {
       
  1454             return $element->getUnfilteredValue();
       
  1455         }
       
  1456         return null;
       
  1457     }
       
  1458 
       
  1459     /**
       
  1460      * Retrieve all unfiltered element values
       
  1461      *
       
  1462      * @return array
       
  1463      */
       
  1464     public function getUnfilteredValues()
       
  1465     {
       
  1466         $values = array();
       
  1467         foreach ($this->getElements() as $key => $element) {
       
  1468             $values[$key] = $element->getUnfilteredValue();
       
  1469         }
       
  1470 
       
  1471         return $values;
       
  1472     }
       
  1473 
       
  1474     /**
       
  1475      * Set all elements' filters
       
  1476      *
       
  1477      * @param  array $filters
       
  1478      * @return Zend_Form
       
  1479      */
       
  1480     public function setElementFilters(array $filters)
       
  1481     {
       
  1482         foreach ($this->getElements() as $element) {
       
  1483             $element->setFilters($filters);
       
  1484         }
       
  1485         return $this;
       
  1486     }
       
  1487 
       
  1488     /**
       
  1489      * Set name of array elements belong to
       
  1490      *
       
  1491      * @param  string $array
       
  1492      * @return Zend_Form
       
  1493      */
       
  1494     public function setElementsBelongTo($array)
       
  1495     {
       
  1496         $origName = $this->getElementsBelongTo();
       
  1497         $name = $this->filterName($array, true);
       
  1498         if ('' === $name) {
       
  1499             $name = null;
       
  1500         }
       
  1501         $this->_elementsBelongTo = $name;
       
  1502 
       
  1503         if (null === $name) {
       
  1504             $this->setIsArray(false);
       
  1505             if (null !== $origName) {
       
  1506                 $this->_setElementsBelongTo();
       
  1507             }
       
  1508         } else {
       
  1509             $this->setIsArray(true);
       
  1510             $this->_setElementsBelongTo();
       
  1511         }
       
  1512 
       
  1513         return $this;
       
  1514     }
       
  1515 
       
  1516     /**
       
  1517      * Set array to which elements belong
       
  1518      *
       
  1519      * @param  string $name Element name
       
  1520      * @return void
       
  1521      */
       
  1522     protected function _setElementsBelongTo($name = null)
       
  1523     {
       
  1524         $array = $this->getElementsBelongTo();
       
  1525 
       
  1526         if (null === $array) {
       
  1527             return;
       
  1528         }
       
  1529 
       
  1530         if (null === $name) {
       
  1531             foreach ($this->getElements() as $element) {
       
  1532                 $element->setBelongsTo($array);
       
  1533             }
       
  1534         } else {
       
  1535             if (null !== ($element = $this->getElement($name))) {
       
  1536                 $element->setBelongsTo($array);
       
  1537             }
       
  1538         }
       
  1539     }
       
  1540 
       
  1541     /**
       
  1542      * Get name of array elements belong to
       
  1543      *
       
  1544      * @return string|null
       
  1545      */
       
  1546     public function getElementsBelongTo()
       
  1547     {
       
  1548         if ((null === $this->_elementsBelongTo) && $this->isArray()) {
       
  1549             $name = $this->getName();
       
  1550             if ('' !== (string)$name) {
       
  1551                 return $name;
       
  1552             }
       
  1553         }
       
  1554         return $this->_elementsBelongTo;
       
  1555     }
       
  1556 
       
  1557     /**
       
  1558      * Set flag indicating elements belong to array
       
  1559      *
       
  1560      * @param  bool $flag Value of flag
       
  1561      * @return Zend_Form
       
  1562      */
       
  1563     public function setIsArray($flag)
       
  1564     {
       
  1565         $this->_isArray = (bool) $flag;
       
  1566         return $this;
       
  1567     }
       
  1568 
       
  1569     /**
       
  1570      * Get flag indicating if elements belong to an array
       
  1571      *
       
  1572      * @return bool
       
  1573      */
       
  1574     public function isArray()
       
  1575     {
       
  1576         return $this->_isArray;
       
  1577     }
       
  1578 
       
  1579     // Element groups:
       
  1580 
       
  1581     /**
       
  1582      * Add a form group/subform
       
  1583      *
       
  1584      * @param  Zend_Form $form
       
  1585      * @param  string $name
       
  1586      * @param  int $order
       
  1587      * @return Zend_Form
       
  1588      */
       
  1589     public function addSubForm(Zend_Form $form, $name, $order = null)
       
  1590     {
       
  1591         $name = (string) $name;
       
  1592         foreach ($this->_loaders as $type => $loader) {
       
  1593             $loaderPaths = $loader->getPaths();
       
  1594             foreach ($loaderPaths as $prefix => $paths) {
       
  1595                 foreach ($paths as $path) {
       
  1596                     $form->addPrefixPath($prefix, $path, $type);
       
  1597                 }
       
  1598             }
       
  1599         }
       
  1600 
       
  1601         if (!empty($this->_elementPrefixPaths)) {
       
  1602             foreach ($this->_elementPrefixPaths as $spec) {
       
  1603                 list($prefix, $path, $type) = array_values($spec);
       
  1604                 $form->addElementPrefixPath($prefix, $path, $type);
       
  1605             }
       
  1606         }
       
  1607 
       
  1608         if (!empty($this->_displayGroupPrefixPaths)) {
       
  1609             foreach ($this->_displayGroupPrefixPaths as $spec) {
       
  1610                 list($prefix, $path) = array_values($spec);
       
  1611                 $form->addDisplayGroupPrefixPath($prefix, $path);
       
  1612             }
       
  1613         }
       
  1614 
       
  1615         if (null !== $order) {
       
  1616             $form->setOrder($order);
       
  1617         }
       
  1618 
       
  1619         if (($oldName = $form->getName()) &&
       
  1620             $oldName !== $name &&
       
  1621             $oldName === $form->getElementsBelongTo()) {
       
  1622             $form->setElementsBelongTo($name);
       
  1623         }
       
  1624 
       
  1625         $form->setName($name);
       
  1626         $this->_subForms[$name] = $form;
       
  1627         $this->_order[$name]    = $order;
       
  1628         $this->_orderUpdated    = true;
       
  1629         return $this;
       
  1630     }
       
  1631 
       
  1632     /**
       
  1633      * Add multiple form subForms/subforms at once
       
  1634      *
       
  1635      * @param  array $subForms
       
  1636      * @return Zend_Form
       
  1637      */
       
  1638     public function addSubForms(array $subForms)
       
  1639     {
       
  1640         foreach ($subForms as $key => $spec) {
       
  1641             $name = null;
       
  1642             if (!is_numeric($key)) {
       
  1643                 $name = $key;
       
  1644             }
       
  1645 
       
  1646             if ($spec instanceof Zend_Form) {
       
  1647                 $this->addSubForm($spec, $name);
       
  1648                 continue;
       
  1649             }
       
  1650 
       
  1651             if (is_array($spec)) {
       
  1652                 $argc  = count($spec);
       
  1653                 $order = null;
       
  1654                 switch ($argc) {
       
  1655                     case 0:
       
  1656                         continue;
       
  1657                     case (1 <= $argc):
       
  1658                         $subForm = array_shift($spec);
       
  1659                     case (2 <= $argc):
       
  1660                         $name  = array_shift($spec);
       
  1661                     case (3 <= $argc):
       
  1662                         $order = array_shift($spec);
       
  1663                     default:
       
  1664                         $this->addSubForm($subForm, $name, $order);
       
  1665                 }
       
  1666             }
       
  1667         }
       
  1668         return $this;
       
  1669     }
       
  1670 
       
  1671     /**
       
  1672      * Set multiple form subForms/subforms (overwrites)
       
  1673      *
       
  1674      * @param  array $subForms
       
  1675      * @return Zend_Form
       
  1676      */
       
  1677     public function setSubForms(array $subForms)
       
  1678     {
       
  1679         $this->clearSubForms();
       
  1680         return $this->addSubForms($subForms);
       
  1681     }
       
  1682 
       
  1683     /**
       
  1684      * Retrieve a form subForm/subform
       
  1685      *
       
  1686      * @param  string $name
       
  1687      * @return Zend_Form|null
       
  1688      */
       
  1689     public function getSubForm($name)
       
  1690     {
       
  1691         $name = (string) $name;
       
  1692         if (isset($this->_subForms[$name])) {
       
  1693             return $this->_subForms[$name];
       
  1694         }
       
  1695         return null;
       
  1696     }
       
  1697 
       
  1698     /**
       
  1699      * Retrieve all form subForms/subforms
       
  1700      *
       
  1701      * @return array
       
  1702      */
       
  1703     public function getSubForms()
       
  1704     {
       
  1705         return $this->_subForms;
       
  1706     }
       
  1707 
       
  1708     /**
       
  1709      * Remove form subForm/subform
       
  1710      *
       
  1711      * @param  string $name
       
  1712      * @return boolean
       
  1713      */
       
  1714     public function removeSubForm($name)
       
  1715     {
       
  1716         $name = (string) $name;
       
  1717         if (array_key_exists($name, $this->_subForms)) {
       
  1718             unset($this->_subForms[$name]);
       
  1719             if (array_key_exists($name, $this->_order)) {
       
  1720                 unset($this->_order[$name]);
       
  1721                 $this->_orderUpdated = true;
       
  1722             }
       
  1723             return true;
       
  1724         }
       
  1725 
       
  1726         return false;
       
  1727     }
       
  1728 
       
  1729     /**
       
  1730      * Remove all form subForms/subforms
       
  1731      *
       
  1732      * @return Zend_Form
       
  1733      */
       
  1734     public function clearSubForms()
       
  1735     {
       
  1736         foreach (array_keys($this->_subForms) as $key) {
       
  1737             if (array_key_exists($key, $this->_order)) {
       
  1738                 unset($this->_order[$key]);
       
  1739             }
       
  1740         }
       
  1741         $this->_subForms     = array();
       
  1742         $this->_orderUpdated = true;
       
  1743         return $this;
       
  1744     }
       
  1745 
       
  1746 
       
  1747     // Display groups:
       
  1748 
       
  1749     /**
       
  1750      * Set default display group class
       
  1751      *
       
  1752      * @param  string $class
       
  1753      * @return Zend_Form
       
  1754      */
       
  1755     public function setDefaultDisplayGroupClass($class)
       
  1756     {
       
  1757         $this->_defaultDisplayGroupClass = (string) $class;
       
  1758         return $this;
       
  1759     }
       
  1760 
       
  1761     /**
       
  1762      * Retrieve default display group class
       
  1763      *
       
  1764      * @return string
       
  1765      */
       
  1766     public function getDefaultDisplayGroupClass()
       
  1767     {
       
  1768         return $this->_defaultDisplayGroupClass;
       
  1769     }
       
  1770 
       
  1771     /**
       
  1772      * Add a display group
       
  1773      *
       
  1774      * Groups named elements for display purposes.
       
  1775      *
       
  1776      * If a referenced element does not yet exist in the form, it is omitted.
       
  1777      *
       
  1778      * @param  array $elements
       
  1779      * @param  string $name
       
  1780      * @param  array|Zend_Config $options
       
  1781      * @return Zend_Form
       
  1782      * @throws Zend_Form_Exception if no valid elements provided
       
  1783      */
       
  1784     public function addDisplayGroup(array $elements, $name, $options = null)
       
  1785     {
       
  1786         $group = array();
       
  1787         foreach ($elements as $element) {
       
  1788             if($element instanceof Zend_Form_Element) {
       
  1789                 $element = $element->getId();
       
  1790             }
       
  1791 
       
  1792             if (isset($this->_elements[$element])) {
       
  1793                 $add = $this->getElement($element);
       
  1794                 if (null !== $add) {
       
  1795                     $group[] = $add;
       
  1796                 }
       
  1797             }
       
  1798         }
       
  1799         if (empty($group)) {
       
  1800             require_once 'Zend/Form/Exception.php';
       
  1801             throw new Zend_Form_Exception('No valid elements specified for display group');
       
  1802         }
       
  1803 
       
  1804         $name = (string) $name;
       
  1805 
       
  1806         if (is_array($options)) {
       
  1807             $options['form']     = $this;
       
  1808             $options['elements'] = $group;
       
  1809         } elseif ($options instanceof Zend_Config) {
       
  1810             $options = $options->toArray();
       
  1811             $options['form']     = $this;
       
  1812             $options['elements'] = $group;
       
  1813         } else {
       
  1814             $options = array(
       
  1815                 'form'     => $this,
       
  1816                 'elements' => $group,
       
  1817             );
       
  1818         }
       
  1819 
       
  1820         if (isset($options['displayGroupClass'])) {
       
  1821             $class = $options['displayGroupClass'];
       
  1822             unset($options['displayGroupClass']);
       
  1823         } else {
       
  1824             $class = $this->getDefaultDisplayGroupClass();
       
  1825         }
       
  1826 
       
  1827         if (!class_exists($class)) {
       
  1828             require_once 'Zend/Loader.php';
       
  1829             Zend_Loader::loadClass($class);
       
  1830         }
       
  1831         $this->_displayGroups[$name] = new $class(
       
  1832             $name,
       
  1833             $this->getPluginLoader(self::DECORATOR),
       
  1834             $options
       
  1835         );
       
  1836 
       
  1837         if (!empty($this->_displayGroupPrefixPaths)) {
       
  1838             $this->_displayGroups[$name]->addPrefixPaths($this->_displayGroupPrefixPaths);
       
  1839         }
       
  1840 
       
  1841         $this->_order[$name] = $this->_displayGroups[$name]->getOrder();
       
  1842         $this->_orderUpdated = true;
       
  1843         return $this;
       
  1844     }
       
  1845 
       
  1846     /**
       
  1847      * Add a display group object (used with cloning)
       
  1848      *
       
  1849      * @param  Zend_Form_DisplayGroup $group
       
  1850      * @param  string|null $name
       
  1851      * @return Zend_Form
       
  1852      */
       
  1853     protected function _addDisplayGroupObject(Zend_Form_DisplayGroup $group, $name = null)
       
  1854     {
       
  1855         if (null === $name) {
       
  1856             $name = $group->getName();
       
  1857             if ('' === (string)$name) {
       
  1858                 require_once 'Zend/Form/Exception.php';
       
  1859                 throw new Zend_Form_Exception('Invalid display group added; requires name');
       
  1860             }
       
  1861         }
       
  1862 
       
  1863         $this->_displayGroups[$name] = $group;
       
  1864         $group->setForm($this);
       
  1865 
       
  1866         if (!empty($this->_displayGroupPrefixPaths)) {
       
  1867             $this->_displayGroups[$name]->addPrefixPaths($this->_displayGroupPrefixPaths);
       
  1868         }
       
  1869 
       
  1870         $this->_order[$name] = $this->_displayGroups[$name]->getOrder();
       
  1871         $this->_orderUpdated = true;
       
  1872         return $this;
       
  1873     }
       
  1874 
       
  1875     /**
       
  1876      * Add multiple display groups at once
       
  1877      *
       
  1878      * @param  array $groups
       
  1879      * @return Zend_Form
       
  1880      */
       
  1881     public function addDisplayGroups(array $groups)
       
  1882     {
       
  1883         foreach ($groups as $key => $spec) {
       
  1884             $name = null;
       
  1885             if (!is_numeric($key)) {
       
  1886                 $name = $key;
       
  1887             }
       
  1888 
       
  1889             if ($spec instanceof Zend_Form_DisplayGroup) {
       
  1890                 $this->_addDisplayGroupObject($spec);
       
  1891             }
       
  1892 
       
  1893             if (!is_array($spec) || empty($spec)) {
       
  1894                 continue;
       
  1895             }
       
  1896 
       
  1897             $argc    = count($spec);
       
  1898             $options = array();
       
  1899 
       
  1900             if (isset($spec['elements'])) {
       
  1901                 $elements = $spec['elements'];
       
  1902                 if (isset($spec['name'])) {
       
  1903                     $name = $spec['name'];
       
  1904                 }
       
  1905                 if (isset($spec['options'])) {
       
  1906                     $options = $spec['options'];
       
  1907                 }
       
  1908                 $this->addDisplayGroup($elements, $name, $options);
       
  1909             } else {
       
  1910                 switch ($argc) {
       
  1911                     case (1 <= $argc):
       
  1912                         $elements = array_shift($spec);
       
  1913                         if (!is_array($elements) && (null !== $name)) {
       
  1914                             $elements = array_merge((array) $elements, $spec);
       
  1915                             $this->addDisplayGroup($elements, $name);
       
  1916                             break;
       
  1917                         }
       
  1918                     case (2 <= $argc):
       
  1919                         if (null !== $name) {
       
  1920                             $options = array_shift($spec);
       
  1921                             $this->addDisplayGroup($elements, $name, $options);
       
  1922                             break;
       
  1923                         }
       
  1924                         $name = array_shift($spec);
       
  1925                     case (3 <= $argc):
       
  1926                         $options = array_shift($spec);
       
  1927                     default:
       
  1928                         $this->addDisplayGroup($elements, $name, $options);
       
  1929                 }
       
  1930             }
       
  1931         }
       
  1932         return $this;
       
  1933     }
       
  1934 
       
  1935     /**
       
  1936      * Add multiple display groups (overwrites)
       
  1937      *
       
  1938      * @param  array $groups
       
  1939      * @return Zend_Form
       
  1940      */
       
  1941     public function setDisplayGroups(array $groups)
       
  1942     {
       
  1943         return $this->clearDisplayGroups()
       
  1944                     ->addDisplayGroups($groups);
       
  1945     }
       
  1946 
       
  1947     /**
       
  1948      * Return a display group
       
  1949      *
       
  1950      * @param  string $name
       
  1951      * @return Zend_Form_DisplayGroup|null
       
  1952      */
       
  1953     public function getDisplayGroup($name)
       
  1954     {
       
  1955         $name = (string) $name;
       
  1956         if (isset($this->_displayGroups[$name])) {
       
  1957             return $this->_displayGroups[$name];
       
  1958         }
       
  1959 
       
  1960         return null;
       
  1961     }
       
  1962 
       
  1963     /**
       
  1964      * Return all display groups
       
  1965      *
       
  1966      * @return array
       
  1967      */
       
  1968     public function getDisplayGroups()
       
  1969     {
       
  1970         return $this->_displayGroups;
       
  1971     }
       
  1972 
       
  1973     /**
       
  1974      * Remove a display group by name
       
  1975      *
       
  1976      * @param  string $name
       
  1977      * @return boolean
       
  1978      */
       
  1979     public function removeDisplayGroup($name)
       
  1980     {
       
  1981         $name = (string) $name;
       
  1982         if (array_key_exists($name, $this->_displayGroups)) {
       
  1983             foreach ($this->_displayGroups[$name] as $key => $element) {
       
  1984                 if (array_key_exists($key, $this->_elements)) {
       
  1985                     $this->_order[$key]  = $element->getOrder();
       
  1986                     $this->_orderUpdated = true;
       
  1987                 }
       
  1988             }
       
  1989             unset($this->_displayGroups[$name]);
       
  1990 
       
  1991             if (array_key_exists($name, $this->_order)) {
       
  1992                 unset($this->_order[$name]);
       
  1993                 $this->_orderUpdated = true;
       
  1994             }
       
  1995             return true;
       
  1996         }
       
  1997 
       
  1998         return false;
       
  1999     }
       
  2000 
       
  2001     /**
       
  2002      * Remove all display groups
       
  2003      *
       
  2004      * @return Zend_Form
       
  2005      */
       
  2006     public function clearDisplayGroups()
       
  2007     {
       
  2008         foreach ($this->_displayGroups as $key => $group) {
       
  2009             if (array_key_exists($key, $this->_order)) {
       
  2010                 unset($this->_order[$key]);
       
  2011             }
       
  2012             foreach ($group as $name => $element) {
       
  2013                 if (isset($this->_elements[$name])) {
       
  2014                     $this->_order[$name] = $element->getOrder();
       
  2015                 }
       
  2016                 $this->_order[$name] = $element->getOrder();
       
  2017             }
       
  2018         }
       
  2019         $this->_displayGroups = array();
       
  2020         $this->_orderUpdated  = true;
       
  2021         return $this;
       
  2022     }
       
  2023 
       
  2024 
       
  2025     // Processing
       
  2026 
       
  2027     /**
       
  2028      * Populate form
       
  2029      *
       
  2030      * Proxies to {@link setDefaults()}
       
  2031      *
       
  2032      * @param  array $values
       
  2033      * @return Zend_Form
       
  2034      */
       
  2035     public function populate(array $values)
       
  2036     {
       
  2037         return $this->setDefaults($values);
       
  2038     }
       
  2039 
       
  2040     /**
       
  2041      * Determine array key name from given value
       
  2042      *
       
  2043      * Given a value such as foo[bar][baz], returns the last element (in this case, 'baz').
       
  2044      *
       
  2045      * @param  string $value
       
  2046      * @return string
       
  2047      */
       
  2048     protected function _getArrayName($value)
       
  2049     {
       
  2050         if (!is_string($value) || '' === $value) {
       
  2051             return $value;
       
  2052         }
       
  2053 
       
  2054         if (!strstr($value, '[')) {
       
  2055             return $value;
       
  2056         }
       
  2057 
       
  2058         $endPos = strlen($value) - 1;
       
  2059         if (']' != $value[$endPos]) {
       
  2060             return $value;
       
  2061         }
       
  2062 
       
  2063         $start = strrpos($value, '[') + 1;
       
  2064         $name = substr($value, $start, $endPos - $start);
       
  2065         return $name;
       
  2066     }
       
  2067 
       
  2068     /**
       
  2069      * Extract the value by walking the array using given array path.
       
  2070      *
       
  2071      * Given an array path such as foo[bar][baz], returns the value of the last
       
  2072      * element (in this case, 'baz').
       
  2073      *
       
  2074      * @param  array $value Array to walk
       
  2075      * @param  string $arrayPath Array notation path of the part to extract
       
  2076      * @return string
       
  2077      */
       
  2078     protected function _dissolveArrayValue($value, $arrayPath)
       
  2079     {
       
  2080         // As long as we have more levels
       
  2081         while ($arrayPos = strpos($arrayPath, '[')) {
       
  2082             // Get the next key in the path
       
  2083             $arrayKey = trim(substr($arrayPath, 0, $arrayPos), ']');
       
  2084 
       
  2085             // Set the potentially final value or the next search point in the array
       
  2086             if (isset($value[$arrayKey])) {
       
  2087                 $value = $value[$arrayKey];
       
  2088             }
       
  2089 
       
  2090             // Set the next search point in the path
       
  2091             $arrayPath = trim(substr($arrayPath, $arrayPos + 1), ']');
       
  2092         }
       
  2093 
       
  2094         if (isset($value[$arrayPath])) {
       
  2095             $value = $value[$arrayPath];
       
  2096         }
       
  2097 
       
  2098         return $value;
       
  2099     }
       
  2100 
       
  2101     /**
       
  2102      * Given an array, an optional arrayPath and a key this method
       
  2103      * dissolves the arrayPath and unsets the key within the array
       
  2104      * if it exists.
       
  2105      * 
       
  2106      * @param array $array 
       
  2107      * @param string|null $arrayPath
       
  2108      * @param string $key
       
  2109      * @return array
       
  2110      */
       
  2111     protected function _dissolveArrayUnsetKey($array, $arrayPath, $key)
       
  2112     {
       
  2113         $unset =& $array;
       
  2114         $path  = trim(strtr((string)$arrayPath, array('[' => '/', ']' => '')), '/');
       
  2115         $segs  = ('' !== $path) ? explode('/', $path) : array();
       
  2116         
       
  2117         foreach ($segs as $seg) {
       
  2118             if (!array_key_exists($seg, (array)$unset)) {
       
  2119                 return $array;
       
  2120             }
       
  2121             $unset =& $unset[$seg];
       
  2122         }
       
  2123         if (array_key_exists($key, (array)$unset)) {
       
  2124             unset($unset[$key]);
       
  2125         }
       
  2126         return $array;
       
  2127     }
       
  2128 
       
  2129     /**
       
  2130      * Converts given arrayPath to an array and attaches given value at the end of it.
       
  2131      *
       
  2132      * @param  mixed $value The value to attach
       
  2133      * @param  string $arrayPath Given array path to convert and attach to.
       
  2134      * @return array
       
  2135      */
       
  2136     protected function _attachToArray($value, $arrayPath)
       
  2137     {
       
  2138         // As long as we have more levels
       
  2139         while ($arrayPos = strrpos($arrayPath, '[')) {
       
  2140             // Get the next key in the path
       
  2141             $arrayKey = trim(substr($arrayPath, $arrayPos + 1), ']');
       
  2142 
       
  2143             // Attach
       
  2144             $value = array($arrayKey => $value);
       
  2145 
       
  2146             // Set the next search point in the path
       
  2147             $arrayPath = trim(substr($arrayPath, 0, $arrayPos), ']');
       
  2148         }
       
  2149 
       
  2150         $value = array($arrayPath => $value);
       
  2151 
       
  2152         return $value;
       
  2153     }
       
  2154 
       
  2155     /**
       
  2156      * Returns a one dimensional numerical indexed array with the
       
  2157      * Elements, SubForms and Elements from DisplayGroups as Values.
       
  2158      *
       
  2159      * Subitems are inserted based on their order Setting if set,
       
  2160      * otherwise they are appended, the resulting numerical index
       
  2161      * may differ from the order value.
       
  2162      * 
       
  2163      * @access protected
       
  2164      * @return array 
       
  2165      */
       
  2166     public function getElementsAndSubFormsOrdered()
       
  2167     {
       
  2168         $ordered = array();
       
  2169         foreach ($this->_order as $name => $order) {
       
  2170             $order = isset($order) ? $order : count($ordered);
       
  2171             if ($this->$name instanceof Zend_Form_Element ||
       
  2172                 $this->$name instanceof Zend_Form) {
       
  2173                 array_splice($ordered, $order, 0, array($this->$name));
       
  2174             } else if ($this->$name instanceof Zend_Form_DisplayGroup) {
       
  2175                 $subordered = array();
       
  2176                 foreach ($this->$name->getElements() as $element) {
       
  2177                     $suborder = $element->getOrder();
       
  2178                     $suborder = (null !== $suborder) ? $suborder : count($subordered);
       
  2179                     array_splice($subordered, $suborder, 0, array($element));
       
  2180                 }
       
  2181                 if (!empty($subordered)) {
       
  2182                     array_splice($ordered, $order, 0, $subordered);
       
  2183                 }
       
  2184             }
       
  2185         }
       
  2186         return $ordered;
       
  2187     }
       
  2188 
       
  2189     /**
       
  2190      * This is a helper function until php 5.3 is widespreaded 
       
  2191      * 
       
  2192      * @param array $into
       
  2193      * @access protected
       
  2194      * @return void
       
  2195      */
       
  2196     protected function _array_replace_recursive(array $into)
       
  2197     {
       
  2198         $fromArrays = array_slice(func_get_args(),1);
       
  2199 
       
  2200         foreach ($fromArrays as $from) {
       
  2201             foreach ($from as $key => $value) {
       
  2202                 if (is_array($value)) {
       
  2203                     if (!isset($into[$key])) {
       
  2204                         $into[$key] = array();
       
  2205                     }
       
  2206                     $into[$key] = $this->_array_replace_recursive($into[$key], $from[$key]);
       
  2207                 } else {
       
  2208                     $into[$key] = $value;
       
  2209                 }
       
  2210             }
       
  2211         }
       
  2212         return $into;
       
  2213     }
       
  2214 
       
  2215     /**
       
  2216      * Validate the form
       
  2217      *
       
  2218      * @param  array $data
       
  2219      * @return boolean
       
  2220      */
       
  2221     public function isValid($data)
       
  2222     {
       
  2223         if (!is_array($data)) {
       
  2224             require_once 'Zend/Form/Exception.php';
       
  2225             throw new Zend_Form_Exception(__METHOD__ . ' expects an array');
       
  2226         }
       
  2227         $translator = $this->getTranslator();
       
  2228         $valid      = true;
       
  2229         $eBelongTo  = null;
       
  2230 
       
  2231         if ($this->isArray()) {
       
  2232             $eBelongTo = $this->getElementsBelongTo();
       
  2233             $data = $this->_dissolveArrayValue($data, $eBelongTo);
       
  2234         }
       
  2235         $context = $data;
       
  2236         foreach ($this->getElements() as $key => $element) {
       
  2237             if (null !== $translator && $this->hasTranslator()
       
  2238                     && !$element->hasTranslator()) {
       
  2239                 $element->setTranslator($translator);
       
  2240             }
       
  2241             $check = $data;
       
  2242             if (($belongsTo = $element->getBelongsTo()) !== $eBelongTo) {
       
  2243                 $check = $this->_dissolveArrayValue($data, $belongsTo);
       
  2244             }
       
  2245             if (!isset($check[$key])) {
       
  2246                 $valid = $element->isValid(null, $context) && $valid;
       
  2247             } else {
       
  2248                 $valid = $element->isValid($check[$key], $context) && $valid;
       
  2249                 $data = $this->_dissolveArrayUnsetKey($data, $belongsTo, $key);
       
  2250             }
       
  2251         }
       
  2252         foreach ($this->getSubForms() as $key => $form) {
       
  2253             if (null !== $translator && !$form->hasTranslator()) {
       
  2254                 $form->setTranslator($translator);
       
  2255             }
       
  2256             if (isset($data[$key]) && !$form->isArray()) {
       
  2257                 $valid = $form->isValid($data[$key]) && $valid;
       
  2258             } else {
       
  2259                 $valid = $form->isValid($data) && $valid;
       
  2260             }
       
  2261         }
       
  2262 
       
  2263         $this->_errorsExist = !$valid;
       
  2264 
       
  2265         // If manually flagged as an error, return invalid status
       
  2266         if ($this->_errorsForced) {
       
  2267             return false;
       
  2268         }
       
  2269 
       
  2270         return $valid;
       
  2271     }
       
  2272 
       
  2273     /**
       
  2274      * Validate a partial form
       
  2275      *
       
  2276      * Does not check for required flags.
       
  2277      *
       
  2278      * @param  array $data
       
  2279      * @return boolean
       
  2280      */
       
  2281     public function isValidPartial(array $data)
       
  2282     {
       
  2283         $eBelongTo  = null;
       
  2284 
       
  2285         if ($this->isArray()) {
       
  2286             $eBelongTo = $this->getElementsBelongTo();
       
  2287             $data = $this->_dissolveArrayValue($data, $eBelongTo);
       
  2288         }
       
  2289 
       
  2290         $translator = $this->getTranslator();
       
  2291         $valid      = true;
       
  2292         $context    = $data;
       
  2293 
       
  2294         foreach ($this->getElements() as $key => $element) {
       
  2295             $check = $data;
       
  2296             if (($belongsTo = $element->getBelongsTo()) !== $eBelongTo) {
       
  2297                 $check = $this->_dissolveArrayValue($data, $belongsTo);
       
  2298             }
       
  2299             if (isset($check[$key])) {
       
  2300                 if (null !== $translator && !$element->hasTranslator()) {
       
  2301                     $element->setTranslator($translator);
       
  2302                 }
       
  2303                 $valid = $element->isValid($check[$key], $context) && $valid;
       
  2304                 $data = $this->_dissolveArrayUnsetKey($data, $belongsTo, $key);
       
  2305             }
       
  2306         }
       
  2307         foreach ($this->getSubForms() as $key => $form) {
       
  2308             if (null !== $translator && !$form->hasTranslator()) {
       
  2309                 $form->setTranslator($translator);
       
  2310             }
       
  2311             if (isset($data[$key]) && !$form->isArray()) {
       
  2312                 $valid = $form->isValidPartial($data[$key]) && $valid;
       
  2313             } else {
       
  2314                 $valid = $form->isValidPartial($data) && $valid;
       
  2315             }
       
  2316         }
       
  2317 
       
  2318         $this->_errorsExist = !$valid;
       
  2319         return $valid;
       
  2320     }
       
  2321 
       
  2322     /**
       
  2323      * Process submitted AJAX data
       
  2324      *
       
  2325      * Checks if provided $data is valid, via {@link isValidPartial()}. If so,
       
  2326      * it returns JSON-encoded boolean true. If not, it returns JSON-encoded
       
  2327      * error messages (as returned by {@link getMessages()}).
       
  2328      *
       
  2329      * @param  array $data
       
  2330      * @return string JSON-encoded boolean true or error messages
       
  2331      */
       
  2332     public function processAjax(array $data)
       
  2333     {
       
  2334         require_once 'Zend/Json.php';
       
  2335         if ($this->isValidPartial($data)) {
       
  2336             return Zend_Json::encode(true);
       
  2337         }
       
  2338         $messages = $this->getMessages();
       
  2339         return Zend_Json::encode($messages);
       
  2340     }
       
  2341 
       
  2342     /**
       
  2343      * Add a custom error message to return in the event of failed validation
       
  2344      *
       
  2345      * @param  string $message
       
  2346      * @return Zend_Form
       
  2347      */
       
  2348     public function addErrorMessage($message)
       
  2349     {
       
  2350         $this->_errorMessages[] = (string) $message;
       
  2351         return $this;
       
  2352     }
       
  2353 
       
  2354     /**
       
  2355      * Add multiple custom error messages to return in the event of failed validation
       
  2356      *
       
  2357      * @param  array $messages
       
  2358      * @return Zend_Form
       
  2359      */
       
  2360     public function addErrorMessages(array $messages)
       
  2361     {
       
  2362         foreach ($messages as $message) {
       
  2363             $this->addErrorMessage($message);
       
  2364         }
       
  2365         return $this;
       
  2366     }
       
  2367 
       
  2368     /**
       
  2369      * Same as addErrorMessages(), but clears custom error message stack first
       
  2370      *
       
  2371      * @param  array $messages
       
  2372      * @return Zend_Form
       
  2373      */
       
  2374     public function setErrorMessages(array $messages)
       
  2375     {
       
  2376         $this->clearErrorMessages();
       
  2377         return $this->addErrorMessages($messages);
       
  2378     }
       
  2379 
       
  2380     /**
       
  2381      * Retrieve custom error messages
       
  2382      *
       
  2383      * @return array
       
  2384      */
       
  2385     public function getErrorMessages()
       
  2386     {
       
  2387         return $this->_errorMessages;
       
  2388     }
       
  2389 
       
  2390     /**
       
  2391      * Clear custom error messages stack
       
  2392      *
       
  2393      * @return Zend_Form
       
  2394      */
       
  2395     public function clearErrorMessages()
       
  2396     {
       
  2397         $this->_errorMessages = array();
       
  2398         return $this;
       
  2399     }
       
  2400 
       
  2401     /**
       
  2402      * Mark the element as being in a failed validation state
       
  2403      *
       
  2404      * @return Zend_Form
       
  2405      */
       
  2406     public function markAsError()
       
  2407     {
       
  2408         $this->_errorsExist  = true;
       
  2409         $this->_errorsForced = true;
       
  2410         return $this;
       
  2411     }
       
  2412 
       
  2413     /**
       
  2414      * Add an error message and mark element as failed validation
       
  2415      *
       
  2416      * @param  string $message
       
  2417      * @return Zend_Form
       
  2418      */
       
  2419     public function addError($message)
       
  2420     {
       
  2421         $this->addErrorMessage($message);
       
  2422         $this->markAsError();
       
  2423         return $this;
       
  2424     }
       
  2425 
       
  2426     /**
       
  2427      * Add multiple error messages and flag element as failed validation
       
  2428      *
       
  2429      * @param  array $messages
       
  2430      * @return Zend_Form
       
  2431      */
       
  2432     public function addErrors(array $messages)
       
  2433     {
       
  2434         foreach ($messages as $message) {
       
  2435             $this->addError($message);
       
  2436         }
       
  2437         return $this;
       
  2438     }
       
  2439 
       
  2440     /**
       
  2441      * Overwrite any previously set error messages and flag as failed validation
       
  2442      *
       
  2443      * @param  array $messages
       
  2444      * @return Zend_Form
       
  2445      */
       
  2446     public function setErrors(array $messages)
       
  2447     {
       
  2448         $this->clearErrorMessages();
       
  2449         return $this->addErrors($messages);
       
  2450     }
       
  2451 
       
  2452 
       
  2453     public function persistData()
       
  2454     {
       
  2455     }
       
  2456 
       
  2457     /**
       
  2458      * Are there errors in the form?
       
  2459      *
       
  2460      * @return bool
       
  2461      */
       
  2462     public function isErrors()
       
  2463     {
       
  2464         return $this->_errorsExist;
       
  2465     }
       
  2466 
       
  2467     /**
       
  2468      * Get error codes for all elements failing validation
       
  2469      *
       
  2470      * @param  string $name
       
  2471      * @return array
       
  2472      */
       
  2473     public function getErrors($name = null, $suppressArrayNotation = false)
       
  2474     {
       
  2475         $errors = array();
       
  2476         if (null !== $name) {
       
  2477             if (isset($this->_elements[$name])) {
       
  2478                 return $this->getElement($name)->getErrors();
       
  2479             } else if (isset($this->_subForms[$name])) {
       
  2480                 return $this->getSubForm($name)->getErrors(null, true);
       
  2481             }
       
  2482         }
       
  2483         
       
  2484         foreach ($this->_elements as $key => $element) {
       
  2485             $errors[$key] = $element->getErrors();
       
  2486         }
       
  2487         foreach ($this->getSubForms() as $key => $subForm) {
       
  2488             $merge = array();
       
  2489             if (!$subForm->isArray()) {
       
  2490                 $merge[$key] = $subForm->getErrors();
       
  2491             } else {
       
  2492                 $merge = $this->_attachToArray($subForm->getErrors(null, true),
       
  2493                                                $subForm->getElementsBelongTo());
       
  2494             }
       
  2495             $errors = $this->_array_replace_recursive($errors, $merge);
       
  2496         }
       
  2497 
       
  2498         if (!$suppressArrayNotation &&
       
  2499             $this->isArray() &&
       
  2500             !$this->_getIsRendered()) {
       
  2501             $errors = $this->_attachToArray($errors, $this->getElementsBelongTo());
       
  2502         }
       
  2503 
       
  2504         return $errors;
       
  2505     }
       
  2506 
       
  2507     /**
       
  2508      * Retrieve error messages from elements failing validations
       
  2509      *
       
  2510      * @param  string $name
       
  2511      * @param  bool $suppressArrayNotation
       
  2512      * @return array
       
  2513      */
       
  2514     public function getMessages($name = null, $suppressArrayNotation = false)
       
  2515     {
       
  2516         if (null !== $name) {
       
  2517             if (isset($this->_elements[$name])) {
       
  2518                 return $this->getElement($name)->getMessages();
       
  2519             } else if (isset($this->_subForms[$name])) {
       
  2520                 return $this->getSubForm($name)->getMessages(null, true);
       
  2521             }
       
  2522             foreach ($this->getSubForms() as $key => $subForm) {
       
  2523                 if ($subForm->isArray()) {
       
  2524                     $belongTo = $subForm->getElementsBelongTo();
       
  2525                     if ($name == $this->_getArrayName($belongTo)) {
       
  2526                         return $subForm->getMessages(null, true);
       
  2527                     }
       
  2528                 }
       
  2529             }
       
  2530         }
       
  2531 
       
  2532         $customMessages = $this->_getErrorMessages();
       
  2533         if ($this->isErrors() && !empty($customMessages)) {
       
  2534             return $customMessages;
       
  2535         }
       
  2536 
       
  2537         $messages = array();
       
  2538 
       
  2539         foreach ($this->getElements() as $name => $element) {
       
  2540             $eMessages = $element->getMessages();
       
  2541             if (!empty($eMessages)) {
       
  2542                 $messages[$name] = $eMessages;
       
  2543             }
       
  2544         }
       
  2545 
       
  2546         foreach ($this->getSubForms() as $key => $subForm) {
       
  2547             $merge = $subForm->getMessages(null, true);
       
  2548             if (!empty($merge)) {
       
  2549                 if (!$subForm->isArray()) {
       
  2550                     $merge = array($key => $merge);
       
  2551                 } else {
       
  2552                     $merge = $this->_attachToArray($merge,
       
  2553                                                    $subForm->getElementsBelongTo());
       
  2554                 }
       
  2555                 $messages = $this->_array_replace_recursive($messages, $merge);
       
  2556             }
       
  2557         }
       
  2558 
       
  2559         if (!$suppressArrayNotation &&
       
  2560             $this->isArray() &&
       
  2561             !$this->_getIsRendered()) {
       
  2562             $messages = $this->_attachToArray($messages, $this->getElementsBelongTo());
       
  2563         }
       
  2564 
       
  2565         return $messages;
       
  2566     }
       
  2567 
       
  2568     /**
       
  2569      * Retrieve translated custom error messages
       
  2570      * Proxies to {@link _getErrorMessages()}.
       
  2571      * 
       
  2572      * @return array
       
  2573      */
       
  2574     public function getCustomMessages()
       
  2575     {
       
  2576         return $this->_getErrorMessages();
       
  2577     }
       
  2578 
       
  2579 
       
  2580     // Rendering
       
  2581 
       
  2582     /**
       
  2583      * Set view object
       
  2584      *
       
  2585      * @param  Zend_View_Interface $view
       
  2586      * @return Zend_Form
       
  2587      */
       
  2588     public function setView(Zend_View_Interface $view = null)
       
  2589     {
       
  2590         $this->_view = $view;
       
  2591         return $this;
       
  2592     }
       
  2593 
       
  2594     /**
       
  2595      * Retrieve view object
       
  2596      *
       
  2597      * If none registered, attempts to pull from ViewRenderer.
       
  2598      *
       
  2599      * @return Zend_View_Interface|null
       
  2600      */
       
  2601     public function getView()
       
  2602     {
       
  2603         if (null === $this->_view) {
       
  2604             require_once 'Zend/Controller/Action/HelperBroker.php';
       
  2605             $viewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer');
       
  2606             $this->setView($viewRenderer->view);
       
  2607         }
       
  2608 
       
  2609         return $this->_view;
       
  2610     }
       
  2611 
       
  2612     /**
       
  2613      * Instantiate a decorator based on class name or class name fragment
       
  2614      *
       
  2615      * @param  string $name
       
  2616      * @param  null|array $options
       
  2617      * @return Zend_Form_Decorator_Interface
       
  2618      */
       
  2619     protected function _getDecorator($name, $options)
       
  2620     {
       
  2621         $class = $this->getPluginLoader(self::DECORATOR)->load($name);
       
  2622         if (null === $options) {
       
  2623             $decorator = new $class;
       
  2624         } else {
       
  2625             $decorator = new $class($options);
       
  2626         }
       
  2627 
       
  2628         return $decorator;
       
  2629     }
       
  2630 
       
  2631     /**
       
  2632      * Add a decorator for rendering the element
       
  2633      *
       
  2634      * @param  string|Zend_Form_Decorator_Interface $decorator
       
  2635      * @param  array|Zend_Config $options Options with which to initialize decorator
       
  2636      * @return Zend_Form
       
  2637      */
       
  2638     public function addDecorator($decorator, $options = null)
       
  2639     {
       
  2640         if ($decorator instanceof Zend_Form_Decorator_Interface) {
       
  2641             $name = get_class($decorator);
       
  2642         } elseif (is_string($decorator)) {
       
  2643             $name      = $decorator;
       
  2644             $decorator = array(
       
  2645                 'decorator' => $name,
       
  2646                 'options'   => $options,
       
  2647             );
       
  2648         } elseif (is_array($decorator)) {
       
  2649             foreach ($decorator as $name => $spec) {
       
  2650                 break;
       
  2651             }
       
  2652             if (is_numeric($name)) {
       
  2653                 require_once 'Zend/Form/Exception.php';
       
  2654                 throw new Zend_Form_Exception('Invalid alias provided to addDecorator; must be alphanumeric string');
       
  2655             }
       
  2656             if (is_string($spec)) {
       
  2657                 $decorator = array(
       
  2658                     'decorator' => $spec,
       
  2659                     'options'   => $options,
       
  2660                 );
       
  2661             } elseif ($spec instanceof Zend_Form_Decorator_Interface) {
       
  2662                 $decorator = $spec;
       
  2663             }
       
  2664         } else {
       
  2665             require_once 'Zend/Form/Exception.php';
       
  2666             throw new Zend_Form_Exception('Invalid decorator provided to addDecorator; must be string or Zend_Form_Decorator_Interface');
       
  2667         }
       
  2668 
       
  2669         $this->_decorators[$name] = $decorator;
       
  2670 
       
  2671         return $this;
       
  2672     }
       
  2673 
       
  2674     /**
       
  2675      * Add many decorators at once
       
  2676      *
       
  2677      * @param  array $decorators
       
  2678      * @return Zend_Form
       
  2679      */
       
  2680     public function addDecorators(array $decorators)
       
  2681     {
       
  2682         foreach ($decorators as $decoratorName => $decoratorInfo) {
       
  2683             if (is_string($decoratorInfo) ||
       
  2684                 $decoratorInfo instanceof Zend_Form_Decorator_Interface) {
       
  2685                 if (!is_numeric($decoratorName)) {
       
  2686                     $this->addDecorator(array($decoratorName => $decoratorInfo));
       
  2687                 } else {
       
  2688                     $this->addDecorator($decoratorInfo);
       
  2689                 }
       
  2690             } elseif (is_array($decoratorInfo)) {
       
  2691                 $argc    = count($decoratorInfo);
       
  2692                 $options = array();
       
  2693                 if (isset($decoratorInfo['decorator'])) {
       
  2694                     $decorator = $decoratorInfo['decorator'];
       
  2695                     if (isset($decoratorInfo['options'])) {
       
  2696                         $options = $decoratorInfo['options'];
       
  2697                     }
       
  2698                     $this->addDecorator($decorator, $options);
       
  2699                 } else {
       
  2700                     switch (true) {
       
  2701                         case (0 == $argc):
       
  2702                             break;
       
  2703                         case (1 <= $argc):
       
  2704                             $decorator  = array_shift($decoratorInfo);
       
  2705                         case (2 <= $argc):
       
  2706                             $options = array_shift($decoratorInfo);
       
  2707                         default:
       
  2708                             $this->addDecorator($decorator, $options);
       
  2709                             break;
       
  2710                     }
       
  2711                 }
       
  2712             } else {
       
  2713                 require_once 'Zend/Form/Exception.php';
       
  2714                 throw new Zend_Form_Exception('Invalid decorator passed to addDecorators()');
       
  2715             }
       
  2716         }
       
  2717 
       
  2718         return $this;
       
  2719     }
       
  2720 
       
  2721     /**
       
  2722      * Overwrite all decorators
       
  2723      *
       
  2724      * @param  array $decorators
       
  2725      * @return Zend_Form
       
  2726      */
       
  2727     public function setDecorators(array $decorators)
       
  2728     {
       
  2729         $this->clearDecorators();
       
  2730         return $this->addDecorators($decorators);
       
  2731     }
       
  2732 
       
  2733     /**
       
  2734      * Retrieve a registered decorator
       
  2735      *
       
  2736      * @param  string $name
       
  2737      * @return false|Zend_Form_Decorator_Abstract
       
  2738      */
       
  2739     public function getDecorator($name)
       
  2740     {
       
  2741         if (!isset($this->_decorators[$name])) {
       
  2742             $len = strlen($name);
       
  2743             foreach ($this->_decorators as $localName => $decorator) {
       
  2744                 if ($len > strlen($localName)) {
       
  2745                     continue;
       
  2746                 }
       
  2747 
       
  2748                 if (0 === substr_compare($localName, $name, -$len, $len, true)) {
       
  2749                     if (is_array($decorator)) {
       
  2750                         return $this->_loadDecorator($decorator, $localName);
       
  2751                     }
       
  2752                     return $decorator;
       
  2753                 }
       
  2754             }
       
  2755             return false;
       
  2756         }
       
  2757 
       
  2758         if (is_array($this->_decorators[$name])) {
       
  2759             return $this->_loadDecorator($this->_decorators[$name], $name);
       
  2760         }
       
  2761 
       
  2762         return $this->_decorators[$name];
       
  2763     }
       
  2764 
       
  2765     /**
       
  2766      * Retrieve all decorators
       
  2767      *
       
  2768      * @return array
       
  2769      */
       
  2770     public function getDecorators()
       
  2771     {
       
  2772         foreach ($this->_decorators as $key => $value) {
       
  2773             if (is_array($value)) {
       
  2774                 $this->_loadDecorator($value, $key);
       
  2775             }
       
  2776         }
       
  2777         return $this->_decorators;
       
  2778     }
       
  2779 
       
  2780     /**
       
  2781      * Remove a single decorator
       
  2782      *
       
  2783      * @param  string $name
       
  2784      * @return bool
       
  2785      */
       
  2786     public function removeDecorator($name)
       
  2787     {
       
  2788         $decorator = $this->getDecorator($name);
       
  2789         if ($decorator) {
       
  2790             if (array_key_exists($name, $this->_decorators)) {
       
  2791                 unset($this->_decorators[$name]);
       
  2792             } else {
       
  2793                 $class = get_class($decorator);
       
  2794                 if (!array_key_exists($class, $this->_decorators)) {
       
  2795                     return false;
       
  2796                 }
       
  2797                 unset($this->_decorators[$class]);
       
  2798             }
       
  2799             return true;
       
  2800         }
       
  2801 
       
  2802         return false;
       
  2803     }
       
  2804 
       
  2805     /**
       
  2806      * Clear all decorators
       
  2807      *
       
  2808      * @return Zend_Form
       
  2809      */
       
  2810     public function clearDecorators()
       
  2811     {
       
  2812         $this->_decorators = array();
       
  2813         return $this;
       
  2814     }
       
  2815 
       
  2816     /**
       
  2817      * Set all element decorators as specified
       
  2818      *
       
  2819      * @param  array $decorators
       
  2820      * @param  array|null $elements Specific elements to decorate or exclude from decoration
       
  2821      * @param  bool $include Whether $elements is an inclusion or exclusion list
       
  2822      * @return Zend_Form
       
  2823      */
       
  2824     public function setElementDecorators(array $decorators, array $elements = null, $include = true)
       
  2825     {
       
  2826         if (is_array($elements)) {
       
  2827             if ($include) {
       
  2828                 $elementObjs = array();
       
  2829                 foreach ($elements as $name) {
       
  2830                     if (null !== ($element = $this->getElement($name))) {
       
  2831                         $elementObjs[] = $element;
       
  2832                     }
       
  2833                 }
       
  2834             } else {
       
  2835                 $elementObjs = $this->getElements();
       
  2836                 foreach ($elements as $name) {
       
  2837                     if (array_key_exists($name, $elementObjs)) {
       
  2838                         unset($elementObjs[$name]);
       
  2839                     }
       
  2840                 }
       
  2841             }
       
  2842         } else {
       
  2843             $elementObjs = $this->getElements();
       
  2844         }
       
  2845 
       
  2846         foreach ($elementObjs as $element) {
       
  2847             $element->setDecorators($decorators);
       
  2848         }
       
  2849 
       
  2850         $this->_elementDecorators = $decorators;
       
  2851 
       
  2852         return $this;
       
  2853     }
       
  2854 
       
  2855     /**
       
  2856      * Set all display group decorators as specified
       
  2857      *
       
  2858      * @param  array $decorators
       
  2859      * @return Zend_Form
       
  2860      */
       
  2861     public function setDisplayGroupDecorators(array $decorators)
       
  2862     {
       
  2863         foreach ($this->getDisplayGroups() as $group) {
       
  2864             $group->setDecorators($decorators);
       
  2865         }
       
  2866 
       
  2867         return $this;
       
  2868     }
       
  2869 
       
  2870     /**
       
  2871      * Set all subform decorators as specified
       
  2872      *
       
  2873      * @param  array $decorators
       
  2874      * @return Zend_Form
       
  2875      */
       
  2876     public function setSubFormDecorators(array $decorators)
       
  2877     {
       
  2878         foreach ($this->getSubForms() as $form) {
       
  2879             $form->setDecorators($decorators);
       
  2880         }
       
  2881 
       
  2882         return $this;
       
  2883     }
       
  2884 
       
  2885     /**
       
  2886      * Render form
       
  2887      *
       
  2888      * @param  Zend_View_Interface $view
       
  2889      * @return string
       
  2890      */
       
  2891     public function render(Zend_View_Interface $view = null)
       
  2892     {
       
  2893         if (null !== $view) {
       
  2894             $this->setView($view);
       
  2895         }
       
  2896 
       
  2897         $content = '';
       
  2898         foreach ($this->getDecorators() as $decorator) {
       
  2899             $decorator->setElement($this);
       
  2900             $content = $decorator->render($content);
       
  2901         }
       
  2902         $this->_setIsRendered();
       
  2903         return $content;
       
  2904     }
       
  2905 
       
  2906     /**
       
  2907      * Serialize as string
       
  2908      *
       
  2909      * Proxies to {@link render()}.
       
  2910      *
       
  2911      * @return string
       
  2912      */
       
  2913     public function __toString()
       
  2914     {
       
  2915         try {
       
  2916             $return = $this->render();
       
  2917             return $return;
       
  2918         } catch (Exception $e) {
       
  2919             $message = "Exception caught by form: " . $e->getMessage()
       
  2920                      . "\nStack Trace:\n" . $e->getTraceAsString();
       
  2921             trigger_error($message, E_USER_WARNING);
       
  2922             return '';
       
  2923         }
       
  2924     }
       
  2925 
       
  2926 
       
  2927     // Localization:
       
  2928 
       
  2929     /**
       
  2930      * Set translator object
       
  2931      *
       
  2932      * @param  Zend_Translate|Zend_Translate_Adapter|null $translator
       
  2933      * @return Zend_Form
       
  2934      */
       
  2935     public function setTranslator($translator = null)
       
  2936     {
       
  2937         if (null === $translator) {
       
  2938             $this->_translator = null;
       
  2939         } elseif ($translator instanceof Zend_Translate_Adapter) {
       
  2940             $this->_translator = $translator;
       
  2941         } elseif ($translator instanceof Zend_Translate) {
       
  2942             $this->_translator = $translator->getAdapter();
       
  2943         } else {
       
  2944             require_once 'Zend/Form/Exception.php';
       
  2945             throw new Zend_Form_Exception('Invalid translator specified');
       
  2946         }
       
  2947 
       
  2948         return $this;
       
  2949     }
       
  2950 
       
  2951     /**
       
  2952      * Set global default translator object
       
  2953      *
       
  2954      * @param  Zend_Translate|Zend_Translate_Adapter|null $translator
       
  2955      * @return void
       
  2956      */
       
  2957     public static function setDefaultTranslator($translator = null)
       
  2958     {
       
  2959         if (null === $translator) {
       
  2960             self::$_translatorDefault = null;
       
  2961         } elseif ($translator instanceof Zend_Translate_Adapter) {
       
  2962             self::$_translatorDefault = $translator;
       
  2963         } elseif ($translator instanceof Zend_Translate) {
       
  2964             self::$_translatorDefault = $translator->getAdapter();
       
  2965         } else {
       
  2966             require_once 'Zend/Form/Exception.php';
       
  2967             throw new Zend_Form_Exception('Invalid translator specified');
       
  2968         }
       
  2969     }
       
  2970 
       
  2971     /**
       
  2972      * Retrieve translator object
       
  2973      *
       
  2974      * @return Zend_Translate|null
       
  2975      */
       
  2976     public function getTranslator()
       
  2977     {
       
  2978         if ($this->translatorIsDisabled()) {
       
  2979             return null;
       
  2980         }
       
  2981 
       
  2982         if (null === $this->_translator) {
       
  2983             return self::getDefaultTranslator();
       
  2984         }
       
  2985 
       
  2986         return $this->_translator;
       
  2987     }
       
  2988     
       
  2989     /**
       
  2990      * Does this form have its own specific translator?
       
  2991      * 
       
  2992      * @return bool
       
  2993      */
       
  2994     public function hasTranslator()
       
  2995     {
       
  2996         return (bool)$this->_translator;
       
  2997     }    
       
  2998 
       
  2999     /**
       
  3000      * Get global default translator object
       
  3001      *
       
  3002      * @return null|Zend_Translate
       
  3003      */
       
  3004     public static function getDefaultTranslator()
       
  3005     {
       
  3006         if (null === self::$_translatorDefault) {
       
  3007             require_once 'Zend/Registry.php';
       
  3008             if (Zend_Registry::isRegistered('Zend_Translate')) {
       
  3009                 $translator = Zend_Registry::get('Zend_Translate');
       
  3010                 if ($translator instanceof Zend_Translate_Adapter) {
       
  3011                     return $translator;
       
  3012                 } elseif ($translator instanceof Zend_Translate) {
       
  3013                     return $translator->getAdapter();
       
  3014                 }
       
  3015             }
       
  3016         }
       
  3017         return self::$_translatorDefault;
       
  3018     }
       
  3019 
       
  3020     /**
       
  3021      * Is there a default translation object set?
       
  3022      * 
       
  3023      * @return boolean
       
  3024      */
       
  3025     public static function hasDefaultTranslator()
       
  3026     { 
       
  3027         return (bool)self::$_translatorDefault;
       
  3028     }
       
  3029     
       
  3030     /**
       
  3031      * Indicate whether or not translation should be disabled
       
  3032      *
       
  3033      * @param  bool $flag
       
  3034      * @return Zend_Form
       
  3035      */
       
  3036     public function setDisableTranslator($flag)
       
  3037     {
       
  3038         $this->_translatorDisabled = (bool) $flag;
       
  3039         return $this;
       
  3040     }
       
  3041 
       
  3042     /**
       
  3043      * Is translation disabled?
       
  3044      *
       
  3045      * @return bool
       
  3046      */
       
  3047     public function translatorIsDisabled()
       
  3048     {
       
  3049         return $this->_translatorDisabled;
       
  3050     }
       
  3051 
       
  3052     /**
       
  3053      * Overloading: access to elements, form groups, and display groups
       
  3054      *
       
  3055      * @param  string $name
       
  3056      * @return Zend_Form_Element|Zend_Form|null
       
  3057      */
       
  3058     public function __get($name)
       
  3059     {
       
  3060         if (isset($this->_elements[$name])) {
       
  3061             return $this->_elements[$name];
       
  3062         } elseif (isset($this->_subForms[$name])) {
       
  3063             return $this->_subForms[$name];
       
  3064         } elseif (isset($this->_displayGroups[$name])) {
       
  3065             return $this->_displayGroups[$name];
       
  3066         }
       
  3067 
       
  3068         return null;
       
  3069     }
       
  3070 
       
  3071     /**
       
  3072      * Overloading: access to elements, form groups, and display groups
       
  3073      *
       
  3074      * @param  string $name
       
  3075      * @param  Zend_Form_Element|Zend_Form $value
       
  3076      * @return void
       
  3077      * @throws Zend_Form_Exception for invalid $value
       
  3078      */
       
  3079     public function __set($name, $value)
       
  3080     {
       
  3081         if ($value instanceof Zend_Form_Element) {
       
  3082             $this->addElement($value, $name);
       
  3083             return;
       
  3084         } elseif ($value instanceof Zend_Form) {
       
  3085             $this->addSubForm($value, $name);
       
  3086             return;
       
  3087         } elseif (is_array($value)) {
       
  3088             $this->addDisplayGroup($value, $name);
       
  3089             return;
       
  3090         }
       
  3091 
       
  3092         require_once 'Zend/Form/Exception.php';
       
  3093         if (is_object($value)) {
       
  3094             $type = get_class($value);
       
  3095         } else {
       
  3096             $type = gettype($value);
       
  3097         }
       
  3098         throw new Zend_Form_Exception('Only form elements and groups may be overloaded; variable of type "' . $type . '" provided');
       
  3099     }
       
  3100 
       
  3101     /**
       
  3102      * Overloading: access to elements, form groups, and display groups
       
  3103      *
       
  3104      * @param  string $name
       
  3105      * @return boolean
       
  3106      */
       
  3107     public function __isset($name)
       
  3108     {
       
  3109         if (isset($this->_elements[$name])
       
  3110             || isset($this->_subForms[$name])
       
  3111             || isset($this->_displayGroups[$name]))
       
  3112         {
       
  3113             return true;
       
  3114         }
       
  3115 
       
  3116         return false;
       
  3117     }
       
  3118 
       
  3119     /**
       
  3120      * Overloading: access to elements, form groups, and display groups
       
  3121      *
       
  3122      * @param  string $name
       
  3123      * @return void
       
  3124      */
       
  3125     public function __unset($name)
       
  3126     {
       
  3127         if (isset($this->_elements[$name])) {
       
  3128             unset($this->_elements[$name]);
       
  3129         } elseif (isset($this->_subForms[$name])) {
       
  3130             unset($this->_subForms[$name]);
       
  3131         } elseif (isset($this->_displayGroups[$name])) {
       
  3132             unset($this->_displayGroups[$name]);
       
  3133         }
       
  3134     }
       
  3135 
       
  3136     /**
       
  3137      * Overloading: allow rendering specific decorators
       
  3138      *
       
  3139      * Call renderDecoratorName() to render a specific decorator.
       
  3140      *
       
  3141      * @param  string $method
       
  3142      * @param  array $args
       
  3143      * @return string
       
  3144      * @throws Zend_Form_Exception for invalid decorator or invalid method call
       
  3145      */
       
  3146     public function __call($method, $args)
       
  3147     {
       
  3148         if ('render' == substr($method, 0, 6)) {
       
  3149             $decoratorName = substr($method, 6);
       
  3150             if (false !== ($decorator = $this->getDecorator($decoratorName))) {
       
  3151                 $decorator->setElement($this);
       
  3152                 $seed = '';
       
  3153                 if (0 < count($args)) {
       
  3154                     $seed = array_shift($args);
       
  3155                 }
       
  3156                 if ($decoratorName === 'FormElements' ||
       
  3157                     $decoratorName === 'PrepareElements') {
       
  3158                         $this->_setIsRendered();
       
  3159                 }
       
  3160                 return $decorator->render($seed);
       
  3161             }
       
  3162 
       
  3163             require_once 'Zend/Form/Exception.php';
       
  3164             throw new Zend_Form_Exception(sprintf('Decorator by name %s does not exist', $decoratorName));
       
  3165         }
       
  3166 
       
  3167         require_once 'Zend/Form/Exception.php';
       
  3168         throw new Zend_Form_Exception(sprintf('Method %s does not exist', $method));
       
  3169     }
       
  3170 
       
  3171     // Interfaces: Iterator, Countable
       
  3172 
       
  3173     /**
       
  3174      * Current element/subform/display group
       
  3175      *
       
  3176      * @return Zend_Form_Element|Zend_Form_DisplayGroup|Zend_Form
       
  3177      */
       
  3178     public function current()
       
  3179     {
       
  3180         $this->_sort();
       
  3181         current($this->_order);
       
  3182         $key = key($this->_order);
       
  3183 
       
  3184         if (isset($this->_elements[$key])) {
       
  3185             return $this->getElement($key);
       
  3186         } elseif (isset($this->_subForms[$key])) {
       
  3187             return $this->getSubForm($key);
       
  3188         } elseif (isset($this->_displayGroups[$key])) {
       
  3189             return $this->getDisplayGroup($key);
       
  3190         } else {
       
  3191             require_once 'Zend/Form/Exception.php';
       
  3192             throw new Zend_Form_Exception(sprintf('Corruption detected in form; invalid key ("%s") found in internal iterator', (string) $key));
       
  3193         }
       
  3194     }
       
  3195 
       
  3196     /**
       
  3197      * Current element/subform/display group name
       
  3198      *
       
  3199      * @return string
       
  3200      */
       
  3201     public function key()
       
  3202     {
       
  3203         $this->_sort();
       
  3204         return key($this->_order);
       
  3205     }
       
  3206 
       
  3207     /**
       
  3208      * Move pointer to next element/subform/display group
       
  3209      *
       
  3210      * @return void
       
  3211      */
       
  3212     public function next()
       
  3213     {
       
  3214         $this->_sort();
       
  3215         next($this->_order);
       
  3216     }
       
  3217 
       
  3218     /**
       
  3219      * Move pointer to beginning of element/subform/display group loop
       
  3220      *
       
  3221      * @return void
       
  3222      */
       
  3223     public function rewind()
       
  3224     {
       
  3225         $this->_sort();
       
  3226         reset($this->_order);
       
  3227     }
       
  3228 
       
  3229     /**
       
  3230      * Determine if current element/subform/display group is valid
       
  3231      *
       
  3232      * @return bool
       
  3233      */
       
  3234     public function valid()
       
  3235     {
       
  3236         $this->_sort();
       
  3237         return (current($this->_order) !== false);
       
  3238     }
       
  3239 
       
  3240     /**
       
  3241      * Count of elements/subforms that are iterable
       
  3242      *
       
  3243      * @return int
       
  3244      */
       
  3245     public function count()
       
  3246     {
       
  3247         return count($this->_order);
       
  3248     }
       
  3249 
       
  3250     /**
       
  3251      * Set flag to disable loading default decorators
       
  3252      *
       
  3253      * @param  bool $flag
       
  3254      * @return Zend_Form
       
  3255      */
       
  3256     public function setDisableLoadDefaultDecorators($flag)
       
  3257     {
       
  3258         $this->_disableLoadDefaultDecorators = (bool) $flag;
       
  3259         return $this;
       
  3260     }
       
  3261 
       
  3262     /**
       
  3263      * Should we load the default decorators?
       
  3264      *
       
  3265      * @return bool
       
  3266      */
       
  3267     public function loadDefaultDecoratorsIsDisabled()
       
  3268     {
       
  3269         return $this->_disableLoadDefaultDecorators;
       
  3270     }
       
  3271 
       
  3272     /**
       
  3273      * Load the default decorators
       
  3274      *
       
  3275      * @return void
       
  3276      */
       
  3277     public function loadDefaultDecorators()
       
  3278     {
       
  3279         if ($this->loadDefaultDecoratorsIsDisabled()) {
       
  3280             return $this;
       
  3281         }
       
  3282 
       
  3283         $decorators = $this->getDecorators();
       
  3284         if (empty($decorators)) {
       
  3285             $this->addDecorator('FormElements')
       
  3286                  ->addDecorator('HtmlTag', array('tag' => 'dl', 'class' => 'zend_form'))
       
  3287                  ->addDecorator('Form');
       
  3288         }
       
  3289         return $this;
       
  3290     }
       
  3291 
       
  3292     /**
       
  3293      * Remove an element from iteration
       
  3294      * 
       
  3295      * @param  string $name Element/group/form name
       
  3296      * @return void
       
  3297      */
       
  3298     public function removeFromIteration($name)
       
  3299     {
       
  3300         if (array_key_exists($name, $this->_order)) {
       
  3301             unset($this->_order[$name]);
       
  3302             $this->_orderUpdated = true;
       
  3303         }
       
  3304     }
       
  3305 
       
  3306     /**
       
  3307      * Sort items according to their order
       
  3308      *
       
  3309      * @return void
       
  3310      */
       
  3311     protected function _sort()
       
  3312     {
       
  3313         if ($this->_orderUpdated) {
       
  3314             $items = array();
       
  3315             $index = 0;
       
  3316             foreach ($this->_order as $key => $order) {
       
  3317                 if (null === $order) {
       
  3318                     if (null === ($order = $this->{$key}->getOrder())) {
       
  3319                         while (array_search($index, $this->_order, true)) {
       
  3320                             ++$index;
       
  3321                         }
       
  3322                         $items[$index] = $key;
       
  3323                         ++$index;
       
  3324                     } else {
       
  3325                         $items[$order] = $key;
       
  3326                     }
       
  3327                 } else {
       
  3328                     $items[$order] = $key;
       
  3329                 }
       
  3330             }
       
  3331 
       
  3332             $items = array_flip($items);
       
  3333             asort($items);
       
  3334             $this->_order = $items;
       
  3335             $this->_orderUpdated = false;
       
  3336         }
       
  3337     }
       
  3338 
       
  3339     /**
       
  3340      * Lazy-load a decorator
       
  3341      *
       
  3342      * @param  array $decorator Decorator type and options
       
  3343      * @param  mixed $name Decorator name or alias
       
  3344      * @return Zend_Form_Decorator_Interface
       
  3345      */
       
  3346     protected function _loadDecorator(array $decorator, $name)
       
  3347     {
       
  3348         $sameName = false;
       
  3349         if ($name == $decorator['decorator']) {
       
  3350             $sameName = true;
       
  3351         }
       
  3352 
       
  3353         $instance = $this->_getDecorator($decorator['decorator'], $decorator['options']);
       
  3354         if ($sameName) {
       
  3355             $newName            = get_class($instance);
       
  3356             $decoratorNames     = array_keys($this->_decorators);
       
  3357             $order              = array_flip($decoratorNames);
       
  3358             $order[$newName]    = $order[$name];
       
  3359             $decoratorsExchange = array();
       
  3360             unset($order[$name]);
       
  3361             asort($order);
       
  3362             foreach ($order as $key => $index) {
       
  3363                 if ($key == $newName) {
       
  3364                     $decoratorsExchange[$key] = $instance;
       
  3365                     continue;
       
  3366                 }
       
  3367                 $decoratorsExchange[$key] = $this->_decorators[$key];
       
  3368             }
       
  3369             $this->_decorators = $decoratorsExchange;
       
  3370         } else {
       
  3371             $this->_decorators[$name] = $instance;
       
  3372         }
       
  3373 
       
  3374         return $instance;
       
  3375     }
       
  3376 
       
  3377     /**
       
  3378      * Retrieve optionally translated custom error messages
       
  3379      *
       
  3380      * @return array
       
  3381      */
       
  3382     protected function _getErrorMessages()
       
  3383     {
       
  3384         $messages   = $this->getErrorMessages();
       
  3385         $translator = $this->getTranslator();
       
  3386         if (null !== $translator) {
       
  3387             foreach ($messages as $key => $message) {
       
  3388                 $messages[$key] = $translator->translate($message);
       
  3389             }
       
  3390         }
       
  3391         return $messages;
       
  3392     }
       
  3393 }