Skip to content

spatie/laravel-collection-macros

Folders and files

NameName
Last commit message
Last commit date
Aug 25, 2017
Aug 25, 2017
Jul 26, 2016
Jul 26, 2016
Jul 26, 2016
Jul 26, 2016
Aug 22, 2017
Aug 22, 2017
Aug 25, 2017
Jan 24, 2017
Aug 22, 2017
Aug 25, 2017
Aug 22, 2017
Jul 26, 2016

Repository files navigation

A set of useful Laravel collection macros

Latest Version on Packagist StyleCI Build Status SensioLabsInsight Quality Score Total Downloads

This repository contains some useful collection macros.

This version is targeted at Laravel 5.4. For Laravel 5.2 or 5.3, take a look at the v1 branch.

Spatie is a webdesign agency based in Antwerp, Belgium. You'll find an overview of all our open source projects on our website.

Postcardware

You're free to use this package (it's MIT-licensed), but if it makes it to your production environment you are required to send us a postcard from your hometown, mentioning which of our package(s) you are using.

Our address is: Spatie, Samberstraat 69D, 2060 Antwerp, Belgium.

The best postcards will get published on the open source page on our website.

Installation

You can pull in the package via composer:

composer require spatie/laravel-collection-macros

This service provider must be installed.

// config/app.php
'providers' => [
    ...
    Spatie\CollectionMacros\CollectionMacroServiceProvider::class,
];

Usage

These macro's will be added to the Illuminate\Support\Collection class.

dd

Dumps the contents of the collection and terminates the script. This macro makes debugging a collection much easier.

collect([1,2,3])->dd();

dump

Dumps the given arguments together with the current collection. This macro makes debugging a chain of collection functions much easier.

collect([1,2,3])
    ->dump('original')
    ->map(function(int $number) {
        return $number * 2;
    })
    ->dump('modified')
    ->dd();

ifAny

Executes the passed callable if the collection isn't empty. The entire collection will be returned.

collect()->ifAny(function(Collection $collection) { // empty collection so this won't get called
   echo 'Hello';
});

collect([1, 2, 3])->ifAny(function(Collection $collection) { // non-empty collection so this will get called
   echo 'Hello';
});

ifEmpty

Executes the passed callable if the collection is empty. The entire collection will be returned.

collect()->ifEmpty(function(Collection $collection) { // empty collection so this will called
   echo 'Hello';
});

collect([1, 2, 3])->ifEmpty(function(Collection $collection) { // non-empty collection so this won't get called
   echo 'Hello';
});

none

Checks whether a collection doesn't contain any occurrences of a given item, key-value pair, or passing truth test. The function accepts the same parameters as the contains collection method.

collect(['foo'])->none('bar'); // returns true
collect(['foo'])->none('foo'); // returns false

collect([['name' => 'foo']])->none('name', 'bar'); // returns true
collect([['name' => 'foo']])->none('name', 'foo'); // returns false

collect(['name' => 'foo'])->none(function ($key, $value) {
   return $key === 'name' && $value === 'bar';
}); // returns true

Note: When using a callable as argument, Collection::none behaves differently in Laravel 5.3 and higher. In 5.2, the parameter order is $key, $value, and in 5.3+ the parameter order is $value, $key.

range

Creates a new collection instance with a range of numbers. This functions accepts the same parameters as PHP's standard range function.

collect()->range(1, 3)->toArray(); //returns [1,2,3]

validate

Returns true if the given $callback returns true for every item. If $callback is a string or an array, regard it as a validation rule.

collect(['foo', 'foo'])->validate(function ($item) {
   return $item === 'foo';
}); // returns true


collect(['sebastian@spatie.be', 'bla'])->validate('email'); // returns false
collect(['sebastian@spatie.be', 'freek@spatie.be'])->validate('email'); // returns true

fromPairs

Transform a collection into an associative array form collection item.

$collection = collect(['a', 'b'], ['c', 'd'], ['e', 'f'])->fromPairs();

$collection->toArray(); // returns ['a' => 'b', 'c' => 'd', 'e' => 'f']

toPairs

Transform a collection in to a array with pairs.

$collection = collect(['a' => 'b', 'c' => 'd', 'e' => 'f'])->toPairs();

$collection->toArray(); // returns ['a', 'b'], ['c', 'd'], ['e', 'f']

transpose

The goal of transpose is to rotate a multidimensional array, turning the rows into columns and the columns into rows.

collect([
    ['Jane', 'Bob', 'Mary'],
    ['jane@example.com', 'bob@example.com', 'mary@example.com'],
    ['Doctor', 'Plumber', 'Dentist'],
])->transpose()->toArray();

// [
//     ['Jane', 'jane@example.com', 'Doctor'],
//     ['Bob', 'bob@example.com', 'Plumber'],
//     ['Mary', 'mary@example.com', 'Dentist'],
// ]

withSize

Create a new collection with the specified amount of items.

Collection::withSize(1)->toArray(); // return [1];
Collection::withSize(5)->toArray(); // return [1,2,3,4,5];

groupByModel

Similar to groupBy, but groups the collection by an Eloquent model. Since the key is an object instead of an integer or string, the results are divided into separate arrays.

$collection = collect([
    ['model' => $model1, 'foo' => 'bar'],
    ['model' => $model1, 'foo' => 'baz'],
    ['model' => $model2, 'foo' => 'qux'],
]);

$collection->groupByModel('model');

// [
//     [
//         'model' => $model1,
//         'items' => [
//             ['model' => $model1, 'foo' => 'bar'],
//             ['model' => $model1, 'foo' => 'baz'],
//         ],
//     ],
//     [
//         'model' => $model2,
//         'items' => [
//             ['model' => $model2, 'foo' => 'qux'],
//         ],
//     ],
// ];

You can also use a callable for more flexibility:

$collection->groupByModel(function ($item) {
    return $item['model']
});

If you want to specify the model key's name, you can pass it as the second parameter:

$collection->groupByModel('model', 'myModel');

// [
//     [
//         'myModel' => $model1,
//         'items' => [
//             ['model' => $model1, 'foo' => 'bar'],
//             ['model' => $model1, 'foo' => 'baz'],
//         ],
//     ],
//     [
//         'myModel' => $model2,
//         'items' => [
//             ['model' => $model2, 'foo' => 'qux'],
//         ],
//     ],
// ];

If you want to specify the model items' name, you can pass it as the third parameter:

$collection->groupByModel('model', 'myModel', 'myItems');

It's also possible to preserve the items' keys.

$collection->groupByModel('model', null, null, true);

sectionBy

Splits a collection into sections grouped by a given key. Similar to groupBy but respects the order of the items in the collection and reuses existing keys.

$collection = collect([
    ['name' => 'Lesson 1', 'module' => 'Basics'],
    ['name' => 'Lesson 2', 'module' => 'Basics'],
    ['name' => 'Lesson 3', 'module' => 'Advanced'],
    ['name' => 'Lesson 4', 'module' => 'Advanced'],
    ['name' => 'Lesson 5', 'module' => 'Basics'],
]);

$collection->sectionBy('module');

// [
//     [
//         'module' => 'Basics',
//         'items' => [
//              ['name' => 'Lesson 1', 'module' => 'Basics'],
//              ['name' => 'Lesson 2', 'module' => 'Basics'],
//         ],
//     ],
//     [
//         'module' => 'Advanced',
//         'items' => [
//              ['name' => 'Lesson 3', 'module' => 'Advanced'],
//              ['name' => 'Lesson 4', 'module' => 'Advanced'],
//         ],
//     ],
//     [
//         'module' => 'Basics',
//         'items' => [
//              ['name' => 'Lesson 5', 'module' => 'Basics'],
//         ],
//     ],
// ];

You can also pass the $sectionKey, $itemsKey and $preserveKeys parameters to customize the sectioned output:

$collection = collect([
    'lesson1' => ['name' => 'Lesson 1', 'module' => 'Basics'],
    'lesson2' => ['name' => 'Lesson 2', 'module' => 'Basics'],
    'lesson3' => ['name' => 'Lesson 3', 'module' => 'Advanced'],
    'lesson4' => ['name' => 'Lesson 4', 'module' => 'Advanced'],
    'lesson5' => ['name' => 'Lesson 5', 'module' => 'Basics'],
]);
    
$collection->sectionBy('module', 'moduleName', 'lessons', true);

