php
45 lines · 8 steps
Resolving the current team in Laravel middleware
A middleware picks the active team for each request, shares it app-wide, and remembers the choice in a cookie.
Explained by
highlit
1<?php
2
3namespace App\Http\Middleware;
4
5use Closure;
6use Illuminate\Http\Request;
7use Illuminate\Support\Facades\Cookie;
8use Symfony\Component\HttpFoundation\Response;
9
10class ResolveCurrentTeam
11{
12 protected const COOKIE = 'current_team';
13 protected const TTL = 60 * 24 * 365;
14
15 public function handle(Request $request, Closure $next): Response
16 {
17 $user = $request->user();
18
19 if (! $user) {
20 return $next($request);
21 }
22
23 $teamId = $request->route('team')
24 ?? $request->cookie(self::COOKIE);
25
26 $team = $user->teams()->find($teamId)
27 ?? $user->currentTeam
28 ?? $user->teams()->first();
29
30 abort_if($team === null, 403, 'You do not belong to any team.');
31
32 app()->instance('current_team', $team);
33 $request->attributes->set('current_team', $team);
34
35 $response = $next($request);
36
37 if ((string) $request->cookie(self::COOKIE) !== (string) $team->getKey()) {
38 $response->withCookie(
39 Cookie::make(self::COOKIE, $team->getKey(), self::TTL)
40 );
41 }
42
43 return $response;
44 }
45}
01 / 01
STEP 01
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1Chained null-coalescing operators express a clean priority order of fallbacks for resolving a value.
- 2Binding a resolved object into the container and request attributes lets the rest of the app read it without re-querying.
- 3Writing the cookie only when the value actually changed avoids emitting a redundant Set-Cookie on every response.
Related explainers
javascript
const ROLE_PERMISSIONS = { admin: ['users:read', 'users:write', 'billing:read', 'billing:write'], manager: ['users:read', 'billing:read'], member: ['users:read'],
Role-based permissions middleware in Express
authorization
middleware
rbac
Intermediate
9 steps
php
<?php namespace App\Console\Commands;
Releasing stale document locks in Laravel
artisan-command
transactions
row-locking
Intermediate
6 steps
php
<?php namespace App\Providers;
Subdomain multi-tenancy routing in Laravel
multi-tenancy
service-container
route-binding
Advanced
7 steps
typescript
import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common'; import { Observable, catchError, concatMap, finalize } from 'rxjs'; import { DataSource, QueryRunner } from 'typeorm';
Wrapping requests in a transaction with NestJS
interceptors
transactions
rxjs
Advanced
7 steps
php
<?php namespace App\Broadcasting;
Authorizing presence channels in Laravel
broadcasting
authorization
presence-channels
Intermediate
3 steps
javascript
const express = require('express'); const app = express(); app.get('/health', (req, res) => res.json({ status: 'ok' }));
Graceful shutdown in an Express server
graceful-shutdown
signal-handling
connection-tracking
Advanced
9 steps
Share this explainer
Here's the card — post it anywhere.
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code
Embed this explainer
Drop the interactive walkthrough into a blog or docs. Views never cost a credit.
<iframe src="https://highlit.co/explainers/resolving-the-current-team-in-laravel-middleware-explained-php-42b1/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.