Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
4d4c098
[6.x] The `hasAttributes` trait is divided into two: `hasAttributes` …
Dec 27, 2019
1dfd194
[6.x] Added creation of custom Cast classes for Eloquent
Dec 27, 2019
3920b01
[6.x] Added make console command of custom Cast
Dec 27, 2019
67e2562
Updated codestyle
Dec 27, 2019
3914f73
Fixed docblocks
Dec 28, 2019
ec1ba01
Fixed docblock
Dec 28, 2019
f67cb97
Fixed transfer of null value to custom castes
Dec 28, 2019
38b62f9
Fixed getting values for custom castes
Dec 28, 2019
f7689b4
Added verification and storage of initialized instances of custom castes
Dec 28, 2019
0503111
Fixed null-casting test
Dec 28, 2019
99f4ded
Fixed procedure for checking NULL values
Dec 28, 2019
27eb546
Added test for checking NULL values
Dec 28, 2019
4b8a2d1
Fixed `return null` style-ci errors
Dec 28, 2019
0954ebf
Fixed cast.stub file for the custom Cast console command creating
Dec 28, 2019
ad8adbc
Changed the variable name from snake_case to camelCase.
Dec 29, 2019
6fa8bd1
Updated docblocks
Dec 29, 2019
febda92
Updated make:cast command description
Dec 29, 2019
d5ddc3b
Updated test for DateTime custom case testing
Dec 29, 2019
ce3985a
Added the ability to store the key and the original value in custom c…
Dec 29, 2019
e578d21
The `get` and `set` methods are renamed `fromDatabase` and `toDatabas…
Dec 29, 2019
92db2cd
The `hasAttributes` trait split has been canceled
Dec 29, 2019
eb397ef
Small fixed code in the `hasAttributes` trait
Dec 29, 2019
064353a
`array_key_exists` function replaced with faster `isset`
Dec 30, 2019
3e51364
Replaced class instance creation method
Dec 30, 2019
493e4d7
Added method call skipped when canceling the separation of traits
Dec 30, 2019
13ceace
The principle of creating a container has been changed
Dec 30, 2019
3446cbe
Added a docblock for the `registerCastMakeCommand` method
Dec 30, 2019
d62cd8d
Storage of custom Cast instances transferred to the global static arr…
Dec 30, 2019
14720d4
Updated docblock
Dec 30, 2019
b8adc68
Replaced `new $cast` by Container make method
Dec 30, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions src/Illuminate/Contracts/Database/Eloquent/Castable.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

namespace Illuminate\Contracts\Database\Eloquent;

interface Castable
{
/**
* Get a given attribute from the model.
*
* @param string $key
* @param mixed $value
* @return mixed
*/
public function fromDatabase($key, $value = null);

/**
* Set a given attribute on the model.
*
* @param string $key
* @param mixed $value
* @return mixed
*/
public function toDatabase($key, $value = null);
}
112 changes: 109 additions & 3 deletions src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

use Carbon\CarbonInterface;
use DateTimeInterface;
use Illuminate\Container\Container;
use Illuminate\Contracts\Database\Eloquent\Castable;
use Illuminate\Contracts\Support\Arrayable;
use Illuminate\Database\Eloquent\JsonEncodingException;
use Illuminate\Database\Eloquent\Relations\Relation;
Expand Down Expand Up @@ -79,10 +81,18 @@ trait HasAttributes
*/
protected static $mutatorCache = [];

/**
* Initialized instances of custom casts.
*
* @var \Illuminate\Contracts\Database\Eloquent\Castable[]
*/
protected static $castsCache = [];

/**
* Convert the model's attributes to an array.
*
* @return array
* @throws \Illuminate\Contracts\Container\BindingResolutionException
*/
public function attributesToArray()
{
Expand Down Expand Up @@ -169,6 +179,7 @@ protected function addMutatedAttributesToArray(array $attributes, array $mutated
* @param array $attributes
* @param array $mutatedAttributes
* @return array
* @throws \Illuminate\Contracts\Container\BindingResolutionException
*/
protected function addCastAttributesToArray(array $attributes, array $mutatedAttributes)
{
Expand Down Expand Up @@ -308,6 +319,7 @@ protected function getArrayableItems(array $values)
*
* @param string $key
* @return mixed
* @throws \Illuminate\Contracts\Container\BindingResolutionException
*/
public function getAttribute($key)
{
Expand Down Expand Up @@ -338,6 +350,7 @@ public function getAttribute($key)
*
* @param string $key
* @return mixed
* @throws \Illuminate\Contracts\Container\BindingResolutionException
*/
public function getAttributeValue($key)
{
Expand Down Expand Up @@ -474,9 +487,14 @@ protected function mutateAttributeForArray($key, $value)
* @param string $key
* @param mixed $value
* @return mixed
* @throws \Illuminate\Contracts\Container\BindingResolutionException
*/
protected function castAttribute($key, $value)
{
if ($this->isCustomCastable($key)) {
return $this->fromCustomCastable($key, $value);
}

if (is_null($value)) {
return $value;
}
Expand Down Expand Up @@ -523,15 +541,17 @@ protected function castAttribute($key, $value)
*/
protected function getCastType($key)
{
if ($this->isCustomDateTimeCast($this->getCasts()[$key])) {
$cast = $this->getCast($key);

if ($this->isCustomDateTimeCast($cast)) {
return 'custom_datetime';
}

if ($this->isDecimalCast($this->getCasts()[$key])) {
if ($this->isDecimalCast($cast)) {
return 'decimal';
}

return trim(strtolower($this->getCasts()[$key]));
return trim(strtolower($cast));
}

/**
Expand All @@ -557,12 +577,28 @@ protected function isDecimalCast($cast)
return strncmp($cast, 'decimal:', 8) === 0;
}

/**
* Is the checked value a custom Cast.
*
* @param string $key
* @return bool
*/
protected function isCustomCastable($key)
{
if ($cast = $this->getCast($key)) {
return is_subclass_of($cast, Castable::class);
}

return false;
}

/**
* Set a given attribute on the model.
*
* @param string $key
* @param mixed $value
* @return mixed
* @throws \Illuminate\Contracts\Container\BindingResolutionException
*/
public function setAttribute($key, $value)
{
Expand All @@ -580,6 +616,12 @@ public function setAttribute($key, $value)
$value = $this->fromDateTime($value);
}

// If the attribute is specified as Cast, we will convert it according to
// the method specified in it.
if ($this->isCustomCastable($key)) {
$value = $this->toCustomCastable($key, $value);
}

if ($this->isJsonCastable($key) && ! is_null($value)) {
$value = $this->castAttributeAsJson($key, $value);
}
Expand Down Expand Up @@ -929,6 +971,17 @@ public function getCasts()
return $this->casts;
}

/**
* Get the cast from casts array.
*
* @param string $key
* @return string|null
*/
public function getCast($key)
{
return $this->getCasts()[$key] ?? null;
}

/**
* Determine whether a value is Date / DateTime castable for inbound manipulation.
*
Expand All @@ -951,6 +1004,53 @@ protected function isJsonCastable($key)
return $this->hasCast($key, ['array', 'json', 'object', 'collection']);
}

/**
* Getting the execution result from a user Cast object.
*
* @param string $key
* @param mixed $value
* @return mixed
* @throws \Illuminate\Contracts\Container\BindingResolutionException
*/
protected function fromCustomCastable($key, $value = null)
{
return $this
->normalizeCastToCallable($key)
->fromDatabase($key, $value);
}

/**
* Converting a value by custom Cast.
*
* @param string $key
* @param mixed $value
* @return mixed
* @throws \Illuminate\Contracts\Container\BindingResolutionException
*/
protected function toCustomCastable($key, $value = null)
{
return $this
->normalizeCastToCallable($key)
->toDatabase($key, $value);
}

/**
* Getting a custom cast instance.
*
* @param string $key
* @return \Illuminate\Contracts\Database\Eloquent\Castable
* @throws \Illuminate\Contracts\Container\BindingResolutionException
*/
protected function normalizeCastToCallable($key)
{
if (! isset(static::$castsCache[$key])) {
static::$castsCache[$key] = Container::getInstance()
->make($this->getCast($key));
}

return static::$castsCache[$key];
}

/**
* Get all of the current attributes on the model.
*
Expand Down Expand Up @@ -996,6 +1096,7 @@ public function getOriginal($key = null, $default = null)
*
* @param array|mixed $attributes
* @return array
* @throws \Illuminate\Contracts\Container\BindingResolutionException
*/
public function only($attributes)
{
Expand Down Expand Up @@ -1052,6 +1153,7 @@ public function syncOriginalAttributes($attributes)
* Sync the changed attributes.
*
* @return $this
* @throws \Illuminate\Contracts\Container\BindingResolutionException
*/
public function syncChanges()
{
Expand All @@ -1065,6 +1167,7 @@ public function syncChanges()
*
* @param array|string|null $attributes
* @return bool
* @throws \Illuminate\Contracts\Container\BindingResolutionException
*/
public function isDirty($attributes = null)
{
Expand All @@ -1078,6 +1181,7 @@ public function isDirty($attributes = null)
*
* @param array|string|null $attributes
* @return bool
* @throws \Illuminate\Contracts\Container\BindingResolutionException
*/
public function isClean($attributes = null)
{
Expand Down Expand Up @@ -1129,6 +1233,7 @@ protected function hasChanges($changes, $attributes = null)
* Get the attributes that have been changed since last sync.
*
* @return array
* @throws \Illuminate\Contracts\Container\BindingResolutionException
*/
public function getDirty()
{
Expand Down Expand Up @@ -1159,6 +1264,7 @@ public function getChanges()
* @param string $key
* @param mixed $current
* @return bool
* @throws \Illuminate\Contracts\Container\BindingResolutionException
*/
public function originalIsEquivalent($key, $current)
{
Expand Down
51 changes: 51 additions & 0 deletions src/Illuminate/Foundation/Console/CastMakeCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<?php

namespace Illuminate\Foundation\Console;

use Illuminate\Console\GeneratorCommand;

class CastMakeCommand extends GeneratorCommand
{
/**
* The console command name.
*
* @var string
*/
protected $name = 'make:cast';

/**
* The console command description.
*
* @var string
*/
protected $description = 'Create a new custom Eloquent attribute caster';

/**
* The type of class being generated.
*
* @var string
*/
protected $type = 'Cast';

/**
* Get the stub file for the generator.
*
* @return string
*/
protected function getStub()
{
return __DIR__.'/stubs/cast.stub';
}

/**
* Get the default namespace for the class.
*
* @param string $rootNamespace
*
* @return string
*/
protected function getDefaultNamespace($rootNamespace)
{
return $rootNamespace.'\Casts';
}
}
32 changes: 32 additions & 0 deletions src/Illuminate/Foundation/Console/stubs/cast.stub
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

namespace DummyNamespace;

use Illuminate\Contracts\Database\Eloquent\Castable;

class DummyClass implements Castable
{
/**
* Get a given attribute from the model.
*
* @param string $key
* @param mixed $value
* @return mixed
*/
public function fromDatabase($key, $value = null)
{
return $value;
}

/**
* Set a given attribute on the model.
*
* @param string $key
* @param mixed $value
* @return mixed
*/
public function toDatabase($key, $value = null)
{
return $value;
}
}
14 changes: 14 additions & 0 deletions src/Illuminate/Foundation/Providers/ArtisanServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
use Illuminate\Database\Console\Seeds\SeedCommand;
use Illuminate\Database\Console\Seeds\SeederMakeCommand;
use Illuminate\Database\Console\WipeCommand;
use Illuminate\Foundation\Console\CastMakeCommand;
use Illuminate\Foundation\Console\ChannelMakeCommand;
use Illuminate\Foundation\Console\ClearCompiledCommand;
use Illuminate\Foundation\Console\ConfigCacheCommand;
Expand Down Expand Up @@ -130,6 +131,7 @@ class ArtisanServiceProvider extends ServiceProvider implements DeferrableProvid
'MailMake' => 'command.mail.make',
'MiddlewareMake' => 'command.middleware.make',
'ModelMake' => 'command.model.make',
'CastMake' => 'command.cast.make',
'NotificationMake' => 'command.notification.make',
'NotificationTable' => 'command.notification.table',
'ObserverMake' => 'command.observer.make',
Expand Down Expand Up @@ -486,6 +488,18 @@ protected function registerModelMakeCommand()
});
}

/**
* Register the command.
*
* @return void
*/
protected function registerCastMakeCommand()
{
$this->app->singleton('command.cast.make', function ($app) {
return new CastMakeCommand($app['files']);
});
}

/**
* Register the command.
*
Expand Down
Loading