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