1: <?php
2:
3: 4: 5: 6:
7:
8: namespace Nette\Forms;
9:
10: use Nette;
11:
12:
13: 14: 15:
16: class Rules implements \IteratorAggregate
17: {
18: use Nette\SmartObject;
19:
20:
21: public static $defaultMessages;
22:
23:
24: private $required;
25:
26:
27: private $rules = [];
28:
29:
30: private $parent;
31:
32:
33: private $toggles = [];
34:
35:
36: private $control;
37:
38:
39: public function __construct(IControl $control)
40: {
41: $this->control = $control;
42: }
43:
44:
45: 46: 47: 48: 49:
50: public function setRequired($value = TRUE)
51: {
52: if ($value) {
53: $this->addRule(Form::REQUIRED, $value === TRUE ? NULL : $value);
54: } else {
55: $this->required = FALSE;
56: }
57: return $this;
58: }
59:
60:
61: 62: 63: 64:
65: public function isRequired()
66: {
67: return (bool) $this->required;
68: }
69:
70:
71: 72: 73:
74: public function isOptional()
75: {
76: return $this->required === FALSE;
77: }
78:
79:
80: 81: 82: 83: 84: 85: 86:
87: public function addRule($validator, $message = NULL, $arg = NULL)
88: {
89: if ($validator === Form::VALID || $validator === ~Form::VALID) {
90: throw new Nette\InvalidArgumentException('You cannot use Form::VALID in the addRule method.');
91: }
92: $rule = new Rule;
93: $rule->control = $this->control;
94: $rule->validator = $validator;
95: $this->adjustOperation($rule);
96: $rule->arg = $arg;
97: $rule->message = $message;
98: if ($rule->validator === Form::REQUIRED) {
99: $this->required = $rule;
100: } else {
101: $this->rules[] = $rule;
102: }
103: return $this;
104: }
105:
106:
107: 108: 109: 110: 111: 112:
113: public function addCondition($validator, $arg = NULL)
114: {
115: if ($validator === Form::VALID || $validator === ~Form::VALID) {
116: throw new Nette\InvalidArgumentException('You cannot use Form::VALID in the addCondition method.');
117: }
118: return $this->addConditionOn($this->control, $validator, $arg);
119: }
120:
121:
122: 123: 124: 125: 126: 127: 128:
129: public function addConditionOn(IControl $control, $validator, $arg = NULL)
130: {
131: $rule = new Rule;
132: $rule->control = $control;
133: $rule->validator = $validator;
134: $rule->arg = $arg;
135: $rule->branch = new static($this->control);
136: $rule->branch->parent = $this;
137: $this->adjustOperation($rule);
138:
139: $this->rules[] = $rule;
140: return $rule->branch;
141: }
142:
143:
144: 145: 146: 147:
148: public function elseCondition()
149: {
150: $rule = clone end($this->parent->rules);
151: $rule->isNegative = !$rule->isNegative;
152: $rule->branch = new static($this->parent->control);
153: $rule->branch->parent = $this->parent;
154: $this->parent->rules[] = $rule;
155: return $rule->branch;
156: }
157:
158:
159: 160: 161: 162:
163: public function endCondition()
164: {
165: return $this->parent;
166: }
167:
168:
169: 170: 171: 172: 173:
174: public function addFilter($filter)
175: {
176: Nette\Utils\Callback::check($filter);
177: $this->rules[] = $rule = new Rule;
178: $rule->control = $this->control;
179: $rule->validator = function (IControl $control) use ($filter) {
180: $control->setValue(call_user_func($filter, $control->getValue()));
181: return TRUE;
182: };
183: return $this;
184: }
185:
186:
187: 188: 189: 190: 191: 192:
193: public function toggle($id, $hide = TRUE)
194: {
195: $this->toggles[$id] = $hide;
196: return $this;
197: }
198:
199:
200: 201: 202: 203:
204: public function getToggles($actual = FALSE)
205: {
206: return $actual ? $this->getToggleStates() : $this->toggles;
207: }
208:
209:
210: 211: 212: 213:
214: public function getToggleStates($toggles = [], $success = TRUE)
215: {
216: foreach ($this->toggles as $id => $hide) {
217: $toggles[$id] = ($success xor !$hide) || !empty($toggles[$id]);
218: }
219:
220: foreach ($this->rules as $rule) {
221: if ($rule->branch) {
222: $toggles = $rule->branch->getToggleStates($toggles, $success && static::validateRule($rule));
223: }
224: }
225: return $toggles;
226: }
227:
228:
229: 230: 231: 232:
233: public function validate($emptyOptional = FALSE)
234: {
235: $emptyOptional = $emptyOptional || $this->isOptional() && !$this->control->isFilled();
236: foreach ($this as $rule) {
237: if (!$rule->branch && $emptyOptional && $rule->validator !== Form::FILLED) {
238: continue;
239: }
240:
241: $success = $this->validateRule($rule);
242: if ($success && $rule->branch && !$rule->branch->validate($rule->validator === Form::BLANK ? FALSE : $emptyOptional)) {
243: return FALSE;
244:
245: } elseif (!$success && !$rule->branch) {
246: $rule->control->addError(Validator::formatMessage($rule, TRUE));
247: return FALSE;
248: }
249: }
250: return TRUE;
251: }
252:
253:
254: 255: 256:
257: public function check()
258: {
259: if ($this->required !== NULL) {
260: return;
261: }
262: foreach ($this->rules as $rule) {
263: if ($rule->control === $this->control && ($rule->validator === Form::FILLED || $rule->validator === Form::BLANK)) {
264:
265: } elseif ($rule->branch) {
266: if ($rule->branch->check() === TRUE) {
267: return TRUE;
268: }
269: } else {
270: trigger_error("Missing setRequired(TRUE | FALSE) on field '{$rule->control->getName()}' in form '{$rule->control->getForm()->getName()}'.", E_USER_WARNING);
271: return TRUE;
272: }
273: }
274: }
275:
276:
277: 278: 279: 280:
281: public static function validateRule(Rule $rule)
282: {
283: $args = is_array($rule->arg) ? $rule->arg : [$rule->arg];
284: foreach ($args as & $val) {
285: $val = $val instanceof IControl ? $val->getValue() : $val;
286: }
287: return $rule->isNegative
288: xor call_user_func(self::getCallback($rule), $rule->control, is_array($rule->arg) ? $args : $args[0]);
289: }
290:
291:
292: 293: 294: 295:
296: public function getIterator()
297: {
298: $rules = $this->rules;
299: if ($this->required) {
300: array_unshift($rules, $this->required);
301: }
302: return new \ArrayIterator($rules);
303: }
304:
305:
306: 307: 308: 309: 310:
311: private function adjustOperation($rule)
312: {
313: if (is_string($rule->validator) && ord($rule->validator[0]) > 127) {
314: $rule->isNegative = TRUE;
315: $rule->validator = ~$rule->validator;
316: if (!$rule->branch) {
317: $name = strncmp($rule->validator, ':', 1) ? $rule->validator : 'Form:' . strtoupper($rule->validator);
318: trigger_error("Negative validation rules such as ~$name are deprecated.", E_USER_DEPRECATED);
319: }
320: if ($rule->validator === Form::FILLED) {
321: $rule->validator = Form::BLANK;
322: $rule->isNegative = FALSE;
323: trigger_error('Replace negative validation rule ~Form::FILLED with Form::BLANK.', E_USER_DEPRECATED);
324: }
325: }
326:
327: if (!is_callable($this->getCallback($rule))) {
328: $validator = is_scalar($rule->validator) ? " '$rule->validator'" : '';
329: throw new Nette\InvalidArgumentException("Unknown validator$validator for control '{$rule->control->name}'.");
330: }
331: }
332:
333:
334: private static function getCallback($rule)
335: {
336: $op = $rule->validator;
337: if (is_string($op) && strncmp($op, ':', 1) === 0) {
338: return 'Nette\Forms\Validator::validate' . ltrim($op, ':');
339: } else {
340: return $op;
341: }
342: }
343:
344: }
345:
346: Rules::$defaultMessages = & Validator::$messages;
347: