feat: Add Global Context feature#9970
Conversation
|
Before deciding whether we need this, we should ask if other frameworks have already faced it. I did some research. Laravel introduced a first-class Context facade in v11. The idea is simple: set data once in middleware and have it automatically available everywhere (including in log entries) without passing values through every method. It even propagates context into queued jobs, so a Symfony approaches it differently. It uses What this PR is proposing is closer to Laravel model: a single, consistent concept that works the same whether we're handling HTTP, or running a command. Why is context useful? When something breaks in production, we want every log entry from that request to have the same |
|
@michalsn Yes. When I myself created few pure API projects with CI 4, I almost everytime have to create custom solution for global context management. Also for better traceability and monitoring, central global context is a good idea (I think). With just one boolean toggle to turn on or off the logging of this context will enable devs to switch between dev environment (where all log levels are enabled and log files fill up really quickly) and prod environment (where not all log levels are enabled but you need traceability) really easily without much headache. For normal website projects, this is not much useful as you have sessions and cookies. But I guess this feature would serve as helpful addon rather than unnecessary debt. But again, decision makers are community members and maintainers, not me. |
|
Haven't worked with this. The attributes in the symfony contain a twig. |
Do you mean that Symfony request attributes are accessible from templates directly? |
michalsn
left a comment
There was a problem hiding this comment.
Overall, I think the new Context service is a valuable addition and the implementation is heading in a good direction.
I have one suggestion: context data should be displayed in the Toolbar under the "Vars" section, with a clear separation between normal and hidden data. But this may also be done in a separate PR.
|
@datamweb instead of downvoting, I think it would be more beneficial for all to hear your thoughts on this. |
Request available as https://symfony.com/doc/current/templates.html#the-app-global-variable I haven't tested a symfony in a long time. There was something like that once: |
|
Thanks @neznaika0. I believe this is a topic for a separate discussion, as it would involve changes to the Parser to make the context automatically available. It's something we can consider in the future, although I'm not a big fan of the idea. For now, let's focus on the Context class itself. |
|
@paulbalandan To be completely honest, I read this entire PR yesterday. I initially held back from commenting because I truly didn't want to drain the energy of an active contributor. The core concept of a Context is highly valuable and modern, but my downvote stems from severe concerns regarding the implementation and the default behavior. Here is a breakdown of my technical concerns: Recently, we have been moving towards FrankenPHP, and a part of the CI4 community relies on the CodeIgniter4-Burner library (which enables high-performance servers like RoadRunner, OpenSwoole, and Workerman). In these persistent, long-running worker environments, the application does not die after a request. If the Context class is implemented as a shared service or global state without a bulletproof, automatic reset() hook explicitly tied to the end of the HTTP lifecycle, we will encounter State Bleeding. Metadata from Request A (e.g., As developers begin adopting this new feature in 4.8.0 to store general request data (emails, IPs, phone), they naturally won't mark everything as hidden (since they aren't strict "passwords"). Because I am not against the feature itself, but I strongly advocate for the following before we merge this into the Core: Keep If you believe I am misunderstanding any part of the implementation or its guarantees, please feel free to correct me. |
|
You are right to call out the risk of accidental context logging. I had proposed As for worker mode, |
@michalsn Thanks for clarifying! class AuthFilter implements FilterInterface
{
public function __construct() {
$this->context = service('context'); // Cached once per worker
}
}Since the AuthFilter instance stays alive across multiple requests, wouldn’t If so, should we add a strict warning in the docs advising developers to never store |
|
@datamweb Filters do not persist between requests. We reset pretty much everything - one way or another. |
@michalsn A major part of my security concerns is now resolved. Thanks! |
|
Hello all. I was looking at the discussion and I think, we can also do one more thing for this feature. What if we introduce a third array $shared?? The normal as well as hidden data will be resetted after every request. (Though I haven't seen much implementation of Worker mode and I don't know much how services are cleared and reinitialised) This is just a thought. This shared array will only benefit when worker mode is enabled. Else everything will be normal. This is just a thought. |
|
@patel-vansh Technically, this would be doable if a dedicated method were provided. However, I'm not sure about the practical benefits - why would we need this? I don't recall other frameworks offering this feature. |
|
@michalsn Yeah, I think we can leave $shared array for now. If we need that in future, we can always add that. |
Co-authored-by: John Paul E. Balandan, CPA <paulbalandan@gmail.com> Co-authored-by: michalsn <michal@sniatala.pl>
| */ | ||
| public function get(string $key, mixed $default = null): mixed | ||
| { | ||
| return ArrayHelper::dotSearch($key, $this->data) ?? $default; |
There was a problem hiding this comment.
Using ?? with ArrayHelper::dotSearch() introduces a logical bug, an explicitly stored null value is treated the same as a missing key and replaced by $default.
Would it make sense to check key existence with dotHas() first to preserve the distinction between unset and explicit null?
| return ArrayHelper::dotSearch($key, $this->data) ?? $default; | |
| return ArrayHelper::dotHas($key, $this->data) ? ArrayHelper::dotSearch($key, $this->data) : $default; |
Description
This PR adds Global Context feature for requests.
Normal context is automatically added to logs if
$logGlobalContextis enabled inapp/Config/Logger.phpfile. This provides better monitoring for any logs or exceptions along with maintaining security with hidden context feature.Checklist: