1: <?php
2:
3: 4: 5: 6: 7: 8: 9: 10: 11:
12:
13:
14:
15: 16: 17: 18: 19: 20:
21: final class Rules extends Object implements IteratorAggregate
22: {
23:
24: const VALIDATE_PREFIX = 'validate';
25:
26:
27: public static $defaultMessages = array(
28: Form::PROTECTION => 'Please submit this form again (security token has expired).',
29: Form::EQUAL => 'Please enter %s.',
30: Form::FILLED => 'Please complete mandatory field.',
31: Form::MIN_LENGTH => 'Please enter a value of at least %d characters.',
32: Form::MAX_LENGTH => 'Please enter a value no longer than %d characters.',
33: Form::LENGTH => 'Please enter a value between %d and %d characters long.',
34: Form::EMAIL => 'Please enter a valid email address.',
35: Form::URL => 'Please enter a valid URL.',
36: Form::INTEGER => 'Please enter a numeric value.',
37: Form::FLOAT => 'Please enter a numeric value.',
38: Form::RANGE => 'Please enter a value between %d and %d.',
39: Form::MAX_FILE_SIZE => 'The size of the uploaded file can be up to %d bytes.',
40: Form::IMAGE => 'The uploaded file must be image in format JPEG, GIF or PNG.',
41: );
42:
43:
44: private $rules = array();
45:
46:
47: private $parent;
48:
49:
50: private $toggles = array();
51:
52:
53: private $control;
54:
55:
56:
57: public function __construct(IFormControl $control)
58: {
59: $this->control = $control;
60: }
61:
62:
63:
64: 65: 66: 67: 68: 69: 70:
71: public function addRule($operation, $message = NULL, $arg = NULL)
72: {
73: $rule = new Rule;
74: $rule->control = $this->control;
75: $rule->operation = $operation;
76: $this->adjustOperation($rule);
77: $rule->arg = $arg;
78: $rule->type = Rule::VALIDATOR;
79: if ($message === NULL && is_string($rule->operation) && isset(self::$defaultMessages[$rule->operation])) {
80: $rule->message = self::$defaultMessages[$rule->operation];
81: } else {
82: $rule->message = $message;
83: }
84: $this->rules[] = $rule;
85: return $this;
86: }
87:
88:
89:
90: 91: 92: 93: 94: 95:
96: public function addCondition($operation, $arg = NULL)
97: {
98: return $this->addConditionOn($this->control, $operation, $arg);
99: }
100:
101:
102:
103: 104: 105: 106: 107: 108: 109:
110: public function addConditionOn(IFormControl $control, $operation, $arg = NULL)
111: {
112: $rule = new Rule;
113: $rule->control = $control;
114: $rule->operation = $operation;
115: $this->adjustOperation($rule);
116: $rule->arg = $arg;
117: $rule->type = Rule::CONDITION;
118: $rule->subRules = new self($this->control);
119: $rule->subRules->parent = $this;
120:
121: $this->rules[] = $rule;
122: return $rule->subRules;
123: }
124:
125:
126:
127: 128: 129: 130:
131: public function elseCondition()
132: {
133: $rule = clone end($this->parent->rules);
134: $rule->isNegative = !$rule->isNegative;
135: $rule->subRules = new self($this->parent->control);
136: $rule->subRules->parent = $this->parent;
137: $this->parent->rules[] = $rule;
138: return $rule->subRules;
139: }
140:
141:
142:
143: 144: 145: 146:
147: public function endCondition()
148: {
149: return $this->parent;
150: }
151:
152:
153:
154: 155: 156: 157: 158: 159:
160: public function toggle($id, $hide = TRUE)
161: {
162: $this->toggles[$id] = $hide;
163: return $this;
164: }
165:
166:
167:
168: 169: 170: 171: 172:
173: public function validate($onlyCheck = FALSE)
174: {
175: foreach ($this->rules as $rule) {
176: if ($rule->control->isDisabled()) {
177: continue;
178: }
179:
180: $success = ($rule->isNegative xor $this->getCallback($rule)->invoke($rule->control, $rule->arg));
181:
182: if ($rule->type === Rule::CONDITION && $success) {
183: if (!$rule->subRules->validate($onlyCheck)) {
184: return FALSE;
185: }
186:
187: } elseif ($rule->type === Rule::VALIDATOR && !$success) {
188: if (!$onlyCheck) {
189: $rule->control->addError(self::formatMessage($rule, TRUE));
190: }
191: return FALSE;
192: }
193: }
194: return TRUE;
195: }
196:
197:
198:
199: 200: 201: 202:
203: final public function getIterator()
204: {
205: return new ArrayIterator($this->rules);
206: }
207:
208:
209:
210: 211: 212:
213: final public function getToggles()
214: {
215: return $this->toggles;
216: }
217:
218:
219:
220: 221: 222: 223: 224:
225: private function adjustOperation($rule)
226: {
227: if (is_string($rule->operation) && ord($rule->operation[0]) > 127) {
228: $rule->isNegative = TRUE;
229: $rule->operation = ~$rule->operation;
230: }
231:
232: if (!$this->getCallback($rule)->isCallable()) {
233: $operation = is_scalar($rule->operation) ? " '$rule->operation'" : '';
234: throw new InvalidArgumentException("Unknown operation$operation for control '{$rule->control->name}'.");
235: }
236: }
237:
238:
239:
240: private function getCallback($rule)
241: {
242: $op = $rule->operation;
243: if (is_string($op) && strncmp($op, ':', 1) === 0) {
244: return new Callback(get_class($rule->control), self::VALIDATE_PREFIX . ltrim($op, ':'));
245: } else {
246: return new Callback($op);
247: }
248: }
249:
250:
251:
252: public static function formatMessage($rule, $withValue)
253: {
254: $message = $rule->message;
255: if ($message instanceof Html) {
256: return $message;
257: }
258: if (!isset($message)) {
259: $message = self::$defaultMessages[$rule->operation];
260: }
261: if ($translator = $rule->control->getForm()->getTranslator()) {
262: $message = $translator->translate($message, is_int($rule->arg) ? $rule->arg : NULL);
263: }
264: $message = vsprintf(preg_replace('#%(name|label|value)#', '%$0', $message), (array) $rule->arg);
265: $message = str_replace('%name', $rule->control->getName(), $message);
266: $message = str_replace('%label', $rule->control->translate($rule->control->caption), $message);
267: if ($withValue && strpos($message, '%value') !== FALSE) {
268: $message = str_replace('%value', $rule->control->getValue(), $message);
269: }
270: return $message;
271: }
272:
273: }
274: