Error "cannot use object of type AppDataTransferObjectsTestDTO as array" in Laravel when working with collection of DTOs

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 AppDataTransferObjects;
​
use IlluminateSupportCollection;
​
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.

AppDataTransferObjectsTestDTOCollection^ {#942
  #items: array:2 [
    0 => AppDataTransferObjectsTestDTO^ {#962
      +id: "0123456789"
      #exceptKeys: []
      #onlyKeys: []
    }
    1 => AppDataTransferObjectsTestDTO^ {#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 AppDataTransferObjectsTestDTO 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 I don’t understand is that I’m definitely not trying to use TestDTO as an array in the constructor or anywhere else, and yet this error still pops up—and even weirder still, it points to the TestDTOCollection constructor.

For reference, here is the TestDTO class:

namespace AppDataTransferObjects;

use SpatieDataTransferObjectDataTransferObject;

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. Do some Collection methods like filter expect to work with arrays under the hood or is there something else happening?

Source: Laravel

Leave a Reply