Use Laravel Context in a lovely & maintainable way ๐Ÿฅฐ

Use Laravel Context in a lovely & maintainable way ๐Ÿฅฐ

ยท

3 min read

Hey guys,

For everybody that has been upgraded to Laravel 11, cheers (me too). Laravel 11 has shipped a lot of bug fixes, improvements, and some new awesome features.

Today we'll talk about the Context - one of the new features of Laravel 11.

Laravel Context

Laravel Context is the easiest way to manage & share data in a request (or jobs, commands).

It's a layer to handle the shortage cache of your request.

Using PHP-FPM, we all know that every request is independent, thus allowing us to create static properties to store in-memory data and after the request ends, data will be flushed.

However, commands & jobs are different. They are long-lived processes, the data won't be flushed until the process ends. This makes thing harder to manage and share data.

  • Same for Laravel Octane, our applications will be run in a long-lived process.

Won't be the case anymore, Laravel Context has our backs now ๐Ÿ˜Ž. It will ensure Context is only available during a request lifecycle (HTTP, Job, Command, and Octane's request).

Using Context

As same as how you using Cache facade:

Context::set('seth', $seth);
Context::get('seth');
Context::forget('seth');
// and so many others

Unlike Cache, you can store anything in-memory: string, int, Eloquent Model, Objects, etc which is really cool ๐Ÿ˜Ž.

All of them will be cleaned after the request ends.

Use Context in a lovely way

As we can see, whenever we need to use Context, we have to specify the $key

If we use hardcoded string, later it will become a big mess, and hard to track usage.

Let's create a simple class to access your context.

For example, I'll have this

namespace App\Contexts; // app/Contexts folder

use App\Models\ApiKey;
use Illuminate\Support\Facades\Context;

class CurrentApiKeyContext
{
    protected static string $key = 'currentApiKey';

    public static function set(ApiKey $apiKey): void
    {
        Context::add(static::$key, $apiKey);
    }

    public static function get(): ApiKey
    {
        return Context::get(static::$key);
    }
}

And when the authentication happens, I'd do:

namespace App\Http\Middleware;

use App\Contexts\CurrentApiKeyContext;

class AuthenticateApiKey
{
    public function handle(Request $request, Closure $next): Response
    {
        $apiKey = ApiKey::findByKey($request->bearerToken());
        if (!$apiKey) {
            return response()->json([], 401);
        }

        // set key
        CurrentApiKeyContext::set($apiKey);

        return $next($apiKey);
    }
}

After that, whenever I need to access the currentApiKey, I'd do:

use App\Contexts\CurrentApiKeyContext;

CurrentApiKeyContext::get(); // ApiKey instance

The PROs

  • Your $key will be defined once and maintained inside a class

  • Your data will be strictly-typed & IDE-friendly

    • No more /** @var ... */ pain, I feel that
  • Easy to write unit test cases

The CONs

  • You have a new layer to manage

Conclusion

Everything is a trade-off in tech, and since the PROs are better, why don't we go that? ๐Ÿ˜Ž

Let's just not make it work, let's make it better & easier to manage in a later stage โค๏ธ.

Cheers, and happy Friday!

ย