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