mockInteger($dataFormat, $minimum, $maximum, $exclusiveMinimum, $exclusiveMaximum); } return $this->mockNumber($dataFormat, $minimum, $maximum, $exclusiveMinimum, $exclusiveMaximum); case IMocker::DATA_TYPE_STRING: $minLength = $options['minLength'] ?? 0; $maxLength = $options['maxLength'] ?? null; return $this->mockString($dataFormat, $minLength, $maxLength); case IMocker::DATA_TYPE_BOOLEAN: return $this->mockBoolean(); case IMocker::DATA_TYPE_ARRAY: $items = $options['items'] ?? null; $minItems = $options['minItems'] ?? 0; $maxItems = $options['maxItems'] ?? null; $uniqueItems = $options['uniqueItems'] ?? false; return $this->mockArray($items, $minItems, $maxItems, $uniqueItems); default: throw new InvalidArgumentException('"dataType" must be one of ' . implode(', ', [ IMocker::DATA_TYPE_INTEGER, IMocker::DATA_TYPE_NUMBER, IMocker::DATA_TYPE_STRING, IMocker::DATA_TYPE_BOOLEAN, IMocker::DATA_TYPE_ARRAY, ])); } } /** * Shortcut to mock integer type * Equivalent to mockData(DATA_TYPE_INTEGER); * * @param string|null $dataFormat (optional) int32 or int64 * @param number|null $minimum (optional) Default is 0 * @param number|null $maximum (optional) Default is mt_getrandmax() * @param bool|null $exclusiveMinimum (optional) Default is false * @param bool|null $exclusiveMaximum (optional) Default is false * * @throws \InvalidArgumentException when $maximum less than $minimum or invalid arguments provided * * @return int */ public function mockInteger( $dataFormat = null, $minimum = null, $maximum = null, $exclusiveMinimum = false, $exclusiveMaximum = false ) { return $this->getRandomNumber($minimum, $maximum, $exclusiveMinimum, $exclusiveMaximum, 0); } /** * Shortcut to mock number type * Equivalent to mockData(DATA_TYPE_NUMBER); * * @param string|null $dataFormat (optional) float or double * @param number|null $minimum (optional) Default is 0 * @param number|null $maximum (optional) Default is mt_getrandmax() * @param bool|null $exclusiveMinimum (optional) Default is false * @param bool|null $exclusiveMaximum (optional) Default is false * * @throws \InvalidArgumentException when $maximum less than $minimum or invalid arguments provided * * @return float */ public function mockNumber( $dataFormat = null, $minimum = null, $maximum = null, $exclusiveMinimum = false, $exclusiveMaximum = false ) { return $this->getRandomNumber($minimum, $maximum, $exclusiveMinimum, $exclusiveMaximum, 4); } /** * Shortcut to mock string type * Equivalent to mockData(DATA_TYPE_STRING); * * @param string|null $dataFormat (optional) one of byte, binary, date, date-time, password * @param int|null $minLength (optional) Default is 0 * @param int|null $maxLength (optional) Default is 100 chars * @param array $enum (optional) This array should have at least one element. * Elements in the array should be unique. * @param string|null $pattern (optional) This string should be a valid regular expression, according to the ECMA 262 regular expression dialect. * Recall: regular expressions are not implicitly anchored. * * @throws \InvalidArgumentException when invalid arguments passed * * @return string */ public function mockString( $dataFormat = null, $minLength = 0, $maxLength = null, $enum = null, $pattern = null ) { if ($enum !== null) { if ( is_array($enum) === false || empty($enum) || count($enum) > count(array_unique($enum)) ) { throw new InvalidArgumentException('"enum" must be an array. This array should have at least one element. Elements in the array should be unique.'); } // return random variant return $enum[mt_rand(0, count($enum) - 1)]; } if ($minLength !== 0 && $minLength !== null) { if (is_int($minLength) === false) { throw new InvalidArgumentException('"minLength" must be an integer'); } elseif ($minLength < 0) { throw new InvalidArgumentException('"minLength" must be greater than, or equal to, 0'); } } else { $minLength = 0; } if ($maxLength !== null) { if (is_int($maxLength) === false) { throw new InvalidArgumentException('"maxLength" must be an integer'); } elseif ($maxLength < 0) { throw new InvalidArgumentException('"maxLength" must be greater than, or equal to, 0'); } } else { // since we don't need huge texts by default, lets cut them down to 100 chars $maxLength = 100; } if ($maxLength < $minLength) { throw new InvalidArgumentException('"maxLength" value cannot be less than "minLength"'); } return str_pad('', mt_rand($minLength, $maxLength), 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. ', \STR_PAD_RIGHT); } /** * Shortcut to mock boolean type * Equivalent to mockData(DATA_TYPE_BOOLEAN); * * @return bool */ public function mockBoolean() { return (bool) mt_rand(0, 1); } /** * Shortcut to mock array type * Equivalent to mockData(DATA_TYPE_ARRAY); * * @param array $items Array of described items * @param int|null $minItems (optional) An array instance is valid against "minItems" if its size is greater than, or equal to, the value of this keyword. * @param int|null $maxItems (optional) An array instance is valid against "maxItems" if its size is less than, or equal to, the value of this keyword * @param bool|null $uniqueItems (optional) If it has boolean value true, the instance validates successfully if all of its elements are unique * * @throws \InvalidArgumentException when invalid arguments passed * * @return array */ public function mockArray( $items, $minItems = 0, $maxItems = null, $uniqueItems = false ) { $arr = []; $minSize = 0; $maxSize = \PHP_INT_MAX; if (is_array($items) === false || array_key_exists('type', $items) === false) { throw new InvalidArgumentException('"items" must be assoc array with "type" key'); } if ($minItems !== null) { if (is_integer($minItems) === false || $minItems < 0) { throw new InvalidArgumentException('"mitItems" must be an integer. This integer must be greater than, or equal to, 0'); } $minSize = $minItems; } if ($maxItems !== null) { if (is_integer($maxItems) === false || $maxItems < 0) { throw new InvalidArgumentException('"maxItems" must be an integer. This integer must be greater than, or equal to, 0.'); } if ($maxItems < $minItems) { throw new InvalidArgumentException('"maxItems" value cannot be less than "minItems"'); } $maxSize = $maxItems; } $dataType = $items['type']; $dataFormat = $items['format'] ?? null; $options = $this->extractSchemaProperties($items); // always genarate smallest possible array to avoid huge JSON responses $arrSize = ($maxSize < 1) ? $maxSize : max($minSize, 1); while (count($arr) < $arrSize) { $arr[] = $this->mock($dataType, $dataFormat, $options); } return $arr; } /** * @internal Extract OAS properties from array or object. * * @param array $arr Processed array * * @return array */ private function extractSchemaProperties($arr) { $props = []; foreach ( [ 'minimum', 'maximum', 'exclusiveMinimum', 'exclusiveMaximum', 'minLength', 'maxLength', 'pattern', 'enum', 'items', 'minItems', 'maxItems', 'uniqueItems', 'properties', 'minProperties', 'maxProperties', 'additionalProperties', 'required', 'example', ] as $propName ) { if (array_key_exists($propName, $arr)) { $props[$propName] = $arr[$propName]; } } return $props; } /** * @internal * * @return float|int */ protected function getRandomNumber( $minimum = null, $maximum = null, $exclusiveMinimum = false, $exclusiveMaximum = false, $maxDecimals = 4 ) { $min = 0; $max = mt_getrandmax(); if ($minimum !== null) { if (is_numeric($minimum) === false) { throw new InvalidArgumentException('"minimum" must be a number'); } $min = $minimum; } if ($maximum !== null) { if (is_numeric($maximum) === false) { throw new InvalidArgumentException('"maximum" must be a number'); } $max = $maximum; } if ($exclusiveMinimum !== false) { if (is_bool($exclusiveMinimum) === false) { throw new InvalidArgumentException('"exclusiveMinimum" must be a boolean'); } elseif ($minimum === null) { throw new InvalidArgumentException('If "exclusiveMinimum" is present, "minimum" must also be present'); } $min += 1; } if ($exclusiveMaximum !== false) { if (is_bool($exclusiveMaximum) === false) { throw new InvalidArgumentException('"exclusiveMaximum" must be a boolean'); } elseif ($maximum === null) { throw new InvalidArgumentException('If "exclusiveMaximum" is present, "maximum" must also be present'); } $max -= 1; } if ($max < $min) { throw new InvalidArgumentException('"maximum" value cannot be less than "minimum"'); } if ($maxDecimals > 0) { return round($min + mt_rand() / mt_getrandmax() * ($max - $min), $maxDecimals); } return mt_rand($min, $max); } }