I'm trying to create a custom collection of a specific type of Data Transfer Objects. I'm using the "spatie/data-transfer-object" package.
Here is a test class I'm using to debug this issue that popped up within the last few days.
namespace App\DataTransferObjects;
use Illuminate\Support\Collection;
class TestDTOCollection extends Collection
{
public function __construct($items)
{
$DTOs = [];
foreach($items as $item) {
array_push($DTOs, new TestDTO(
id: $item['id'],
));
}
parent::__construct($DTOs);
}
}
I'm using it like this elsewhere:
$collection = TestDTOCollection::make($items);
dd($collection);
The output is the contents of the collection containing TestDTO objects, as expected.
App\DataTransferObjects\TestDTOCollection^ {#942
#items: array:2 [
0 => App\DataTransferObjects\TestDTO^ {#962
+id: "0123456789"
#exceptKeys: []
#onlyKeys: []
}
1 => App\DataTransferObjects\TestDTO^ {#986
+id: "000000000"
#exceptKeys: []
#onlyKeys: []
}
]
}
But if I use the filter method too:
TestDTOCollection::make($items)
->filter(fn ($item) => $item->id === $someId));
it'll throw this error:
Cannot use object of type App\DataTransferObjects\TestDTO as array
at app/DataTransferObjects/TestDTOCollection.php:15
11▕ $DTOs = [];
12▕
13▕ foreach($items as $item) {
14▕ array_push($DTOs, new TestDTO(
➜ 15▕ id: $item['id'],
16▕ ));
17▕ }
18▕
19▕ parent::__construct($DTOs);
What's made this difficult to debug is that I'm definitely not trying to use TestDTO objects as arrays in the constructor or anywhere else, and yet this error still pops up—and even weirder still, it points to the TestDTOCollection constructor after the collection is instantiated without any problems.
For reference, here is the TestDTO class:
namespace App\DataTransferObjects;
use Spatie\DataTransferObject\DataTransferObject;
class TestDTO extends DataTransferObject
{
public string $id;
}
I'm using Laravel 8 with PHP 8. I was instantiating my DTOs using PHP 8's named arguments syntax and that much does seem to work, so I'm very stumped on how to fix this or what's even wrong in the first place.
Small update
It seems when I'm not using a custom collection class, it just works as expected. For example:
collect($items)
->transform(fn ($item) => new TestDTO(
id: $item['id'],
))
->filter(fn ($item) => isset($item->id));
Still, if anyone is able to help me figure out why this is happening, I'd greatly appreciate it. I'll move along for now, but I hate not at least knowing why what I was doing wasn't working, especially if the issue is so hazy.