Container Attributes in Laravel
When you’re working with service classes in Laravel that you would inject into your controllers or anywhere else, you might need to pass some configuration values to them.
Let’s take the following example.
use App\Actions\DemoService;
Route::get('/demo-service', function (DemoService $demoService) {
// do something with $demoService
});
As you can tell, we have an App\Actions\DemoService
class that we’re injecting into a route. Now, let’s take a look at the DemoService
class.
namespace App\Actions;
class DemoService
{
public function __construct(
string $appName
)
{
dd($appName);
}
}
As you can tell, the DemoService
class has a constructor that takes a single parameter called $appName
. And we’re dumping the value of this parameter in the constructor.
Now, if visit the /demo-service
route, the app will throw the following exception.
That exception is thrown because we haven’t provided a value for the $appName
parameter in the DemoService
class while injecting it into the route and Laravel can’t resolve it on its own.
Resolving the value of dependencies
To get around this, you would need to use a boilerplate code like the following in the boot
method of your app’s AppServiceProvider
class.
namespace App\Providers;
use App\Actions\DemoService;
class AppServiceProvider extends ServiceProvider
{
public function boot(): void
{
$this->app->when(DemoService::class)
->needs('$appName')
->give(function () {
return config('app.name');
});
}
}
This code will tell Laravel to resolve the $appName
parameter in the DemoService
class constructor using the config
helper function.
Now, if you visit the /demo-service
route, the app will dump the value of the app.name
configuration value which is set in the config/app.php
file.
Container Attributes
In the recent release of Laravel, they introduced a new feature called Container Attributes which allows you to resolve the dependencies of a class using a simple PHP attribute in the constructor itself reducing the boilerplate code that you need to write in the AppServiceProvider
class.
The Config
attribute
So, if we want to rewrite the previous example using Container Attributes, we can do so like so.
namespace App\Actions;
use Illuminate\Container\Attributes\Config;
class DemoService
{
public function __construct(
#[Config('app.name')]
string $appName
)
{
dd($appName);
}
}
As you can tell, we now have a new attribute called Illuminate\Container\Attributes\Config
which we’re using to resolve the $appName
parameter in the DemoService
class constructor.
We don’t need to do anything in the AppServiceProvider
class anymore. And everything will work as before.
The CurrentUser
attribute
The Illuminate\Container\Attributes\Config
attribute is only one of the many attributes that you can use to resolve dependencies in your classes.
There are other attributes such as Illuminate\Container\Attributes\CurrentUser
that can be used to resolve the current user of your application.
namespace App\Actions;
use Illuminate\Container\Attributes\CurrentUser;
use App\Models\User;
class DemoService
{
public function __construct(
#[CurrentUser]
User $currentUser
)
{
dd($currentUser->toArray());
/*
[
'id' => 1,
'name' => 'John Doe',
'email' => '[email protected]',
'email_verified_at' => null,
'created_at' => '2021-09-08T13:22:34.000000Z',
]
*/
}
}
The DB
attribute
The Illuminate\Container\Attributes\DB
attribute can be used to resolve the database connection of your application.
namespace App\Actions;
use Illuminate\Container\Attributes\DB;
use Illuminate\Database\Connection;
class DemoService
{
public function __construct(
#[DB('mysql')]
Connection $db
)
{
dd($db->getDatabaseName());
/*
'database'
*/
}
}
Other attributes
Here is the list of the rest of the available attributes that you can use to resolve dependencies in your classes.
Illuminate\Container\Attributes\Auth
Illuminate\Container\Attributes\Cache
Illuminate\Container\Attributes\Log
Illuminate\Container\Attributes\Storage
Apart from these core Laravel attributes, you can also create your own custom container attributes by implementing the Illuminate\Contracts\Container\ContextualAttribute
interface to make your code simpler and easier to read.
In closing
Container Attributes presents yet another real-world use case of the PHP attributes and how they can be used to write more fluent and expressive code.
If you’re interested in learning more about PHP attributes, you can check out the following resources.
Like this article?
Buy me a coffee👋 Hi there! I'm Amit. I write articles about all things web development. You can become a sponsor on my blog to help me continue my writing journey and get your brand in front of thousands of eyes.