Validator::getArguments()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 0
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
namespace Agavi\Validator;
3
4
// +---------------------------------------------------------------------------+
5
// | This file is part of the Agavi package.                                   |
6
// | Copyright (c) 2005-2011 the Agavi Project.                                |
7
// |                                                                           |
8
// | For the full copyright and license information, please view the LICENSE   |
9
// | file that was distributed with this source code. You can also view the    |
10
// | LICENSE file online at http://www.agavi.org/LICENSE.txt                   |
11
// |   vi: set noexpandtab:                                                    |
12
// |   Local Variables:                                                        |
13
// |   indent-tabs-mode: t                                                     |
14
// |   End:                                                                    |
15
// +---------------------------------------------------------------------------+
16
use Agavi\Core\Context;
17
use Agavi\Exception\ConfigurationException;
18
use Agavi\Exception\ValidatorException;
19
use Agavi\Request\RequestDataHolder;
20
use Agavi\Util\ArrayPathDefinition;
21
use Agavi\Util\ParameterHolder;
22
use Agavi\Util\Toolkit;
23
use Agavi\Util\VirtualArrayPath;
24
25
/**
26
 * Validator allows you to validate input
27
 *
28
 * Parameters for use in most validators:
29
 *   'name'       name of validator
30
 *   'base'       base path for validation of arrays
31
 *   'arguments'  an array of input parameter keys to validate
32
 *   'export'     destination for exported data
33
 *   'depends'    list of dependencies needed by the validator
34
 *   'provides'   list of dependencies the validator provides after success
35
 *   'severity'   error severity in case of failure
36
 *   'error'      error message when validation fails
37
 *   'errors'     an array of errors with the reason as key
38
 *   'required'   if true the validator will fail when the input parameter is
39
 *                not set
40
 *
41
 * @package    agavi
42
 * @subpackage validator
43
 *
44
 * @author     Dominik del Bondio <[email protected]>
45
 * @author     Uwe Mesecke <[email protected]>
46
 * @copyright  Authors
47
 * @copyright  The Agavi Project
48
 *
49
 * @since      0.11.0
50
 *
51
 * @version    $Id$
52
 */
