~clinton-collins/familyproject/trunk

« back to all changes in this revision

Viewing changes to ZendFramework/library/Zend/Form/Element.php

  • Committer: Clinton Collins
  • Date: 2009-06-26 19:54:58 UTC
  • Revision ID: clinton.collins@gmail.com-20090626195458-5ebba0qcvo15xlpy
Initial Import

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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-2008 Zend Technologies USA Inc. (http://www.zend.com)
 
18
 * @license    http://framework.zend.com/license/new-bsd     New BSD License
 
19
 */
 
20
 
 
21
/** Zend_Filter */
 
22
require_once 'Zend/Filter.php';
 
23
 
 
24
/** Zend_Validate_Interface */
 
25
require_once 'Zend/Validate/Interface.php';
 
26
 
 
27
/**
 
28
 * Zend_Form_Element
 
29
 *
 
30
 * @category   Zend
 
31
 * @package    Zend_Form
 
32
 * @subpackage Element
 
33
 * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
 
34
 * @license    http://framework.zend.com/license/new-bsd     New BSD License
 
35
 * @version    $Id: Element.php 13615 2009-01-13 19:52:10Z norm2782 $
 
36
 */
 
37
class Zend_Form_Element implements Zend_Validate_Interface
 
38
{
 
39
    /**
 
40
     * Element Constants
 
41
     */
 
42
    const DECORATOR = 'DECORATOR';
 
43
    const FILTER    = 'FILTER';
 
44
    const VALIDATE  = 'VALIDATE';
 
45
 
 
46
    /**
 
47
     * Default view helper to use
 
48
     * @var string
 
49
     */
 
50
    public $helper = 'formText';
 
51
 
 
52
    /**
 
53
     * 'Allow empty' flag
 
54
     * @var bool
 
55
     */
 
56
    protected $_allowEmpty = true;
 
57
 
 
58
    /**
 
59
     * Flag indicating whether or not to insert NotEmpty validator when element is required
 
60
     * @var bool
 
61
     */
 
62
    protected $_autoInsertNotEmptyValidator = true;
 
63
 
 
64
    /**
 
65
     * Array to which element belongs
 
66
     * @var string
 
67
     */
 
68
    protected $_belongsTo;
 
69
 
 
70
    /**
 
71
     * Element decorators
 
72
     * @var array
 
73
     */
 
74
    protected $_decorators = array();
 
75
 
 
76
    /**
 
77
     * Element 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
     * Custom error messages
 
90
     * @var array
 
91
     */
 
92
    protected $_errorMessages = array();
 
93
 
 
94
    /**
 
95
     * Validation errors
 
96
     * @var array
 
97
     */
 
98
    protected $_errors = array();
 
99
 
 
100
    /**
 
101
     * Element filters
 
102
     * @var array
 
103
     */
 
104
    protected $_filters = array();
 
105
 
 
106
    /**
 
107
     * Ignore flag (used when retrieving values at form level)
 
108
     * @var bool
 
109
     */
 
110
    protected $_ignore = false;
 
111
 
 
112
    /**
 
113
     * Does the element represent an array?
 
114
     * @var bool
 
115
     */
 
116
    protected $_isArray = false;
 
117
 
 
118
    /**
 
119
     * Is the error marked as in an invalid state?
 
120
     * @var bool
 
121
     */
 
122
    protected $_isError = false;
 
123
 
 
124
    /**
 
125
     * Element label
 
126
     * @var string
 
127
     */
 
128
    protected $_label;
 
129
 
 
130
    /**
 
131
     * Plugin loaders for filter and validator chains
 
132
     * @var array
 
133
     */
 
134
    protected $_loaders = array();
 
135
 
 
136
    /**
 
137
     * Formatted validation error messages
 
138
     * @var array
 
139
     */
 
140
    protected $_messages = array();
 
141
 
 
142
    /**
 
143
     * Element name
 
144
     * @var string
 
145
     */
 
146
    protected $_name;
 
147
 
 
148
    /**
 
149
     * Order of element
 
150
     * @var int
 
151
     */
 
152
    protected $_order;
 
153
 
 
154
    /**
 
155
     * Required flag
 
156
     * @var bool
 
157
     */
 
158
    protected $_required = false;
 
159
 
 
160
    /**
 
161
     * @var Zend_Translate
 
162
     */
 
163
    protected $_translator;
 
164
 
 
165
    /**
 
166
     * Is translation disabled?
 
167
     * @var bool
 
168
     */
 
169
    protected $_translatorDisabled = false;
 
170
 
 
171
    /**
 
172
     * Element type
 
173
     * @var string
 
174
     */
 
175
    protected $_type;
 
176
 
 
177
    /**
 
178
     * Array of initialized validators
 
179
     * @var array Validators
 
180
     */
 
181
    protected $_validators = array();
 
182
 
 
183
    /**
 
184
     * Array of un-initialized validators
 
185
     * @var array
 
186
     */
 
187
    protected $_validatorRules = array();
 
188
 
 
189
    /**
 
190
     * Element value
 
191
     * @var mixed
 
192
     */
 
193
    protected $_value;
 
194
 
 
195
    /**
 
196
     * @var Zend_View_Interface
 
197
     */
 
198
    protected $_view;
 
199
 
 
200
    /**
 
201
     * Constructor
 
202
     *
 
203
     * $spec may be:
 
204
     * - string: name of element
 
205
     * - array: options with which to configure element
 
206
     * - Zend_Config: Zend_Config with options for configuring element
 
207
     *
 
208
     * @param  string|array|Zend_Config $spec
 
209
     * @return void
 
210
     * @throws Zend_Form_Exception if no element name after initialization
 
211
     */
 
212
    public function __construct($spec, $options = null)
 
213
    {
 
214
        if (is_string($spec)) {
 
215
            $this->setName($spec);
 
216
        } elseif (is_array($spec)) {
 
217
            $this->setOptions($spec);
 
218
        } elseif ($spec instanceof Zend_Config) {
 
219
            $this->setConfig($spec);
 
220
        }
 
221
 
 
222
        if (is_string($spec) && is_array($options)) {
 
223
            $this->setOptions($options);
 
224
        } elseif (is_string($spec) && ($options instanceof Zend_Config)) {
 
225
            $this->setConfig($options);
 
226
        }
 
227
 
 
228
        if (null === $this->getName()) {
 
229
            require_once 'Zend/Form/Exception.php';
 
230
            throw new Zend_Form_Exception('Zend_Form_Element requires each element to have a name');
 
231
        }
 
232
 
 
233
        /**
 
234
         * Extensions
 
235
         */
 
236
        $this->init();
 
237
 
 
238
        /**
 
239
         * Register ViewHelper decorator by default
 
240
         */
 
241
        $this->loadDefaultDecorators();
 
242
    }
 
243
 
 
244
    /**
 
245
     * Initialize object; used by extending classes
 
246
     *
 
247
     * @return void
 
248
     */
 
249
    public function init()
 
250
    {
 
251
    }
 
252
 
 
253
    /**
 
254
     * Set flag to disable loading default decorators
 
255
     *
 
256
     * @param  bool $flag
 
257
     * @return Zend_Form_Element
 
258
     */
 
259
    public function setDisableLoadDefaultDecorators($flag)
 
260
    {
 
261
        $this->_disableLoadDefaultDecorators = (bool) $flag;
 
262
        return $this;
 
263
    }
 
264
 
 
265
    /**
 
266
     * Should we load the default decorators?
 
267
     *
 
268
     * @return bool
 
269
     */
 
270
    public function loadDefaultDecoratorsIsDisabled()
 
271
    {
 
272
        return $this->_disableLoadDefaultDecorators;
 
273
    }
 
274
 
 
275
    /**
 
276
     * Load default decorators
 
277
     *
 
278
     * @return void
 
279
     */
 
280
    public function loadDefaultDecorators()
 
281
    {
 
282
        if ($this->loadDefaultDecoratorsIsDisabled()) {
 
283
            return;
 
284
        }
 
285
 
 
286
        $decorators = $this->getDecorators();
 
287
        if (empty($decorators)) {
 
288
            $this->addDecorator('ViewHelper')
 
289
                ->addDecorator('Errors')
 
290
                ->addDecorator('Description', array('tag' => 'p', 'class' => 'description'))
 
291
                ->addDecorator('HtmlTag', array('tag' => 'dd',
 
292
                                                'id'  => $this->getName() . '-element'))
 
293
                ->addDecorator('Label', array('tag' => 'dt'));
 
294
        }
 
295
    }
 
296
 
 
297
    /**
 
298
     * Set object state from options array
 
299
     *
 
300
     * @param  array $options
 
301
     * @return Zend_Form_Element
 
302
     */
 
303
    public function setOptions(array $options)
 
304
    {
 
305
        if (isset($options['prefixPath'])) {
 
306
            $this->addPrefixPaths($options['prefixPath']);
 
307
            unset($options['prefixPath']);
 
308
        }
 
309
 
 
310
        if (isset($options['disableTranslator'])) {
 
311
            $this->setDisableTranslator($options['disableTranslator']);
 
312
            unset($options['disableTranslator']);
 
313
        }
 
314
 
 
315
        unset($options['options']);
 
316
        unset($options['config']);
 
317
 
 
318
        foreach ($options as $key => $value) {
 
319
            $method = 'set' . ucfirst($key);
 
320
 
 
321
            if (in_array($method, array('setTranslator', 'setPluginLoader', 'setView'))) {
 
322
                if (!is_object($value)) {
 
323
                    continue;
 
324
                }
 
325
            }
 
326
 
 
327
            if (method_exists($this, $method)) {
 
328
                // Setter exists; use it
 
329
                $this->$method($value);
 
330
            } else {
 
331
                // Assume it's metadata
 
332
                $this->setAttrib($key, $value);
 
333
            }
 
334
        }
 
335
        return $this;
 
336
    }
 
337
 
 
338
    /**
 
339
     * Set object state from Zend_Config object
 
340
     *
 
341
     * @param  Zend_Config $config
 
342
     * @return Zend_Form_Element
 
343
     */
 
344
    public function setConfig(Zend_Config $config)
 
345
    {
 
346
        return $this->setOptions($config->toArray());
 
347
    }
 
348
 
 
349
 
 
350
    // Localization:
 
351
 
 
352
    /**
 
353
     * Set translator object for localization
 
354
     *
 
355
     * @param  Zend_Translate|null $translator
 
356
     * @return Zend_Form_Element
 
357
     */
 
358
    public function setTranslator($translator = null)
 
359
    {
 
360
        if (null === $translator) {
 
361
            $this->_translator = null;
 
362
        } elseif ($translator instanceof Zend_Translate_Adapter) {
 
363
            $this->_translator = $translator;
 
364
        } elseif ($translator instanceof Zend_Translate) {
 
365
            $this->_translator = $translator->getAdapter();
 
366
        } else {
 
367
            require_once 'Zend/Form/Exception.php';
 
368
            throw new Zend_Form_Exception('Invalid translator specified');
 
369
        }
 
370
        return $this;
 
371
    }
 
372
 
 
373
    /**
 
374
     * Retrieve localization translator object
 
375
     *
 
376
     * @return Zend_Translate_Adapter|null
 
377
     */
 
378
    public function getTranslator()
 
379
    {
 
380
        if ($this->translatorIsDisabled()) {
 
381
            return null;
 
382
        }
 
383
 
 
384
        if (null === $this->_translator) {
 
385
            require_once 'Zend/Form.php';
 
386
            return Zend_Form::getDefaultTranslator();
 
387
        }
 
388
        return $this->_translator;
 
389
    }
 
390
 
 
391
    /**
 
392
     * Indicate whether or not translation should be disabled
 
393
     *
 
394
     * @param  bool $flag
 
395
     * @return Zend_Form_Element
 
396
     */
 
397
    public function setDisableTranslator($flag)
 
398
    {
 
399
        $this->_translatorDisabled = (bool) $flag;
 
400
        return $this;
 
401
    }
 
402
 
 
403
    /**
 
404
     * Is translation disabled?
 
405
     *
 
406
     * @return bool
 
407
     */
 
408
    public function translatorIsDisabled()
 
409
    {
 
410
        return $this->_translatorDisabled;
 
411
    }
 
412
 
 
413
    // Metadata
 
414
 
 
415
    /**
 
416
     * Filter a name to only allow valid variable characters
 
417
     *
 
418
     * @param  string $value
 
419
     * @param  bool $allowBrackets
 
420
     * @return string
 
421
     */
 
422
    public function filterName($value, $allowBrackets = false)
 
423
    {
 
424
        $charset = '^a-zA-Z0-9_\x7f-\xff';
 
425
        if ($allowBrackets) {
 
426
            $charset .= '\[\]';
 
427
        }
 
428
        return preg_replace('/[' . $charset . ']/', '', (string) $value);
 
429
    }
 
430
 
 
431
    /**
 
432
     * Set element name
 
433
     *
 
434
     * @param  string $name
 
435
     * @return Zend_Form_Element
 
436
     */
 
437
    public function setName($name)
 
438
    {
 
439
        $name = $this->filterName($name);
 
440
        if ('' === $name) {
 
441
            require_once 'Zend/Form/Exception.php';
 
442
            throw new Zend_Form_Exception('Invalid name provided; must contain only valid variable characters and be non-empty');
 
443
        }
 
444
 
 
445
        $this->_name = $name;
 
446
        return $this;
 
447
    }
 
448
 
 
449
    /**
 
450
     * Return element name
 
451
     *
 
452
     * @return string
 
453
     */
 
454
    public function getName()
 
455
    {
 
456
        return $this->_name;
 
457
    }
 
458
 
 
459
    /**
 
460
     * Get fully qualified name
 
461
     *
 
462
     * Places name as subitem of array and/or appends brackets.
 
463
     *
 
464
     * @return string
 
465
     */
 
466
    public function getFullyQualifiedName()
 
467
    {
 
468
        $name = $this->getName();
 
469
 
 
470
        if (null !== ($belongsTo = $this->getBelongsTo())) {
 
471
            $name = $belongsTo . '[' . $name . ']';
 
472
        }
 
473
 
 
474
        if ($this->isArray()) {
 
475
            $name .= '[]';
 
476
        }
 
477
 
 
478
        return $name;
 
479
    }
 
480
 
 
481
    /**
 
482
     * Get element id
 
483
     *
 
484
     * @return string
 
485
     */
 
486
    public function getId()
 
487
    {
 
488
        if (isset($this->id)) {
 
489
            return $this->id;
 
490
        }
 
491
 
 
492
        $id = $this->getFullyQualifiedName();
 
493
 
 
494
        // Bail early if no array notation detected
 
495
        if (!strstr($id, '[')) {
 
496
            return $id;
 
497
        }
 
498
 
 
499
        // Strip array notation
 
500
        if ('[]' == substr($id, -2)) {
 
501
            $id = substr($id, 0, strlen($id) - 2);
 
502
        }
 
503
        $id = str_replace('][', '-', $id);
 
504
        $id = str_replace(array(']', '['), '-', $id);
 
505
        $id = trim($id, '-');
 
506
 
 
507
        return $id;
 
508
    }
 
509
 
 
510
    /**
 
511
     * Set element value
 
512
     *
 
513
     * @param  mixed $value
 
514
     * @return Zend_Form_Element
 
515
     */
 
516
    public function setValue($value)
 
517
    {
 
518
        $this->_value = $value;
 
519
        return $this;
 
520
    }
 
521
 
 
522
    /**
 
523
     * Filter a value
 
524
     *
 
525
     * @param  string $value
 
526
     * @param  string $key
 
527
     * @return void
 
528
     */
 
529
    protected function _filterValue(&$value, &$key)
 
530
    {
 
531
        foreach ($this->getFilters() as $filter) {
 
532
            $value = $filter->filter($value);
 
533
        }
 
534
    }
 
535
 
 
536
    /**
 
537
     * Retrieve filtered element value
 
538
     *
 
539
     * @return mixed
 
540
     */
 
541
    public function getValue()
 
542
    {
 
543
        $valueFiltered = $this->_value;
 
544
 
 
545
        if ($this->isArray() && is_array($valueFiltered)) {
 
546
            array_walk_recursive($valueFiltered, array($this, '_filterValue'));
 
547
        } else {
 
548
            $this->_filterValue($valueFiltered, $valueFiltered);
 
549
        }
 
550
 
 
551
        return $valueFiltered;
 
552
    }
 
553
 
 
554
    /**
 
555
     * Retrieve unfiltered element value
 
556
     *
 
557
     * @return mixed
 
558
     */
 
559
    public function getUnfilteredValue()
 
560
    {
 
561
        return $this->_value;
 
562
    }
 
563
 
 
564
    /**
 
565
     * Set element label
 
566
     *
 
567
     * @param  string $label
 
568
     * @return Zend_Form_Element
 
569
     */
 
570
    public function setLabel($label)
 
571
    {
 
572
        $this->_label = (string) $label;
 
573
        return $this;
 
574
    }
 
575
 
 
576
    /**
 
577
     * Retrieve element label
 
578
     *
 
579
     * @return string
 
580
     */
 
581
    public function getLabel()
 
582
    {
 
583
        return $this->_label;
 
584
    }
 
585
 
 
586
    /**
 
587
     * Set element order
 
588
     *
 
589
     * @param  int $order
 
590
     * @return Zend_Form_Element
 
591
     */
 
592
    public function setOrder($order)
 
593
    {
 
594
        $this->_order = (int) $order;
 
595
        return $this;
 
596
    }
 
597
 
 
598
    /**
 
599
     * Retrieve element order
 
600
     *
 
601
     * @return int
 
602
     */
 
603
    public function getOrder()
 
604
    {
 
605
        return $this->_order;
 
606
    }
 
607
 
 
608
    /**
 
609
     * Set required flag
 
610
     *
 
611
     * @param  bool $flag Default value is true
 
612
     * @return Zend_Form_Element
 
613
     */
 
614
    public function setRequired($flag = true)
 
615
    {
 
616
        $this->_required = (bool) $flag;
 
617
        return $this;
 
618
    }
 
619
 
 
620
    /**
 
621
     * Is the element required?
 
622
     *
 
623
     * @return bool
 
624
     */
 
625
    public function isRequired()
 
626
    {
 
627
        return $this->_required;
 
628
    }
 
629
 
 
630
    /**
 
631
     * Set flag indicating whether a NotEmpty validator should be inserted when element is required
 
632
     *
 
633
     * @param  bool $flag
 
634
     * @return Zend_Form_Element
 
635
     */
 
636
    public function setAutoInsertNotEmptyValidator($flag)
 
637
    {
 
638
        $this->_autoInsertNotEmptyValidator = (bool) $flag;
 
639
        return $this;
 
640
    }
 
641
 
 
642
    /**
 
643
     * Get flag indicating whether a NotEmpty validator should be inserted when element is required
 
644
     *
 
645
     * @return bool
 
646
     */
 
647
    public function autoInsertNotEmptyValidator()
 
648
    {
 
649
        return $this->_autoInsertNotEmptyValidator;
 
650
    }
 
651
 
 
652
    /**
 
653
     * Set element description
 
654
     *
 
655
     * @param  string $description
 
656
     * @return Zend_Form_Element
 
657
     */
 
658
    public function setDescription($description)
 
659
    {
 
660
        $this->_description = (string) $description;
 
661
        return $this;
 
662
    }
 
663
 
 
664
    /**
 
665
     * Retrieve element description
 
666
     *
 
667
     * @return string
 
668
     */
 
669
    public function getDescription()
 
670
    {
 
671
        return $this->_description;
 
672
    }
 
673
 
 
674
    /**
 
675
     * Set 'allow empty' flag
 
676
     *
 
677
     * When the allow empty flag is enabled and the required flag is false, the
 
678
     * element will validate with empty values.
 
679
     *
 
680
     * @param  bool $flag
 
681
     * @return Zend_Form_Element
 
682
     */
 
683
    public function setAllowEmpty($flag)
 
684
    {
 
685
        $this->_allowEmpty = (bool) $flag;
 
686
        return $this;
 
687
    }
 
688
 
 
689
    /**
 
690
     * Get 'allow empty' flag
 
691
     *
 
692
     * @return bool
 
693
     */
 
694
    public function getAllowEmpty()
 
695
    {
 
696
        return $this->_allowEmpty;
 
697
    }
 
698
 
 
699
    /**
 
700
     * Set ignore flag (used when retrieving values at form level)
 
701
     *
 
702
     * @param  bool $flag
 
703
     * @return Zend_Form_Element
 
704
     */
 
705
    public function setIgnore($flag)
 
706
    {
 
707
        $this->_ignore = (bool) $flag;
 
708
        return $this;
 
709
    }
 
710
 
 
711
    /**
 
712
     * Get ignore flag (used when retrieving values at form level)
 
713
     *
 
714
     * @return bool
 
715
     */
 
716
    public function getIgnore()
 
717
    {
 
718
        return $this->_ignore;
 
719
    }
 
720
 
 
721
    /**
 
722
     * Set flag indicating if element represents an array
 
723
     *
 
724
     * @param  bool $flag
 
725
     * @return Zend_Form_Element
 
726
     */
 
727
    public function setIsArray($flag)
 
728
    {
 
729
        $this->_isArray = (bool) $flag;
 
730
        return $this;
 
731
    }
 
732
 
 
733
    /**
 
734
     * Is the element representing an array?
 
735
     *
 
736
     * @return bool
 
737
     */
 
738
    public function isArray()
 
739
    {
 
740
        return $this->_isArray;
 
741
    }
 
742
 
 
743
    /**
 
744
     * Set array to which element belongs
 
745
     *
 
746
     * @param  string $array
 
747
     * @return Zend_Form_Element
 
748
     */
 
749
    public function setBelongsTo($array)
 
750
    {
 
751
        $array = $this->filterName($array, true);
 
752
        if (!empty($array)) {
 
753
            $this->_belongsTo = $array;
 
754
        }
 
755
 
 
756
        return $this;
 
757
    }
 
758
 
 
759
    /**
 
760
     * Return array name to which element belongs
 
761
     *
 
762
     * @return string
 
763
     */
 
764
    public function getBelongsTo()
 
765
    {
 
766
        return $this->_belongsTo;
 
767
    }
 
768
 
 
769
    /**
 
770
     * Return element type
 
771
     *
 
772
     * @return string
 
773
     */
 
774
    public function getType()
 
775
    {
 
776
        if (null === $this->_type) {
 
777
            $this->_type = get_class($this);
 
778
        }
 
779
 
 
780
        return $this->_type;
 
781
    }
 
782
 
 
783
    /**
 
784
     * Set element attribute
 
785
     *
 
786
     * @param  string $name
 
787
     * @param  mixed $value
 
788
     * @return Zend_Form_Element
 
789
     * @throws Zend_Form_Exception for invalid $name values
 
790
     */
 
791
    public function setAttrib($name, $value)
 
792
    {
 
793
        $name = (string) $name;
 
794
        if ('_' == $name[0]) {
 
795
            require_once 'Zend/Form/Exception.php';
 
796
            throw new Zend_Form_Exception(sprintf('Invalid attribute "%s"; must not contain a leading underscore', $name));
 
797
        }
 
798
 
 
799
        if (null === $value) {
 
800
            unset($this->$name);
 
801
        } else {
 
802
            $this->$name = $value;
 
803
        }
 
804
 
 
805
        return $this;
 
806
    }
 
807
 
 
808
    /**
 
809
     * Set multiple attributes at once
 
810
     *
 
811
     * @param  array $attribs
 
812
     * @return Zend_Form_Element
 
813
     */
 
814
    public function setAttribs(array $attribs)
 
815
    {
 
816
        foreach ($attribs as $key => $value) {
 
817
            $this->setAttrib($key, $value);
 
818
        }
 
819
 
 
820
        return $this;
 
821
    }
 
822
 
 
823
    /**
 
824
     * Retrieve element attribute
 
825
     *
 
826
     * @param  string $name
 
827
     * @return string
 
828
     */
 
829
    public function getAttrib($name)
 
830
    {
 
831
        $name = (string) $name;
 
832
        if (isset($this->$name)) {
 
833
            return $this->$name;
 
834
        }
 
835
 
 
836
        return null;
 
837
    }
 
838
 
 
839
    /**
 
840
     * Return all attributes
 
841
     *
 
842
     * @return array
 
843
     */
 
844
    public function getAttribs()
 
845
    {
 
846
        $attribs = get_object_vars($this);
 
847
        foreach ($attribs as $key => $value) {
 
848
            if ('_' == substr($key, 0, 1)) {
 
849
                unset($attribs[$key]);
 
850
            }
 
851
        }
 
852
 
 
853
        return $attribs;
 
854
    }
 
855
 
 
856
    /**
 
857
     * Overloading: retrieve object property
 
858
     *
 
859
     * Prevents access to properties beginning with '_'.
 
860
     *
 
861
     * @param  string $key
 
862
     * @return mixed
 
863
     */
 
864
    public function __get($key)
 
865
    {
 
866
        if ('_' == $key[0]) {
 
867
            require_once 'Zend/Form/Exception.php';
 
868
            throw new Zend_Form_Exception(sprintf('Cannot retrieve value for protected/private property "%s"', $key));
 
869
        }
 
870
 
 
871
        if (!isset($this->$key)) {
 
872
            return null;
 
873
        }
 
874
 
 
875
        return $this->$key;
 
876
    }
 
877
 
 
878
    /**
 
879
     * Overloading: set object property
 
880
     *
 
881
     * @param  string $key
 
882
     * @param  mixed $value
 
883
     * @return voide
 
884
     */
 
885
    public function __set($key, $value)
 
886
    {
 
887
        $this->setAttrib($key, $value);
 
888
    }
 
889
 
 
890
    /**
 
891
     * Overloading: allow rendering specific decorators
 
892
     *
 
893
     * Call renderDecoratorName() to render a specific decorator.
 
894
     *
 
895
     * @param  string $method
 
896
     * @param  array $args
 
897
     * @return string
 
898
     * @throws Zend_Form_Exception for invalid decorator or invalid method call
 
899
     */
 
900
    public function __call($method, $args)
 
901
    {
 
902
        if ('render' == substr($method, 0, 6)) {
 
903
            $decoratorName = substr($method, 6);
 
904
            if (false !== ($decorator = $this->getDecorator($decoratorName))) {
 
905
                $decorator->setElement($this);
 
906
                $seed = '';
 
907
                if (0 < count($args)) {
 
908
                    $seed = array_shift($args);
 
909
                }
 
910
                return $decorator->render($seed);
 
911
            }
 
912
 
 
913
            require_once 'Zend/Form/Element/Exception.php';
 
914
            throw new Zend_Form_Element_Exception(sprintf('Decorator by name %s does not exist', $decoratorName));
 
915
        }
 
916
 
 
917
        require_once 'Zend/Form/Element/Exception.php';
 
918
        throw new Zend_Form_Element_Exception(sprintf('Method %s does not exist', $method));
 
919
    }
 
920
 
 
921
    // Loaders
 
922
 
 
923
    /**
 
924
     * Set plugin loader to use for validator or filter chain
 
925
     *
 
926
     * @param  Zend_Loader_PluginLoader_Interface $loader
 
927
     * @param  string $type 'decorator', 'filter', or 'validate'
 
928
     * @return Zend_Form_Element
 
929
     * @throws Zend_Form_Exception on invalid type
 
930
     */
 
931
    public function setPluginLoader(Zend_Loader_PluginLoader_Interface $loader, $type)
 
932
    {
 
933
        $type = strtoupper($type);
 
934
        switch ($type) {
 
935
            case self::DECORATOR:
 
936
            case self::FILTER:
 
937
            case self::VALIDATE:
 
938
                $this->_loaders[$type] = $loader;
 
939
                return $this;
 
940
            default:
 
941
                require_once 'Zend/Form/Exception.php';
 
942
                throw new Zend_Form_Exception(sprintf('Invalid type "%s" provided to setPluginLoader()', $type));
 
943
        }
 
944
    }
 
945
 
 
946
    /**
 
947
     * Retrieve plugin loader for validator or filter chain
 
948
     *
 
949
     * Instantiates with default rules if none available for that type. Use
 
950
     * 'decorator', 'filter', or 'validate' for $type.
 
951
     *
 
952
     * @param  string $type
 
953
     * @return Zend_Loader_PluginLoader
 
954
     * @throws Zend_Loader_Exception on invalid type.
 
955
     */
 
956
    public function getPluginLoader($type)
 
957
    {
 
958
        $type = strtoupper($type);
 
959
        switch ($type) {
 
960
            case self::FILTER:
 
961
            case self::VALIDATE:
 
962
                $prefixSegment = ucfirst(strtolower($type));
 
963
                $pathSegment   = $prefixSegment;
 
964
            case self::DECORATOR:
 
965
                if (!isset($prefixSegment)) {
 
966
                    $prefixSegment = 'Form_Decorator';
 
967
                    $pathSegment   = 'Form/Decorator';
 
968
                }
 
969
                if (!isset($this->_loaders[$type])) {
 
970
                    require_once 'Zend/Loader/PluginLoader.php';
 
971
                    $this->_loaders[$type] = new Zend_Loader_PluginLoader(
 
972
                        array('Zend_' . $prefixSegment . '_' => 'Zend/' . $pathSegment . '/')
 
973
                    );
 
974
                }
 
975
                return $this->_loaders[$type];
 
976
            default:
 
977
                require_once 'Zend/Form/Exception.php';
 
978
                throw new Zend_Form_Exception(sprintf('Invalid type "%s" provided to getPluginLoader()', $type));
 
979
        }
 
980
    }
 
981
 
 
982
    /**
 
983
     * Add prefix path for plugin loader
 
984
     *
 
985
     * If no $type specified, assumes it is a base path for both filters and
 
986
     * validators, and sets each according to the following rules:
 
987
     * - decorators: $prefix = $prefix . '_Decorator'
 
988
     * - filters: $prefix = $prefix . '_Filter'
 
989
     * - validators: $prefix = $prefix . '_Validate'
 
990
     *
 
991
     * Otherwise, the path prefix is set on the appropriate plugin loader.
 
992
     *
 
993
     * @param  string $path
 
994
     * @return Zend_Form_Element
 
995
     * @throws Zend_Form_Exception for invalid type
 
996
     */
 
997
    public function addPrefixPath($prefix, $path, $type = null)
 
998
    {
 
999
        $type = strtoupper($type);
 
1000
        switch ($type) {
 
1001
            case self::DECORATOR:
 
1002
            case self::FILTER:
 
1003
            case self::VALIDATE:
 
1004
                $loader = $this->getPluginLoader($type);
 
1005
                $loader->addPrefixPath($prefix, $path);
 
1006
                return $this;
 
1007
            case null:
 
1008
                $prefix = rtrim($prefix, '_');
 
1009
                $path   = rtrim($path, DIRECTORY_SEPARATOR);
 
1010
                foreach (array(self::DECORATOR, self::FILTER, self::VALIDATE) as $type) {
 
1011
                    $cType        = ucfirst(strtolower($type));
 
1012
                    $pluginPath   = $path . DIRECTORY_SEPARATOR . $cType . DIRECTORY_SEPARATOR;
 
1013
                    $pluginPrefix = $prefix . '_' . $cType;
 
1014
                    $loader       = $this->getPluginLoader($type);
 
1015
                    $loader->addPrefixPath($pluginPrefix, $pluginPath);
 
1016
                }
 
1017
                return $this;
 
1018
            default:
 
1019
                require_once 'Zend/Form/Exception.php';
 
1020
                throw new Zend_Form_Exception(sprintf('Invalid type "%s" provided to getPluginLoader()', $type));
 
1021
        }
 
1022
    }
 
1023
 
 
1024
    /**
 
1025
     * Add many prefix paths at once
 
1026
     *
 
1027
     * @param  array $spec
 
1028
     * @return Zend_Form_Element
 
1029
     */
 
1030
    public function addPrefixPaths(array $spec)
 
1031
    {
 
1032
        if (isset($spec['prefix']) && isset($spec['path'])) {
 
1033
            return $this->addPrefixPath($spec['prefix'], $spec['path']);
 
1034
        }
 
1035
        foreach ($spec as $type => $paths) {
 
1036
            if (is_numeric($type) && is_array($paths)) {
 
1037
                $type = null;
 
1038
                if (isset($paths['prefix']) && isset($paths['path'])) {
 
1039
                    if (isset($paths['type'])) {
 
1040
                        $type = $paths['type'];
 
1041
                    }
 
1042
                    $this->addPrefixPath($paths['prefix'], $paths['path'], $type);
 
1043
                }
 
1044
            } elseif (!is_numeric($type)) {
 
1045
                if (!isset($paths['prefix']) || !isset($paths['path'])) {
 
1046
                    foreach ($paths as $prefix => $spec) {
 
1047
                        if (is_array($spec)) {
 
1048
                            foreach ($spec as $path) {
 
1049
                                if (!is_string($path)) {
 
1050
                                    continue;
 
1051
                                }
 
1052
                                $this->addPrefixPath($prefix, $path, $type);
 
1053
                            }
 
1054
                        } elseif (is_string($spec)) {
 
1055
                            $this->addPrefixPath($prefix, $spec, $type);
 
1056
                        }
 
1057
                    }
 
1058
                } else {
 
1059
                    $this->addPrefixPath($paths['prefix'], $paths['path'], $type);
 
1060
                }
 
1061
            }
 
1062
        }
 
1063
        return $this;
 
1064
    }
 
1065
 
 
1066
    // Validation
 
1067
 
 
1068
    /**
 
1069
     * Add validator to validation chain
 
1070
     *
 
1071
     * Note: will overwrite existing validators if they are of the same class.
 
1072
     *
 
1073
     * @param  string|Zend_Validate_Interface $validator
 
1074
     * @param  bool $breakChainOnFailure
 
1075
     * @param  array $options
 
1076
     * @return Zend_Form_Element
 
1077
     * @throws Zend_Form_Exception if invalid validator type
 
1078
     */
 
1079
    public function addValidator($validator, $breakChainOnFailure = false, $options = array())
 
1080
    {
 
1081
        if ($validator instanceof Zend_Validate_Interface) {
 
1082
            $name = get_class($validator);
 
1083
 
 
1084
            if (!isset($validator->zfBreakChainOnFailure)) {
 
1085
                $validator->zfBreakChainOnFailure = $breakChainOnFailure;
 
1086
            }
 
1087
        } elseif (is_string($validator)) {
 
1088
            $name      = $validator;
 
1089
            $validator = array(
 
1090
                'validator' => $validator,
 
1091
                'breakChainOnFailure' => $breakChainOnFailure,
 
1092
                'options'             => $options,
 
1093
            );
 
1094
        } else {
 
1095
            require_once 'Zend/Form/Exception.php';
 
1096
            throw new Zend_Form_Exception('Invalid validator provided to addValidator; must be string or Zend_Validate_Interface');
 
1097
        }
 
1098
 
 
1099
 
 
1100
        $this->_validators[$name] = $validator;
 
1101
 
 
1102
        return $this;
 
1103
    }
 
1104
 
 
1105
    /**
 
1106
     * Add multiple validators
 
1107
     *
 
1108
     * @param  array $validators
 
1109
     * @return Zend_Form_Element
 
1110
     */
 
1111
    public function addValidators(array $validators)
 
1112
    {
 
1113
        foreach ($validators as $validatorInfo) {
 
1114
            if (is_string($validatorInfo)) {
 
1115
                $this->addValidator($validatorInfo);
 
1116
            } elseif ($validatorInfo instanceof Zend_Validate_Interface) {
 
1117
                $this->addValidator($validatorInfo);
 
1118
            } elseif (is_array($validatorInfo)) {
 
1119
                $argc                = count($validatorInfo);
 
1120
                $breakChainOnFailure = false;
 
1121
                $options             = array();
 
1122
                if (isset($validatorInfo['validator'])) {
 
1123
                    $validator = $validatorInfo['validator'];
 
1124
                    if (isset($validatorInfo['breakChainOnFailure'])) {
 
1125
                        $breakChainOnFailure = $validatorInfo['breakChainOnFailure'];
 
1126
                    }
 
1127
                    if (isset($validatorInfo['options'])) {
 
1128
                        $options = $validatorInfo['options'];
 
1129
                    }
 
1130
                    $this->addValidator($validator, $breakChainOnFailure, $options);
 
1131
                } else {
 
1132
                    switch (true) {
 
1133
                        case (0 == $argc):
 
1134
                            break;
 
1135
                        case (1 <= $argc):
 
1136
                            $validator  = array_shift($validatorInfo);
 
1137
                        case (2 <= $argc):
 
1138
                            $breakChainOnFailure = array_shift($validatorInfo);
 
1139
                        case (3 <= $argc):
 
1140
                            $options = array_shift($validatorInfo);
 
1141
                        default:
 
1142
                            $this->addValidator($validator, $breakChainOnFailure, $options);
 
1143
                            break;
 
1144
                    }
 
1145
                }
 
1146
            } else {
 
1147
                require_once 'Zend/Form/Exception.php';
 
1148
                throw new Zend_Form_Exception('Invalid validator passed to addValidators()');
 
1149
            }
 
1150
        }
 
1151
 
 
1152
        return $this;
 
1153
    }
 
1154
 
 
1155
    /**
 
1156
     * Set multiple validators, overwriting previous validators
 
1157
     *
 
1158
     * @param  array $validators
 
1159
     * @return Zend_Form_Element
 
1160
     */
 
1161
    public function setValidators(array $validators)
 
1162
    {
 
1163
        $this->clearValidators();
 
1164
        return $this->addValidators($validators);
 
1165
    }
 
1166
 
 
1167
    /**
 
1168
     * Retrieve a single validator by name
 
1169
     *
 
1170
     * @param  string $name
 
1171
     * @return Zend_Validate_Interface|false False if not found, validator otherwise
 
1172
     */
 
1173
    public function getValidator($name)
 
1174
    {
 
1175
        if (!isset($this->_validators[$name])) {
 
1176
            $len = strlen($name);
 
1177
            foreach ($this->_validators as $localName => $validator) {
 
1178
                if ($len > strlen($localName)) {
 
1179
                    continue;
 
1180
                }
 
1181
                if (0 === substr_compare($localName, $name, -$len, $len, true)) {
 
1182
                    if (is_array($validator)) {
 
1183
                        return $this->_loadValidator($validator);
 
1184
                    }
 
1185
                    return $validator;
 
1186
                }
 
1187
            }
 
1188
            return false;
 
1189
        }
 
1190
 
 
1191
        if (is_array($this->_validators[$name])) {
 
1192
            return $this->_loadValidator($this->_validators[$name]);
 
1193
        }
 
1194
 
 
1195
        return $this->_validators[$name];
 
1196
    }
 
1197
 
 
1198
    /**
 
1199
     * Retrieve all validators
 
1200
     *
 
1201
     * @return array
 
1202
     */
 
1203
    public function getValidators()
 
1204
    {
 
1205
        $validators = array();
 
1206
        foreach ($this->_validators as $key => $value) {
 
1207
            if ($value instanceof Zend_Validate_Interface) {
 
1208
                $validators[$key] = $value;
 
1209
                continue;
 
1210
            }
 
1211
            $validator = $this->_loadValidator($value);
 
1212
            $validators[get_class($validator)] = $validator;
 
1213
        }
 
1214
        return $validators;
 
1215
    }
 
1216
 
 
1217
    /**
 
1218
     * Remove a single validator by name
 
1219
     *
 
1220
     * @param  string $name
 
1221
     * @return bool
 
1222
     */
 
1223
    public function removeValidator($name)
 
1224
    {
 
1225
        if (isset($this->_validators[$name])) {
 
1226
            unset($this->_validators[$name]);
 
1227
        } else {
 
1228
            $len = strlen($name);
 
1229
            foreach (array_keys($this->_validators) as $validator) {
 
1230
                if ($len > strlen($validator)) {
 
1231
                    continue;
 
1232
                }
 
1233
                if (0 === substr_compare($validator, $name, -$len, $len, true)) {
 
1234
                    unset($this->_validators[$validator]);
 
1235
                    break;
 
1236
                }
 
1237
            }
 
1238
        }
 
1239
 
 
1240
        return $this;
 
1241
    }
 
1242
 
 
1243
    /**
 
1244
     * Clear all validators
 
1245
     *
 
1246
     * @return Zend_Form_Element
 
1247
     */
 
1248
    public function clearValidators()
 
1249
    {
 
1250
        $this->_validators = array();
 
1251
        return $this;
 
1252
    }
 
1253
 
 
1254
    /**
 
1255
     * Validate element value
 
1256
     *
 
1257
     * If a translation adapter is registered, any error messages will be
 
1258
     * translated according to the current locale, using the given error code;
 
1259
     * if no matching translation is found, the original message will be
 
1260
     * utilized.
 
1261
     *
 
1262
     * Note: The *filtered* value is validated.
 
1263
     *
 
1264
     * @param  mixed $value
 
1265
     * @param  mixed $context
 
1266
     * @return boolean
 
1267
     */
 
1268
    public function isValid($value, $context = null)
 
1269
    {
 
1270
        $this->setValue($value);
 
1271
        $value = $this->getValue();
 
1272
 
 
1273
        if ((('' === $value) || (null === $value))
 
1274
            && !$this->isRequired()
 
1275
            && $this->getAllowEmpty()
 
1276
        ) {
 
1277
            return true;
 
1278
        }
 
1279
 
 
1280
        if ($this->isRequired()
 
1281
            && $this->autoInsertNotEmptyValidator()
 
1282
            && !$this->getValidator('NotEmpty'))
 
1283
        {
 
1284
            $validators = $this->getValidators();
 
1285
            $notEmpty   = array('validator' => 'NotEmpty', 'breakChainOnFailure' => true);
 
1286
            array_unshift($validators, $notEmpty);
 
1287
            $this->setValidators($validators);
 
1288
        }
 
1289
 
 
1290
        $this->_messages = array();
 
1291
        $this->_errors   = array();
 
1292
        $result          = true;
 
1293
        $translator      = $this->getTranslator();
 
1294
        $isArray         = $this->isArray();
 
1295
        foreach ($this->getValidators() as $key => $validator) {
 
1296
            if (method_exists($validator, 'setTranslator')) {
 
1297
                $validator->setTranslator($translator);
 
1298
            }
 
1299
 
 
1300
            if ($isArray && is_array($value)) {
 
1301
                $messages = array();
 
1302
                $errors   = array();
 
1303
                foreach ($value as $val) {
 
1304
                    if (!$validator->isValid($val, $context)) {
 
1305
                        $result = false;
 
1306
                        if ($this->_hasErrorMessages()) {
 
1307
                            $messages = $this->_getErrorMessages();
 
1308
                            $errors   = $messages;
 
1309
                        } else {
 
1310
                            $messages = array_merge($messages, $validator->getMessages());
 
1311
                            $errors   = array_merge($errors,   $validator->getErrors());
 
1312
                        }
 
1313
                    }
 
1314
                }
 
1315
                if ($result) {
 
1316
                    continue;
 
1317
                }
 
1318
            } elseif ($validator->isValid($value, $context)) {
 
1319
                continue;
 
1320
            } else {
 
1321
                $result = false;
 
1322
                if ($this->_hasErrorMessages()) {
 
1323
                    $messages = $this->_getErrorMessages();
 
1324
                    $errors   = $messages;
 
1325
                } else {
 
1326
                    $messages = $validator->getMessages();
 
1327
                    $errors   = array_keys($messages);
 
1328
                }
 
1329
            }
 
1330
 
 
1331
            $result          = false;
 
1332
            $this->_messages = array_merge($this->_messages, $messages);
 
1333
            $this->_errors   = array_merge($this->_errors,   $errors);
 
1334
 
 
1335
            if ($validator->zfBreakChainOnFailure) {
 
1336
                break;
 
1337
            }
 
1338
        }
 
1339
 
 
1340
        return $result;
 
1341
    }
 
1342
 
 
1343
    /**
 
1344
     * Add a custom error message to return in the event of failed validation
 
1345
     *
 
1346
     * @param  string $message
 
1347
     * @return Zend_Form_Element
 
1348
     */
 
1349
    public function addErrorMessage($message)
 
1350
    {
 
1351
        $this->_errorMessages[] = (string) $message;
 
1352
        return $this;
 
1353
    }
 
1354
 
 
1355
    /**
 
1356
     * Add multiple custom error messages to return in the event of failed validation
 
1357
     *
 
1358
     * @param  array $messages
 
1359
     * @return Zend_Form_Element
 
1360
     */
 
1361
    public function addErrorMessages(array $messages)
 
1362
    {
 
1363
        foreach ($messages as $message) {
 
1364
            $this->addErrorMessage($message);
 
1365
        }
 
1366
        return $this;
 
1367
    }
 
1368
 
 
1369
    /**
 
1370
     * Same as addErrorMessages(), but clears custom error message stack first
 
1371
     *
 
1372
     * @param  array $messages
 
1373
     * @return Zend_Form_Element
 
1374
     */
 
1375
    public function setErrorMessages(array $messages)
 
1376
    {
 
1377
        $this->clearErrorMessages();
 
1378
        return $this->addErrorMessages($messages);
 
1379
    }
 
1380
 
 
1381
    /**
 
1382
     * Retrieve custom error messages
 
1383
     *
 
1384
     * @return array
 
1385
     */
 
1386
    public function getErrorMessages()
 
1387
    {
 
1388
        return $this->_errorMessages;
 
1389
    }
 
1390
 
 
1391
    /**
 
1392
     * Clear custom error messages stack
 
1393
     *
 
1394
     * @return Zend_Form_Element
 
1395
     */
 
1396
    public function clearErrorMessages()
 
1397
    {
 
1398
        $this->_errorMessages = array();
 
1399
        return $this;
 
1400
    }
 
1401
 
 
1402
    /**
 
1403
     * Mark the element as being in a failed validation state
 
1404
     *
 
1405
     * @return Zend_Form_Element
 
1406
     */
 
1407
    public function markAsError()
 
1408
    {
 
1409
        $messages       = $this->getMessages();
 
1410
        $customMessages = $this->_getErrorMessages();
 
1411
        $messages       = $messages + $customMessages;
 
1412
        if (empty($messages)) {
 
1413
            $this->_isError = true;
 
1414
        } else {
 
1415
            $this->_messages = $messages;
 
1416
        }
 
1417
        return $this;
 
1418
    }
 
1419
 
 
1420
    /**
 
1421
     * Add an error message and mark element as failed validation
 
1422
     *
 
1423
     * @param  string $message
 
1424
     * @return Zend_Form_Element
 
1425
     */
 
1426
    public function addError($message)
 
1427
    {
 
1428
        $this->addErrorMessage($message);
 
1429
        $this->markAsError();
 
1430
        return $this;
 
1431
    }
 
1432
 
 
1433
    /**
 
1434
     * Add multiple error messages and flag element as failed validation
 
1435
     *
 
1436
     * @param  array $messages
 
1437
     * @return Zend_Form_Element
 
1438
     */
 
1439
    public function addErrors(array $messages)
 
1440
    {
 
1441
        foreach ($messages as $message) {
 
1442
            $this->addError($message);
 
1443
        }
 
1444
        return $this;
 
1445
    }
 
1446
 
 
1447
    /**
 
1448
     * Overwrite any previously set error messages and flag as failed validation
 
1449
     *
 
1450
     * @param  array $messages
 
1451
     * @return Zend_Form_Element
 
1452
     */
 
1453
    public function setErrors(array $messages)
 
1454
    {
 
1455
        $this->clearErrorMessages();
 
1456
        return $this->addErrors($messages);
 
1457
    }
 
1458
 
 
1459
    /**
 
1460
     * Are there errors registered?
 
1461
     *
 
1462
     * @return bool
 
1463
     */
 
1464
    public function hasErrors()
 
1465
    {
 
1466
        return (!empty($this->_messages) || $this->_isError);
 
1467
    }
 
1468
 
 
1469
    /**
 
1470
     * Retrieve validator chain errors
 
1471
     *
 
1472
     * @return array
 
1473
     */
 
1474
    public function getErrors()
 
1475
    {
 
1476
        return $this->_errors;
 
1477
    }
 
1478
 
 
1479
    /**
 
1480
     * Retrieve error messages
 
1481
     *
 
1482
     * @return array
 
1483
     */
 
1484
    public function getMessages()
 
1485
    {
 
1486
        return $this->_messages;
 
1487
    }
 
1488
 
 
1489
 
 
1490
    // Filtering
 
1491
 
 
1492
    /**
 
1493
     * Add a filter to the element
 
1494
     *
 
1495
     * @param  string|Zend_Filter_Interface $filter
 
1496
     * @return Zend_Form_Element
 
1497
     */
 
1498
    public function addFilter($filter, $options = array())
 
1499
    {
 
1500
        if ($filter instanceof Zend_Filter_Interface) {
 
1501
            $name = get_class($filter);
 
1502
        } elseif (is_string($filter)) {
 
1503
            $name = $filter;
 
1504
            $filter = array(
 
1505
                'filter'  => $filter,
 
1506
                'options' => $options,
 
1507
            );
 
1508
            $this->_filters[$name] = $filter;
 
1509
        } else {
 
1510
            require_once 'Zend/Form/Exception.php';
 
1511
            throw new Zend_Form_Exception('Invalid filter provided to addFilter; must be string or Zend_Filter_Interface');
 
1512
        }
 
1513
 
 
1514
        $this->_filters[$name] = $filter;
 
1515
 
 
1516
        return $this;
 
1517
    }
 
1518
 
 
1519
    /**
 
1520
     * Add filters to element
 
1521
     *
 
1522
     * @param  array $filters
 
1523
     * @return Zend_Form_Element
 
1524
     */
 
1525
    public function addFilters(array $filters)
 
1526
    {
 
1527
        foreach ($filters as $filterInfo) {
 
1528
            if (is_string($filterInfo)) {
 
1529
                $this->addFilter($filterInfo);
 
1530
            } elseif ($filterInfo instanceof Zend_Filter_Interface) {
 
1531
                $this->addFilter($filterInfo);
 
1532
            } elseif (is_array($filterInfo)) {
 
1533
                $argc                = count($filterInfo);
 
1534
                $options             = array();
 
1535
                if (isset($filterInfo['filter'])) {
 
1536
                    $filter = $filterInfo['filter'];
 
1537
                    if (isset($filterInfo['options'])) {
 
1538
                        $options = $filterInfo['options'];
 
1539
                    }
 
1540
                    $this->addFilter($filter, $options);
 
1541
                } else {
 
1542
                    switch (true) {
 
1543
                        case (0 == $argc):
 
1544
                            break;
 
1545
                        case (1 <= $argc):
 
1546
                            $filter  = array_shift($filterInfo);
 
1547
                        case (2 <= $argc):
 
1548
                            $options = array_shift($filterInfo);
 
1549
                        default:
 
1550
                            $this->addFilter($filter, $options);
 
1551
                            break;
 
1552
                    }
 
1553
                }
 
1554
            } else {
 
1555
                require_once 'Zend/Form/Exception.php';
 
1556
                throw new Zend_Form_Exception('Invalid filter passed to addFilters()');
 
1557
            }
 
1558
        }
 
1559
 
 
1560
        return $this;
 
1561
    }
 
1562
 
 
1563
    /**
 
1564
     * Add filters to element, overwriting any already existing
 
1565
     *
 
1566
     * @param  array $filters
 
1567
     * @return Zend_Form_Element
 
1568
     */
 
1569
    public function setFilters(array $filters)
 
1570
    {
 
1571
        $this->clearFilters();
 
1572
        return $this->addFilters($filters);
 
1573
    }
 
1574
 
 
1575
    /**
 
1576
     * Retrieve a single filter by name
 
1577
     *
 
1578
     * @param  string $name
 
1579
     * @return Zend_Filter_Interface
 
1580
     */
 
1581
    public function getFilter($name)
 
1582
    {
 
1583
        if (!isset($this->_filters[$name])) {
 
1584
            $len = strlen($name);
 
1585
            foreach ($this->_filters as $localName => $filter) {
 
1586
                if ($len > strlen($localName)) {
 
1587
                    continue;
 
1588
                }
 
1589
 
 
1590
                if (0 === substr_compare($localName, $name, -$len, $len, true)) {
 
1591
                    if (is_array($filter)) {
 
1592
                        return $this->_loadFilter($filter);
 
1593
                    }
 
1594
                    return $filter;
 
1595
                }
 
1596
            }
 
1597
            return false;
 
1598
        }
 
1599
 
 
1600
        if (is_array($this->_filters[$name])) {
 
1601
            return $this->_loadFilter($this->_filters[$name]);
 
1602
        }
 
1603
 
 
1604
        return $this->_filters[$name];
 
1605
    }
 
1606
 
 
1607
    /**
 
1608
     * Get all filters
 
1609
     *
 
1610
     * @return array
 
1611
     */
 
1612
    public function getFilters()
 
1613
    {
 
1614
        $filters = array();
 
1615
        foreach ($this->_filters as $key => $value) {
 
1616
            if ($value instanceof Zend_Filter_Interface) {
 
1617
                $filters[$key] = $value;
 
1618
                continue;
 
1619
            }
 
1620
            $filter = $this->_loadFilter($value);
 
1621
            $filters[get_class($filter)] = $filter;
 
1622
        }
 
1623
        return $filters;
 
1624
    }
 
1625
 
 
1626
    /**
 
1627
     * Remove a filter by name
 
1628
     *
 
1629
     * @param  string $name
 
1630
     * @return Zend_Form_Element
 
1631
     */
 
1632
    public function removeFilter($name)
 
1633
    {
 
1634
        if (isset($this->_filters[$name])) {
 
1635
            unset($this->_filters[$name]);
 
1636
        } else {
 
1637
            $len = strlen($name);
 
1638
            foreach (array_keys($this->_filters) as $filter) {
 
1639
                if ($len > strlen($filter)) {
 
1640
                    continue;
 
1641
                }
 
1642
                if (0 === substr_compare($filter, $name, -$len, $len, true)) {
 
1643
                    unset($this->_filters[$filter]);
 
1644
                    break;
 
1645
                }
 
1646
            }
 
1647
        }
 
1648
 
 
1649
        return $this;
 
1650
    }
 
1651
 
 
1652
    /**
 
1653
     * Clear all filters
 
1654
     *
 
1655
     * @return Zend_Form_Element
 
1656
     */
 
1657
    public function clearFilters()
 
1658
    {
 
1659
        $this->_filters = array();
 
1660
        return $this;
 
1661
    }
 
1662
 
 
1663
    // Rendering
 
1664
 
 
1665
    /**
 
1666
     * Set view object
 
1667
     *
 
1668
     * @param  Zend_View_Interface $view
 
1669
     * @return Zend_Form_Element
 
1670
     */
 
1671
    public function setView(Zend_View_Interface $view = null)
 
1672
    {
 
1673
        $this->_view = $view;
 
1674
        return $this;
 
1675
    }
 
1676
 
 
1677
    /**
 
1678
     * Retrieve view object
 
1679
     *
 
1680
     * Retrieves from ViewRenderer if none previously set.
 
1681
     *
 
1682
     * @return null|Zend_View_Interface
 
1683
     */
 
1684
    public function getView()
 
1685
    {
 
1686
        if (null === $this->_view) {
 
1687
            require_once 'Zend/Controller/Action/HelperBroker.php';
 
1688
            $viewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer');
 
1689
            $this->setView($viewRenderer->view);
 
1690
        }
 
1691
        return $this->_view;
 
1692
    }
 
1693
 
 
1694
    /**
 
1695
     * Instantiate a decorator based on class name or class name fragment
 
1696
     *
 
1697
     * @param  string $name
 
1698
     * @param  null|array $options
 
1699
     * @return Zend_Form_Decorator_Interface
 
1700
     */
 
1701
    protected function _getDecorator($name, $options)
 
1702
    {
 
1703
        $class = $this->getPluginLoader(self::DECORATOR)->load($name);
 
1704
        if (null === $options) {
 
1705
            $decorator = new $class;
 
1706
        } else {
 
1707
            $decorator = new $class($options);
 
1708
        }
 
1709
 
 
1710
        return $decorator;
 
1711
    }
 
1712
 
 
1713
    /**
 
1714
     * Add a decorator for rendering the element
 
1715
     *
 
1716
     * @param  string|Zend_Form_Decorator_Interface $decorator
 
1717
     * @param  array|Zend_Config $options Options with which to initialize decorator
 
1718
     * @return Zend_Form_Element
 
1719
     */
 
1720
    public function addDecorator($decorator, $options = null)
 
1721
    {
 
1722
        if ($decorator instanceof Zend_Form_Decorator_Interface) {
 
1723
            $name = get_class($decorator);
 
1724
        } elseif (is_string($decorator)) {
 
1725
            $name      = $decorator;
 
1726
            $decorator = array(
 
1727
                'decorator' => $name,
 
1728
                'options'   => $options,
 
1729
            );
 
1730
        } elseif (is_array($decorator)) {
 
1731
            foreach ($decorator as $name => $spec) {
 
1732
                break;
 
1733
            }
 
1734
            if (is_numeric($name)) {
 
1735
                require_once 'Zend/Form/Exception.php';
 
1736
                throw new Zend_Form_Exception('Invalid alias provided to addDecorator; must be alphanumeric string');
 
1737
            }
 
1738
            if (is_string($spec)) {
 
1739
                $decorator = array(
 
1740
                    'decorator' => $spec,
 
1741
                    'options'   => $options,
 
1742
                );
 
1743
            } elseif ($spec instanceof Zend_Form_Decorator_Interface) {
 
1744
                $decorator = $spec;
 
1745
            }
 
1746
        } else {
 
1747
            require_once 'Zend/Form/Exception.php';
 
1748
            throw new Zend_Form_Exception('Invalid decorator provided to addDecorator; must be string or Zend_Form_Decorator_Interface');
 
1749
        }
 
1750
 
 
1751
        $this->_decorators[$name] = $decorator;
 
1752
 
 
1753
        return $this;
 
1754
    }
 
1755
 
 
1756
    /**
 
1757
     * Add many decorators at once
 
1758
     *
 
1759
     * @param  array $decorators
 
1760
     * @return Zend_Form_Element
 
1761
     */
 
1762
    public function addDecorators(array $decorators)
 
1763
    {
 
1764
        foreach ($decorators as $decoratorInfo) {
 
1765
            if (is_string($decoratorInfo)) {
 
1766
                $this->addDecorator($decoratorInfo);
 
1767
            } elseif ($decoratorInfo instanceof Zend_Form_Decorator_Interface) {
 
1768
                $this->addDecorator($decoratorInfo);
 
1769
            } elseif (is_array($decoratorInfo)) {
 
1770
                $argc    = count($decoratorInfo);
 
1771
                $options = array();
 
1772
                if (isset($decoratorInfo['decorator'])) {
 
1773
                    $decorator = $decoratorInfo['decorator'];
 
1774
                    if (isset($decoratorInfo['options'])) {
 
1775
                        $options = $decoratorInfo['options'];
 
1776
                    }
 
1777
                    $this->addDecorator($decorator, $options);
 
1778
                } else {
 
1779
                    switch (true) {
 
1780
                        case (0 == $argc):
 
1781
                            break;
 
1782
                        case (1 <= $argc):
 
1783
                            $decorator  = array_shift($decoratorInfo);
 
1784
                        case (2 <= $argc):
 
1785
                            $options = array_shift($decoratorInfo);
 
1786
                        default:
 
1787
                            $this->addDecorator($decorator, $options);
 
1788
                            break;
 
1789
                    }
 
1790
                }
 
1791
            } else {
 
1792
                require_once 'Zend/Form/Exception.php';
 
1793
                throw new Zend_Form_Exception('Invalid decorator passed to addDecorators()');
 
1794
            }
 
1795
        }
 
1796
 
 
1797
        return $this;
 
1798
    }
 
1799
 
 
1800
    /**
 
1801
     * Overwrite all decorators
 
1802
     *
 
1803
     * @param  array $decorators
 
1804
     * @return Zend_Form_Element
 
1805
     */
 
1806
    public function setDecorators(array $decorators)
 
1807
    {
 
1808
        $this->clearDecorators();
 
1809
        return $this->addDecorators($decorators);
 
1810
    }
 
1811
 
 
1812
    /**
 
1813
     * Retrieve a registered decorator
 
1814
     *
 
1815
     * @param  string $name
 
1816
     * @return false|Zend_Form_Decorator_Abstract
 
1817
     */
 
1818
    public function getDecorator($name)
 
1819
    {
 
1820
        if (!isset($this->_decorators[$name])) {
 
1821
            $len = strlen($name);
 
1822
            foreach ($this->_decorators as $localName => $decorator) {
 
1823
                if ($len > strlen($localName)) {
 
1824
                    continue;
 
1825
                }
 
1826
 
 
1827
                if (0 === substr_compare($localName, $name, -$len, $len, true)) {
 
1828
                    if (is_array($decorator)) {
 
1829
                        return $this->_loadDecorator($decorator, $localName);
 
1830
                    }
 
1831
                    return $decorator;
 
1832
                }
 
1833
            }
 
1834
            return false;
 
1835
        }
 
1836
 
 
1837
        if (is_array($this->_decorators[$name])) {
 
1838
            return $this->_loadDecorator($this->_decorators[$name], $name);
 
1839
        }
 
1840
 
 
1841
        return $this->_decorators[$name];
 
1842
    }
 
1843
 
 
1844
    /**
 
1845
     * Retrieve all decorators
 
1846
     *
 
1847
     * @return array
 
1848
     */
 
1849
    public function getDecorators()
 
1850
    {
 
1851
        foreach ($this->_decorators as $key => $value) {
 
1852
            if (is_array($value)) {
 
1853
                $this->_loadDecorator($value, $key);
 
1854
            }
 
1855
        }
 
1856
        return $this->_decorators;
 
1857
    }
 
1858
 
 
1859
    /**
 
1860
     * Remove a single decorator
 
1861
     *
 
1862
     * @param  string $name
 
1863
     * @return bool
 
1864
     */
 
1865
    public function removeDecorator($name)
 
1866
    {
 
1867
        if (isset($this->_decorators[$name])) {
 
1868
            unset($this->_decorators[$name]);
 
1869
        } else {
 
1870
            $len = strlen($name);
 
1871
            foreach (array_keys($this->_decorators) as $decorator) {
 
1872
                if ($len > strlen($decorator)) {
 
1873
                    continue;
 
1874
                }
 
1875
                if (0 === substr_compare($decorator, $name, -$len, $len, true)) {
 
1876
                    unset($this->_decorators[$decorator]);
 
1877
                    break;
 
1878
                }
 
1879
            }
 
1880
        }
 
1881
 
 
1882
        return $this;
 
1883
    }
 
1884
 
 
1885
    /**
 
1886
     * Clear all decorators
 
1887
     *
 
1888
     * @return Zend_Form_Element
 
1889
     */
 
1890
    public function clearDecorators()
 
1891
    {
 
1892
        $this->_decorators = array();
 
1893
        return $this;
 
1894
    }
 
1895
 
 
1896
    /**
 
1897
     * Render form element
 
1898
     *
 
1899
     * @param  Zend_View_Interface $view
 
1900
     * @return string
 
1901
     */
 
1902
    public function render(Zend_View_Interface $view = null)
 
1903
    {
 
1904
        if (null !== $view) {
 
1905
            $this->setView($view);
 
1906
        }
 
1907
 
 
1908
        $content = '';
 
1909
        foreach ($this->getDecorators() as $decorator) {
 
1910
            $decorator->setElement($this);
 
1911
            $content = $decorator->render($content);
 
1912
        }
 
1913
        return $content;
 
1914
    }
 
1915
 
 
1916
    /**
 
1917
     * String representation of form element
 
1918
     *
 
1919
     * Proxies to {@link render()}.
 
1920
     *
 
1921
     * @return string
 
1922
     */
 
1923
    public function __toString()
 
1924
    {
 
1925
        try {
 
1926
            $return = $this->render();
 
1927
            return $return;
 
1928
        } catch (Exception $e) {
 
1929
            trigger_error($e->getMessage(), E_USER_WARNING);
 
1930
            return '';
 
1931
        }
 
1932
    }
 
1933
 
 
1934
    /**
 
1935
     * Lazy-load a filter
 
1936
     *
 
1937
     * @param  array $filter
 
1938
     * @return Zend_Filter_Interface
 
1939
     */
 
1940
    protected function _loadFilter(array $filter)
 
1941
    {
 
1942
        $origName = $filter['filter'];
 
1943
        $name     = $this->getPluginLoader(self::FILTER)->load($filter['filter']);
 
1944
 
 
1945
        if (array_key_exists($name, $this->_filters)) {
 
1946
            require_once 'Zend/Form/Exception.php';
 
1947
            throw new Zend_Form_Exception(sprintf('Filter instance already exists for filter "%s"', $origName));
 
1948
        }
 
1949
 
 
1950
        if (empty($filter['options'])) {
 
1951
            $instance = new $name;
 
1952
        } else {
 
1953
            $r = new ReflectionClass($name);
 
1954
            if ($r->hasMethod('__construct')) {
 
1955
                $instance = $r->newInstanceArgs((array) $filter['options']);
 
1956
            } else {
 
1957
                $instance = $r->newInstance();
 
1958
            }
 
1959
        }
 
1960
 
 
1961
        if ($origName != $name) {
 
1962
            $filterNames  = array_keys($this->_filters);
 
1963
            $order        = array_flip($filterNames);
 
1964
            $order[$name] = $order[$origName];
 
1965
            $filtersExchange = array();
 
1966
            unset($order[$origName]);
 
1967
            asort($order);
 
1968
            foreach ($order as $key => $index) {
 
1969
                if ($key == $name) {
 
1970
                    $filtersExchange[$key] = $instance;
 
1971
                    continue;
 
1972
                }
 
1973
                $filtersExchange[$key] = $this->_filters[$key];
 
1974
            }
 
1975
            $this->_filters = $filtersExchange;
 
1976
        } else {
 
1977
            $this->_filters[$name] = $instance;
 
1978
        }
 
1979
 
 
1980
        return $instance;
 
1981
    }
 
1982
 
 
1983
    /**
 
1984
     * Lazy-load a validator
 
1985
     *
 
1986
     * @param  array $validator Validator definition
 
1987
     * @return Zend_Validate_Interface
 
1988
     */
 
1989
    protected function _loadValidator(array $validator)
 
1990
    {
 
1991
        $origName = $validator['validator'];
 
1992
        $name     = $this->getPluginLoader(self::VALIDATE)->load($validator['validator']);
 
1993
 
 
1994
        if (array_key_exists($name, $this->_validators)) {
 
1995
            require_once 'Zend/Form/Exception.php';
 
1996
            throw new Zend_Form_Exception(sprintf('Validator instance already exists for validator "%s"', $origName));
 
1997
        }
 
1998
 
 
1999
        if (empty($validator['options'])) {
 
2000
            $instance = new $name;
 
2001
        } else {
 
2002
            $messages = false;
 
2003
            if (isset($validator['options']['messages'])) {
 
2004
                $messages = $validator['options']['messages'];
 
2005
                unset($validator['options']['messages']);
 
2006
            }
 
2007
 
 
2008
            $r = new ReflectionClass($name);
 
2009
            if ($r->hasMethod('__construct')) {
 
2010
                $instance = $r->newInstanceArgs((array) $validator['options']);
 
2011
            } else {
 
2012
                $instance = $r->newInstance();
 
2013
            }
 
2014
 
 
2015
            if ($messages) {
 
2016
                if (is_array($messages)) {
 
2017
                    $instance->setMessages($messages);
 
2018
                } elseif (is_string($messages)) {
 
2019
                    $instance->setMessage($messages);
 
2020
                }
 
2021
            }
 
2022
        }
 
2023
 
 
2024
        $instance->zfBreakChainOnFailure = $validator['breakChainOnFailure'];
 
2025
 
 
2026
        if ($origName != $name) {
 
2027
            $validatorNames     = array_keys($this->_validators);
 
2028
            $order              = array_flip($validatorNames);
 
2029
            $order[$name]       = $order[$origName];
 
2030
            $validatorsExchange = array();
 
2031
            unset($order[$origName]);
 
2032
            asort($order);
 
2033
            foreach ($order as $key => $index) {
 
2034
                if ($key == $name) {
 
2035
                    $validatorsExchange[$key] = $instance;
 
2036
                    continue;
 
2037
                }
 
2038
                $validatorsExchange[$key] = $this->_validators[$key];
 
2039
            }
 
2040
            $this->_validators = $validatorsExchange;
 
2041
        } else {
 
2042
            $this->_validators[$name] = $instance;
 
2043
        }
 
2044
 
 
2045
        return $instance;
 
2046
    }
 
2047
 
 
2048
    /**
 
2049
     * Lazy-load a decorator
 
2050
     *
 
2051
     * @param  array $decorator Decorator type and options
 
2052
     * @param  mixed $name Decorator name or alias
 
2053
     * @return Zend_Form_Decorator_Interface
 
2054
     */
 
2055
    protected function _loadDecorator(array $decorator, $name)
 
2056
    {
 
2057
        $sameName = false;
 
2058
        if ($name == $decorator['decorator']) {
 
2059
            $sameName = true;
 
2060
        }
 
2061
 
 
2062
        $instance = $this->_getDecorator($decorator['decorator'], $decorator['options']);
 
2063
        if ($sameName) {
 
2064
            $newName            = get_class($instance);
 
2065
            $decoratorNames     = array_keys($this->_decorators);
 
2066
            $order              = array_flip($decoratorNames);
 
2067
            $order[$newName]    = $order[$name];
 
2068
            $decoratorsExchange = array();
 
2069
            unset($order[$name]);
 
2070
            asort($order);
 
2071
            foreach ($order as $key => $index) {
 
2072
                if ($key == $newName) {
 
2073
                    $decoratorsExchange[$key] = $instance;
 
2074
                    continue;
 
2075
                }
 
2076
                $decoratorsExchange[$key] = $this->_decorators[$key];
 
2077
            }
 
2078
            $this->_decorators = $decoratorsExchange;
 
2079
        } else {
 
2080
            $this->_decorators[$name] = $instance;
 
2081
        }
 
2082
 
 
2083
        return $instance;
 
2084
    }
 
2085
 
 
2086
    /**
 
2087
     * Retrieve error messages and perform translation and value substitution
 
2088
     *
 
2089
     * @return array
 
2090
     */
 
2091
    protected function _getErrorMessages()
 
2092
    {
 
2093
        $translator = $this->getTranslator();
 
2094
        $messages   = $this->getErrorMessages();
 
2095
        $value      = $this->getValue();
 
2096
        foreach ($messages as $key => $message) {
 
2097
            if (null !== $translator) {
 
2098
                $message = $translator->translate($message);
 
2099
            }
 
2100
            if ($this->isArray() || is_array($value)) {
 
2101
                $aggregateMessages = array();
 
2102
                foreach ($value as $val) {
 
2103
                    $aggregateMessages[] = str_replace('%value%', $val, $message);
 
2104
                }
 
2105
                $messages[$key] = $aggregateMessages;
 
2106
            } else {
 
2107
                $messages[$key] = str_replace('%value%', $value, $message);
 
2108
            }
 
2109
        }
 
2110
        return $messages;
 
2111
    }
 
2112
 
 
2113
    /**
 
2114
     * Are there custom error messages registered?
 
2115
     *
 
2116
     * @return bool
 
2117
     */
 
2118
    protected function _hasErrorMessages()
 
2119
    {
 
2120
        return !empty($this->_errorMessages);
 
2121
    }
 
2122
}