Development

/branches/1.0/lib/config/sfValidatorConfigHandler.class.php

You must first sign up to be able to contribute.

root/branches/1.0/lib/config/sfValidatorConfigHandler.class.php

Revision 8754, 17.0 kB (checked in by FabianLange, 7 years ago)

validation yml with fillin is used even without other validators defined in the file. fixed #3232

  • 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 <sean@code-box.org>
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 <sean@code-box.org>
19  * @version    SVN: $Id$
20  */
21 class sfValidatorConfigHandler extends sfYamlConfigHandler
22 {
23   /**
24    * Executes 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         if (!isset($config['fillin']))
49         {
50           throw new sfParseException(sprintf('Configuration file "%s" is missing "%s" category', $configFiles[0], $category));
51         }
52         $config[$category] = array();
53       }
54     }
55
56     // init our data, includes, methods, names and validators arrays
57     $data       = array();
58     $includes   = array();
59     $methods    = array();
60     $names      = array();
61     $validators = array();
62
63     // get a list of methods and their registered files/parameters
64     foreach ($config['methods'] as $method => $list)
65     {
66       $method = strtoupper($method);
67
68       if (!isset($methods[$method]))
69       {
70         // make sure that this method is GET or POST
71         if ($method != 'GET' && $method != 'POST')
72         {
73           // unsupported request method
74           $error = sprintf('Configuration file "%s" specifies unsupported request method "%s"', $configFiles[0], $method);
75
76           throw new sfParseException($error);
77         }
78
79         // create our method
80         $methods[$method] = array();
81       }
82
83       if (!count($list))
84       {
85         // we have an empty list of names
86         continue;
87       }
88
89       // load name list
90       $this->loadNames($configFiles, $method, $methods, $names, $config, $list);
91     }
92
93     // load attribute list
94     $this->loadAttributes($configFiles, $methods, $names, $validators, $config, $list);
95
96     // fill-in filter configuration
97     $fillin = var_export(isset($config['fillin']) ? $config['fillin'] : array(), true);
98
99     // generate GET file/parameter data
100
101     $data[] = "if (\$_SERVER['REQUEST_METHOD'] == 'GET')";
102     $data[] = "{";
103
104     $this->generateRegistration('GET', $data, $methods, $names, $validators);
105
106     if (count($fillin))
107     {
108       $data[] = sprintf("  \$context->getRequest()->setAttribute('fillin', %s, 'symfony/filter');", $fillin);
109     }
110
111     // generate POST file/parameter data
112
113     $data[] = "}";
114     $data[] = "else if (\$_SERVER['REQUEST_METHOD'] == 'POST')";
115     $data[] = "{";
116
117     $this->generateRegistration('POST', $data, $methods, $names, $validators);
118
119     if (count($fillin))
120     {
121       $data[] = sprintf("  \$context->getRequest()->setAttribute('fillin', %s, 'symfony/filter');", $fillin);
122     }
123
124     $data[] = "}";
125
126     // compile data
127     $retval = sprintf("<?php\n".
128                       "// auto-generated by sfValidatorConfigHandler\n".
129                       "// date: %s\n%s\n%s\n", date('Y/m/d H:i:s'),
130                       implode("\n", $includes), implode("\n", $data));
131
132     return $retval;
133   }
134
135   /**
136    * Generates raw cache data.
137    *
138    * @param string A request method
139    * @param array  The data array where our cache code will be appended
140    * @param array  An associative array of request method data
141    * @param array  An associative array of file/parameter data
142    * @param array  A validators array
143    *
144    * @return boolean Returns true if there is some validators for this file/parameter
145    */
146   protected function generateRegistration($method, &$data, &$methods, &$names, &$validators)
147   {
148     // setup validator array
149     $data[] = "  \$validators = array();";
150
151     if (!isset($methods[$method]))
152     {
153       $methods[$method] = array();
154     }
155
156     // determine which validators we need to create for this request method
157     foreach ($methods[$method] as $name)
158     {
159       if (preg_match('/^([a-z0-9_-]+)\{([a-z0-9\s_-]+)\}$/i', $name, $match))
160       {
161         // this file/parameter has a parent
162         $subname = $match[2];
163         $parent  = $match[1];
164
165         $valList = $names[$parent][$subname]['validators'];
166       }
167       else
168       {
169         // no parent
170         $valList = $names[$name]['validators'];
171       }
172
173       if ($valList == null)
174       {
175         // no validator list for this file/parameter
176         continue;
177       }
178
179       foreach ($valList as $valName)
180       {
181         if (isset($validators[$valName]) && !isset($validators[$valName][$method]))
182         {
183           // retrieve this validator's info
184           $validator =& $validators[$valName];
185
186           $data[] = sprintf("  \$validators['%s'] = new %s();\n".
187                             "  \$validators['%s']->initialize(%s, %s);",
188                             $valName, $validator['class'], $valName, '$context', $validator['parameters']);
189
190           // mark this validator as created for this request method
191           $validators[$valName][$method] = true;
192         }
193       }
194     }
195
196     foreach ($methods[$method] as $name)
197     {
198       if (preg_match('/^([a-z0-9_-]+)\{([a-z0-9\s_-]+)\}$/i', $name, $match))
199       {
200         // this file/parameter has a parent
201         $subname = $match[2];
202         $parent  = $match[1];
203         $name    = $match[2];
204
205         $attributes = $names[$parent][$subname];
206       }
207       else
208       {
209         // no parent
210         $attributes = $names[$name];
211       }
212
213       // register file/parameter
214       $data[] = sprintf("  \$validatorManager->registerName('%s', %s, %s, %s, %s, %s);",
215                         $name, $attributes['required'] ? 1 : 0,
216                         isset($attributes['required_msg']) ? $attributes['required_msg'] : "''",
217                         $attributes['parent'], $attributes['group'],
218                         $attributes['file']);
219
220       // register validators for this file/parameter
221       foreach ($attributes['validators'] as &$validator)
222       {
223         $data[] = sprintf("  \$validatorManager->registerValidator('%s', %s, %s);", $name,
224                           "\$validators['$validator']",
225                           $attributes['parent']);
226       }
227     }
228
229     return count($methods[$method]) ? true : false;
230   }
231
232   /**
233    * Loads the linear list of attributes from the [names] category.
234    *
235    * @param string The configuration file name (for exception usage)
236    * @param array  An associative array of request method data
237    * @param array  An associative array of file/parameter names in which to store loaded information
238    * @param array  An associative array of validator data
239    * @param array  The loaded ini configuration that we'll use for verification purposes
240    * @param string A comma delimited list of file/parameter names
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    * Loads 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 store loaded information
305    * @param array  The loaded ini configuration that we'll use for verification purposes
306    * @param string A comma delimited list of file/parameter names
307    */
308   protected function loadNames(&$configFiles, &$method, &$methods, &$names, &$config, &$list)
309   {
310     // explode the list of names
311     $array = $list;
312
313     // loop through the names
314     foreach ($array as $name)
315     {
316       // make sure we have the required status of this file or parameter
317       if (!isset($config['names'][$name]['required']))
318       {
319         // missing 'required' attribute
320         $error = sprintf('Configuration file "%s" specifies file or parameter "%s", but it is missing the "required" attribute', $configFiles[0], $name);
321         throw new sfParseException($error);
322       }
323
324       // determine parent status
325       if (preg_match('/^([a-z0-9_-]+)\{([a-z0-9\s_-]+)\}$/i', $name, $match))
326       {
327         // this name has a parent
328         $subname = $match[2];
329         $parent  = $match[1];
330
331         if (!isset($names[$parent]) || !isset($names[$parent][$name]))
332         {
333           if (!isset($names[$parent]))
334           {
335             // create our parent
336             $names[$parent] = array('_is_parent' => true);
337           }
338
339           // create our new name entry
340           $entry                 = array();
341           $entry['file']         = 'false';
342           $entry['group']        = 'null';
343           $entry['parent']       = "'$parent'";
344           $entry['required']     = 'true';
345           $entry['required_msg'] = "'Required'";
346           $entry['validators']   = array();
347
348           // add our name entry
349           $names[$parent][$subname] = $entry;
350         }
351       }
352       else if (strpos($name, '{') !== false || strpos($name, '}') !== false)
353       {
354         // name contains an invalid character
355         // this is most likely a typo where the user forgot to add a brace
356         $error = sprintf('Configuration file "%s" specifies method "%s" with invalid file/parameter name "%s"', $configFiles[0], $method, $name);
357         throw new sfParseException($error);
358       }
359       else
360       {
361         // no parent
362         if (!isset($names[$name]))
363         {
364           // create our new name entry
365           $entry                 = array();
366           $entry['file']         = 'false';
367           $entry['group']        = 'null';
368           $entry['parent']       = 'null';
369           $entry['required']     = 'true';
370           $entry['required_msg'] = "'Required'";
371           $entry['type']         = 'parameter';
372           $entry['validators']   = array();
373
374           // add our name entry
375           $names[$name] = $entry;
376         }
377       }
378
379       // add this name to the current request method
380       $methods[$method][] = $name;
381     }
382   }
383
384   /**
385    * Loads a list of validators.
386    *
387    * @param string The configuration file name (for exception usage)
388    * @param array  An associative array of validator data
389    * @param array  The loaded ini configuration that we'll use for verification purposes
390    * @param string A comma delimited list of validator names
391    * @param array  A file/parameter name entry
392    */
393   protected function loadValidators(&$configFiles, &$validators, &$config, &$list, &$entry)
394   {
395     // create our empty entry validator array
396     $entry['validators'] = array();
397
398     if (!$list || (!is_array($list) && trim($list) == ''))
399     {
400       // skip the empty list
401       return;
402     }
403
404     // get our validator array
405     $array = is_array($list) ? $list : explode(',', $list);
406
407     foreach ($array as $validator)
408     {
409       $validator = trim($validator);
410
411       // add this validator name to our entry
412       $entry['validators'][] = $validator;
413
414       // make sure the specified validator exists
415       if (!isset($config[$validator]))
416       {
417         // validator hasn't been registered
418         $error = sprintf('Configuration file "%s" specifies unregistered validator "%s"', $configFiles[0], $validator);
419         throw new sfParseException($error);
420       }
421
422       // has it already been registered?
423       if (isset($validators[$validator]))
424       {
425         continue;
426       }
427
428       if (!isset($config[$validator]['class']))
429       {
430         // missing class key
431         $error = sprintf('Configuration file "%s" specifies category "%s" with missing class key', $configFiles[0], $validator);
432         throw new sfParseException($error);
433       }
434
435       // create our validator
436       $validators[$validator]               = array();
437       $validators[$validator]['class']      = $config[$validator]['class'];
438       $validators[$validator]['file']       = null;
439       $validators[$validator]['parameters'] = null;
440
441       if (isset($config[$validator]['file']))
442       {
443         // we have a file for this validator
444         $file = $config[$validator]['file'];
445
446         // keyword replacement
447         $file = $this->replaceConstants($file);
448         $file = $this->replacePath($file);
449
450         if (!is_readable($file))
451         {
452           // file doesn't exist
453           $error = sprintf('Configuration file "%s" specifies category "%s" with nonexistent or unreadable file "%s"', $configFiles[0], $validator, $file);
454           throw new sfParseException($error);
455         }
456
457         $validators[$validator]['file'] = $file;
458       }
459
460       // parse parameters
461       $parameters = (isset($config[$validator]['param']) ? var_export($config[$validator]['param'], true) : 'null');
462
463       $validators[$validator]['parameters'] = $parameters;
464     }
465   }
466
467   /**
468    * Converts alternate format to standard format.
469    *
470    * @param array  Configuration data
471    */
472   protected function convertAlternate2Standard(&$config)
473   {
474     $defaultMethods = isset($config['methods']) ? $config['methods'] : array('post');
475     $config['methods'] = array();
476
477     // validators
478     if (isset($config['validators']))
479     {
480       foreach ((array) $config['validators'] as $validator => $params)
481       {
482         $config[$validator] = $params;
483       }
484
485       unset($config['validators']);
486     }
487
488     // names
489     $config['names'] = $config['fields'];
490     unset($config['fields']);
491
492     foreach ($config['names'] as $name => $values)
493     {
494       // validators
495       $validators = array();
496       foreach ($values as $validator => $params)
497       {
498         if (in_array($validator, array('required', 'group', 'group_msg', 'parent', 'file', 'methods')))
499         {
500           continue;
501         }
502
503         // class or validator
504         if (!isset($config[$validator]))
505         {
506           $config[$validator] = array('class' => $validator);
507         }
508
509         $validatorName = $validator;
510         if ($params)
511         {
512           // create a new validator
513           $validatorName = $validator.'_'.$name;
514           $config[$validatorName] = $config[$validator];
515           $config[$validatorName]['param'] = array_merge(isset($config[$validator]['param']) ? (array) $config[$validator]['param'] : array(), $params);
516         }
517
518         $validators[] = $validatorName;
519
520         unset($values[$validator]);
521       }
522       $values['validators'] = $validators;
523
524       // group
525       if (isset($values['group']) && isset($values['group_msg']))
526       {
527         $values['required_msg'] = $values['group_msg'];
528       }
529
530       // required
531       if (isset($values['required']))
532       {
533         $values['required_msg'] = $values['required']['msg'];
534         $values['required'] = true;
535       }
536       else
537       {
538         $values['required'] = false;
539       }
540
541       // methods
542       if (isset($values['methods']))
543       {
544         $methods = (array) $values['methods'];
545         unset($values['methods']);
546       }
547       else
548       {
549         $methods = $defaultMethods;
550       }
551       foreach ($methods as $method)
552       {
553         $config['methods'][$method][] = $name;
554       }
555
556       $config['names'][$name] = $values;
557     }
558   }
559 }
560
Note: See TracBrowser for help on using the browser.