// [
//     [
//         'moduleName' => 'Basics',
//         'lessons' => [
//              'lesson1' => ['name' => 'Lesson 1', 'module' => 'Basics'],
//              'lesson2' => ['name' => 'Lesson 2', 'module' => 'Basics'],
//         ],
//     ],
//     [
//         'moduleName' => 'Advanced',
//         'lessons' => [
//              'lesson3' => ['name' => 'Lesson 3', 'module' => 'Advanced'],
//              'lesson4' => ['name' => 'Lesson 4', 'module' => 'Advanced'],
//         ],
//     ],
//     [
//         'moduleName' => 'Basics',
//         'lessons' => [
//              'lesson5' => ['name' => 'Lesson 5', 'module' => 'Basics'],
//         ],
//     ],
// ];

after

Get the next item from the collection.

$collection = collect([1,2,3]);

$currentItem = 2;

$currentItem = $collection->after($currentItem); // return 3;
$collection->after($currentItem); // return null;

$currentItem = $collection->after(function($item) {
    return $item > 1;
}); // return 3;

You can also pass a second parameter to be used as a fallback.

$collection = collect([1,2,3]);

$currentItem = 3;

$collection->after($currentItem, $collection->first()); // return 1;

before

Get the previous item from the collection.

$collection = collect([1,2,3]);

$currentItem = 2;

$currentItem = $collection->before($currentItem); // return 1;
$collection->before($currentItem); // return null;

$currentItem = $collection->before(function($item) {
    return $item > 2;
}); // return 2;

You can also pass a second parameter to be used as a fallback.

$collection = collect([1,2,3]);

$currentItem = 1;

$collection->before($currentItem, $collection->last()); // return 3;

collect

Get an item at a given key, and collect it.

$collection = collect([
    'foo' => [1, 2, 3], 
    'bar' => [4, 5, 6],
]);

$collection->collect('foo'); // Collection([1, 2, 3])

You can also pass a second parameter to be used as a fallback.

$collection = collect([
    'foo' => [1, 2, 3], 
    'bar' => [4, 5, 6],
]);

$collection->collect('baz', ['Nope']); // Collection(['Nope'])

paginate

Create a LengthAwarePaginator instance for the items in the collection.

collect($posts)->paginate(5);

This paginates the contents of $posts with 5 items per page. paginate accepts quite some options, head over to the Laravel docs for an in-depth guide.

paginate(int $perPage = 15, string $pageName = 'page', int $page = null, int $total = null, array $options = [])

simplePaginate

Create a Paginator instance for the items in the collection.

collect($posts)->simplePaginate(5);

This paginates the contents of $posts with 5 items per page. simplePaginate accepts quite some options, head over to the Laravel docs for an in-depth guide.

simplePaginate(int $perPage = 15, string $pageName = 'page', int $page = null, int $total = null, array $options = [])

For a in-depth guide on pagination, check out the Laravel docs.

extract

Extract keys from a collection. This is very similar to only, with two key differences:

  • extract returns an array of values, not an associative array
  • If a value doesn't exist, it will fill the value with null instead of omitting it

extract is useful when using PHP 7.1 short list() syntax.

[$name, $role] = collect($user)->extract('name', 'role.name');

tail

Extract the tail from a collection. So everything except the first element. It's a shorthand for slice(1)->values(), but nevertheless very handy.

collect([1, 2, 3))->tail(); // return collect([2, 3])

eachCons

Get the following consecutive neighbours in a collection from a given chunk size.

collect([1, 2, 3, 4])->eachCons(2); // return collect([[1, 2], [2, 3], [3, 4]])

sliceBefore

Slice the values out from a collection before the given callback is true.

collect([20, 51, 10, 50, 66])->sliceBefore(function($item) {
    return $item > 50;
}); // return collect([[20],[51, 10]])

chunkBy

Chunks the values from a collection into groups as long the given callback is true.

collect(['A', 'A', 'B', 'A'])->chunkBy(function($item) {
    return $item == 'A';
}); // return Collection([['A', 'A'],['B'], ['A']])

Changelog

Please see CHANGELOG for more information what has changed recently.

Testing

$ composer test

Contributing

Please see CONTRIBUTING for details.

Security

If you discover any security related issues, please email freek@spatie.be instead of using the issue tracker.

Credits

About Spatie

Spatie is a webdesign agency based in Antwerp, Belgium. You'll find an overview of all our open source projects on our website.

License

The MIT License (MIT). Please see License File for more information.