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, $errorMessage = 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 = $errorMessage;
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: } elseif (is_bool($validator)) {
118: $arg = $validator;
119: $validator = ':static';
120: }
121: return $this->addConditionOn($this->control, $validator, $arg);
122: }
123:
124:
125: 126: 127: 128: 129: 130: 131:
132: public function addConditionOn(IControl $control, $validator, $arg = null)
133: {
134: $rule = new Rule;
135: $rule->control = $control;
136: $rule->validator = $validator;
137: $rule->arg = $arg;
138: $rule->branch = new static($this->control);
139: $rule->branch->parent = $this;
140: $this->adjustOperation($rule);
141:
142: $this->rules[] = $rule;
143: return $rule->branch;
144: }
145:
146:
147: 148: 149: 150:
151: public function elseCondition()
152: {
153: $rule = clone end($this->parent->rules);
154: $rule->isNegative = !$rule->isNegative;
155: $rule->branch = new static($this->parent->control);
156: $rule->branch->parent = $this->parent;
157: $this->parent->rules[] = $rule;
158: return $rule->branch;
159: }
160:
161:
162: 163: 164: 165:
166: public function endCondition()
167: {
168: return $this->parent;
169: }
170:
171:
172: 173: 174: 175: 176:
177: public function addFilter($filter)
178: {
179: Nette\Utils\Callback::check($filter);
180: $this->rules[] = $rule = new Rule;
181: $rule->control = $this->control;
182: $rule->validator = function (IControl $control) use ($filter) {
183: $control->setValue(call_user_func($filter, $control->getValue()));
184: return true;
185: };
186: return $this;
187: }
188:
189:
190: 191: 192: 193: 194: 195:
196: public function toggle($id, $hide = true)
197: {
198: $this->toggles[$id] = $hide;
199: return $this;
200: }
201:
202:
203: 204: 205: 206:
207: public function getToggles($actual = false)
208: {
209: return $actual ? $this->getToggleStates() : $this->toggles;
210: }
211:
212:
213: 214: 215: 216:
217: public function getToggleStates($toggles = [], $success = true)
218: {
219: foreach ($this->toggles as $id => $hide) {
220: $toggles[$id] = ($success xor !$hide) || !empty($toggles[$id]);
221: }
222:
223: foreach ($this->rules as $rule) {
224: if ($rule->branch) {
225: $toggles = $rule->branch->getToggleStates($toggles, $success && static::validateRule($rule));
226: }
227: }
228: return $toggles;
229: }
230:
231:
232: 233: 234: 235:
236: public function validate($emptyOptional = false)
237: {
238: $emptyOptional = $emptyOptional || $this->isOptional() && !$this->control->isFilled();
239: foreach ($this as $rule) {
240: if (!$rule->branch && $emptyOptional && $rule->validator !== Form::FILLED) {
241: continue;
242: }
243:
244: $success = $this->validateRule($rule);
245: if ($success && $rule->branch && !$rule->branch->validate($rule->validator === Form::BLANK ? false : $emptyOptional)) {
246: return false;
247:
248: } elseif (!$success && !$rule->branch) {
249: $rule->control->addError(Validator::formatMessage($rule, true), false);
250: return false;
251: }
252: }
253: return true;
254: }
255:
256:
257: 258: 259:
260: public function check()
261: {
262: if ($this->required !== null) {
263: return;
264: }
265: foreach ($this->rules as $rule) {
266: if ($rule->control === $this->control && ($rule->validator === Form::FILLED || $rule->validator === Form::BLANK)) {
267:
268: } elseif ($rule->branch) {
269: if ($rule->branch->check() === true) {
270: return true;
271: }
272: } else {
273: trigger_error("Missing setRequired(true | false) on field '{$rule->control->getName()}' in form '{$rule->control->getForm()->getName()}'.", E_USER_WARNING);
274: return true;
275: }
276: }
277: }
278:
279:
280: 281: 282:
283: public function reset()
284: {
285: $this->rules = [];
286: }
287:
288:
289: 290: 291: 292:
293: public static function validateRule(Rule $rule)
294: {
295: $args = is_array($rule->arg) ? $rule->arg : [$rule->arg];
296: foreach ($args as &$val) {
297: $val = $val instanceof IControl ? $val->getValue() : $val;
298: }
299: return $rule->isNegative
300: xor call_user_func(self::getCallback($rule), $rule->control, is_array($rule->arg) ? $args : $args[0]);
301: }
302:
303:
304: 305: 306: 307:
308: public function getIterator()
309: {
310: $rules = $this->rules;
311: if ($this->required) {
312: array_unshift($rules, $this->required);
313: }
314: return new \ArrayIterator($rules);
315: }
316:
317:
318: 319: 320: 321:
322: private function adjustOperation(Rule $rule)
323: {
324: if (is_string($rule->validator) && ord($rule->validator[0]) > 127) {
325: $rule->isNegative = true;
326: $rule->validator = ~$rule->validator;
327: if (!$rule->branch) {
328: $name = strncmp($rule->validator, ':', 1) ? $rule->validator : 'Form:' . strtoupper($rule->validator);
329: trigger_error("Negative validation rules such as ~$name are deprecated.", E_USER_DEPRECATED);
330: }
331: if ($rule->validator === Form::FILLED) {
332: $rule->validator = Form::BLANK;
333: $rule->isNegative = false;
334: trigger_error('Replace negative validation rule ~Form::FILLED with Form::BLANK.', E_USER_DEPRECATED);
335: }
336: }
337:
338: if (!is_callable($this->getCallback($rule))) {
339: $validator = is_scalar($rule->validator) ? " '$rule->validator'" : '';
340: throw new Nette\InvalidArgumentException("Unknown validator$validator for control '{$rule->control->name}'.");
341: }
342: }
343:
344:
345: private static function getCallback(Rule $rule)
346: {
347: $op = $rule->validator;
348: if (is_string($op) && strncmp($op, ':', 1) === 0) {
349: return 'Nette\Forms\Validator::validate' . ltrim($op, ':');
350: } else {
351: return $op;
352: }
353: }
354: }
355:
356: Rules::$defaultMessages = &Validator::$messages;
357: