Development

/trunk/lib/config/sfValidatorConfigHandler.class.php

You must first sign up to be able to contribute.

root/trunk/lib/config/sfValidatorConfigHandler.class.php

Revision 3169, 16.9 kB (checked in by fabien, 6 years ago)

added group error message in alternate validation format

  • Property svn:mime-type set to text/x-php
  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Rev Date
Line 
1 <?php
2
3 /*
4  * This file is part of the symfony package.
5  * (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
6  * (c) 2004-2006 Sean Kerr.
7  *
8  * For the full copyright and license information, please view the LICENSE
9  * file that was distributed with this source code.
10  */
11
12 /**
13  * sfValidatorConfigHandler allows you to register validators with the system.
14  *
15  * @package    symfony
16  * @subpackage config
17  * @author     Fabien Potencier <fabien.potencier@symfony-project.com>
18  * @author     Sean Kerr <skerr@mojavi.org>
19  * @version    SVN: $Id$
20  */
21 class sfValidatorConfigHandler extends sfYamlConfigHandler
22 {
23   /**
24    * Execute this configuration handler.
25    *
26    * @param array An array of absolute filesystem path to a configuration file.
27    *
28    * @return string Data to be written to a cache file.
29    *
30    * @throws sfConfigurationException If a requested configuration file does not exist or is not readable.
31    * @throws sfParseException If a requested configuration file is improperly formatted.
32    */
33   public function execute($configFiles)
34   {
35     // parse the yaml
36     $config = $this->parseYamls($configFiles);
37
38     // alternate format?
39     if (isset($config['fields']))
40     {
41       $this->convertAlternate2Standard($config);
42     }
43
44     foreach (array('methods', 'names') as $category)
45     {
46       if (!isset($config[$category]))
47       {
48         throw new sfParseException(sprintf('Configuration file "%s" is missing "%s" category', $configFiles[0], $category));
49       }
50     }
51
52     // init our data, includes, methods, names and validators arrays
53     $data       = array();
54     $includes   = array();
55     $methods    = array();
56     $names      = array();
57     $validators = array();
58
59     // get a list of methods and their registered files/parameters
60     foreach ($config['methods'] as $method => $list)
61     {
62       $method = strtoupper($method);
63
64       if (!isset($methods[$method]))
65       {
66         // make sure that this method is GET or POST
67         if ($method != 'GET' && $method != 'POST')
68         {
69           // unsupported request method
70           $error = sprintf('Configuration file "%s" specifies unsupported request method "%s"', $configFiles[0], $method);
71
72           throw new sfParseException($method);
73         }
74
75         // create our method
76         $methods[$method] = array();
77       }
78
79       if (!count($list))
80       {
81         // we have an empty list of names
82         continue;
83       }
84
85       // load name list
86       $this->loadNames($configFiles, $method, $methods, $names, $config, $list);
87     }
88
89     // load attribute list
90     $this->loadAttributes($configFiles, $methods, $names, $validators, $config, $list);
91
92     // fill-in filter configuration
93     $fillin = var_export(isset($config['fillin']) ? $config['fillin'] : array(), true);
94
95     // generate GET file/parameter data
96
97     $data[] = "if (\$_SERVER['REQUEST_METHOD'] == 'GET')";
98     $data[] = "{";
99
100     $ret = $this->generateRegistration('GET', $data, $methods, $names, $validators);
101
102     if ($ret)
103     {
104       $data[] = sprintf("  \$context->getRequest()->setAttribute('fillin', %s, 'symfony/filter');", $fillin);
105     }
106
107     // generate POST file/parameter data
108
109     $data[] = "}";
110     $data[] = "else if (\$_SERVER['REQUEST_METHOD'] == 'POST')";
111     $data[] = "{";
112
113     $ret = $this->generateRegistration('POST', $data, $methods, $names, $validators);
114
115     if ($ret)
116     {
117       $data[] = sprintf("  \$context->getRequest()->setAttribute('fillin', %s, 'symfony/filter');", $fillin);
118     }
119
120     $data[] = "}";
121
122     // compile data
123     $retval = sprintf("<?php\n".
124                       "// auto-generated by sfValidatorConfigHandler\n".
125                       "// date: %s\n%s\n%s\n", date('Y/m/d H:i:s'),
126                       implode("\n", $includes), implode("\n", $data));
127
128     return $retval;
129   }
130
131   /**
132    * Generate raw cache data.
133    *
134    * @param string A request method.
135    * @param array  The data array where our cache code will be appended.
136    * @param array  An associative array of request method data.
137    * @param array  An associative array of file/parameter data.
138    * @param array  A validators array.
139    *
140    * @return boolean Returns true if there is some validators for this file/parameter
141    */
142   protected function generateRegistration($method, &$data, &$methods, &$names, &$validators)
143   {
144     // setup validator array
145     $data[] = "  \$validators = array();";
146
147     if (!isset($methods[$method]))
148     {
149       $methods[$method] = array();
150     }
151
152     // determine which validators we need to create for this request method
153     foreach ($methods[$method] as $name)
154     {
155       if (preg_match('/^([a-z0-9_-]+)\{([a-z0-9\s_-]+)\}$/i', $name, $match))
156       {
157         // this file/parameter has a parent
158         $subname = $match[2];
159         $parent  = $match[1];
160
161         $valList = $names[$parent][$subname]['validators'];
162       }
163       else
164       {
165         // no parent
166         $valList = $names[$name]['validators'];
167       }
168
169       if ($valList == null)
170       {
171         // no validator list for this file/parameter
172         continue;
173       }
174
175       foreach ($valList as $valName)
176       {
177         if (isset($validators[$valName]) && !isset($validators[$valName][$method]))
178         {
179           // retrieve this validator's info
180           $validator =& $validators[$valName];
181
182           $data[] = sprintf("  \$validators['%s'] = new %s();\n".
183                             "  \$validators['%s']->initialize(%s, %s);",
184                             $valName, $validator['class'], $valName, '$context', $validator['parameters']);
185
186           // mark this validator as created for this request method
187           $validators[$valName][$method] = true;
188         }
189       }
190     }
191
192     foreach ($methods[$method] as $name)
193     {
194       if (preg_match('/^([a-z0-9_-]+)\{([a-z0-9\s_-]+)\}$/i', $name, $match))
195       {
196         // this file/parameter has a parent
197         $subname = $match[2];
198         $parent  = $match[1];
199         $name    = $match[2];
200
201         $attributes = $names[$parent][$subname];
202       }
203       else
204       {
205         // no parent
206         $attributes = $names[$name];
207       }
208
209       // register file/parameter
210       $data[] = sprintf("  \$validatorManager->registerName('%s', %s, %s, %s, %s, %s);",
211                         $name, $attributes['required'] ? 1 : 0,
212                         isset($attributes['required_msg']) ? $attributes['required_msg'] : "''",
213                         $attributes['parent'], $attributes['group'],
214                         $attributes['file']);
215
216       // register validators for this file/parameter
217       foreach ($attributes['validators'] as &$validator)
218       {
219         $data[] = sprintf("  \$validatorManager->registerValidator('%s', %s, %s);", $name,
220                           "\$validators['$validator']",
221                           $attributes['parent']);
222       }
223     }
224
225     return count($methods[$method]) ? true : false;
226   }
227
228   /**
229    * Load the linear list of attributes from the [names] category.
230    *
231    * @param string The configuration file name (for exception usage).
232    * @param array  An associative array of request method data.
233    * @param array  An associative array of file/parameter names in which to
234    *               store loaded information.
235    * @param array  An associative array of validator data.
236    * @param array  The loaded ini configuration that we'll use for
237    *               verification purposes.
238    * @param string A comma delimited list of file/parameter names.
239    *
240    * @return void
241    */
242   protected function loadAttributes(&$configFiles, &$methods, &$names, &$validators, &$config, &$list)
243   {
244     foreach ($config['names'] as $name => $attributes)
245     {
246       // get a reference to the name entry
247       if (preg_match('/^([a-z0-9_-]+)\{([a-z0-9\s_-]+)\}$/i', $name, $match))
248       {
249         // this name entry has a parent
250         $subname = $match[2];
251         $parent  = $match[1];
252
253         if (!isset($names[$parent][$subname]))
254         {
255           // unknown parent or subname
256           $error = sprintf('Configuration file "%s" specifies unregistered parent "%s" or subname "%s"', $configFiles[0], $parent, $subname);
257           throw new sfParseException($error);
258         }
259
260         $entry =& $names[$parent][$subname];
261       }
262       else
263       {
264         // no parent
265         if (!isset($names[$name]))
266         {
267           // unknown name
268           $error = sprintf('Configuration file "%s" specifies unregistered name "%s"', $configFiles[0], $name);
269           throw new sfParseException($error);
270         }
271
272         $entry =& $names[$name];
273       }
274
275       foreach ($attributes as $attribute => $value)
276       {
277         if ($attribute == 'validators')
278         {
279           // load validators for this file/parameter name
280           $this->loadValidators($configFiles, $validators, $config, $value, $entry);
281         }
282         else if ($attribute == 'type')
283         {
284           // name type
285           $lvalue = strtolower($value);
286           $entry['file'] = ($lvalue == 'file' ? 'true' : 'false');
287         }
288         else
289         {
290           // just a normal attribute
291           $entry[$attribute] = sfToolkit::literalize($value, true);
292         }
293       }
294     }
295   }
296
297   /**
298    * Load all request methods and the file/parameter names that will be
299    * validated from the [methods] category.
300    *
301    * @param string The configuration file name (for exception usage).
302    * @param string A request method.
303    * @param array  An associative array of request method data.
304    * @param array  An associative array of file/parameter names in which to
305    *               store loaded information.
306    * @param array  The loaded ini configuration that we'll use for
307    *               verification purposes.
308    * @param string A comma delimited list of file/parameter names.
309    *
310    * @return void
311    */
312   protected function loadNames(&$configFiles, &$method, &$methods, &$names, &$config, &$list)
313   {
314     // explode the list of names
315     $array = $list;
316
317     // loop through the names
318     foreach ($array as $name)
319     {
320       // make sure we have the required status of this file or parameter
321       if (!isset($config['names'][$name]['required']))
322       {
323         // missing 'required' attribute
324         $error = sprintf('Configuration file "%s" specifies file or parameter "%s", but it is missing the "required" attribute', $configFiles[0], $name);
325         throw new sfParseException($error);
326       }
327
328       // determine parent status
329       if (preg_match('/^([a-z0-9_-]+)\{([a-z0-9\s_-]+)\}$/i', $name, $match))
330       {
331         // this name has a parent
332         $subname = $match[2];
333         $parent  = $match[1];
334
335         if (!isset($names[$parent]) || !isset($names[$parent][$name]))
336         {
337           if (!isset($names[$parent]))
338           {
339             // create our parent
340             $names[$parent] = array('_is_parent' => true);
341           }
342
343           // create our new name entry
344           $entry                 = array();
345           $entry['file']         = 'false';
346           $entry['group']        = 'null';
347           $entry['parent']       = "'$parent'";
348           $entry['required']     = 'true';
349           $entry['required_msg'] = "'Required'";
350           $entry['validators']   = array();
351
352           // add our name entry
353           $names[$parent][$subname] = $entry;
354         }
355       }
356       else if (strpos($name, '{') !== false || strpos($name, '}') !== false)
357       {
358         // name contains an invalid character
359         // this is most likely a typo where the user forgot to add a brace
360         $error = sprintf('Configuration file "%s" specifies method "%s" with invalid file/parameter name "%s"', $configFiles[0], $method, $name);
361         throw new sfParseException($error);
362       }
363       else
364       {
365         // no parent
366         if (!isset($names[$name]))
367         {
368           // create our new name entry
369           $entry                 = array();
370           $entry['file']         = 'false';
371           $entry['group']        = 'null';
372           $entry['parent']       = 'null';
373           $entry['required']     = 'true';
374           $entry['required_msg'] = "'Required'";
375           $entry['type']         = 'parameter';
376           $entry['validators']   = array();
377
378           // add our name entry
379           $names[$name] = $entry;
380         }
381       }
382
383       // add this name to the current request method
384       $methods[$method][] = $name;
385     }
386   }
387
388   /**
389    * Load a list of validators.
390    *
391    * @param string The configuration file name (for exception usage).
392    * @param array  An associative array of validator data.
393    * @param array  The loaded ini configuration that we'll use for
394    *               verification purposes.
395    * @param string A comma delimited list of validator names.
396    * @return void
397    * @param array  A file/parameter name entry.
398    */
399   protected function loadValidators(&$configFiles, &$validators, &$config, &$list, &$entry)
400   {
401     // create our empty entry validator array
402     $entry['validators'] = array();
403
404     if (!$list || (!is_array($list) && trim($list) == ''))
405     {
406       // skip the empty list
407       return;
408     }
409
410     // get our validator array
411     $array = is_array($list) ? $list : explode(',', $list);
412
413     foreach ($array as $validator)
414     {
415       $validator = trim($validator);
416
417       // add this validator name to our entry
418       $entry['validators'][] = $validator;
419
420       // make sure the specified validator exists
421       if (!isset($config[$validator]))
422       {
423         // validator hasn't been registered
424         $error = sprintf('Configuration file "%s" specifies unregistered validator "%s"', $configFiles[0], $validator);
425         throw new sfParseException($error);
426       }
427
428       // has it already been registered?
429       if (isset($validators[$validator]))
430       {
431         continue;
432       }
433
434       if (!isset($config[$validator]['class']))
435       {
436         // missing class key
437         $error = sprintf('Configuration file "%s" specifies category "%s" with missing class key', $configFiles[0], $validator);
438         throw new sfParseException($error);
439       }
440
441       // create our validator
442       $validators[$validator]               = array();
443       $validators[$validator]['class']      = $config[$validator]['class'];
444       $validators[$validator]['file']       = null;
445       $validators[$validator]['parameters'] = null;
446
447       if (isset($config[$validator]['file']))
448       {
449         // we have a file for this validator
450         $file = $config[$validator]['file'];
451
452         // keyword replacement
453         $file = $this->replaceConstants($file);
454         $file = $this->replacePath($file);
455
456         if (!is_readable($file))
457         {
458           // file doesn't exist
459           $error = sprintf('Configuration file "%s" specifies category "%s" with nonexistent or unreadable file "%s"', $configFiles[0], $validator, $file);
460           throw new sfParseException($error);
461         }
462
463         $validators[$validator]['file'] = $file;
464       }
465
466       // parse parameters
467       $parameters = (isset($config[$validator]['param']) ? var_export($config[$validator]['param'], true) : 'null');
468
469       $validators[$validator]['parameters'] = $parameters;
470     }
471   }
472
473   /**
474    * Convert alternate format to standard format
475    *
476    * @param array  Configuration data.
477    */
478   protected function convertAlternate2Standard(&$config)
479   {
480     $defaultMethods = isset($config['methods']) ? $config['methods'] : array('post');
481     $config['methods'] = array();
482
483     // validators
484     if (isset($config['validators']))
485     {
486       foreach ((array) $config['validators'] as $validator => $params)
487       {
488         $config[$validator] = $params;
489       }
490
491       unset($config['validators']);
492     }
493
494     // names
495     $config['names'] = $config['fields'];
496     unset($config['fields']);
497
498     foreach ($config['names'] as $name => $values)
499     {
500       // validators
501       $validators = array();
502       foreach ($values as $validator => $params)
503       {
504         if (in_array($validator, array('required', 'group', 'group_msg', 'parent', 'file')))
505         {
506           continue;
507         }
508
509         // class or validator
510         if (!isset($config[$validator]))
511         {
512           $config[$validator] = array('class' => $validator);
513         }
514
515         $validatorName = $validator;
516         if ($params)
517         {
518           // create a new validator
519           $validatorName = $validator.'_'.$name;
520           $config[$validatorName] = $config[$validator];
521           $config[$validatorName]['param'] = array_merge(isset($config[$validator]['param']) ? (array) $config[$validator]['param'] : array(), $params);
522         }
523
524         $validators[] = $validatorName;
525
526         unset($values[$validator]);
527       }
528       $values['validators'] = $validators;
529
530       // group
531       if (isset($values['group']) && isset($values['group_msg']))
532       {
533         $values['required_msg'] = $values['group_msg'];
534       }
535
536       // required
537       if (isset($values['required']))
538       {
539         $values['required_msg'] = $values['required']['msg'];
540         $values['required'] = true;
541       }
542       else
543       {
544         $values['required'] = false;
545       }
546
547       // methods
548       $methods = isset($values['methods']) ? (array) $values['methods'] : $defaultMethods;
549       foreach ($methods as $method)
550       {
551         $config['methods'][$method][] = $name;
552       }
553
554       $config['names'][$name] = $values;
555     }
556   }
557 }
558
Note: See TracBrowser for help on using the browser.