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