53
abstract class Validator extends ParameterHolder
54
{
55
    /**
56
     * validator field success flag
57
     */
58
    const NOT_PROCESSED = -1;
59
60
    /**
61
     * validator error severity (the validator succeeded)
62
     */
63
    const SUCCESS = 0;
64
65
    /**
66
     * validator error severity (validator failed but without impact on result
67
     * of whole validation process, completely silent and does not remove the
68
     * "failed" parameters from the input parameters)
69
     */
70
    const INFO = 100;
71
    
72
    /**
73
     * validator error severity (validator failed but without impact on result
74
     * of whole validation process and completely silent)
75
     */
76
    const SILENT = 200;
77
    const NONE = Validator::SILENT;
78
    
79
    /**
80
     * validator error severity (validator failed but without impact on result
81
     * of whole validation process)
82
     */
83
    const NOTICE = 300;
84
85
    /**
86
     * validation error severity (validator failed but validation process
87
     * continues)
88
     */
89
    const ERROR = 400;
90
91
    /**
92
     * validation error severity (validator failed and validation process will
93
     * be aborted)
94
     */
95
    const CRITICAL = 500;
96
97
    /**
98
     * @var        Context An Context instance.
99
     */
100
    protected $context = null;
101
102
    /**
103
     * @var        ValidatorContainerInterface parent validator container (in
104
     *                                      most cases the validator manager)
105
     */
106
    protected $parentContainer = null;
107
108
    /**
109
     * @var        VirtualArrayPath The current base for input names,
110
     *                                   dependencies etc.
111
     */
112
    protected $curBase = null;
113
114
    /**
115
     * @var        string The name of this validator instance. This will either
116
     *                    be the user supplied name (if any) or a random string
117
     */
118
    protected $name = null;
119
120
    /**
121
     * @var        RequestDataHolder The parameters which should be validated
122
     *                                  in the current validation run.
123
     */
124
    protected $validationParameters = null;
125
126
    /**
127
     * @var        array The name of the request parameters serving as argument to
128
     *                   this validator.
129
     */
130
    protected $arguments = array();
131
132
    /**
133
     * @var        array The error messages.
134
     */
135
    protected $errorMessages = array();
136
137
    /**
138
     * @var        ValidationIncident The current incident.
139
     */
140
    protected $incident = null;
141
    
142
    /**
143
     * @var        array The affected arguments of this validation run.
144
     */
145
    protected $affectedArguments = array();
146
147
    /**
148
     * Returns the base path of this validator.
149
     *
150
     * @return     VirtualArrayPath The basepath of this validator
151
     *
152
     * @author     Dominik del Bondio <[email protected]>
153
     * @since      0.11.0
154
     */
155
    public function getBase()
156
    {
157
        return $this->curBase;
158
    }
159
160
    /**
161
     * Returns the "keys" in the path of the base
162
     *
163
     * @return     array The keys from left to right
164
     *
165
     * @author     Dominik del Bondio <[email protected]>
166
     * @since      0.11.0
167
     */
168
    public function getBaseKeys()
169
    {
170
        $keys = array();
171
        $l = $this->curBase->length();
172
        for ($i = 1; $i < $l; ++$i) {
173
            $keys[] = $this->curBase->get($i);
174
        }
175
176
        return $keys;
177
    }
178
179
    /**
180
     * Returns the last "keys" in the path of the base
181
     *
182
     * @return     mixed The key
183
     *
184
     * @author     Dominik del Bondio <[email protected]>
185
     * @since      0.11.0
186
     */
187
    public function getLastKey()
188
    {
189
        $base = $this->curBase;
190
        if ($base->length() == 0 || ($base->length() == 1 && $base->isAbsolute())) {
191
            return null;
192
        }
193
194
        return $base->get($base->length() - 1);
195
    }
196
197
    /**
198
     * Returns the name of this validator.
199
     *
200
     * @return     string The name
201
     *
202
     * @author     Dominik del Bondio <[email protected]>
203
     * @since      0.11.0
204
     */
205
    public function getName()
206
    {
207
        return $this->name;
208
    }
209
210
    /**
211
     * Initialize this validator.
212
     *
213
     * @param      Context $context The Context.
214
     * @param      array   $parameters An array of validator parameters.
215
     * @param      array   $arguments An array of argument names which should be validated.
216
     * @param      array   $errors An array of error messages.
217
     *
218
     * @author     Dominik del Bondio <[email protected]>
219
     * @since      0.11.0
220
     */
221
    public function initialize(Context $context, array $parameters = array(), array $arguments = array(), array $errors = array())
222
    {
223
        $this->context = $context;
224
225
        $this->arguments = $arguments;
226
        $this->errorMessages = $errors;
227
228 View Code Duplication
        if (!isset($parameters['depends']) || !is_array($parameters['depends'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
229
            $parameters['depends'] = (!empty($parameters['depends'])) ? explode(' ', $parameters['depends']) : array();
230
        }
231 View Code Duplication
        if (!isset($parameters['provides']) || !is_array($parameters['provides'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
232
            $parameters['provides'] = (!empty($parameters['provides'])) ? explode(' ', $parameters['provides']) : array();
233
        }
234
235
        if (!isset($parameters['source'])) {
236
            $parameters['source'] = RequestDataHolder::SOURCE_PARAMETERS;
237
        }
238
239
        $this->setParameters($parameters);
240
241
        $this->name = $this->getParameter('name', Toolkit::uniqid());
242
    }
243
244
    /**
245
     * Retrieve the current application context.
246
     *
247
     * @return     Context The current Context instance.
248
     *
249
     * @author     David Zülke <[email protected]>
250
     * @since      0.11.0
251
     */
252
    final public function getContext()
253
    {
254
        return $this->context;
255
    }
256
257
    /**
258
     * Retrieve the parent container.
259
     *
260
     * @return     ValidatorContainerInterface The parent container.
261
     *
262
     * @author     Dominik del Bondio <[email protected]>
263
     * @since      0.11.0
264
     */
265
    final public function getParentContainer()
266
    {
267
        return $this->parentContainer;
268
    }
269
270
    /**
271
     * Sets the parent container.
272
     *
273
     * @param      ValidatorContainerInterface $parent The parent container.
274
     *
275
     * @author     Dominik del Bondio <[email protected]>
276
     * @since      0.11.0
277
     */
278
    public function setParentContainer(ValidatorContainerInterface $parent)
279
    {
280
        // we need a reference here, so when looping happens in a parent
281
        // we always have the right base
282
        $this->curBase = $parent->getBase();
283
        $this->parentContainer = $parent;
284
    }
285
286
    /**
287
     * Validates the input.
288
     *
289
     * This is the method where all the validation stuff is going to happen.
290
     * Inherited classes have to implement their validation logic here. It
291
     * returns only true or false as validation results. The handling of
292
     * error severities is done by the validator itself and should not concern
293
     * the writer of a new validator.
294
     *
295
     * @return     bool The result of the validation.
296
     *
297
     * @author     Uwe Mesecke <[email protected]>
298
     * @since      0.11.0
299
     */
300
    abstract protected function validate();
301
302
    /**
303
     * Shuts the validator down.
304
     *
305
     * This method can be used in validators to shut down used models or
306
     * other activities before the validator is killed.
307
     *
308
     * @see        AgaviValidationManager::shutdown()
309
     *
310
     * @author     Uwe Mesecke <[email protected]>
311
     * @since      0.11.0
312
     */
313
    public function shutdown()
314
    {
315
    }
316
317
    /**
318
     * Returns the specified input value.
319
     *
320
     * The given parameter is fetched from the request. You should _always_
321
     * use this method to fetch data from the request because it pays attention
322
     * to specified paths.
323
     *
324
     * @param      string $paramName The name of the parameter to fetch from request.
325
     *
326
     * @return     mixed The input value from the validation input.
327
     *
328
     * @author     Dominik del Bondio <[email protected]>
329
     * @since      0.11.0
330
     */
331
    protected function &getData($paramName)
332
    {
333
        $paramType = $this->getParameter('source');
334
        $array =& $this->validationParameters->getAll($paramType);
335
        return $this->curBase->getValueByChildPath($paramName, $array);
336
    }
337
338
    /**
339
     * Returns true if this validator has multiple arguments which need to be
340
     * validated.
341
     *
342
     * @return     bool Whether this validator has multiple arguments or not.
343
     *
344
     * @author     Dominik del Bondio <[email protected]>
345
     * @since      0.11.0
346
     */
347
    protected function hasMultipleArguments()
348
    {
349
        return count($this->arguments) > 1;
350
    }
351
352
    /**
353
     * Returns the name of the argument which should be validated.
354
     * Returns the name of the first (and typically only) argument by default, or,
355
     * if a string is provided to the method, returns the name of the argument
356
     * as configured for that identifier.
357
     *
358
     * @param      string $name The optional argument identifier, as configured.
359
     *
360
     * @return     string The resulting name of the argument in the request data.
361
     *
362
     * @author     Dominik del Bondio <[email protected]>
363
     * @author     David Zülke <[email protected]>
364
     *
365
     * @since      0.11.0
366
     */
367
    protected function getArgument($name = null)
368
    {
369
        if ($name === null) {
370
            $argNames = $this->arguments;
371
            reset($argNames);
372
            return current($argNames);
373
        } else {
374
            if (isset($this->arguments[$name])) {
375
                return $this->arguments[$name];
376
            }
377
        }
378
    }
379
380
    /**
381
     * Returns all arguments which should be validated.
382
     *
383
     * @return     array A list of input arguments names.
384
     *
385
     * @author     Dominik del Bondio <[email protected]>
386
     * @since      0.11.0
387
     */
388
    protected function getArguments()
389
    {
390
        return $this->arguments;
391
    }
392
    
393
    /**
394
     * Sets the arguments which should be flagged with the result of the
395
     * validator
396
     *
397
     * @param      array $arguments A list of (absolute) argument names
398
     *
399
     * @author     Dominik del Bondio <[email protected]>
400
     * @since      0.11.0
401
     */
402
    protected function setAffectedArguments($arguments)
403
    {
404
        $this->affectedArguments = $arguments;
405
    }
406
407
    /**
408
     * Returns whether all arguments are set in the validation input parameters.
409
     * Set means anything but empty string.
410
     *
411
     * @param      bool $throwError Whether an error should be thrown for each missing
412
     *                  argument if this validator is required.
413
     *
414
     * @return     bool Whether the arguments are set.
415
     *
416
     * @author     Dominik del Bondio <[email protected]>
417
     * @since      0.11.0
418
     */
419
    protected function checkAllArgumentsSet($throwError = true)
420
    {
421
        $isRequired = $this->getParameter('required', true);
422
        $paramType = $this->getParameter('source');
423
        $result = true;
424
425
        foreach ($this->getArguments() as $argument) {
426
            $pName = $this->curBase->pushRetNew($argument)->__toString();
427
            if ($this->validationParameters->isValueEmpty($paramType, $pName)) {
428
                if ($throwError && $isRequired) {
429
                    $this->throwError('required', $pName);
430
                }
431
                $result = false;
432
            }
433
        }
434
        return $result;
435
    }
436
437
    /**
438
     * Retrieves the error message for the given index with fallback.
439
     *
440
     * If the given index does not exist in the error messages array, it first
441
     * checks if an unnamed error message exists and returns it or falls back the
442
     * the backup message.
443
     *
444
     * @param      string $index The name of the error.
445
     * @param      string $backupMessage The backup error message.
446
     *
447
     * @author     Dominik del Bondio <[email protected]>
448
     * @since      0.11.0
449
     */
450
    protected function getErrorMessage($index = null, $backupMessage = null)
451
    {
452
        if ($index !== null && isset($this->errorMessages[$index])) {
453
            $error = $this->errorMessages[$index];
454
        } elseif (isset($this->errorMessages[''])) {
455
            // check if a default error exists.
456
            $error = $this->errorMessages[''];
457
        } else {
458
            $error = $backupMessage;
459
        }
460
461
        return $error;
462
    }
463
464
    /**
465
     * Submits an error to the error manager.
466
     *
467
     * Will look up the index in the errors array with automatic fallback to the
468
     * default error. You can optionally specify the fields affected by this
469
     * error. The error will be appended to the current incident.
470
     *
471
     * @param      string $index The name of the error parameter to fetch the message
472
     *                    from.
473
     * @param      string|array $affectedArgument The arguments which are affected by this error.
474
     *                          If null is given it will affect all fields.
475
     * @param      boolean $argumentsRelative Whether the argument names in $affectedArgument are
476
     *                     relative or absolute.
477
     * @param      boolean $setAffected Whether to set the affected fields of the validator
478
     *                     to the $affectedArguments
479
     *
480
     * @author     Dominik del Bondio <[email protected]>
481
     * @since      0.11.0
482
     */
483
    protected function throwError($index = null, $affectedArgument = null, $argumentsRelative = false, $setAffected = false)
484
    {
485
        if ($affectedArgument === null) {
486
            $affectedArguments = $this->getFullArgumentNames();
487
        } else {
488
            $affectedArguments = (array) $affectedArgument;
489
            if ($argumentsRelative) {
490
                foreach ($affectedArguments as &$arg) {
491
                    $arg = $this->curBase->pushRetNew($arg)->__toString();
492
                }
493
            }
494
        }
495
        
496
        if ($setAffected) {
497
            $this->affectedArguments = $affectedArguments;
498
        }
499
500
        $error = $this->getErrorMessage($index);
501
502
        if ($this->hasParameter('translation_domain')) {
503
            $error = $this->getContext()->getTranslationManager()->_($error, $this->getParameter('translation_domain'));
504
        }
505
506
        if (!$this->incident) {
507
            $this->incident = new ValidationIncident($this, self::mapErrorCode($this->getParameter('severity', 'error')));
508
        }
509
510
        foreach ($affectedArguments as &$argument) {
511
            $argument = new ValidationArgument($argument, $this->getParameter('source'));
512
        }
513
        
514
        if ($error !== null || count($affectedArguments) != 0) {
515
            // don't throw empty error messages without affected fields
516
            $this->incident->addError(new ValidationError($error, $index, $affectedArguments));
517
        }
518
    }
519
520
    /**
521
     * Exports a value back into the request.
522
     *
523
     * Exports data into the request at the index given in the parameter
524
     * 'export'. If there is no such parameter, then the method returns
525
     * without exporting.
526
     *
527
     * Similar to getData() you should always use export() to submit data to
528
     * the request because it pays attention to paths and otherwise you could
529
     * overwrite stuff you don't want to.
530
     *
531
     * @param      mixed $value The value to be exported.
532
     * @param      mixed $argument An optional parameter name which should be used for
533
     *                   exporting instead of the "export" attribute value, or an
534
     *                   AgaviValidationArgument object if the value should be
535
     *                   exported to a different source.
536
     * @param      int   $result The result status code to use for the exported value.
537
     *                   Defaults to AgaviValidator::SUCCESS.
538
     *
539
     * @author     Dominik del Bondio <[email protected]>
540
     * @author     David Zülke <[email protected]>
541
     * @since      0.11.0
542
     */
543
    protected function export($value, $argument = null, $result = null)
544
    {
545
        if ($argument === null) {
546
            $argument = $this->getParameter('export');
547
        }
548
        
549
        if ($result === null) {
550
            $result = $this->getParameter('export_severity', Validator::SUCCESS);
551
            if (!is_numeric($result) && defined($result)) {
552
                $result = constant($result);
553
            }
554
        }
555
556
        if (!($argument instanceof ValidationArgument) && (!is_string($argument) || $argument === '')) {
557
            return;
558
        }
559
560
        if ($argument instanceof ValidationArgument) {
561
            $source = $argument->getSource();
562
            $name = $argument->getName();
563
        } else {
564
            $source = $this->getParameter('export_to_source', $this->getParameter('source'));
565
            $name = $argument;
566
        }
567
568
        $array =& $this->validationParameters->getAll($source);
569
        $currentParts = $this->curBase->getParts();
570
        
571
        if (count($currentParts) > 0 && strpos($name, '%') !== false) {
572
            // this is a validator which actually has a base (<arguments base="xx">) set
573
            // and the export name contains sprintf syntax
574
            $name = vsprintf($name, $currentParts);
575
        }
576
        // CAUTION
577
        // we had a feature here during development that would allow [] at the end to append values to an array
578
        // that would, however, mean that we have to cast the value to an array, and, either way, a user would be able to manipulate the keys
579
        // example: we export to foo[], and the user supplies ?foo[28] in the URL. that means our export will be in foo[29]. foo[28] will be removed by the validation, but the keys are still potentially harmful
580
        // that's why we decided to remove this again
581
        $cp = new VirtualArrayPath($name);
582
        $cp->setValue($array, $value);
583
        if ($this->parentContainer !== null) {
584
            // make sure the parameter doesn't get removed by the validation manager
585
            if (is_array($value)) {
586
                // for arrays all child elements need to be marked as not processed
587
                foreach (ArrayPathDefinition::getFlatKeyNames($value) as $keyName) {
588
                    $this->parentContainer->addArgumentResult(new ValidationArgument($cp->pushRetNew($keyName)->__toString(), $source), $result, $this);
589
                }
590
            }
591
            $this->parentContainer->addArgumentResult(new ValidationArgument($cp->__toString(), $source), $result, $this);
592
        }
593
    }
594
595
    /**
596
     * Validates this validator in the given base.
597
     *
598
     * @param      VirtualArrayPath $base The base in which the input should be
599
     *                                   validated.
600
     *
601
     * @return     int AgaviValidator::SUCCESS if validation succeeded or given
602
     *                 error severity.
603
     *
604
     * @author     Dominik del Bondio <[email protected]>
605
     * @author     Uwe Mesecke <[email protected]>
606
     * @since      0.11.0
607
     */
608
    protected function validateInBase(VirtualArrayPath $base)
609
    {
610
        $base = clone $base;
611
        if ($base->length() == 0) {
612
            // we have an empty base so we do the actual validation
613 View Code Duplication
            if ($this->getDependencyManager() && (count($this->getParameter('depends')) > 0 && !$this->getDependencyManager()->checkDependencies($this->getParameter('depends'), $this->curBase))) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
614
                // dependencies not met, exit with success
615
                return self::NOT_PROCESSED;
616
            }
617
618
            $this->affectedArguments = $this->getFullArgumentNames();
619
620
            $result = self::SUCCESS;
621
            $errorCode = self::mapErrorCode($this->getParameter('severity', 'error'));
622
623
            if ($this->checkAllArgumentsSet(false)) {
624
                if (!$this->validate()) {
625
                    // validation failed, exit with configured error code
626
                    $result = $errorCode;
627
                }
628
            } else {
629
                if ($this->getParameter('required', true)) {
630
                    $this->throwError('required');
631
                    $result = $errorCode;
632
                } else {
633
                    // we don't throw an error here because this is not an incident per se
634
                    // but rather a non validated field
635
                    $result = self::NOT_PROCESSED;
636
                }
637
            }
638
639
            if ($this->parentContainer !== null) {
640
                foreach ($this->affectedArguments as $fieldname) {
641
                    $this->parentContainer->addArgumentResult(new ValidationArgument($fieldname, $this->getParameter('source')), $result, $this);
642
                }
643
644
                if ($this->incident) {
645
                    $this->parentContainer->addIncident($this->incident);
646
                }
647
            }
648
649
            $this->incident = null;
650
            // put dependencies provided by this validator into manager
651 View Code Duplication
            if ($this->getDependencyManager() && ($result == self::SUCCESS && count($this->getParameter('provides')) > 0)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
652
                $this->getDependencyManager()->addDependTokens($this->getParameter('provides'), $this->curBase);
653
            }
654
            return $result;
655
        } elseif ($base->left() !== '') {
656
            /*
657
			 * the next component in the base is no wildcard so we
658
			 * just put it into our own base and validate further
659
			 * into the base.
660
			 */
661
662
            $this->curBase->push($base->shift());
663
            $ret = $this->validateInBase($base);
664
            $this->curBase->pop();
665
666
            return $ret;
667
        } else {
668
            /*
669
			 * now we have a wildcard as next component so we collect
670
			 * all defined value names in the request at the path
671
			 * specified by our own base and validate in each of that
672
			 * names
673
			 */
674
            $names = $this->getKeysInCurrentBase();
675
676
            // if the names array is empty this means we need to throw an error since
677
            // this means the input doesn't exist
678
            if (count($names) == 0) {
679
                if ($this->getDependencyManager() && (count($this->getParameter('depends')) > 0 && !$this->getDependencyManager()->checkDependencies($this->getParameter('depends'), $this->curBase))) {
680
                    // since the dependencies are only ever checked if the base gets empty (which happens when
681
                    // the validation is about to validate an argument), but we are already bailing out in an earlier
682
                    // stage, lets do the dependency check so the validator doesn't accidently return an error even
683
                    // if it's dependencies aren't met
684
                    return self::NOT_PROCESSED;
685
                } else {
686
                    if ($this->getParameter('required', true)) {
687
                        $this->throwError('required');
688
                        return self::mapErrorCode($this->getParameter('severity', 'error'));
689
                    } else {
690
                        return self::NOT_PROCESSED;
691
                    }
692
                }
693
            }
694
695
            // throw the wildcard away
696
            $base->shift();
697
698
            $ret = self::NOT_PROCESSED;
699
700
            // validate in every name defined in the request
701
            foreach ($names as $name) {
702
                $newBase = clone $base;
703
                $newBase->unshift($name);
704
                $t = $this->validateInBase($newBase);
705
706
                if ($t == self::CRITICAL) {
707
                    return $t;
708
                }
709
710
                // remember the highest error severity
711
                $ret = max($ret, $t);
712
            }
713
714
            return $ret;
715
        }
716
    }
717
718
    /**
719
     * Executes the validator.
720
     *
721
     * @param      RequestDataHolder $parameters The data which should be validated.
722
     *
723
     * @return     int The validation result (see severity constants).
724
     *
725
     * @author     Uwe Mesecke <[email protected]>
726
     * @since      0.11.0
727
     */
728
    public function execute(RequestDataHolder $parameters)
729
    {
730
        if ($this->getParameter('source') != RequestDataHolder::SOURCE_PARAMETERS && !in_array($this->getParameter('source'), $parameters->getSourceNames())) {
731
            throw new ConfigurationException('Unknown source "' . $this->getParameter('source') . '" specified in validator ' . $this->getName());
732
        }
733
734
        $this->validationParameters = $parameters;
735
        $base = new VirtualArrayPath($this->getParameter('base'));
736
737
        $res = $this->validateInBase($base);
738
        if ($this->incident && $this->parentContainer) {
739
            $this->parentContainer->addIncident($this->incident);
740
            $this->incident = null;
741
        }
742
        return $res;
743
    }
744
745
    /**
746
     * Converts string severity codes into integer values
747
     * (see severity constants)
748
     *
749
     * critical -> Validator::CRITICAL
750
     * error    -> Validator::ERROR
751
     * notice   -> Validator::NOTICE
752
     * none     -> Validator::NONE
753
     * success  -> not allowed to be specified by the user.
754
     *
755
     * @param      string $code The error severity as string.
756
     *
757
     * @return     int The error severity as in (see severity constants).
758
     *
759
     * @throws     <b>AgaviValidatorException</b> if the input was no known
760
     *                                           severity
761
     *
762
     * @author     Uwe Mesecke <[email protected]>
763
     * @since      0.11.0
764
     */
765
    public static function mapErrorCode($code)
766
    {
767
        switch (strtolower($code)) {
768
            case 'critical':
769
                return self::CRITICAL;
770
            case 'error':
771
                return self::ERROR;
772
            case 'notice':
773
                return self::NOTICE;
774
            case 'none':
775
            case 'silent':
776
                return self::SILENT;
777
            case 'info':
778
                return self::INFO;
779
            default:
780
                throw new ValidatorException('unknown error code: '.$code);
781
        }
782
    }
783
784
    /**
785
     * Returns all available keys in the currently set base.
786
     *
787
     * @return     array The available keys.
788
     *
789
     * @author     Dominik del Bondio <[email protected]>
790
     * @since      0.11.0
791
     */
792
    protected function getKeysInCurrentBase()
793
    {
794
        $paramType = $this->getParameter('source');
795
796
        $array = $this->validationParameters->getAll($paramType);
797
        $names = $this->curBase->getValue($array, array());
798
799
        return is_array($names) ? array_keys($names) : array();
800
    }
801
802
    /**
803
     * Returns all arguments with their full path.
804
     *
805
     * @return     array The arguments.
806
     *
807
     * @author     Dominik del Bondio <[email protected]>
808
     * @since      0.11.0
809
     */
810
    protected function getFullArgumentNames()
811
    {
812
        $arguments = array();
813
        foreach ($this->getArguments() as $argument) {
814
            if ($argument) {
815
                $arguments[] = $this->curBase->pushRetNew($argument)->__toString();
816
            } else {
817
                $arguments[] = $this->curBase->__toString();
818
            }
819
        }
820
821
        return $arguments;
822
    }
823
824
    /**
825
     * Returns the depency manager of the parent container if any.
826
     *
827
     * @return     DependencyManager The parent's dependency manager.
828
     *
829
     * @author     Dominik del Bondio <[email protected]>
830
     * @since      0.11.0
831
     */
832
    public function getDependencyManager()
833
    {
834
        if ($this->parentContainer instanceof ValidatorContainerInterface) {
835
            return $this->parentContainer->getDependencyManager();
836
        }
837
        return null;
838
    }
839
}
840