Skip to main content

Command Palette

Search for a command to run...

Use Laravel Context in a lovely & maintainable way 🥰

Updated
3 min read
Use Laravel Context in a lovely & maintainable way 🥰
S

develops awesome software, contributes to OSS, writes tech tips, and loves Vietnamese milk coffee!

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!

More from this blog

S

Seth Phat Tech Blog

69 posts

develops awesome software, contributes to OSS, writes tech tips, and loves Vietnamese milk coffee!