DEV Community

Ash Allen
Ash Allen

Posted on • Originally published at ashallendesign.co.uk

How to Swap Items in an Array Using Laravel Macros

Introduction

There may be times when you are working with arrays in your PHP code and need to switch the order of two items. If you're using an array that uses integers as keys, this can be a pretty straightforward task. However, if you're trying to swap two items of an associative array, this can be little bit more hands-on. So, in this short post, I'll show you how you can use macros in Laravel to keep your code looking clean and reusable.

By the end of the post, you should have a brief idea on how to create a macro that you can use to change the order of your like in this example:

$assocArray = [
    'item_one'   => ['name' => 'One'],
    'item_two'   => ['name' => 'Two'],
    'item_three' => ['name' => 'Three'],
    'item_four'  => ['name' => 'Four'],
];

$newArray = Arr::swap($array, 'item_one', 'item_three');

/*
 * $newArray is now:
 * [
 *     'item_three' => ['name' => 'Three'],
 *     'item_two'   => ['name' => 'Two'],
 *     'item_one'   => ['name' => 'One'],
 *     'item_four'  => ['name' => 'Four'],
 * ]
 */
Enter fullscreen mode Exit fullscreen mode

What Are Macros?

In Laravel, macros are methods that can be added to classes at runtime. They can be a pretty cool way of extending the functionality of a class that you might not have full access to and might not want to inherit from. Not all classes are "macroable", but if you want a full list of the Laravel classes that you can add macros to, check out this article written by Caleb Porzio.

Where Do I Define The Macro?

Whenever we create a new macro, we'll need to let Laravel new that we're providing a new macro; and we can do this inside a service provider. In theory, we can add this code to the AppServiceProvider but I like to try and keep the providers split out; otherwise, that file starts to get full pretty early on in your project. But this is just my personal opinion though, so feel free to use the AppServiceProvider if that helps you.

So, if you want to add the macro to a separate provider, let's start by creating a new MacroServiceProvider using the following command:

php artisan make:provider MacroServiceProvider
Enter fullscreen mode Exit fullscreen mode

We'll then need to remember to register this service provider inside the app/config.php like below:

return [

    'providers' => [
        // ...
        \App\Providers\MacroServiceProvider::class,
        // ...
    ],

]
Enter fullscreen mode Exit fullscreen mode

Now that we've created the new service provider, let's create the macro. This is the macro that we're going to be adding:

Arr::macro('swap', function (array $array, $keyOne, $keyTwo): array {
    if (! Arr::isAssoc($array)) {
        $itemOneTmp = $array[$keyOne];

        $array[$keyOne] = $array[$keyTwo];
        $array[$keyTwo] = $itemOneTmp;

        return $array;
    }

    $updatedArray = [];
    foreach ($array as $key => $value) {
        if ($key === $keyOne) {
            $updatedArray[$keyTwo] = $array[$keyTwo];
        } elseif ($key === $keyTwo) {
            $updatedArray[$keyOne] = $array[$keyOne];
        } else {
            $updatedArray[$key] = $value;
        }
    }

    return $updatedArray;
});
Enter fullscreen mode Exit fullscreen mode

So, let's add this macro to the service provider so that we can access it:

namespace App\Providers;

use Illuminate\Support\Arr;
use Illuminate\Support\ServiceProvider;

class MacroServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap services.
     *
     * @return void
     */
    public function boot(): void
    {
        Arr::macro('swap', function (array $array, $keyOne, $keyTwo): array {
            if (! Arr::isAssoc($array)) {
                $itemOneTmp = $array[$keyOne];

                $array[$keyOne] = $array[$keyTwo];
                $array[$keyTwo] = $itemOneTmp;

                return $array;
            }

            $updatedArray = [];
            foreach ($array as $key => $value) {
                if ($key === $keyOne) {
                    $updatedArray[$keyTwo] = $array[$keyTwo];
                } elseif ($key === $keyTwo) {
                    $updatedArray[$keyOne] = $array[$keyOne];
                } else {
                    $updatedArray[$key] = $value;
                }
            }

            return $updatedArray;
        });
    }
}
Enter fullscreen mode Exit fullscreen mode

Now that we've defined the macro inside the service provider, we can swap items in arrays using the Arr::swap() method. Here are some examples below of how we would be able to use this method:

$array = [
    ['name' => 'One'],
    ['name' => 'Two'],
    ['name' => 'Three'],
    ['name' => 'Four'],
];

$newArray = Arr::swap($array, 0, 2);

/*
 * $newArray is now:
 * [
 *     ['name' => 'Three'],
 *     ['name' => 'Two'],
 *     ['name' => 'One'],
 *     ['name' => 'Four'],
 * ]
 */
Enter fullscreen mode Exit fullscreen mode
$assocArray = [
    'item_one'   => ['name' => 'One'],
    'item_two'   => ['name' => 'Two'],
    'item_three' => ['name' => 'Three'],
    'item_four'  => ['name' => 'Four'],
];

$newArray = Arr::swap($array, 'item_one', 'item_three');

/*
 * $newArray is now:
 * [
 *     'item_three' => ['name' => 'Three'],
 *     'item_two'   => ['name' => 'Two'],
 *     'item_one'   => ['name' => 'One'],
 *     'item_four'  => ['name' => 'Four'],
 * ]
 */
Enter fullscreen mode Exit fullscreen mode

Hopefully, this short post will have given you a very brief overview of how to quickly create a macro that we can use swap two items in a PHP array. And a pretty nice benefit is that we can reuse that macro method across our system and keep our code looking readable and Laravel-y.

I'd love to hear any feedback in the comments if this helped you or not! 🚀

Top comments (0)