Namespaces

  • 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
  • none

Classes

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

Interfaces

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