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