Namespaces

  • Nette
    • Application
      • Diagnostics
      • Responses
      • Routers
      • UI
    • Caching
      • Storages
    • ComponentModel
    • Config
      • Adapters
      • Extensions
    • Database
      • Diagnostics
      • Drivers
      • Reflection
      • Table
    • DI
      • Diagnostics
    • Diagnostics
    • Forms
      • Controls
      • Rendering
    • Http
    • Iterators
    • Latte
      • Macros
    • Loaders
    • Localization
    • Mail
    • Reflection
    • Security
      • Diagnostics
    • Templating
    • Utils
      • PhpGenerator
  • NetteModule
  • None
  • PHP

Classes

  • Container
  • ControlGroup
  • Form
  • 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:  *
  6:  * Copyright (c) 2004 David Grudl (http://davidgrudl.com)
  7:  *
  8:  * For the full copyright and license information, please view
  9:  * the file license.txt that was distributed with this source code.
 10:  */
 11: 
 12: namespace Nette\Forms;
 13: 
 14: use Nette;
 15: 
 16: 
 17: 
 18: /**
 19:  * List of validation & condition rules.
 20:  *
 21:  * @author     David Grudl
 22:  */
 23: final class Rules extends Nette\Object implements \IteratorAggregate
 24: {
 25:     /** @internal */
 26:     const VALIDATE_PREFIX = 'validate';
 27: 
 28:     /** @var array */
 29:     public static $defaultMessages = array(
 30:         Form::PROTECTION => 'Security token did not match. Possible CSRF attack.',
 31:         Form::EQUAL => 'Please enter %s.',
 32:         Form::FILLED => 'Please complete mandatory field.',
 33:         Form::MIN_LENGTH => 'Please enter a value of at least %d characters.',
 34:         Form::MAX_LENGTH => 'Please enter a value no longer than %d characters.',
 35:         Form::LENGTH => 'Please enter a value between %d and %d characters long.',
 36:         Form::EMAIL => 'Please enter a valid email address.',
 37:         Form::URL => 'Please enter a valid URL.',
 38:         Form::INTEGER => 'Please enter a numeric value.',
 39:         Form::FLOAT => 'Please enter a numeric value.',
 40:         Form::RANGE => 'Please enter a value between %d and %d.',
 41:         Form::MAX_FILE_SIZE => 'The size of the uploaded file can be up to %d bytes.',
 42:         Form::IMAGE => 'The uploaded file must be image in format JPEG, GIF or PNG.',
 43:     );
 44: 
 45:     /** @var array of Rule */
 46:     private $rules = array();
 47: 
 48:     /** @var Rules */
 49:     private $parent;
 50: 
 51:     /** @var array */
 52:     private $toggles = array();
 53: 
 54:     /** @var IControl */
 55:     private $control;
 56: 
 57: 
 58: 
 59:     public function __construct(IControl $control)
 60:     {
 61:         $this->control = $control;
 62:     }
 63: 
 64: 
 65: 
 66:     /**
 67:      * Adds a validation rule for the current control.
 68:      * @param  mixed      rule type
 69:      * @param  string     message to display for invalid data
 70:      * @param  mixed      optional rule arguments
 71:      * @return Rules      provides a fluent interface
 72:      */
 73:     public function addRule($operation, $message = NULL, $arg = NULL)
 74:     {
 75:         $rule = new Rule;
 76:         $rule->control = $this->control;
 77:         $rule->operation = $operation;
 78:         $this->adjustOperation($rule);
 79:         $rule->arg = $arg;
 80:         $rule->type = Rule::VALIDATOR;
 81:         if ($message === NULL && is_string($rule->operation) && isset(static::$defaultMessages[$rule->operation])) {
 82:             $rule->message = static::$defaultMessages[$rule->operation];
 83:         } else {
 84:             $rule->message = $message;
 85:         }
 86:         $this->rules[] = $rule;
 87:         return $this;
 88:     }
 89: 
 90: 
 91: 
 92:     /**
 93:      * Adds a validation condition a returns new branch.
 94:      * @param  mixed      condition type
 95:      * @param  mixed      optional condition arguments
 96:      * @return Rules      new branch
 97:      */
 98:     public function addCondition($operation, $arg = NULL)
 99:     {
100:         return $this->addConditionOn($this->control, $operation, $arg);
101:     }
102: 
103: 
104: 
105:     /**
106:      * Adds a validation condition on specified control a returns new branch.
107:      * @param  IControl form control
108:      * @param  mixed      condition type
109:      * @param  mixed      optional condition arguments
110:      * @return Rules      new branch
111:      */
112:     public function addConditionOn(IControl $control, $operation, $arg = NULL)
113:     {
114:         $rule = new Rule;
115:         $rule->control = $control;
116:         $rule->operation = $operation;
117:         $this->adjustOperation($rule);
118:         $rule->arg = $arg;
119:         $rule->type = Rule::CONDITION;
120:         $rule->subRules = new static($this->control);
121:         $rule->subRules->parent = $this;
122: 
123:         $this->rules[] = $rule;
124:         return $rule->subRules;
125:     }
126: 
127: 
128: 
129:     /**
130:      * Adds a else statement.
131:      * @return Rules      else branch
132:      */
133:     public function elseCondition()
134:     {
135:         $rule = clone end($this->parent->rules);
136:         $rule->isNegative = !$rule->isNegative;
137:         $rule->subRules = new static($this->parent->control);
138:         $rule->subRules->parent = $this->parent;
139:         $this->parent->rules[] = $rule;
140:         return $rule->subRules;
141:     }
142: 
143: 
144: 
145:     /**
146:      * Ends current validation condition.
147:      * @return Rules      parent branch
148:      */
149:     public function endCondition()
150:     {
151:         return $this->parent;
152:     }
153: 
154: 
155: 
156:     /**
157:      * Toggles HTML elememnt visibility.
158:      * @param  string     element id
159:      * @param  bool       hide element?
160:      * @return Rules      provides a fluent interface
161:      */
162:     public function toggle($id, $hide = TRUE)
163:     {
164:         $this->toggles[$id] = $hide;
165:         return $this;
166:     }
167: 
168: 
169: 
170:     /**
171:      * Validates against ruleset.
172:      * @param  bool    stop before first error?
173:      * @return bool    is valid?
174:      */
175:     public function validate($onlyCheck = FALSE)
176:     {
177:         foreach ($this->rules as $rule) {
178:             if ($rule->control->isDisabled()) {
179:                 continue;
180:             }
181: 
182:             $success = ($rule->isNegative xor $this->getCallback($rule)->invoke($rule->control, $rule->arg));
183: 
184:             if ($rule->type === Rule::CONDITION && $success) {
185:                 if (!$rule->subRules->validate($onlyCheck)) {
186:                     return FALSE;
187:                 }
188: 
189:             } elseif ($rule->type === Rule::VALIDATOR && !$success) {
190:                 if (!$onlyCheck) {
191:                     $rule->control->addError(static::formatMessage($rule, TRUE));
192:                 }
193:                 return FALSE;
194:             }
195:         }
196:         return TRUE;
197:     }
198: 
199: 
200: 
201:     /**
202:      * Iterates over ruleset.
203:      * @return \ArrayIterator
204:      */
205:     final public function getIterator()
206:     {
207:         return new \ArrayIterator($this->rules);
208:     }
209: 
210: 
211: 
212:     /**
213:      * @return array
214:      */
215:     final public function getToggles()
216:     {
217:         return $this->toggles;
218:     }
219: 
220: 
221: 
222:     /**
223:      * Process 'operation' string.
224:      * @param  Rule
225:      * @return void
226:      */
227:     private function adjustOperation($rule)
228:     {
229:         if (is_string($rule->operation) && ord($rule->operation[0]) > 127) {
230:             $rule->isNegative = TRUE;
231:             $rule->operation = ~$rule->operation;
232:         }
233: 
234:         if (!$this->getCallback($rule)->isCallable()) {
235:             $operation = is_scalar($rule->operation) ? " '$rule->operation'" : '';
236:             throw new Nette\InvalidArgumentException("Unknown operation$operation for control '{$rule->control->name}'.");
237:         }
238:     }
239: 
240: 
241: 
242:     private function getCallback($rule)
243:     {
244:         $op = $rule->operation;
245:         if (is_string($op) && strncmp($op, ':', 1) === 0) {
246:             return callback(get_class($rule->control), self::VALIDATE_PREFIX . ltrim($op, ':'));
247:         } else {
248:             return callback($op);
249:         }
250:     }
251: 
252: 
253: 
254:     public static function formatMessage($rule, $withValue)
255:     {
256:         $message = $rule->message;
257:         if ($message instanceof Nette\Utils\Html) {
258:             return $message;
259:         }
260:         if (!isset($message)) { // report missing message by notice
261:             $message = static::$defaultMessages[$rule->operation];
262:         }
263:         if ($translator = $rule->control->getForm()->getTranslator()) {
264:             $message = $translator->translate($message, is_int($rule->arg) ? $rule->arg : NULL);
265:         }
266:         $message = vsprintf(preg_replace('#%(name|label|value)#', '%$0', $message), (array) $rule->arg);
267:         $message = str_replace('%name', $rule->control->getName(), $message);
268:         $message = str_replace('%label', $rule->control->translate($rule->control->caption), $message);
269:         if ($withValue && strpos($message, '%value') !== FALSE) {
270:             $message = str_replace('%value', $rule->control->getValue(), $message);
271:         }
272:         return $message;
273:     }
274: 
275: }
276: 
Nette Framework 2.0.0 API API documentation generated by ApiGen 2.7.0