> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/spatie/laravel-data/llms.txt
> Use this file to discover all available pages before exploring further.

# Collections

> Create and work with collections of data objects using arrays, Laravel collections, and paginators.

It is possible to create a collection of data objects by using the `collect` method:

```php theme={null}
SongData::collect([
    ['title' => 'Never Gonna Give You Up', 'artist' => 'Rick Astley'],
    ['title' => 'Giving Up on Love', 'artist' => 'Rick Astley'],
]); // returns an array of SongData objects
```

Whatever type of collection you pass in, the package will return the same type of collection with the freshly created data objects within it. As long as this type is an array, Laravel collection or paginator or a class extending from it.

## Working with Eloquent Collections

This opens up possibilities to create collections of Eloquent models:

```php theme={null}
SongData::collect(Song::all()); // return an Eloquent collection of SongData objects
```

## Working with Paginators

Or use a paginator:

```php theme={null}
SongData::collect(Song::paginate()); // return a LengthAwarePaginator of SongData objects

// or

SongData::collect(Song::cursorPaginate()); // return a CursorPaginator of SongData objects
```

<Note>
  Internally the `from` method of the data class will be used to create a new data object for each item in the collection.
</Note>

## Collections Already Containing Data Objects

When the collection already contains data objects, the `collect` method will return the same collection:

```php theme={null}
SongData::collect([
    SongData::from(['title' => 'Never Gonna Give You Up', 'artist' => 'Rick Astley']),
    SongData::from(['title' => 'Giving Up on Love', 'artist' => 'Rick Astley']),
]); // returns an array of SongData objects
```

## Type Transformation

The collect method also allows you to cast collections from one type into another. For example, you can pass in an `array` and get back a Laravel collection:

```php theme={null}
SongData::collect($songs, Collection::class); // returns a Laravel collection of SongData objects
```

<Note>
  This transformation will only work with non-paginator collections.
</Note>

## Magically Creating Collections

We've already seen that `from` can create data objects magically. It is also possible to create a collection of data objects magically when using `collect`.

Let's say you've implemented a custom collection class called `SongCollection`:

```php theme={null}
class SongCollection extends Collection
{
    public function __construct(
        $items = [],
        public array $artists = [],
    ) {
        parent::__construct($items);
    }
}
```

Since the constructor of this collection requires an extra property it cannot be created automatically. However, it is possible to define a custom collect method which can create it:

```php theme={null}
class SongData extends Data
{
    public string $title;
    public string $artist;

    public static function collectArray(array $items): SongCollection
    {
        return new SongCollection(
            parent::collect($items),
            array_unique(array_map(fn(SongData $song) => $song->artist, $items))
        );
    }
}
```

Now when collecting an array data objects a `SongCollection` will be returned:

```php theme={null}
SongData::collectArray([
    ['title' => 'Never Gonna Give You Up', 'artist' => 'Rick Astley'],
    ['title' => 'Living on a prayer', 'artist' => 'Bon Jovi'],
]); // returns an SongCollection of SongData objects
```

### Requirements for Magical Collection Methods

There are a few requirements for this to work:

* The method must be **static**
* The method must be **public**
* The method must have a **return type**
* The method name must **start with collect**
* The method name must not be **collect**

## Creating a Data Object with Collections

You can create a data object with a collection of data objects just like you would create a data object with a nested data object:

```php theme={null}
use App\Data\SongData;
use Illuminate\Support\Collection;

class AlbumData extends Data
{    
    public string $title;
    /** @var Collection<int, SongData> */
    public Collection $songs;
}

AlbumData::from([
    'title' => 'Never Gonna Give You Up',
    'songs' => [
        ['title' => 'Never Gonna Give You Up', 'artist' => 'Rick Astley'],
        ['title' => 'Giving Up on Love', 'artist' => 'Rick Astley'],
    ]
]);
```

Since the collection type here is a `Collection`, the package will automatically convert the array into a collection of data objects.

