spatie/laravel-collection-macros

repository·main·Indexed 23 days ago

https://github.com/spatie/laravel-collection-macros

A set of macros for Laravel Collections that extend functionality with methods for positional and relative item access, conditional branching, and exception handling. Key macros include after(), before(), at(), chunkBy(), collectBy(), containsAny(), containsAll(), extract(), filterMap(), firstOrPush(), groupByModel(), if(), try(), catch(), weightedRandom(), and eachCons().

Tokens
4.1K
Snippets
14
Records
25
Agent score
84%

What's inside spatie/laravel-collection-macros

  1. Extract values for short list syntax with `extract()`

    main

    The extract() macro is similar to only(), but it returns a flat array of values instead of an associative array. If a requested key does not exist, it fills the position with null. This is specifically designed for use with PHP's list() or short array destructuring syntax.

    [$name, $role] = collect($user)->extract('name', 'role.name');
  2. Handle exceptions in chains with `try()` and `catch()`

    main

    The try() and catch() macros provide a way to handle exceptions within a collection chain. This behaves similarly to a database transaction: if an exception is thrown between try() and catch(), the collection reverts to its state as it was before the try() call.

    • You can access the original collection inside the catch block by passing it as a second parameter to the handler.
    • You can manipulate the collection within catch by returning a new value.
    $collection = collect(['a', 'b', 'c', 1, 2, 3])
        ->try()
        ->map(function ($item) {
            throw new Exception();
        })
        ->catch(function (Exception $exception, $collection) {
            return collect(['d', 'e', 'f']);
        })
        ->map(function($item) {
            return strtoupper($item);
        });
    
    // Result: ['D', 'E', 'F']
    $collection = collect(['a', 'b', 'c', 1, 2, 3])
        ->try()
        ->map(fn ($letter) => strtoupper($letter))
        ->each(function() {
            throw new Exception('Explosions in the sky');
        })
        ->catch(function (Exception $exception) {
            // handle exception here
        })
        ->map(function() {
            // further operations can be done, if the exception wasn't rethrow in the `catch`
        });
  3. Group by Eloquent models with `groupByModel()`

    main

    The groupByModel() macro is a specialized version of groupBy(). Instead of using strings or integers as keys, it groups the collection by an Eloquent model instance, resulting in an array where the keys are the model objects themselves.

    Signature: groupByModel($callback, $preserveKeys, $modelKey, $itemsKey)

    $posts->groupByModel('category');
    
    // Result structure:
    // [
    //     [$categoryA, [/*...$posts*/]],
    //     [$categoryB, [/*...$posts*/]],
    // ]
    $posts->groupByModel('category');
  4. Collect items by key with `collectBy()`

    main

    The collectBy() macro retrieves an item at a specific key and returns it as a new collection. It accepts an optional fallback value.

    $collection = collect([
        'foo' => [1, 2, 3],
        'bar' => [4, 5, 6],
    ]);
    
    $collection->collectBy('foo'); // Collection([1, 2, 3])
    $collection->collectBy('baz', ['Nope']); // Collection(['Nope'])
    $collection = collect([
        'foo' => [1, 2, 3],
        'bar' => [4, 5, 6],
    ]);
    
    $collection->collectBy('foo'); // Collection([1, 2, 3])
  5. Map and filter in one step with `filterMap()`

    main

    The filterMap() macro allows you to transform items and remove falsy results in a single operation, avoiding the need to chain map() and filter().

    $collection = collect([1, 2, 3, 4, 5, 6])->filterMap(function ($number) {
        $quotient = $number / 3;
        return is_integer($quotient) ? $quotient : null;
    });
    
    $collection->toArray(); // [1, 2]
    $collection = collect([1, 2, 3, 4, 5, 6])->filterMap(function ($number) {
        $quotient = $number / 3;
    
        return is_integer($quotient) ? $quotient : null;
    });
    
    $collection->toArray(); // returns [1, 2]
  6. Get the previous item with `before()`

    main

    The before() macro retrieves the item preceding a given item or condition. You can pass a value or a callback. An optional second parameter provides a fallback if no previous item exists.

    $collection = collect([1,2,3]);
    
    // Using a value
    $collection->before(2); // returns 1
    $collection->before(1); // returns null
    
    // Using a callback
    $collection->before(function($item) {
        return $item > 2;
    }); // returns 2
    
    // Using a fallback
    $collection->before(1, $collection->last()); // returns 3
    $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;
  7. Get the next item with `after()`

    main

    The after() macro retrieves the next item in the collection following a specific item or a condition. You can pass the current item itself or a callback function to determine the starting point. An optional second parameter allows you to specify a fallback value if no subsequent item is found.

    $collection = collect([1,2,3]);
    
    // Using a value
    $currentItem = 2;
    $collection->after($currentItem); // returns 3
    $collection->after(3); // returns null
    
    // Using a callback
    $collection->after(function($item) {
        return $item > 1;
    }); // returns 3
    
    // Using a fallback
    $collection->after(3, $collection->first()); // returns 1
    $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;
  8. Retrieve or push with `firstOrPush()`

    main

    The firstOrPush() macro attempts to find the first item that matches a given callback. If no match is found, it pushes a fallback value into the collection. You can optionally specify a target collection as the third parameter.

    // Push to the current collection
    $collection = collect([1, 2, 3])->firstOrPush(fn($item) => $item === 4, 4);
    $collection->toArray(); // [1, 2, 3, 4]
    
    // Push to a specific target collection
    $target = collect([1, 2, 3]);
    $collection->filter()->firstOrPush(fn($item) => $item === 4, 4, $target);
    $collection = collect([1, 2, 3])->firstOrPush(fn($item) => $item === 4, 4);
    
    $collection->toArray(); // returns [1, 2, 3, 4]
  9. Check existence with `containsAny()` and `containsAll()`

    main

    Use these macros to check for the presence of multiple values:

    • containsAny(array $values): Returns true if one or more of the given values exist in the collection.
    • containsAll(array $values): Returns true if all given values exist in the collection.
    $collection = collect(['a', 'b', 'c']);
    
    $collection->containsAny(['b', 'c', 'd']); // true
    $collection->containsAll(['b', 'c']); // true
    $collection->containsAll(['c', 'd']); // false
    $collection = collect(['a', 'b', 'c']);
    
    $collection->containsAny(['b', 'c', 'd']); // returns true
    $collection->containsAll(['b', 'c',]); // returns true
  10. Perform weighted random selection with `weightedRandom()`

    main

    The weightedRandom() macro returns a random item from the collection based on a weight. You can specify the weight by passing a string (the field name) or a callback.

    // Using a field name
    $randomItem = collect([
        ['value' => 'a', 'weight' => 30],
        ['value' => 'b', 'weight' => 20],
        ['value' => 'c', 'weight' => 10],
    ])->weightedRandom('weight');
    
    // Using a callback
    $randomItem = collect([
        ['value' => 'a', 'weight' => 30],
        ['value' => 'b', 'weight' => 20],
        ['value' => 'c', 'weight' => 10],
    ])->weightedRandom(function(array $item) {
       return $item['weight'];
    });
    $randomItem = collect([
        ['value' => 'a', 'weight' => 30],
        ['value' => 'b', 'weight' => 20],
        ['value' => 'c', 'weight' => 10],
    ])->weightedRandom('weight');
  11. Retrieve items by index with `at()` and positional macros

    main

    You can retrieve items at specific indices using the at() method, which supports negative indices for counting from the end. Additionally, there are semantic macros for common positions:

    • at(int $index): Retrieve item at a specific index.
    • second(): Retrieve item at index 1.
    • third(): Retrieve item at index 2.
    • fourth(): Retrieve item at index 3.
    • fifth(): Retrieve item at index 4.
    • sixth(): Retrieve item at index 5.
    • seventh(): Retrieve item at index 6.
    • eighth(): Retrieve item at index 7.
    • ninth(): Retrieve item at index 8.
    • tenth(): Retrieve item at index 9.
    • getNth(int $n): Retrieve the nth item.
    $data = new Collection([1, 2, 3]);
    
    $data->at(0); // 1
    $data->at(-1); // 3
    $data->second(); // 2
    $data->getNth(3); // 3
    $data = new Collection([1, 2, 3]);
    
    $data->at(0); // 1
    $data->at(1); // 2
    $data->at(-1); // 3