1: <?php
2:
3: 4: 5: 6:
7:
8: namespace Nette\Forms;
9:
10: use Nette;
11:
12:
13: 14: 15: 16: 17:
18: class Rules extends Nette\Object implements \IteratorAggregate
19: {
20:
21: const VALIDATE_PREFIX = 'validate';
22:
23:
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::FILLED => 'Please complete mandatory field.',
28: Form::MIN_LENGTH => 'Please enter a value of at least %d characters.',
29: Form::MAX_LENGTH => 'Please enter a value no longer than %d characters.',
30: Form::LENGTH => 'Please enter a value between %d and %d characters long.',
31: Form::EMAIL => 'Please enter a valid email address.',
32: Form::URL => 'Please enter a valid URL.',
33: Form::INTEGER => 'Please enter a numeric value.',
34: Form::FLOAT => 'Please enter a numeric value.',
35: Form::RANGE => 'Please enter a value between %d and %d.',
36: Form::MAX_FILE_SIZE => 'The size of the uploaded file can be up to %d bytes.',
37: Form::IMAGE => 'The uploaded file must be image in format JPEG, GIF or PNG.',
38: Form::MIME_TYPE => 'The uploaded file is not in the expected format.',
39: );
40:
41:
42: private $rules = array();
43:
44:
45: private $parent;
46:
47:
48: private $toggles = array();
49:
50:
51: private $control;
52:
53:
54: public function __construct(IControl $control)
55: {
56: $this->control = $control;
57: }
58:
59:
60: 61: 62: 63: 64: 65: 66:
67: public function addRule($operation, $message = NULL, $arg = NULL)
68: {
69: $rule = new Rule;
70: $rule->control = $this->control;
71: $rule->operation = $operation;
72: $this->adjustOperation($rule);
73: $rule->arg = $arg;
74: $rule->type = Rule::VALIDATOR;
75: if ($message === NULL && is_string($rule->operation) && isset(static::$defaultMessages[$rule->operation])) {
76: $rule->message = static::$defaultMessages[$rule->operation];
77: } else {
78: $rule->message = $message;
79: }
80: $this->rules[] = $rule;
81: return $this;
82: }
83:
84:
85: 86: 87: 88: 89: 90:
91: public function addCondition($operation, $arg = NULL)
92: {
93: return $this->addConditionOn($this->control, $operation, $arg);
94: }
95:
96:
97: 98: 99: 100: 101: 102: 103:
104: public function addConditionOn(IControl $control, $operation, $arg = NULL)
105: {
106: $rule = new Rule;
107: $rule->control = $control;
108: $rule->operation = $operation;
109: $this->adjustOperation($rule);
110: $rule->arg = $arg;
111: $rule->type = Rule::CONDITION;
112: $rule->subRules = new static($this->control);
113: $rule->subRules->parent = $this;
114:
115: $this->rules[] = $rule;
116: return $rule->subRules;
117: }
118:
119:
120: 121: 122: 123:
124: public function elseCondition()
125: {
126: $rule = clone end($this->parent->rules);
127: $rule->isNegative = !$rule->isNegative;
128: $rule->subRules = new static($this->parent->control);
129: $rule->subRules->parent = $this->parent;
130: $this->parent->rules[] = $rule;
131: return $rule->subRules;
132: }
133:
134:
135: 136: 137: 138:
139: public function endCondition()
140: {
141: return $this->parent;
142: }
143:
144:
145: 146: 147: 148: 149: 150:
151: public function toggle($id, $hide = TRUE)
152: {
153: $this->toggles[$id] = $hide;
154: return $this;
155: }
156:
157:
158: 159: 160: 161: 162:
163: public function validate($onlyCheck = FALSE)
164: {
165: foreach ($this->rules as $rule) {
166: if ($rule->control->isDisabled()) {
167: continue;
168: }
169:
170: $success = ($rule->isNegative xor $this->getCallback($rule)->invoke($rule->control, $rule->arg));
171:
172: if ($rule->type === Rule::CONDITION && $success) {
173: if (!$rule->subRules->validate($onlyCheck)) {
174: return FALSE;
175: }
176:
177: } elseif ($rule->type === Rule::VALIDATOR && !$success) {
178: if (!$onlyCheck) {
179: $rule->control->addError(static::formatMessage($rule, TRUE));
180: }
181: return FALSE;
182: }
183: }
184: return TRUE;
185: }
186:
187:
188: 189: 190: 191:
192: public function getIterator()
193: {
194: return new \ArrayIterator($this->rules);
195: }
196:
197:
198: 199: 200:
201: public function getToggles()
202: {
203: return $this->toggles;
204: }
205:
206:
207: 208: 209: 210: 211:
212: private function adjustOperation($rule)
213: {
214: if (is_string($rule->operation) && ord($rule->operation[0]) > 127) {
215: $rule->isNegative = TRUE;
216: $rule->operation = ~$rule->operation;
217: }
218:
219: if (!$this->getCallback($rule)->isCallable()) {
220: $operation = is_scalar($rule->operation) ? " '$rule->operation'" : '';
221: throw new Nette\InvalidArgumentException("Unknown operation$operation for control '{$rule->control->getName()}'.");
222: }
223: }
224:
225:
226: private function getCallback($rule)
227: {
228: $op = $rule->operation;
229: if (is_string($op) && strncmp($op, ':', 1) === 0) {
230: return new Nette\Callback(get_class($rule->control), self::VALIDATE_PREFIX . ltrim($op, ':'));
231: } else {
232: return new Nette\Callback($op);
233: }
234: }
235:
236:
237: public static function formatMessage($rule, $withValue)
238: {
239: $message = $rule->message;
240: if ($message instanceof Nette\Utils\Html) {
241: return $message;
242: }
243: if ($message == NULL) {
244: trigger_error("Missing validation message for control '{$rule->control->getName()}'.", E_USER_WARNING);
245: }
246: if ($translator = $rule->control->getForm()->getTranslator()) {
247: $message = $translator->translate($message, is_int($rule->arg) ? $rule->arg : NULL);
248: }
249: $message = vsprintf(preg_replace('#%(name|label|value)#', '%$0', $message), (array) $rule->arg);
250: $message = str_replace('%name', $rule->control->getName(), $message);
251: $message = str_replace('%label', $rule->control->translate($rule->control->caption), $message);
252: if ($withValue && strpos($message, '%value') !== FALSE) {
253: $message = str_replace('%value', $rule->control->getValue(), $message);
254: }
255: return $message;
256: }
257:
258: }
259: