1: <?php
2:
3: /**
4: * Jyxo PHP Library
5: *
6: * LICENSE
7: *
8: * This source file is subject to the new BSD license that is bundled
9: * with this package in the file license.txt.
10: * It is also available through the world-wide-web at this URL:
11: * https://github.com/jyxo/php/blob/master/license.txt
12: */
13:
14: /**
15: * Chain of filters a validators for a single variable.
16: *
17: * @category Jyxo
18: * @package Jyxo_Input
19: * @subpackage Chain
20: * @copyright Copyright (c) 2005-2011 Jyxo, s.r.o.
21: * @license https://github.com/jyxo/php/blob/master/license.txt
22: * @author Jakub Tománek
23: */
24: class Jyxo_Input_Chain implements Jyxo_Input_ValidatorInterface
25: {
26: /**
27: * Filter identifier.
28: *
29: * @var string
30: */
31: const FILTER = 'filter';
32:
33: /**
34: * Validator identifier.
35: *
36: * @var string
37: */
38: const VALIDATOR = 'validator';
39:
40: /**
41: * Array walk identifier.
42: *
43: * @var string
44: */
45: const WALK = 'walk';
46:
47: /**
48: * Condition identifier.
49: *
50: * @var string
51: */
52: const CONDITION = 'condition';
53:
54: /**
55: * Subchain closing identifier.
56: *
57: * @var string
58: */
59: const CLOSE = 'close';
60:
61: /**
62: * Chain.
63: *
64: * @var array
65: */
66: private $chain = array();
67:
68: /**
69: * Parent chain reference.
70: *
71: * @var Jyxo_Input_Chain
72: */
73: private $parent = null;
74:
75: /**
76: * Actual variable value.
77: *
78: * @var mixed
79: */
80: protected $value;
81:
82: /**
83: * Validation errors.
84: *
85: * @var array
86: */
87: private $errors = array();
88:
89: /**
90: * Adds a validator to the chain.
91: *
92: * @param Jyxo_Input_ValidatorInterface $validator Validator
93: * @param string $errorMessage Validation error message
94: * @return Jyxo_Input_Chain
95: */
96: public function addValidator(Jyxo_Input_ValidatorInterface $validator, $errorMessage = null)
97: {
98: $this->chain[] = array(self::VALIDATOR, $validator, $errorMessage);
99: return $this;
100: }
101:
102: /**
103: * Adds a filter to the chain.
104: *
105: * @param Jyxo_Input_FilterInterface $filter Filter
106: * @return Jyxo_Input_Chain
107: */
108: public function addFilter(Jyxo_Input_FilterInterface $filter)
109: {
110: $this->chain[] = array(self::FILTER, $filter);
111: return $this;
112: }
113:
114: /**
115: * Adds a new subchain and returns its instance.
116: *
117: * @return Jyxo_Input_Chain
118: */
119: public function addWalk()
120: {
121: $chain = new self();
122: $chain->setParent($this);
123: $this->chain[] = array(self::WALK, $chain);
124: return $chain;
125: }
126:
127: /**
128: * Adds a new conditional subchain and returns its instance.
129: *
130: * @param Jyxo_Input_Chain_Conditional $chain
131: * @return Jyxo_Input_Chain_Conditional
132: */
133: public function addCondition(Jyxo_Input_Chain_Conditional $chain)
134: {
135: $chain->setParent($this);
136: $this->chain[] = array(self::CONDITION, $chain);
137: return $chain;
138: }
139:
140: /**
141: * In case of a subchain returns its parent, the chain itself otherwise.
142: *
143: * @return Jyxo_Input_Chain
144: */
145: public function close()
146: {
147: if (null === $this->getParent()) {
148: return $this;
149: }
150: return $this->getParent();
151: }
152:
153: /**
154: * Starts filtering and validation.
155: *
156: * @param mixed $value Input value
157: * @return boolean
158: */
159: private function run(&$value)
160: {
161: foreach ($this->chain as $item) {
162: if (self::FILTER === $item[0]) {
163: $filter = $item[1];
164: /* @var $filter Jyxo_Input_FilterInterface */
165: $value = $filter->filter($value);
166: } elseif (self::VALIDATOR === $item[0]) {
167: $validator = $item[1];
168: /* @var $validator Jyxo_Input_ValidatorInterface */
169: if (!$validator->isValid($value)) {
170: if ($validator instanceof Jyxo_Input_Validator_ErrorMessage) {
171: $this->errors[] = $validator->getError();
172: } elseif (isset($item[2])) {
173: $this->errors[] = $item[2];
174: }
175: return false;
176: }
177: } elseif (self::CONDITION === $item[0]) {
178: $chain = $item[1];
179: /* @var $chain Jyxo_Input_Chain_Conditional */
180: if ($chain->isValid($value)) {
181: $value = $chain->getValue();
182: } else {
183: $this->errors = array_merge($this->errors, $chain->getErrors());
184: return false;
185: }
186: } elseif (self::WALK === $item[0]) {
187: $chain = $item[1];
188: /* @var $chain Jyxo_Input_Chain */
189: foreach ($value as &$sub) {
190: if ($chain->isValid($sub)) {
191: $sub = $chain->getValue($sub);
192: } else {
193: $this->errors = array_merge($this->errors, $chain->getErrors());
194: return false;
195: }
196: }
197: }
198: }
199:
200: return true;
201: }
202:
203: /**
204: * Returns if the chain contains any rules.
205: *
206: * @return boolean
207: */
208: public function isEmpty()
209: {
210: return empty($this->chain);
211: }
212:
213: /**
214: * Returns if the value is valid.
215: *
216: * @param mixed $value Input value
217: * @return boolean
218: */
219: public function isValid($value)
220: {
221: $success = $this->run($value);
222: // $value passed by reference
223: $this->value = $value;
224: return $success;
225: }
226:
227: /**
228: * Returns a filtered variable value.
229: *
230: * @return mixed
231: */
232: public function &getValue()
233: {
234: return $this->value;
235: }
236:
237: /**
238: * Returns a list of validation errors.
239: *
240: * @return array
241: */
242: public function getErrors()
243: {
244: return $this->errors;
245: }
246:
247: /**
248: * Returns the parent chain.
249: *
250: * @return Jyxo_Input_Chain
251: */
252: public function getParent()
253: {
254: return $this->parent;
255: }
256:
257: /**
258: * Sets the parent chain.
259: *
260: * @param Jyxo_Input_Chain $parent Parent chain
261: * @return Jyxo_Input_Chain
262: */
263: public function setParent(Jyxo_Input_Chain $parent)
264: {
265: $this->parent = $parent;
266: return $this;
267: }
268: }
269: