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