27 if (!self::$instance) {
28 self::$instance =
new self();
43 public function validate(Parameter $param, &$value)
45 $this->errors = array();
48 if (empty($this->errors)) {
63 return $this->errors ?: array();
76 protected function recursiveProcess(Parameter $param, &$value, $path =
'', $depth = 0)
79 $value = $param->getValue($value);
81 $required = $param->getRequired();
83 if ((
null === $value && !$required) || $param->getStatic()) {
87 $type = $param->getType();
89 $valueIsArray = is_array($value);
91 if ($name = $param->getName()) {
95 if ($type ==
'object') {
98 if ($param->getInstanceOf()) {
101 $this->errors[] =
"{$path} must be an instance of {$instance}";
107 $traverse = $temporaryValue =
false;
110 if (!$valueIsArray && $value instanceof ToArrayInterface) {
111 $value = $value->toArray();
116 if (isset($value[0])) {
117 $this->errors[] =
"{$path} must be an array of properties. Got a numerically indexed array.";
121 } elseif ($value ===
null) {
124 $temporaryValue = $valueIsArray = $traverse =
true;
129 if ($properties = $param->getProperties()) {
131 foreach ($properties as $property) {
132 $name = $property->getName();
133 if (isset($value[$name])) {
139 if (
null !== $current) {
140 $value[$name] = $current;
146 $additional = $param->getAdditionalProperties();
147 if ($additional !==
true) {
149 $keys = array_keys($value);
151 $diff = array_diff($keys, array_keys($properties));
154 if ($additional instanceOf Parameter) {
155 foreach ($diff as $key) {
156 $this->
recursiveProcess($additional, $value[$key],
"{$path}[{$key}]", $depth);
160 foreach ($diff as $prop) {
161 $this->errors[] = sprintf(
'%s[%s] is not an allowed property', $path, $prop);
170 if ($temporaryValue && empty($value)) {
172 $valueIsArray =
false;
176 } elseif ($type ==
'array' && $valueIsArray && $param->getItems()) {
177 foreach ($value as $i => &$item) {
179 $this->
recursiveProcess($param->getItems(), $item, $path .
"[{$i}]", $depth + 1);
184 if ($required && $value ===
null && $type !=
'null') {
185 $message =
"{$path} is " . ($param->getType() ? (
'a required ' . implode(
' or ', (array) $param->getType())) :
'required');
186 if ($param->getDescription()) {
187 $message .=
': ' . $param->getDescription();
189 $this->errors[] = $message;
195 if ($type && (!$type = $this->
determineType($type, $value))) {
196 if ($this->castIntegerToStringType && $param->getType() ==
'string' && is_integer($value)) {
197 $value = (string) $value;
199 $this->errors[] =
"{$path} must be of type " . implode(
' or ', (array) $param->getType());
204 if ($type ==
'string') {
207 if (($enum = $param->getEnum()) && !in_array($value, $enum)) {
208 $this->errors[] =
"{$path} must be one of " . implode(
' or ', array_map(
function ($s) {
209 return '"' . addslashes($s) .
'"';
213 if (($pattern = $param->getPattern()) && !preg_match($pattern, $value)) {
214 $this->errors[] =
"{$path} must match the following regular expression: {$pattern}";
218 if ($min = $param->getMinLength()) {
219 $strLen = strlen($value);
220 if ($strLen < $min) {
221 $this->errors[] =
"{$path} length must be greater than or equal to {$min}";
224 if ($max = $param->getMaxLength()) {
225 if (($strLen ?: strlen($value)) > $max) {
226 $this->errors[] =
"{$path} length must be less than or equal to {$max}";
230 } elseif ($type ==
'array') {
233 if ($min = $param->getMinItems()) {
234 $size =
count($value);
236 $this->errors[] =
"{$path} must contain {$min} or more elements";
239 if ($max = $param->getMaxItems()) {
240 if (($size ?:
count($value)) > $max) {
241 $this->errors[] =
"{$path} must contain {$max} or fewer elements";
245 } elseif ($type ==
'integer' || $type ==
'number' || $type ==
'numeric') {
246 if (($min = $param->getMinimum()) && $value < $min) {
247 $this->errors[] =
"{$path} must be greater than or equal to {$min}";
249 if (($max = $param->getMaximum()) && $value > $max) {
250 $this->errors[] =
"{$path} must be less than or equal to {$max}";
254 return empty($this->errors);
267 foreach ((array) $type as $t) {
268 if ($t ==
'string' && (is_string($value) || (is_object($value) && method_exists($value,
'__toString')))) {
270 } elseif ($t ==
'object' && (is_array($value) || is_object($value))) {
272 } elseif ($t ==
'array' && is_array($value)) {
274 } elseif ($t ==
'integer' && is_integer($value)) {
276 } elseif ($t ==
'boolean' && is_bool($value)) {
278 } elseif ($t ==
'number' && is_numeric($value)) {
280 } elseif ($t ==
'numeric' && is_numeric($value)) {
282 } elseif ($t ==
'null' && !$value) {
284 } elseif ($t ==
'any') {