1<?php 2 3/** 4 * @see https://github.com/laminas/laminas-validator for the canonical source repository 5 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md 6 * @license https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License 7 */ 8 9namespace Laminas\Validator; 10 11use Laminas\Stdlib\ArrayUtils; 12use Traversable; 13 14class NotEmpty extends AbstractValidator 15{ 16 const BOOLEAN = 0b000000000001; 17 const INTEGER = 0b000000000010; 18 const FLOAT = 0b000000000100; 19 const STRING = 0b000000001000; 20 const ZERO = 0b000000010000; 21 const EMPTY_ARRAY = 0b000000100000; 22 const NULL = 0b000001000000; 23 const PHP = 0b000001111111; 24 const SPACE = 0b000010000000; 25 const OBJECT = 0b000100000000; 26 const OBJECT_STRING = 0b001000000000; 27 const OBJECT_COUNT = 0b010000000000; 28 const ALL = 0b011111111111; 29 30 const INVALID = 'notEmptyInvalid'; 31 const IS_EMPTY = 'isEmpty'; 32 33 protected $constants = [ 34 self::BOOLEAN => 'boolean', 35 self::INTEGER => 'integer', 36 self::FLOAT => 'float', 37 self::STRING => 'string', 38 self::ZERO => 'zero', 39 self::EMPTY_ARRAY => 'array', 40 self::NULL => 'null', 41 self::PHP => 'php', 42 self::SPACE => 'space', 43 self::OBJECT => 'object', 44 self::OBJECT_STRING => 'objectstring', 45 self::OBJECT_COUNT => 'objectcount', 46 self::ALL => 'all', 47 ]; 48 49 /** 50 * Default value for types; value = 0b000111101001 51 * 52 * @var array 53 */ 54 protected $defaultType = [ 55 self::OBJECT, 56 self::SPACE, 57 self::NULL, 58 self::EMPTY_ARRAY, 59 self::STRING, 60 self::BOOLEAN, 61 ]; 62 63 /** 64 * @var array 65 */ 66 protected $messageTemplates = [ 67 self::IS_EMPTY => "Value is required and can't be empty", 68 self::INVALID => 'Invalid type given. String, integer, float, boolean or array expected', 69 ]; 70 71 /** 72 * Options for this validator 73 * 74 * @var array 75 */ 76 protected $options = []; 77 78 /** 79 * Constructor 80 * 81 * @param array|Traversable|int $options OPTIONAL 82 */ 83 public function __construct($options = null) 84 { 85 if ($options instanceof Traversable) { 86 $options = ArrayUtils::iteratorToArray($options); 87 } 88 89 if (! is_array($options)) { 90 $options = func_get_args(); 91 $temp = []; 92 if (! empty($options)) { 93 $temp['type'] = array_shift($options); 94 } 95 96 $options = $temp; 97 } 98 99 if (! isset($options['type'])) { 100 if (($type = $this->calculateTypeValue($options)) != 0) { 101 $options['type'] = $type; 102 } else { 103 $options['type'] = $this->defaultType; 104 } 105 } 106 107 parent::__construct($options); 108 } 109 110 /** 111 * Returns the set types 112 * 113 * @return array 114 */ 115 public function getType() 116 { 117 return $this->options['type']; 118 } 119 120 /** 121 * @return int 122 */ 123 public function getDefaultType() 124 { 125 return $this->calculateTypeValue($this->defaultType); 126 } 127 128 /** 129 * @param array|int|string $type 130 * @return int 131 */ 132 protected function calculateTypeValue($type) 133 { 134 if (is_array($type)) { 135 $detected = 0; 136 foreach ($type as $value) { 137 if (is_int($value)) { 138 $detected |= $value; 139 } elseif (in_array($value, $this->constants, true)) { 140 $detected |= array_search($value, $this->constants, true); 141 } 142 } 143 144 $type = $detected; 145 } elseif (is_string($type) && in_array($type, $this->constants, true)) { 146 $type = array_search($type, $this->constants, true); 147 } 148 149 return $type; 150 } 151 152 /** 153 * Set the types 154 * 155 * @param int|array $type 156 * @throws Exception\InvalidArgumentException 157 * @return $this 158 */ 159 public function setType($type = null) 160 { 161 $type = $this->calculateTypeValue($type); 162 163 if (! is_int($type) || ($type < 0) || ($type > self::ALL)) { 164 throw new Exception\InvalidArgumentException('Unknown type'); 165 } 166 167 $this->options['type'] = $type; 168 169 return $this; 170 } 171 172 /** 173 * Returns true if and only if $value is not an empty value. 174 * 175 * @param string $value 176 * @return bool 177 */ 178 public function isValid($value) 179 { 180 if ($value !== null && ! is_string($value) && ! is_int($value) && ! is_float($value) && 181 ! is_bool($value) && ! is_array($value) && ! is_object($value) 182 ) { 183 $this->error(self::INVALID); 184 return false; 185 } 186 187 $type = $this->getType(); 188 $this->setValue($value); 189 $object = false; 190 191 // OBJECT_COUNT (countable object) 192 if ($type & self::OBJECT_COUNT) { 193 $object = true; 194 195 if (is_object($value) && $value instanceof \Countable && (count($value) == 0)) { 196 $this->error(self::IS_EMPTY); 197 return false; 198 } 199 } 200 201 // OBJECT_STRING (object's toString) 202 if ($type & self::OBJECT_STRING) { 203 $object = true; 204 205 if ((is_object($value) && (! method_exists($value, '__toString'))) || 206 (is_object($value) && (method_exists($value, '__toString')) && (((string) $value) == ''))) { 207 $this->error(self::IS_EMPTY); 208 return false; 209 } 210 } 211 212 // OBJECT (object) 213 if ($type & self::OBJECT) { 214 // fall trough, objects are always not empty 215 } elseif ($object === false) { 216 // object not allowed but object given -> return false 217 if (is_object($value)) { 218 $this->error(self::IS_EMPTY); 219 return false; 220 } 221 } 222 223 // SPACE (' ') 224 if ($type & self::SPACE) { 225 if (is_string($value) && (preg_match('/^\s+$/s', $value))) { 226 $this->error(self::IS_EMPTY); 227 return false; 228 } 229 } 230 231 // NULL (null) 232 if ($type & self::NULL) { 233 if ($value === null) { 234 $this->error(self::IS_EMPTY); 235 return false; 236 } 237 } 238 239 // EMPTY_ARRAY (array()) 240 if ($type & self::EMPTY_ARRAY) { 241 if (is_array($value) && ($value == [])) { 242 $this->error(self::IS_EMPTY); 243 return false; 244 } 245 } 246 247 // ZERO ('0') 248 if ($type & self::ZERO) { 249 if (is_string($value) && ($value == '0')) { 250 $this->error(self::IS_EMPTY); 251 return false; 252 } 253 } 254 255 // STRING ('') 256 if ($type & self::STRING) { 257 if (is_string($value) && ($value == '')) { 258 $this->error(self::IS_EMPTY); 259 return false; 260 } 261 } 262 263 // FLOAT (0.0) 264 if ($type & self::FLOAT) { 265 if (is_float($value) && ($value == 0.0)) { 266 $this->error(self::IS_EMPTY); 267 return false; 268 } 269 } 270 271 // INTEGER (0) 272 if ($type & self::INTEGER) { 273 if (is_int($value) && ($value == 0)) { 274 $this->error(self::IS_EMPTY); 275 return false; 276 } 277 } 278 279 // BOOLEAN (false) 280 if ($type & self::BOOLEAN) { 281 if (is_bool($value) && ($value == false)) { 282 $this->error(self::IS_EMPTY); 283 return false; 284 } 285 } 286 287 return true; 288 } 289} 290