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