## DataCollections, PaginatedDataCollections and CursorPaginatedCollections

The package also provides a few collection classes which can be used to create collections of data objects. It was a requirement to use these classes in the past versions of the package when nesting data objects collections in data objects. This is no longer the case, but there are still valid use cases for them.

You can create a DataCollection like this:

```php theme={null}
use Spatie\LaravelData\DataCollection;

SongData::collect(Song::all(), DataCollection::class);
```

A PaginatedDataCollection can be created like this:

```php theme={null}
use Spatie\LaravelData\PaginatedDataCollection;

SongData::collect(Song::paginate(), PaginatedDataCollection::class);
```

And a CursorPaginatedCollection can be created like this:

```php theme={null}
use Spatie\LaravelData\CursorPaginatedCollection;

SongData::collect(Song::cursorPaginate(), CursorPaginatedCollection::class);
```

## Transforming paginated collection items

Both `PaginatedDataCollection` and `CursorPaginatedDataCollection` support the `through()` method to transform items in the collection:

```php theme={null}
$paginatedPosts = PostData::collect($posts->paginate(10));

// Transform each item in the paginated collection
$transformedPosts = $paginatedPosts->through(function (PostData $post) {
    return new EnrichedPostData(
        ...$post->toArray(),
        view_count: $post->calculateViews(),
    );
});
```

The `through()` method returns a new collection with transformed items while preserving pagination information.

<Info>
  This works identically for both `PaginatedDataCollection` (using `paginate()`) and `CursorPaginatedDataCollection` (using `cursorPaginate()`).
</Info>

### Why Use These Collection Classes?

We advise you to always use arrays, Laravel collections and paginators within your data objects. But let's say you have a controller like this:

```php theme={null}
class SongController
{
    public function index()
    {
        return SongData::collect(Song::all());    
    }
}
```

In the next chapters of this documentation, we'll see that it is possible to include or exclude properties from the data objects like this:

```php theme={null}
class SongController
{
    public function index()
    {
        return SongData::collect(Song::all(), DataCollection::class)->include('artist');    
    }
}
```

<Note>
  This will only work when you're using a `DataCollection`, `PaginatedDataCollection` or `CursorPaginatedCollection`.
</Note>

### DataCollection Methods

DataCollections provide some extra functionalities like:

```php theme={null}
// Counting the amount of items in the collection
count($collection);

// Changing an item in the collection
$collection[0]->title = 'Giving Up on Love';

// Adding an item to the collection
$collection[] = SongData::from(['title' => 'Never Knew Love', 'artist' => 'Rick Astley']);

// Removing an item from the collection
unset($collection[0]);
```

It is even possible to loop over it with a foreach:

```php theme={null}
foreach ($songs as $song){
    echo $song->title;
}
```

The `DataCollection` class implements a few of the Laravel collection methods:

* through
* map
* filter
* first
* each
* values
* where
* reduce
* sole

You can, for example, get the first item within a collection like this:

```php theme={null}
SongData::collect(Song::all(), DataCollection::class)->first(); // SongData object
```

### The `collection` Method

In previous versions of the package it was possible to use the `collection` method to create a collection of data objects:

```php theme={null}
SongData::collection(Song::all()); // returns a DataCollection of SongData objects
SongData::collection(Song::paginate()); // returns a PaginatedDataCollection of SongData objects
SongData::collection(Song::cursorPaginate()); // returns a CursorPaginatedCollection of SongData objects
```

This method was removed with version v4 of the package in favor for the more powerful `collect` method. The `collection` method can still be used by using the `WithDeprecatedCollectionMethod` trait:

```php theme={null}
use Spatie\LaravelData\Concerns\WithDeprecatedCollectionMethod;

class SongData extends Data
{
    use WithDeprecatedCollectionMethod;
    
    // ...
}
```

<Warning>
  Please note that this trait will be removed in the next major version of the package.
</Warning>
