Skip to content

The AsCollection::class cast does not behave the same as "collection" cast when mutating the collection object. #49995

Closed
@Waghabond

Description

@Waghabond

Laravel Version

10.43.0

PHP Version

8.3.2

Database Driver & Version

Postgres 16

Description

TLDR: the "collection" cast is not able to handle mutations but AsCollection:class handles mutations correctly. These casts should both behave the same as how the AsCollection::class cast behaves.

Consider the following models.

// testAttr is a non-nullable json column with default = "[]"
class MyAsCollectionModel extends Model
{
    protected $casts = ["testAttr" => AsCollection::class];

    protected $attributes = ["testAttr" => "[]"];
}

class MyCollectionModel extends Model
{
    protected $casts = ["testAttr" => "collection"];

    protected $attributes = ["testAttr" => "[]"];
}

The following are examples of the behaviour of the casted attribute for the two models respectively (in the tinker interactive console).

$x = MyAsCollectionModel::first();
// App\Models\MyAsCollectionModel {#6219
//     id: 1,
//     testAttr: "[]",
//   }

$x->testAttr;
// Illuminate\Support\Collection {#6220
//     all: [],
// }

$x->testAttr[] = 'hi taylor';
// "hi taylor"

$x->testAttr;
// Illuminate\Support\Collection {#6220
//     all: [
//         "hi taylor",
//     ],
// }

$x;
// App\Models\MyAsCollectionModel {#6219
//     id: 1,
//     testAttr: "["hi taylor"]",
//   }

$x->testAttr = collect(["I'm a new collection"]);
// Illuminate\Support\Collection {#6221
//     all: [
//         "I'm a new collection",
//     ],
// }

$x->testAttr;
// Illuminate\Support\Collection {#6221
//     all: [
//         "I'm a new collection",
//     ],
// }

$x;
// App\Models\MyAsCollectionModel {#6219
//     id: 1,
//     testAttr: "["I'm a new collection"]",
//   }

vs

$x = MyCollectionModel::first();
// App\Models\MyCollectionModel {#6232
//     id: 1,
//     testAttr: "[]",
//   }

$x->testAttr;
// Illuminate\Support\Collection {#6233
//     all: [],
// }

$x->testAttr[] = 'hi taylor';
// "hi taylor"

$x->testAttr;
// Illuminate\Support\Collection {#6234
//     all: [],
// }

$x;
// App\Models\MyCollectionModel {#6232
//     id: 1,
//     testAttr: "[]",
//   }

$x->testAttr = collect(["I'm a new collection"]);
// Illuminate\Support\Collection {#6235
//     all: [
//         "I'm a new collection",
//     ],
// }

$x->testAttr;
// Illuminate\Support\Collection {#6236
//     all: [
//         "I'm a new collection",
//     ],
// }

$x;
// App\Models\MyCollectionModel {#6232
//     id: 1,
//     testAttr: "["I'm a new collection"]",
//   }

As we can see, appending items to the collection doesn't behave the same for these casts. This seems to be because the "collection" cast is instantiating a new collection every time by JSON decoding the model's data, where as AsCollection doesn't do the same and is able to handle mutations correctly.

I believe that both of these casts should be behaving how AsCollection behaves.

I can provide a minimum recreation of this issue if required and might also endeavour to try creating a PR providing a fix.

Steps To Reproduce

Create a model with a json column that is getting cast to "collection", and an identical model which is casting the column to AsCollection::class. These casts will not behave the same as demonstrated in the description.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions