laravel / ideas

Issues board used for Laravel internals discussions.
940 stars 28 forks source link

Improve Eloquent casting for collection type #460

Closed arcanedev-maroc closed 4 years ago

arcanedev-maroc commented 7 years ago

I'm wondering if it's a good idea to return an empty Collection object instead of null when we specify a casting like this:

// Meta Model Class

protected $casts = [
    'keywords' => 'collection',
];

This will avoid us to add more checks like is_null($this->keywords). And it's views friendly when you do something like this {{ $meta->keywords->implode(', ') }}.

And for if statement, i prefer to do something like @if ($meta->keywords->isEmpty()) than @if (is_null($meta->keywords)).

So, my PR will be something like this (At this section on master branch):

/**
 * Cast an attribute to a native PHP type.
 *
 * @param  string  $key
 * @param  mixed  $value
 * @return mixed
 */
protected function castAttribute($key, $value)
{
    if (is_null($value)) {
        return $this->castNullAttribute($key, $value);
    }

    switch ($this->getCastType($key)) {
        case 'int':
        case 'integer':
            return (int) $value;
        case 'real':
        case 'float':
        case 'double':
            return (float) $value;
        case 'string':
            return (string) $value;
        case 'bool':
        case 'boolean':
            return (bool) $value;
        case 'object':
            return $this->fromJson($value, true);
        case 'array':
        case 'json':
            return $this->fromJson($value);
        case 'collection':
            return new BaseCollection($this->fromJson($value));
        case 'date':
            return $this->asDate($value);
        case 'datetime':
            return $this->asDateTime($value);
        case 'timestamp':
            return $this->asTimestamp($value);
        default:
            return $value;
    }
}

/**
 * Cast a null attribute.
 *
 * @param  string  $key
 * @param  mixed  $value
 * @return mixed
 */
protected function castNullAttribute($key, $value)
{
    switch ($this->getCastType($key)) {
        case 'collection':
            return new BaseCollection;
        default:
            return $value;
    }
}

We can also add array to the casts instead returning a null value.

/**
 * Cast a null attribute.
 *
 * @param  string  $key
 * @param  mixed  $value
 * @return mixed
 */
protected function castNullAttribute($key, $value)
{
    switch ($this->getCastType($key)) {
        case 'array':
            return [];
        case 'collection':
            return new BaseCollection;
        default:
            return $value;
    }
}

cc: @taylorotwell @themsaid @GrahamCampbell

sisve commented 7 years ago

This seems related to #9 (Improve Typecasting)

taylorotwell commented 7 years ago

I agree an empty collection may make sense in this situation. But haven't thought through it fully.

suadhuskic commented 6 years ago

+1

linaspasv commented 6 years ago

@arcanedev-maroc when could we expect PR for this?

sisve commented 6 years ago

It would make sense to add a not-null collection cast (another cast) for this feature to allow code to check for null values vs empty collections. Different models (or same model in different context) may behave differently.

darron1217 commented 6 years ago

I created PR to close this issue :)

linaspasv commented 5 years ago

It's a shame that this idea was not implemented yet.

basepack commented 5 years ago

Yes a great idea, my +1 on it 👍

innocenzi commented 5 years ago

Any news on that? Sounds really great.

kfirba commented 5 years ago

Is this going to get implemented :)?

andrey-helldar commented 4 years ago

@arcanedev-maroc, if I understand your problem correctly, the changes proposed in laravel/framework#30958 will make it easy to solve.