larastan / larastan

⚗️ Adds code analysis to Laravel improving developer productivity and code quality.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Attributes cast as Collections incorrectly interpreted as non-nullable

JackWH opened this issue · comments

  • Larastan Version: 1.10.56
  • --level used: 5

Description

I'm probably doing something wrong here, but I've searched the repo and can't find anything...

I have an Eloquent model which has a fillable property called input_values. This is set as a collection in $casts = [...]. At the database-level, this is stored in a nullable JSON column.

There are no docblocks indicating this is guaranteed as a Collection, and even so, I have treatPhpDocTypesAsCertain: false in my config. But Larastan reports:

------ ------------------------------------------------------------------------------------------------
  Line   Example/ExampleModel.php
 ------ ------------------------------------------------------------------------------------------------
  251    Using nullsafe method call on non-nullable type Illuminate\Support\Collection. Use -> instead.
         ✏️  Example/ExampleModel.php
 ------ ------------------------------------------------------------------------------------------------

The affected line is shown below.

Laravel code where the issue was found

$fallbackValue = $this->input_values?->get($field->id, null) ?? $field->default;

I believe this is a false-positive, because input_values is only cast to a Collection when a non-null value is returned from the DB (as per Laravel docs).

Could be due to bad generics:

class AsCollection implements Castable
{
    /**
     * Get the caster class to use when casting from / to this cast target.
     *
     * @param  array  $arguments
     * @return \Illuminate\Contracts\Database\Eloquent\CastsAttributes<\Illuminate\Support\Collection<array-key, mixed>, iterable>
     */
    public static function castUsing(array $arguments)

Try adding null to the first type of CastsAttributes, and if that works then submit a pr to the framework

So I was digging into this, and the ModelPropertyExtension already adds null to the casted types if the column is nullable:

if ($column->nullable) {
$readableType = TypeCombinator::addNull($readableType);
$writableType = TypeCombinator::addNull($writableType);
}

@JackWH, are you sure the column is nullable? Can you whip up an example Laravel repo so I can replicate?