1 <?php
  2 
  3 /**
  4  * Validator class.
  5  *
  6  * @author gharlan
  7  *
  8  * @package redaxo\core
  9  */
 10 class rex_validator
 11 {
 12     use rex_factory_trait;
 13 
 14     private $types = [];
 15     private $message;
 16 
 17     /**
 18      * Constructor.
 19      */
 20     protected function __construct()
 21     {
 22         // noop
 23     }
 24 
 25     /**
 26      * Factory method.
 27      *
 28      * @return static
 29      */
 30     public static function factory()
 31     {
 32         $class = static::getFactoryClass();
 33         return new $class();
 34     }
 35 
 36     /**
 37      * Adds a validator.
 38      *
 39      * @param string      $type    Validator type (any static method name of this class)
 40      * @param null|string $message Message which is used if this validator type does not match
 41      * @param mixed       $option  Type specific option
 42      *
 43      * @return $this
 44      *
 45      * @throws InvalidArgumentException
 46      */
 47     public function add($type, $message = null, $option = null)
 48     {
 49         if (!method_exists($this, $type)) {
 50             throw new InvalidArgumentException('Unknown validator type: ' . $type);
 51         }
 52         $this->types[] = [$type, $message, $option];
 53 
 54         return $this;
 55     }
 56 
 57     /**
 58      * Checks whether the given value matches all added validators.
 59      *
 60      * @param string $value
 61      *
 62      * @return bool
 63      */
 64     public function isValid($value)
 65     {
 66         $this->message = null;
 67         foreach ($this->types as $type) {
 68             list($type, $message, $option) = $type;
 69 
 70             if ($value === '') {
 71                 if (strtolower($type) !== 'notempty') {
 72                     continue;
 73                 }
 74             }
 75 
 76             if (!$this->$type($value, $option)) {
 77                 $this->message = $message;
 78                 return false;
 79             }
 80         }
 81         return true;
 82     }
 83 
 84     /**
 85      * Returns the message.
 86      *
 87      * @return string[]
 88      */
 89     public function getMessage()
 90     {
 91         return $this->message;
 92     }
 93 
 94     /**
 95      * Checks whether the value is not empty.
 96      *
 97      * @param string $value
 98      *
 99      * @return bool
100      */
101     public function notEmpty($value)
102     {
103         return 0 !== strlen($value);
104     }
105 
106     /**
107      * Checks whether the value is from the given type.
108      *
109      * @param string $value
110      * @param string $type
111      *
112      * @throws InvalidArgumentException
113      *
114      * @return bool
115      */
116     public function type($value, $type)
117     {
118         switch ($type) {
119             case 'int':
120             case 'integer':
121                 return $this->match($value, '/^\d+$/');
122 
123             case 'float':
124             case 'real':
125                 return is_numeric($value);
126 
127             default:
128                 throw new InvalidArgumentException('Unknown $type:' . $type);
129         }
130     }
131 
132     /**
133      * Checks whether the value has the given min length.
134      *
135      * @param string $value
136      * @param int    $minLength
137      *
138      * @return bool
139      */
140     public function minLength($value, $minLength)
141     {
142         return mb_strlen($value) >= $minLength;
143     }
144 
145     /**
146      * Checks whether the value has the given max value.
147      *
148      * @param string $value
149      * @param int    $maxLength
150      *
151      * @return bool
152      */
153     public function maxLength($value, $maxLength)
154     {
155         return mb_strlen($value) <= $maxLength;
156     }
157 
158     /**
159      * Checks whether the value is equal or greater than the given min value.
160      *
161      * @param string $value
162      * @param int    $min
163      *
164      * @return bool
165      */
166     public function min($value, $min)
167     {
168         return $value >= $min;
169     }
170 
171     /**
172      * Checks whether the value is equal or lower than the given max value.
173      *
174      * @param string $value
175      * @param int    $max
176      *
177      * @return bool
178      */
179     public function max($value, $max)
180     {
181         return $value <= $max;
182     }
183 
184     /**
185      * Checks whether the value is an URL.
186      *
187      * @param string $value
188      *
189      * @return bool
190      */
191     public function url($value)
192     {
193         return $this->match($value, '@^\w+://(?:[\w-]+\.)*[\w-]+(?::\d+)?(?:/.*)?$@u');
194     }
195 
196     /**
197      * Checks whether the value is an email address.
198      *
199      * @param string $value
200      *
201      * @return bool
202      */
203     public function email($value)
204     {
205         return $this->match($value, '/^[\w.-]+@[\w.-]+\.[a-z]{2,}$/ui');
206     }
207 
208     /**
209      * Checks whether the value matches the given regex.
210      *
211      * @param string $value
212      * @param string $regex
213      *
214      * @return bool
215      */
216     public function match($value, $regex)
217     {
218         return (bool) preg_match($regex, $value);
219     }
220 
221     /**
222      * Checks whether the value does not match the given regex.
223      *
224      * @param string $value
225      * @param string $regex
226      *
227      * @return bool
228      */
229     public function notMatch($value, $regex)
230     {
231         return !$this->match($value, $regex);
232     }
233 
234     /**
235      * Checks whether the value is one of the given valid values.
236      *
237      * @param string $value
238      * @param array  $validValues
239      *
240      * @return bool
241      */
242     public function values($value, array $validValues)
243     {
244         return in_array($value, $validValues);
245     }
246 
247     /**
248      * Checks the value by using the given callable.
249      *
250      * @param string   $value
251      * @param callable $callback
252      *
253      * @return bool
254      */
255     public function custom($value, callable $callback)
256     {
257         return $callback($value);
258     }
259 }
260