framework icon indicating copy to clipboard operation
framework copied to clipboard

[12.x] Introduce `Contextable`

Open cosmastech opened this issue 2 months ago • 7 comments

Short summary

This is a simply way to create an object that syncs with the logging output.

Why? Dear god, why?

In a project I worked on semi-recently, we needed a "RequestContext" state that we stored. It was a class that was registered as a singleton in the container. A middleware would store the request data in the database, and then it would also keep a few other bits of data. Every time we updated the object via setters, it would re-sync itself to the Context facade.

In order to keep audit tracking, values from the request context was used in a number of inserts, hence why it was so meaningful to have it be a singleton.

Ok... maybe, but how do I use it.

It's pretty easy, just make yourself a Contextable object.

class RequestContext implements Contextable
{
    public function __construct(
        public ApiRequestModel $apiRequest,
        public AuthType $authType
    ) {}

    #[Override]
    public function context($repository)
    {
        return [
            'requesting_app' => $this->apiRequest->app_id,
            'auth_type' => $this->authType->value,
            'request_id' => $this->apiRequest->id,
        ];
    }
}

// then in a middleware or whatever
$requestContext = new RequestContext(ApiRequestModel::capture($request), AuthType::BEARER_TOKEN);

app()->instance(RequestContext::class, $requestContext);
Context::add($requestContext);

// Then in my code, all of my logs will include the requesting_app, auth_type, and request_id data 😃

(Note: I fully expect Taylor to hate the idea of using an interface here, and instead we could just check that a method called contextData() exists on the Contextable. No problem)

cosmastech avatar Oct 09 '25 20:10 cosmastech