Overview

Namespaces

  • Budovy
  • Kdyby
    • BootstrapFormRenderer
      • DI
      • Latte
  • Nette
    • Application
      • Diagnostics
      • Responses
      • Routers
      • UI
    • Caching
      • Storages
    • ComponentModel
    • Database
      • Diagnostics
      • Drivers
      • Reflection
      • Table
    • DI
      • Config
        • Adapters
      • Diagnostics
      • Extensions
    • Diagnostics
    • Forms
      • Controls
      • Rendering
    • Http
      • Diagnostics
    • Iterators
    • Latte
      • Macros
    • Loaders
    • Localization
    • Mail
    • PhpGenerator
    • Reflection
    • Security
      • Diagnostics
    • Templating
    • Utils
  • NetteModule
  • Nextras
    • Datagrid
  • None
  • PHP
  • Tester
    • CodeCoverage
    • Runner
      • Output
  • Vodacek
    • Forms
      • Controls
  • WebLoader
    • Filter
    • Nette

Classes

  • Container
  • ControlGroup
  • Form
  • Helpers
  • Rule
  • Rules

Interfaces

  • IControl
  • IFormRenderer
  • ISubmitterControl
  • Overview
  • Namespace
  • Class
  • Tree
  1: <?php
  2: 
  3: /**
  4:  * This file is part of the Nette Framework (http://nette.org)
  5:  * Copyright (c) 2004 David Grudl (http://davidgrudl.com)
  6:  */
  7: 
  8: namespace Nette\Forms;
  9: 
 10: use Nette;
 11: 
 12: 
 13: /**
 14:  * List of validation & condition rules.
 15:  *
 16:  * @author     David Grudl
 17:  */
 18: class Rules extends Nette\Object implements \IteratorAggregate
 19: {
 20:     /** @internal */
 21:     const VALIDATE_PREFIX = 'validate';
 22: 
 23:     /** @var array */
 24:     public static $defaultMessages = array(
 25:         Form::PROTECTION => 'Please submit this form again (security token has expired).',
 26:         Form::EQUAL => 'Please enter %s.',
 27:         Form::NOT_EQUAL => 'This value should not be %s.',
 28:         Form::FILLED => 'This field is required.',
 29:         Form::BLANK => 'This field should be blank.',
 30:         Form::MIN_LENGTH => 'Please enter at least %d characters.',
 31:         Form::MAX_LENGTH => 'Please enter no more than %d characters.',
 32:         Form::LENGTH => 'Please enter a value between %d and %d characters long.',
 33:         Form::EMAIL => 'Please enter a valid email address.',
 34:         Form::URL => 'Please enter a valid URL.',
 35:         Form::INTEGER => 'Please enter a valid integer.',
 36:         Form::FLOAT => 'Please enter a valid number.',
 37:         Form::RANGE => 'Please enter a value between %d and %d.',
 38:         Form::MAX_FILE_SIZE => 'The size of the uploaded file can be up to %d bytes.',
 39:         Form::MAX_POST_SIZE => 'The uploaded data exceeds the limit of %d bytes.',
 40:         Form::IMAGE => 'The uploaded file must be image in format JPEG, GIF or PNG.',
 41:         Nette\Forms\Controls\SelectBox::VALID => 'Please select a valid option.',
 42:     );
 43: 
 44:     /** @var Rule */
 45:     private $required;
 46: 
 47:     /** @var Rule[] */
 48:     private $rules = array();
 49: 
 50:     /** @var Rules */
 51:     private $parent;
 52: 
 53:     /** @var array */
 54:     private $toggles = array();
 55: 
 56:     /** @var IControl */
 57:     private $control;
 58: 
 59: 
 60:     public function __construct(IControl $control)
 61:     {
 62:         $this->control = $control;
 63:     }
 64: 
 65: 
 66:     /**
 67:      * Makes control mandatory.
 68:      * @param  mixed  state or error message
 69:      * @return self
 70:      */
 71:     public function setRequired($value = TRUE)
 72:     {
 73:         if ($value) {
 74:             $this->addRule(Form::REQUIRED, is_string($value) ? $value : NULL);
 75:         } else {
 76:             $this->required = NULL;
 77:         }
 78:         return $this;
 79:     }
 80: 
 81: 
 82:     /**
 83:      * Is control mandatory?
 84:      * @return bool
 85:      */
 86:     public function isRequired()
 87:     {
 88:         return $this->required instanceof Rule ? !$this->required->isNegative : FALSE;
 89:     }
 90: 
 91: 
 92:     /**
 93:      * Adds a validation rule for the current control.
 94:      * @param  mixed      rule type
 95:      * @param  string     message to display for invalid data
 96:      * @param  mixed      optional rule arguments
 97:      * @return self
 98:      */
 99:     public function addRule($operation, $message = NULL, $arg = NULL)
100:     {
101:         $rule = new Rule;
102:         $rule->control = $this->control;
103:         $rule->operation = $operation;
104:         $this->adjustOperation($rule);
105:         $rule->arg = $arg;
106:         $rule->type = Rule::VALIDATOR;
107:         $rule->message = $message;
108:         if ($rule->operation === Form::REQUIRED) {
109:             $this->required = $rule;
110:         } else {
111:             $this->rules[] = $rule;
112:         }
113:         return $this;
114:     }
115: 
116: 
117:     /**
118:      * Adds a validation condition a returns new branch.
119:      * @param  mixed      condition type
120:      * @param  mixed      optional condition arguments
121:      * @return Rules      new branch
122:      */
123:     public function addCondition($operation, $arg = NULL)
124:     {
125:         return $this->addConditionOn($this->control, $operation, $arg);
126:     }
127: 
128: 
129:     /**
130:      * Adds a validation condition on specified control a returns new branch.
131:      * @param  IControl form control
132:      * @param  mixed      condition type
133:      * @param  mixed      optional condition arguments
134:      * @return Rules      new branch
135:      */
136:     public function addConditionOn(IControl $control, $operation, $arg = NULL)
137:     {
138:         $rule = new Rule;
139:         $rule->control = $control;
140:         $rule->operation = $operation;
141:         $this->adjustOperation($rule);
142:         $rule->arg = $arg;
143:         $rule->type = Rule::CONDITION;
144:         $rule->subRules = new static($this->control);
145:         $rule->subRules->parent = $this;
146: 
147:         $this->rules[] = $rule;
148:         return $rule->subRules;
149:     }
150: 
151: 
152:     /**
153:      * Adds a else statement.
154:      * @return Rules      else branch
155:      */
156:     public function elseCondition()
157:     {
158:         $rule = clone end($this->parent->rules);
159:         $rule->isNegative = !$rule->isNegative;
160:         $rule->subRules = new static($this->parent->control);
161:         $rule->subRules->parent = $this->parent;
162:         $this->parent->rules[] = $rule;
163:         return $rule->subRules;
164:     }
165: 
166: 
167:     /**
168:      * Ends current validation condition.
169:      * @return Rules      parent branch
170:      */
171:     public function endCondition()
172:     {
173:         return $this->parent;
174:     }
175: 
176: 
177:     /**
178:      * Toggles HTML elememnt visibility.
179:      * @param  string     element id
180:      * @param  bool       hide element?
181:      * @return self
182:      */
183:     public function toggle($id, $hide = TRUE)
184:     {
185:         $this->toggles[$id] = $hide;
186:         return $this;
187:     }
188: 
189: 
190:     /**
191:      * Validates against ruleset.
192:      * @return bool
193:      */
194:     public function validate()
195:     {
196:         foreach ($this as $rule) {
197:             $success = $this->validateRule($rule);
198: 
199:             if ($rule->type === Rule::CONDITION && $success && !$rule->subRules->validate()) {
200:                 return FALSE;
201: 
202:             } elseif ($rule->type === Rule::VALIDATOR && !$success) {
203:                 $rule->control->addError(static::formatMessage($rule, TRUE));
204:                 return FALSE;
205:             }
206:         }
207:         return TRUE;
208:     }
209: 
210: 
211:     /**
212:      * Validates single rule.
213:      * @return bool
214:      */
215:     public static function validateRule(Rule $rule)
216:     {
217:         $args = is_array($rule->arg) ? $rule->arg : array($rule->arg);
218:         foreach ($args as & $val) {
219:             $val = $val instanceof IControl ? $val->getValue() : $val;
220:         }
221:         return $rule->isNegative
222:             xor call_user_func(self::getCallback($rule), $rule->control, is_array($rule->arg) ? $args : $args[0]);
223:     }
224: 
225: 
226:     /**
227:      * Iterates over complete ruleset.
228:      * @return \ArrayIterator
229:      */
230:     public function getIterator()
231:     {
232:         $rules = $this->rules;
233:         if ($this->required) {
234:             array_unshift($rules, $this->required);
235:         }
236:         return new \ArrayIterator($rules);
237:     }
238: 
239: 
240:     /**
241:      * @param  bool
242:      * @return array
243:      */
244:     public function getToggles($actual = FALSE)
245:     {
246:         $toggles = $this->toggles;
247:         foreach ($actual ? $this : array() as $rule) {
248:             if ($rule->type === Rule::CONDITION) {
249:                 $success = static::validateRule($rule);
250:                 foreach ($rule->subRules->getToggles(TRUE) as $id => $hide) {
251:                     $toggles[$id] = empty($toggles[$id]) ? ($success && $hide) : TRUE;
252:                 }
253:             }
254:         }
255:         return $toggles;
256:     }
257: 
258: 
259:     /**
260:      * Process 'operation' string.
261:      * @param  Rule
262:      * @return void
263:      */
264:     private function adjustOperation($rule)
265:     {
266:         if (is_string($rule->operation) && ord($rule->operation[0]) > 127) {
267:             $rule->isNegative = TRUE;
268:             $rule->operation = ~$rule->operation;
269:         }
270: 
271:         if (!is_callable($this->getCallback($rule))) {
272:             $operation = is_scalar($rule->operation) ? " '$rule->operation'" : '';
273:             throw new Nette\InvalidArgumentException("Unknown operation$operation for control '{$rule->control->name}'.");
274:         }
275:     }
276: 
277: 
278:     private static function getCallback($rule)
279:     {
280:         $op = $rule->operation;
281:         if (is_string($op) && strncmp($op, ':', 1) === 0) {
282:             return get_class($rule->control) . '::' . self::VALIDATE_PREFIX . ltrim($op, ':');
283:         } else {
284:             return $op;
285:         }
286:     }
287: 
288: 
289:     public static function formatMessage($rule, $withValue)
290:     {
291:         $message = $rule->message;
292:         if ($message instanceof Nette\Utils\Html) {
293:             return $message;
294: 
295:         } elseif ($message === NULL && is_string($rule->operation) && isset(self::$defaultMessages[$rule->operation])) {
296:             $message = self::$defaultMessages[$rule->operation];
297: 
298:         } elseif ($message == NULL) { // intentionally ==
299:             trigger_error("Missing validation message for control '{$rule->control->name}'.", E_USER_WARNING);
300:         }
301: 
302:         if ($translator = $rule->control->getForm()->getTranslator()) {
303:             $message = $translator->translate($message, is_int($rule->arg) ? $rule->arg : NULL);
304:         }
305: 
306:         $message = preg_replace_callback('#%(name|label|value|\d+\$[ds]|[ds])#', function($m) use ($rule, $withValue) {
307:             static $i = -1;
308:             switch ($m[1]) {
309:                 case 'name': return $rule->control->getName();
310:                 case 'label': return $rule->control->translate($rule->control->caption);
311:                 case 'value': return $withValue ? $rule->control->getValue() : $m[0];
312:                 default:
313:                     $args = is_array($rule->arg) ? $rule->arg : array($rule->arg);
314:                     $i = (int) $m[1] ? $m[1] - 1 : $i + 1;
315:                     return isset($args[$i]) ? ($args[$i] instanceof IControl ? ($withValue ? $args[$i]->getValue() : "%$i") : $args[$i]) : '';
316:             }
317:         }, $message);
318:         return $message;
319:     }
320: 
321: 
322: }
323: 
API documentation generated by ApiGen 2.8.0