forked from loafle/openapi-generator-original
		
	* [Slim4] Add new method to Mocker interface * [Slim4] Add implementation and tests for new method * [Slim4] Add test fixture to encrease code coverage * [Slim4] Add ref support to mockArray method * [Slim4] Add mockFromRef method * [Slim4] Add ref support to mockObject method * [Slim4] Add ModelInterface * [Slim4] Refresh samples * [Slim4] Add ref support to mockFromSchema method * [Slim4] Run all test suites by default test command As it turnes out to generate coverage report for a whole project I need to run all test suites at once. * [Slim4] Fix enum option of string mocking
		
			
				
	
	
		
			523 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			523 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
| <?php
 | |
| 
 | |
| /**
 | |
|  * OpenApiDataMocker
 | |
|  *
 | |
|  * PHP version 7.1
 | |
|  *
 | |
|  * @package OpenAPIServer
 | |
|  * @author  OpenAPI Generator team
 | |
|  * @link    https://github.com/openapitools/openapi-generator
 | |
|  */
 | |
| 
 | |
| /**
 | |
|  * OpenAPI Petstore
 | |
|  *
 | |
|  * This spec is mainly for testing Petstore server and contains fake endpoints, models. Please do not use this for any other purpose. Special characters: \" \\
 | |
|  * The version of the OpenAPI document: 1.0.0
 | |
|  * Generated by: https://github.com/openapitools/openapi-generator.git
 | |
|  */
 | |
| 
 | |
| /**
 | |
|  * NOTE: This class is auto generated by the openapi generator program.
 | |
|  * https://github.com/openapitools/openapi-generator
 | |
|  * Do not edit the class manually.
 | |
|  */
 | |
| namespace OpenAPIServer\Mock;
 | |
| 
 | |
| use OpenAPIServer\Mock\OpenApiDataMockerInterface as IMocker;
 | |
| use OpenAPIServer\Utils\ModelUtilsTrait;
 | |
| use StdClass;
 | |
| use InvalidArgumentException;
 | |
| 
 | |
| /**
 | |
|  * OpenApiDataMocker Class Doc Comment
 | |
|  *
 | |
|  * @package OpenAPIServer\Mock
 | |
|  * @author  OpenAPI Generator team
 | |
|  * @link    https://github.com/openapitools/openapi-generator
 | |
|  */
 | |
| final class OpenApiDataMocker implements IMocker
 | |
| {
 | |
|     use ModelUtilsTrait;
 | |
| 
 | |
|     /**
 | |
|      * Mocks OpenApi Data.
 | |
|      * @see https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#data-types
 | |
|      *
 | |
|      * @param $dataType   string     OpenApi data type. Use constants from OpenApiDataMockerInterface class
 | |
|      * @param $dataFormat string     (optional) OpenApi data format
 | |
|      * @param $options    array|null (optional) OpenApi data options
 | |
|      *
 | |
|      * @throws \InvalidArgumentException when invalid arguments passed
 | |
|      *
 | |
|      * @return mixed
 | |
|      */
 | |
|     public function mock($dataType, $dataFormat = null, $options = [])
 | |
|     {
 | |
|         switch ($dataType) {
 | |
|             case IMocker::DATA_TYPE_INTEGER:
 | |
|             case IMocker::DATA_TYPE_NUMBER:
 | |
|                 $minimum = $options['minimum'] ?? null;
 | |
|                 $maximum = $options['maximum'] ?? null;
 | |
|                 $exclusiveMinimum = $options['exclusiveMinimum'] ?? false;
 | |
|                 $exclusiveMaximum = $options['exclusiveMaximum'] ?? false;
 | |
|                 if ($dataType === IMocker::DATA_TYPE_INTEGER) {
 | |
|                     return $this->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;
 | |
|                 $enum = $options['enum'] ?? null;
 | |
|                 return $this->mockString($dataFormat, $minLength, $maxLength, $enum);
 | |
|             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);
 | |
|             case IMocker::DATA_TYPE_OBJECT:
 | |
|                 $properties = $options['properties'] ?? null;
 | |
|                 $minProperties = $options['minProperties'] ?? 0;
 | |
|                 $maxProperties = $options['maxProperties'] ?? null;
 | |
|                 $additionalProperties = $options['additionalProperties'] ?? null;
 | |
|                 $required = $options['required'] ?? null;
 | |
|                 return $this->mockObject($properties, $minProperties, $maxProperties, $additionalProperties, $required);
 | |
|             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,
 | |
|                     IMocker::DATA_TYPE_OBJECT,
 | |
|                 ]));
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * 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 object|array $items       Object or assoc 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 && is_object($items) === false)
 | |
|             || (is_array($items) && array_key_exists('type', $items) === false)
 | |
|             || (is_object($items) && isset($items->type) === false)
 | |
|         ) {
 | |
|             new InvalidArgumentException('"items" must be object or 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;
 | |
|         }
 | |
| 
 | |
|         $options = $this->extractSchemaProperties($items);
 | |
|         $dataType = $options['type'];
 | |
|         $dataFormat = $options['format'] ?? null;
 | |
|         $ref = $options['$ref'] ?? null;
 | |
| 
 | |
|         // always generate smallest possible array to avoid huge JSON responses
 | |
|         $arrSize = ($maxSize < 1) ? $maxSize : max($minSize, 1);
 | |
|         while (count($arr) < $arrSize) {
 | |
|             $data = $this->mockFromRef($ref);
 | |
|             $arr[] = ($data) ? $data : $this->mock($dataType, $dataFormat, $options);
 | |
|         }
 | |
|         return $arr;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Shortcut to mock object type.
 | |
|      * Equivalent to mockData(DATA_TYPE_OBJECT);
 | |
|      *
 | |
|      * @param object|array           $properties           Object or array of described properties
 | |
|      * @param int|null               $minProperties        (optional) An object instance is valid against "minProperties" if its number of properties is greater than, or equal to, the value of this keyword.
 | |
|      * @param int|null               $maxProperties        (optional) An object instance is valid against "maxProperties" if its number of properties is less than, or equal to, the value of this keyword.
 | |
|      * @param bool|object|array|null $additionalProperties (optional) If "additionalProperties" is true, validation always succeeds.
 | |
|      * If "additionalProperties" is false, validation succeeds only if the instance is an object and all properties on the instance were covered by "properties" and/or "patternProperties".
 | |
|      * If "additionalProperties" is an object, validate the value as a schema to all of the properties that weren't validated by "properties" nor "patternProperties".
 | |
|      * @param array|null             $required             (optional) This array MUST have at least one element.  Elements of this array must be strings, and MUST be unique.
 | |
|      * An object instance is valid if its property set contains all elements in this array value.
 | |
|      *
 | |
|      * @throws \InvalidArgumentException when invalid arguments passed
 | |
|      *
 | |
|      * @return object
 | |
|      */
 | |
|     public function mockObject(
 | |
|         $properties,
 | |
|         $minProperties = 0,
 | |
|         $maxProperties = null,
 | |
|         $additionalProperties = null,
 | |
|         $required = null
 | |
|     ) {
 | |
|         $obj = new StdClass();
 | |
| 
 | |
|         if (is_object($properties) === false && is_array($properties) === false) {
 | |
|             throw new InvalidArgumentException('The value of "properties" must be an array or object');
 | |
|         }
 | |
| 
 | |
|         foreach ($properties as $propName => $propValue) {
 | |
|             if (is_object($propValue) === false && is_array($propValue) === false) {
 | |
|                 throw new InvalidArgumentException('Each value of "properties" must be an array or object');
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         if ($minProperties !== null) {
 | |
|             if (is_integer($minProperties) === false || $minProperties < 0) {
 | |
|                 throw new InvalidArgumentException('"minProperties" must be an integer. This integer must be greater than, or equal to, 0');
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         if ($maxProperties !== null) {
 | |
|             if (is_integer($maxProperties) === false || $maxProperties < 0) {
 | |
|                 throw new InvalidArgumentException('"maxProperties" must be an integer. This integer must be greater than, or equal to, 0.');
 | |
|             }
 | |
|             if ($maxProperties < $minProperties) {
 | |
|                 throw new InvalidArgumentException('"maxProperties" value cannot be less than "minProperties"');
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         if ($additionalProperties !== null) {
 | |
|             if (is_bool($additionalProperties) === false && is_object($additionalProperties) === false && is_array($additionalProperties) === false) {
 | |
|                 throw new InvalidArgumentException('The value of "additionalProperties" must be a boolean or object or array.');
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         if ($required !== null) {
 | |
|             if (
 | |
|                 is_array($required) === false
 | |
|                 || count($required) > count(array_unique($required))
 | |
|             ) {
 | |
|                 throw new InvalidArgumentException('The value of "required" must be an array. Elements of this array must be unique.');
 | |
|             }
 | |
|             foreach ($required as $requiredPropName) {
 | |
|                 if (is_string($requiredPropName) === false) {
 | |
|                     throw new InvalidArgumentException('Elements of "required" array must be strings');
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         foreach ($properties as $propName => $propValue) {
 | |
|             $options = $this->extractSchemaProperties($propValue);
 | |
|             $dataType = $options['type'];
 | |
|             $dataFormat = $options['dataFormat'] ?? null;
 | |
|             $ref = $options['$ref'] ?? null;
 | |
|             $data = $this->mockFromRef($ref);
 | |
|             $obj->$propName = ($data) ? $data : $this->mock($dataType, $dataFormat, $options);
 | |
|         }
 | |
| 
 | |
|         return $obj;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Mocks OpenApi Data from schema.
 | |
|      *
 | |
|      * @param array|object $schema OpenAPI schema
 | |
|      *
 | |
|      * @throws \InvalidArgumentException when invalid arguments passed
 | |
|      *
 | |
|      * @return mixed
 | |
|      */
 | |
|     public function mockFromSchema($schema)
 | |
|     {
 | |
|         $props = $this->extractSchemaProperties($schema);
 | |
|         if (array_key_exists('$ref', $props) && !empty($props['$ref'])) {
 | |
|             return $this->mockFromRef($props['$ref']);
 | |
|         } elseif ($props['type'] === null) {
 | |
|             throw new InvalidArgumentException('"schema" must be object or assoc array with "type" property');
 | |
|         }
 | |
|         return $this->mock($props['type'], $props['format'], $props);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Mock data by referenced schema.
 | |
|      * TODO: this method will return model instance, not an StdClass
 | |
|      *
 | |
|      * @param string|null $ref Ref to model, eg. #/components/schemas/User
 | |
|      *
 | |
|      * @return mixed
 | |
|      */
 | |
|     public function mockFromRef($ref)
 | |
|     {
 | |
|         $data = null;
 | |
|         if (is_string($ref) && !empty($ref)) {
 | |
|             $refName = static::getSimpleRef($ref);
 | |
|             $modelName = static::toModelName($refName);
 | |
|             $modelClass = 'OpenAPIServer\Model\\' . $modelName;
 | |
|             if (!class_exists($modelClass) || !method_exists($modelClass, 'getOpenApiSchema')) {
 | |
|                 throw new InvalidArgumentException(sprintf(
 | |
|                     'Model %s not found or method %s doesn\'t exist',
 | |
|                     $modelClass,
 | |
|                     $modelClass . '::getOpenApiSchema'
 | |
|                 ));
 | |
|             }
 | |
|             $data = $this->mockFromSchema($modelClass::getOpenApiSchema(true));
 | |
|         }
 | |
| 
 | |
|         return $data;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @internal Extract OAS properties from array or object.
 | |
|      * @codeCoverageIgnore
 | |
|      *
 | |
|      * @param array|object $val Processed array or object
 | |
|      *
 | |
|      * @return array
 | |
|      */
 | |
|     private function extractSchemaProperties($val)
 | |
|     {
 | |
|         $props = [
 | |
|             'type' => null,
 | |
|             'format' => null,
 | |
|         ];
 | |
|         foreach (
 | |
|             [
 | |
|                 'type',
 | |
|                 'format',
 | |
|                 'minimum',
 | |
|                 'maximum',
 | |
|                 'exclusiveMinimum',
 | |
|                 'exclusiveMaximum',
 | |
|                 'minLength',
 | |
|                 'maxLength',
 | |
|                 'pattern',
 | |
|                 'enum',
 | |
|                 'items',
 | |
|                 'minItems',
 | |
|                 'maxItems',
 | |
|                 'uniqueItems',
 | |
|                 'properties',
 | |
|                 'minProperties',
 | |
|                 'maxProperties',
 | |
|                 'additionalProperties',
 | |
|                 'required',
 | |
|                 'example',
 | |
|                 '$ref',
 | |
|             ] as $propName
 | |
|         ) {
 | |
|             if (is_array($val) && array_key_exists($propName, $val)) {
 | |
|                 $props[$propName] = $val[$propName];
 | |
|             } elseif (is_object($val) && isset($val->$propName)) {
 | |
|                 $props[$propName] = $val->$propName;
 | |
|             }
 | |
|         }
 | |
|         return $props;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @internal
 | |
|      * @codeCoverageIgnore
 | |
|      *
 | |
|      * @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);
 | |
|     }
 | |
| }
 |