Skip to content

[12.x] Add Context contextual attribute #55760

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: 12.x
Choose a base branch
from

Conversation

martinbean
Copy link
Contributor

Adds a new Context contextual attribute for resolving context values.

This idea was borne out of a pattern I use in database seeders, where I usually find myself wanting to re-use created models across seeder classes. For example, creating a User in one seeder class and then using that User instance as a related model in other seeder classes.

I was using context to store these model references to avoid re-querying them in subsequent seeders. Instead of doing Context::get calls (where I have to manually check a value was returned and it’s of the type I’m expecting if a value was returned) I then decided to see if dependency injection worked in the run method of seeder classes (it does), which then led me to the idea of injecting context data as parameters so I could also get type-hinting. However, was surprised to find there wasn’t already a Context contextual attribute.

With this new Context contextual attribute, developers are now able to do something like:

use App\Models\User;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\Context;

class UserSeeder extends Seeder
{
    public function run(): void
    {
        $user = User::factory()->create();

        // Store context data for subsequent seeders...
        Context::add('user', $user);
    }
}
use App\Models\Channel;
use App\Models\User;
use Illuminate\Container\Attributes\Context;
use Illuminate\Database\Seeder;

class ChannelSeeder extends Seeder
{
    public function run(
        // Retrieve context data with added type-hinting...
        #[Context('user')] User $user,
    ): void {
        $channel = Channel::factory()->create();

        $channel->users()->attach($user);
    }
}

@martinbean martinbean force-pushed the feature/context-attribute branch from 491d90d to e3f70d5 Compare May 16, 2025 23:11
@shaedrich
Copy link
Contributor

shaedrich commented May 16, 2025

While this attribute interacts with the Context facade (ultimately, it's an implementation detail, that could also be swapped with another store without changing the result we expect), I'd approach the naming from the other direction (similar to route controller method contextual attributes), and propose using one of the following namings:

  • Model
  • ConcreteModel
  • FactoryResult
  • FactoredModel
  • SeededModel
  • RecycledModel (inspired by the Factory::recycle() method)
  • something similar

You could even take this a step further and—additionally to removing the Context::get() call—also remove the Context::add() call. One way, you could do this would be moving the model creation to a different method, which will automatically add its result to the Context, before returning it to the method, it was called in:

use App\Models\User;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\Context;

class UserSeeder extends Seeder
{
    public function run(
        // Recognizes that
        //   a) the user model is not part of the context
        //   b) the seeder has a method with the same name/return type
        // and therefore,
        //   1) calls said method
        //   2) adds its result to the context
        //   3) passes the result to the run() method
        #[Context('user')] User $user,
    ): void {
        // Store context data for subsequent seeders...
    }

    private function user(): User
    {
        return User::factory()->create();
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants