diff --git a/src/Illuminate/Http/Concerns/InteractsWithInput.php b/src/Illuminate/Http/Concerns/InteractsWithInput.php index c9ccad570501..66bbee025204 100644 --- a/src/Illuminate/Http/Concerns/InteractsWithInput.php +++ b/src/Illuminate/Http/Concerns/InteractsWithInput.php @@ -4,15 +4,14 @@ use Illuminate\Http\UploadedFile; use Illuminate\Support\Arr; -use Illuminate\Support\Facades\Date; use Illuminate\Support\Traits\Dumpable; +use Illuminate\Support\Traits\InteractsWithData; use SplFileInfo; -use stdClass; use Symfony\Component\HttpFoundation\InputBag; trait InteractsWithInput { - use Dumpable; + use Dumpable, InteractsWithData; /** * Retrieve a server variable from the request. @@ -67,199 +66,6 @@ public function bearerToken() } } - /** - * Determine if the request contains a given input item key. - * - * @param string|array $key - * @return bool - */ - public function exists($key) - { - return $this->has($key); - } - - /** - * Determine if the request contains a given input item key. - * - * @param string|array $key - * @return bool - */ - public function has($key) - { - $keys = is_array($key) ? $key : func_get_args(); - - $input = $this->all(); - - foreach ($keys as $value) { - if (! Arr::has($input, $value)) { - return false; - } - } - - return true; - } - - /** - * Determine if the request contains any of the given inputs. - * - * @param string|array $keys - * @return bool - */ - public function hasAny($keys) - { - $keys = is_array($keys) ? $keys : func_get_args(); - - $input = $this->all(); - - return Arr::hasAny($input, $keys); - } - - /** - * Apply the callback if the request contains the given input item key. - * - * @param string $key - * @param callable $callback - * @param callable|null $default - * @return $this|mixed - */ - public function whenHas($key, callable $callback, ?callable $default = null) - { - if ($this->has($key)) { - return $callback(data_get($this->all(), $key)) ?: $this; - } - - if ($default) { - return $default(); - } - - return $this; - } - - /** - * Determine if the request contains a non-empty value for an input item. - * - * @param string|array $key - * @return bool - */ - public function filled($key) - { - $keys = is_array($key) ? $key : func_get_args(); - - foreach ($keys as $value) { - if ($this->isEmptyString($value)) { - return false; - } - } - - return true; - } - - /** - * Determine if the request contains an empty value for an input item. - * - * @param string|array $key - * @return bool - */ - public function isNotFilled($key) - { - $keys = is_array($key) ? $key : func_get_args(); - - foreach ($keys as $value) { - if (! $this->isEmptyString($value)) { - return false; - } - } - - return true; - } - - /** - * Determine if the request contains a non-empty value for any of the given inputs. - * - * @param string|array $keys - * @return bool - */ - public function anyFilled($keys) - { - $keys = is_array($keys) ? $keys : func_get_args(); - - foreach ($keys as $key) { - if ($this->filled($key)) { - return true; - } - } - - return false; - } - - /** - * Apply the callback if the request contains a non-empty value for the given input item key. - * - * @param string $key - * @param callable $callback - * @param callable|null $default - * @return $this|mixed - */ - public function whenFilled($key, callable $callback, ?callable $default = null) - { - if ($this->filled($key)) { - return $callback(data_get($this->all(), $key)) ?: $this; - } - - if ($default) { - return $default(); - } - - return $this; - } - - /** - * Determine if the request is missing a given input item key. - * - * @param string|array $key - * @return bool - */ - public function missing($key) - { - $keys = is_array($key) ? $key : func_get_args(); - - return ! $this->has($keys); - } - - /** - * Apply the callback if the request is missing the given input item key. - * - * @param string $key - * @param callable $callback - * @param callable|null $default - * @return $this|mixed - */ - public function whenMissing($key, callable $callback, ?callable $default = null) - { - if ($this->missing($key)) { - return $callback(data_get($this->all(), $key)) ?: $this; - } - - if ($default) { - return $default(); - } - - return $this; - } - - /** - * Determine if the given input key is an empty string for "filled". - * - * @param string $key - * @return bool - */ - protected function isEmptyString($key) - { - $value = $this->input($key); - - return ! is_bool($value) && ! is_array($value) && trim((string) $value) === ''; - } - /** * Get the keys for all of the input and files. * @@ -307,151 +113,6 @@ public function input($key = null, $default = null) ); } - /** - * Retrieve input from the request as a Stringable instance. - * - * @param string $key - * @param mixed $default - * @return \Illuminate\Support\Stringable - */ - public function str($key, $default = null) - { - return $this->string($key, $default); - } - - /** - * Retrieve input from the request as a Stringable instance. - * - * @param string $key - * @param mixed $default - * @return \Illuminate\Support\Stringable - */ - public function string($key, $default = null) - { - return str($this->input($key, $default)); - } - - /** - * Retrieve input as a boolean value. - * - * Returns true when value is "1", "true", "on", and "yes". Otherwise, returns false. - * - * @param string|null $key - * @param bool $default - * @return bool - */ - public function boolean($key = null, $default = false) - { - return filter_var($this->input($key, $default), FILTER_VALIDATE_BOOLEAN); - } - - /** - * Retrieve input as an integer value. - * - * @param string $key - * @param int $default - * @return int - */ - public function integer($key, $default = 0) - { - return intval($this->input($key, $default)); - } - - /** - * Retrieve input as a float value. - * - * @param string $key - * @param float $default - * @return float - */ - public function float($key, $default = 0.0) - { - return floatval($this->input($key, $default)); - } - - /** - * Retrieve input from the request as a Carbon instance. - * - * @param string $key - * @param string|null $format - * @param string|null $tz - * @return \Illuminate\Support\Carbon|null - * - * @throws \Carbon\Exceptions\InvalidFormatException - */ - public function date($key, $format = null, $tz = null) - { - if ($this->isNotFilled($key)) { - return null; - } - - if (is_null($format)) { - return Date::parse($this->input($key), $tz); - } - - return Date::createFromFormat($format, $this->input($key), $tz); - } - - /** - * Retrieve input from the request as an enum. - * - * @template TEnum of \BackedEnum - * - * @param string $key - * @param class-string $enumClass - * @return TEnum|null - */ - public function enum($key, $enumClass) - { - if ($this->isNotFilled($key) || ! $this->isBackedEnum($enumClass)) { - return null; - } - - return $enumClass::tryFrom($this->input($key)); - } - - /** - * Retrieve input from the request as an array of enums. - * - * @template TEnum of \BackedEnum - * - * @param string $key - * @param class-string $enumClass - * @return TEnum[] - */ - public function enums($key, $enumClass) - { - if ($this->isNotFilled($key) || ! $this->isBackedEnum($enumClass)) { - return []; - } - - return $this->collect($key)->map(function ($value) use ($enumClass) { - return $enumClass::tryFrom($value); - })->filter()->all(); - } - - /** - * Determine if the given enum class is backed. - * - * @param class-string $enumClass - * @return bool - */ - protected function isBackedEnum($enumClass) - { - return enum_exists($enumClass) && method_exists($enumClass, 'tryFrom'); - } - - /** - * Retrieve input from the request as a collection. - * - * @param array|string|null $key - * @return \Illuminate\Support\Collection - */ - public function collect($key = null) - { - return collect(is_array($key) ? $this->only($key) : $this->input($key)); - } - /** * Retrieve input from the request as a Fluent object instance. * @@ -463,48 +124,6 @@ public function fluent($key = null) return fluent(is_array($key) ? $this->only($key) : $this->input($key)); } - /** - * Get a subset containing the provided keys with values from the input data. - * - * @param array|mixed $keys - * @return array - */ - public function only($keys) - { - $results = []; - - $input = $this->all(); - - $placeholder = new stdClass; - - foreach (is_array($keys) ? $keys : func_get_args() as $key) { - $value = data_get($input, $key, $placeholder); - - if ($value !== $placeholder) { - Arr::set($results, $key, $value); - } - } - - return $results; - } - - /** - * Get all of the input except for a specified array of items. - * - * @param array|mixed $keys - * @return array - */ - public function except($keys) - { - $keys = is_array($keys) ? $keys : func_get_args(); - - $results = $this->all(); - - Arr::forget($results, $keys); - - return $results; - } - /** * Retrieve a query string item from the request. * @@ -627,6 +246,18 @@ public function file($key = null, $default = null) return data_get($this->allFiles(), $key, $default); } + /** + * Retrieve data from the instance. + * + * @param string $key + * @param mixed $default + * @return mixed + */ + protected function data($key = null, $default = null) + { + return $this->input($key, $default); + } + /** * Retrieve a parameter item from a given source. * diff --git a/src/Illuminate/Support/Fluent.php b/src/Illuminate/Support/Fluent.php index a4948f2848b2..a1be21b22e83 100755 --- a/src/Illuminate/Support/Fluent.php +++ b/src/Illuminate/Support/Fluent.php @@ -5,6 +5,7 @@ use ArrayAccess; use Illuminate\Contracts\Support\Arrayable; use Illuminate\Contracts\Support\Jsonable; +use Illuminate\Support\Traits\InteractsWithData; use JsonSerializable; /** @@ -16,6 +17,8 @@ */ class Fluent implements Arrayable, ArrayAccess, Jsonable, JsonSerializable { + use InteractsWithData; + /** * All of the attributes set on the fluent instance. * @@ -81,34 +84,58 @@ public function scope($key, $default = null) } /** - * Get the attributes from the fluent instance. + * Get all of the attributes from the fluent instance. * - * @return array + * @param array|mixed|null $keys + * @return array */ - public function getAttributes() + public function all($keys = null) { - return $this->attributes; + $data = $this->data(); + + if (! $keys) { + return $data; + } + + $results = []; + + foreach (is_array($keys) ? $keys : func_get_args() as $key) { + Arr::set($results, $key, Arr::get($data, $key)); + } + + return $results; } /** - * Convert the fluent instance to an array. + * Get data from the fluent instance. + * + * @param string $key + * @param mixed $default + * @return mixed + */ + protected function data($key = null, $default = null) + { + return $this->get($key, $default); + } + + /** + * Get the attributes from the fluent instance. * * @return array */ - public function toArray() + public function getAttributes() { return $this->attributes; } /** - * Convert the fluent instance to a Collection. + * Convert the fluent instance to an array. * - * @param string|null $key - * @return \Illuminate\Support\Collection + * @return array */ - public function collect($key = null) + public function toArray() { - return new Collection($this->get($key)); + return $this->attributes; } /** diff --git a/src/Illuminate/Support/Traits/InteractsWithData.php b/src/Illuminate/Support/Traits/InteractsWithData.php new file mode 100644 index 000000000000..89a035c87ab7 --- /dev/null +++ b/src/Illuminate/Support/Traits/InteractsWithData.php @@ -0,0 +1,407 @@ +has($key); + } + + /** + * Determine if the data contains a given key. + * + * @param string|array $key + * @return bool + */ + public function has($key) + { + $keys = is_array($key) ? $key : func_get_args(); + + $data = $this->all(); + + foreach ($keys as $value) { + if (! Arr::has($data, $value)) { + return false; + } + } + + return true; + } + + /** + * Determine if the instance contains any of the given keys. + * + * @param string|array $keys + * @return bool + */ + public function hasAny($keys) + { + $keys = is_array($keys) ? $keys : func_get_args(); + + $data = $this->all(); + + return Arr::hasAny($data, $keys); + } + + /** + * Apply the callback if the instance contains the given key. + * + * @param string $key + * @param callable $callback + * @param callable|null $default + * @return $this|mixed + */ + public function whenHas($key, callable $callback, ?callable $default = null) + { + if ($this->has($key)) { + return $callback(data_get($this->all(), $key)) ?: $this; + } + + if ($default) { + return $default(); + } + + return $this; + } + + /** + * Determine if the instance contains a non-empty value for the given key. + * + * @param string|array $key + * @return bool + */ + public function filled($key) + { + $keys = is_array($key) ? $key : func_get_args(); + + foreach ($keys as $value) { + if ($this->isEmptyString($value)) { + return false; + } + } + + return true; + } + + /** + * Determine if the instance contains an empty value for the given key. + * + * @param string|array $key + * @return bool + */ + public function isNotFilled($key) + { + $keys = is_array($key) ? $key : func_get_args(); + + foreach ($keys as $value) { + if (! $this->isEmptyString($value)) { + return false; + } + } + + return true; + } + + /** + * Determine if the instance contains a non-empty value for any of the given keys. + * + * @param string|array $keys + * @return bool + */ + public function anyFilled($keys) + { + $keys = is_array($keys) ? $keys : func_get_args(); + + foreach ($keys as $key) { + if ($this->filled($key)) { + return true; + } + } + + return false; + } + + /** + * Apply the callback if the instance contains a non-empty value for the given key. + * + * @param string $key + * @param callable $callback + * @param callable|null $default + * @return $this|mixed + */ + public function whenFilled($key, callable $callback, ?callable $default = null) + { + if ($this->filled($key)) { + return $callback(data_get($this->all(), $key)) ?: $this; + } + + if ($default) { + return $default(); + } + + return $this; + } + + /** + * Determine if the instance is missing a given key. + * + * @param string|array $key + * @return bool + */ + public function missing($key) + { + $keys = is_array($key) ? $key : func_get_args(); + + return ! $this->has($keys); + } + + /** + * Apply the callback if the instance is missing the given key. + * + * @param string $key + * @param callable $callback + * @param callable|null $default + * @return $this|mixed + */ + public function whenMissing($key, callable $callback, ?callable $default = null) + { + if ($this->missing($key)) { + return $callback(data_get($this->all(), $key)) ?: $this; + } + + if ($default) { + return $default(); + } + + return $this; + } + + /** + * Determine if the given key is an empty string for "filled". + * + * @param string $key + * @return bool + */ + protected function isEmptyString($key) + { + $value = $this->data($key); + + return ! is_bool($value) && ! is_array($value) && trim((string) $value) === ''; + } + + /** + * Retrieve data from the instnce as a Stringable instance. + * + * @param string $key + * @param mixed $default + * @return \Illuminate\Support\Stringable + */ + public function str($key, $default = null) + { + return $this->string($key, $default); + } + + /** + * Retrieve data from the instance as a Stringable instance. + * + * @param string $key + * @param mixed $default + * @return \Illuminate\Support\Stringable + */ + public function string($key, $default = null) + { + return str($this->data($key, $default)); + } + + /** + * Retrieve data as a boolean value. + * + * Returns true when value is "1", "true", "on", and "yes". Otherwise, returns false. + * + * @param string|null $key + * @param bool $default + * @return bool + */ + public function boolean($key = null, $default = false) + { + return filter_var($this->data($key, $default), FILTER_VALIDATE_BOOLEAN); + } + + /** + * Retrieve data as an integer value. + * + * @param string $key + * @param int $default + * @return int + */ + public function integer($key, $default = 0) + { + return intval($this->data($key, $default)); + } + + /** + * Retrieve data as a float value. + * + * @param string $key + * @param float $default + * @return float + */ + public function float($key, $default = 0.0) + { + return floatval($this->data($key, $default)); + } + + /** + * Retrieve data from the instance as a Carbon instance. + * + * @param string $key + * @param string|null $format + * @param string|null $tz + * @return \Illuminate\Support\Carbon|null + * + * @throws \Carbon\Exceptions\InvalidFormatException + */ + public function date($key, $format = null, $tz = null) + { + if ($this->isNotFilled($key)) { + return null; + } + + if (is_null($format)) { + return Date::parse($this->data($key), $tz); + } + + return Date::createFromFormat($format, $this->data($key), $tz); + } + + /** + * Retrieve data from the instance as an enum. + * + * @template TEnum of \BackedEnum + * + * @param string $key + * @param class-string $enumClass + * @return TEnum|null + */ + public function enum($key, $enumClass) + { + if ($this->isNotFilled($key) || ! $this->isBackedEnum($enumClass)) { + return null; + } + + return $enumClass::tryFrom($this->data($key)); + } + + /** + * Retrieve data from the instance as an array of enums. + * + * @template TEnum of \BackedEnum + * + * @param string $key + * @param class-string $enumClass + * @return TEnum[] + */ + public function enums($key, $enumClass) + { + if ($this->isNotFilled($key) || ! $this->isBackedEnum($enumClass)) { + return []; + } + + return $this->collect($key)->map(function ($value) use ($enumClass) { + return $enumClass::tryFrom($value); + })->filter()->all(); + } + + /** + * Determine if the given enum class is backed. + * + * @param class-string $enumClass + * @return bool + */ + protected function isBackedEnum($enumClass) + { + return enum_exists($enumClass) && method_exists($enumClass, 'tryFrom'); + } + + /** + * Retrieve data from the instance as a collection. + * + * @param array|string|null $key + * @return \Illuminate\Support\Collection + */ + public function collect($key = null) + { + return collect(is_array($key) ? $this->only($key) : $this->data($key)); + } + + /** + * Get a subset containing the provided keys with values from the instance data. + * + * @param array|mixed $keys + * @return array + */ + public function only($keys) + { + $results = []; + + $data = $this->all(); + + $placeholder = new stdClass; + + foreach (is_array($keys) ? $keys : func_get_args() as $key) { + $value = data_get($data, $key, $placeholder); + + if ($value !== $placeholder) { + Arr::set($results, $key, $value); + } + } + + return $results; + } + + /** + * Get all of the data except for a specified array of items. + * + * @param array|mixed $keys + * @return array + */ + public function except($keys) + { + $keys = is_array($keys) ? $keys : func_get_args(); + + $results = $this->all(); + + Arr::forget($results, $keys); + + return $results; + } +} diff --git a/tests/Support/SupportFluentTest.php b/tests/Support/SupportFluentTest.php index 07c883c55a2a..07eb151fb9cd 100755 --- a/tests/Support/SupportFluentTest.php +++ b/tests/Support/SupportFluentTest.php @@ -3,11 +3,17 @@ namespace Illuminate\Tests\Support; use ArrayIterator; +use Illuminate\Support\Carbon; +use Illuminate\Support\Collection; use Illuminate\Support\Fluent; +use Illuminate\Support\Stringable; +use InvalidArgumentException; use IteratorAggregate; use PHPUnit\Framework\TestCase; use ReflectionObject; +include_once 'Enums.php'; + class SupportFluentTest extends TestCase { public function testAttributesAreSetByConstructor() @@ -133,6 +139,241 @@ public function testToCollection() $fluent = new Fluent(['authors' => ['taylor' => ['products' => ['forge', 'vapour', 'spark']]]]); $this->assertEquals(['forge', 'vapour', 'spark'], $fluent->collect('authors.taylor.products')->all()); } + + public function testStringMethod() + { + $fluent = new Fluent([ + 'int' => 123, + 'int_str' => '456', + 'float' => 123.456, + 'float_str' => '123.456', + 'float_zero' => 0.000, + 'float_str_zero' => '0.000', + 'str' => 'abc', + 'empty_str' => '', + 'null' => null, + ]); + $this->assertTrue($fluent->string('int') instanceof Stringable); + $this->assertTrue($fluent->string('unknown_key') instanceof Stringable); + $this->assertSame('123', $fluent->string('int')->value()); + $this->assertSame('456', $fluent->string('int_str')->value()); + $this->assertSame('123.456', $fluent->string('float')->value()); + $this->assertSame('123.456', $fluent->string('float_str')->value()); + $this->assertSame('0', $fluent->string('float_zero')->value()); + $this->assertSame('0.000', $fluent->string('float_str_zero')->value()); + $this->assertSame('', $fluent->string('empty_str')->value()); + $this->assertSame('', $fluent->string('null')->value()); + $this->assertSame('', $fluent->string('unknown_key')->value()); + } + + public function testBooleanMethod() + { + $fluent = new Fluent(['with_trashed' => 'false', 'download' => true, 'checked' => 1, 'unchecked' => '0', 'with_on' => 'on', 'with_yes' => 'yes']); + $this->assertTrue($fluent->boolean('checked')); + $this->assertTrue($fluent->boolean('download')); + $this->assertFalse($fluent->boolean('unchecked')); + $this->assertFalse($fluent->boolean('with_trashed')); + $this->assertFalse($fluent->boolean('some_undefined_key')); + $this->assertTrue($fluent->boolean('with_on')); + $this->assertTrue($fluent->boolean('with_yes')); + } + + public function testIntegerMethod() + { + $fluent = new Fluent([ + 'int' => '123', + 'raw_int' => 456, + 'zero_padded' => '078', + 'space_padded' => ' 901', + 'nan' => 'nan', + 'mixed' => '1ab', + 'underscore_notation' => '2_000', + 'null' => null, + ]); + $this->assertSame(123, $fluent->integer('int')); + $this->assertSame(456, $fluent->integer('raw_int')); + $this->assertSame(78, $fluent->integer('zero_padded')); + $this->assertSame(901, $fluent->integer('space_padded')); + $this->assertSame(0, $fluent->integer('nan')); + $this->assertSame(1, $fluent->integer('mixed')); + $this->assertSame(2, $fluent->integer('underscore_notation')); + $this->assertSame(123456, $fluent->integer('unknown_key', 123456)); + $this->assertSame(0, $fluent->integer('null')); + $this->assertSame(0, $fluent->integer('null', 123456)); + } + + public function testFloatMethod() + { + $fluent = new Fluent([ + 'float' => '1.23', + 'raw_float' => 45.6, + 'decimal_only' => '.6', + 'zero_padded' => '0.78', + 'space_padded' => ' 90.1', + 'nan' => 'nan', + 'mixed' => '1.ab', + 'scientific_notation' => '1e3', + 'null' => null, + ]); + $this->assertSame(1.23, $fluent->float('float')); + $this->assertSame(45.6, $fluent->float('raw_float')); + $this->assertSame(.6, $fluent->float('decimal_only')); + $this->assertSame(0.78, $fluent->float('zero_padded')); + $this->assertSame(90.1, $fluent->float('space_padded')); + $this->assertSame(0.0, $fluent->float('nan')); + $this->assertSame(1.0, $fluent->float('mixed')); + $this->assertSame(1e3, $fluent->float('scientific_notation')); + $this->assertSame(123.456, $fluent->float('unknown_key', 123.456)); + $this->assertSame(0.0, $fluent->float('null')); + $this->assertSame(0.0, $fluent->float('null', 123.456)); + } + + public function testCollectMethod() + { + $fluent = new Fluent(['users' => [1, 2, 3]]); + + $this->assertInstanceOf(Collection::class, $fluent->collect('users')); + $this->assertTrue($fluent->collect('developers')->isEmpty()); + $this->assertEquals([1, 2, 3], $fluent->collect('users')->all()); + $this->assertEquals(['users' => [1, 2, 3]], $fluent->collect()->all()); + + $fluent = new Fluent(['text-payload']); + $this->assertEquals(['text-payload'], $fluent->collect()->all()); + + $fluent = new Fluent(['email' => 'test@example.com']); + $this->assertEquals(['test@example.com'], $fluent->collect('email')->all()); + + $fluent = new Fluent([]); + $this->assertInstanceOf(Collection::class, $fluent->collect()); + $this->assertTrue($fluent->collect()->isEmpty()); + + $fluent = new Fluent(['users' => [1, 2, 3], 'roles' => [4, 5, 6], 'foo' => ['bar', 'baz'], 'email' => 'test@example.com']); + $this->assertInstanceOf(Collection::class, $fluent->collect(['users'])); + $this->assertTrue($fluent->collect(['developers'])->isEmpty()); + $this->assertTrue($fluent->collect(['roles'])->isNotEmpty()); + $this->assertEquals(['roles' => [4, 5, 6]], $fluent->collect(['roles'])->all()); + $this->assertEquals(['users' => [1, 2, 3], 'email' => 'test@example.com'], $fluent->collect(['users', 'email'])->all()); + $this->assertEquals(collect(['roles' => [4, 5, 6], 'foo' => ['bar', 'baz']]), $fluent->collect(['roles', 'foo'])); + $this->assertEquals(['users' => [1, 2, 3], 'roles' => [4, 5, 6], 'foo' => ['bar', 'baz'], 'email' => 'test@example.com'], $fluent->collect()->all()); + } + + public function testDateMethod() + { + $fluent = new Fluent([ + 'as_null' => null, + 'as_invalid' => 'invalid', + + 'as_datetime' => '20-01-01 16:30:25', + 'as_format' => '1577896225', + 'as_timezone' => '20-01-01 13:30:25', + + 'as_date' => '2020-01-01', + 'as_time' => '16:30:25', + ]); + + $current = Carbon::create(2020, 1, 1, 16, 30, 25); + + $this->assertNull($fluent->date('as_null')); + $this->assertNull($fluent->date('doesnt_exists')); + + $this->assertEquals($current, $fluent->date('as_datetime')); + $this->assertEquals($current->format('Y-m-d H:i:s P'), $fluent->date('as_format', 'U')->format('Y-m-d H:i:s P')); + $this->assertEquals($current, $fluent->date('as_timezone', null, 'America/Santiago')); + + $this->assertTrue($fluent->date('as_date')->isSameDay($current)); + $this->assertTrue($fluent->date('as_time')->isSameSecond('16:30:25')); + } + + public function testDateMethodExceptionWhenValueInvalid() + { + $this->expectException(InvalidArgumentException::class); + + $fluent = new Fluent([ + 'date' => 'invalid', + ]); + + $fluent->date('date'); + } + + public function testDateMethodExceptionWhenFormatInvalid() + { + $this->expectException(InvalidArgumentException::class); + + $fluent = new Fluent([ + 'date' => '20-01-01 16:30:25', + ]); + + $fluent->date('date', 'invalid_format'); + } + + public function testEnumMethod() + { + $fluent = new Fluent([ + 'valid_enum_value' => 'A', + 'invalid_enum_value' => 'invalid', + 'empty_value_request' => '', + 'string' => [ + 'a' => '1', + 'b' => '2', + 'doesnt_exist' => '-1024', + ], + 'int' => [ + 'a' => 1, + 'b' => 2, + 'doesnt_exist' => 1024, + ], + ]); + + $this->assertNull($fluent->enum('doesnt_exist', TestEnum::class)); + + $this->assertEquals(TestStringBackedEnum::A, $fluent->enum('valid_enum_value', TestStringBackedEnum::class)); + + $this->assertNull($fluent->enum('invalid_enum_value', TestStringBackedEnum::class)); + $this->assertNull($fluent->enum('empty_value_request', TestStringBackedEnum::class)); + $this->assertNull($fluent->enum('valid_enum_value', TestEnum::class)); + + $this->assertEquals(TestBackedEnum::A, $fluent->enum('string.a', TestBackedEnum::class)); + $this->assertEquals(TestBackedEnum::B, $fluent->enum('string.b', TestBackedEnum::class)); + $this->assertNull($fluent->enum('string.doesnt_exist', TestBackedEnum::class)); + $this->assertEquals(TestBackedEnum::A, $fluent->enum('int.a', TestBackedEnum::class)); + $this->assertEquals(TestBackedEnum::B, $fluent->enum('int.b', TestBackedEnum::class)); + $this->assertNull($fluent->enum('int.doesnt_exist', TestBackedEnum::class)); + } + + public function testEnumsMethod() + { + $fluent = new Fluent([ + 'valid_enum_values' => ['A', 'B'], + 'invalid_enum_values' => ['invalid', 'invalid'], + 'empty_value_request' => [], + 'string' => [ + 'a' => ['1', '2'], + 'b' => '2', + 'doesnt_exist' => '-1024', + ], + 'int' => [ + 'a' => [1, 2], + 'b' => 2, + 'doesnt_exist' => 1024, + ], + ]); + + $this->assertEmpty($fluent->enums('doesnt_exist', TestEnum::class)); + + $this->assertEquals([TestStringBackedEnum::A, TestStringBackedEnum::B], $fluent->enums('valid_enum_values', TestStringBackedEnum::class)); + + $this->assertEmpty($fluent->enums('invalid_enum_value', TestStringBackedEnum::class)); + $this->assertEmpty($fluent->enums('empty_value_request', TestStringBackedEnum::class)); + $this->assertEmpty($fluent->enums('valid_enum_value', TestEnum::class)); + + $this->assertEquals([TestBackedEnum::A, TestBackedEnum::B], $fluent->enums('string.a', TestBackedEnum::class)); + $this->assertEquals([TestBackedEnum::B], $fluent->enums('string.b', TestBackedEnum::class)); + $this->assertEmpty($fluent->enums('string.doesnt_exist', TestBackedEnum::class)); + + $this->assertEquals([TestBackedEnum::A, TestBackedEnum::B], $fluent->enums('int.a', TestBackedEnum::class)); + $this->assertEquals([TestBackedEnum::B], $fluent->enums('int.b', TestBackedEnum::class)); + $this->assertEmpty($fluent->enums('int.doesnt_exist', TestBackedEnum::class)); + } } class FluentArrayIteratorStub implements IteratorAggregate