Laravel 5.0 introduit la possibilité pour le conteneur de résoudre les dépendances injectées dans toutes les méthodes qui sont résolus par le conteneur. Lisez la suite pour savoir comment, quand et pourquoi cela fonctionne.
Les bases de l’injection de dépendance
L’une des premières choses que les développeurs PHP apprennent lorsqu’ils commencent à se développer dans les pratiques de codage modernes est d’utiliser injection de dépendance afin de suivre la D dans SOLIDE: Inversion de dépendance.
Le conteneur de Laravel est appelé un conteneur IOC (“Inversion of Control”), et c’est le cas car il permet à votre contrôle de se produire au niveau supérieur de l’application : vous demandez dans votre code de bas niveau (contrôleurs, classes d’implémentation, etc. ) pour une instance de “mailer”, et le conteneur vous en donne une. Votre code de bas niveau ne se soucie pas du service qui est réellement Envoi en cours votre courrier–Mandrill ? Mailgun ? Envoyer un mail? Cela n’a pas d’importance, tant que l’interface avec la classe de messagerie est la même.
Injection de constructeur dans Laravel 4
Voici un exemple rapide d’injection de dépendance traditionnelle.
...
class Listener
{
protected $mailer;
public function __construct(Mailer $mailer)
{
$this->mailer = $mailer;
}
public function userWasAdded(User $user)
{
// Do some stuff...
$this->mailer->send('emails.welcome', ['user' => $user], function($message)
{
$message->to($user->email, $user->name)->subject('Welcome!');
});
}
}
Comme vous pouvez le voir, nous injecter la classe Mailer dans l’objet à l’aide du constructeur. Et le conteneur de Laravel simplifie l’instanciation de cette classe, car il automatise l’injection dans le constructeur. Remarquez que je peux créer un nouveau Auditeur sans passer dans un Mailer ; c’est parce que Laravel le résout pour moi et l’injecte.
$listener = App::make('Listener');
C’est génial parce que A) je peux maintenant décider quel Mailer je veux une fois dans l’application, plutôt que à chaque foiset B) cela rend le test de cette classe beaucoup plus facile.
Le conflit
Mais que se passe-t-il si vous n’avez besoin d’utiliser la classe injectée que dans une seule méthode ? Votre constructeur peut être assez encombré d’injections à usage unique.
Ou que se passe-t-il si vous devez effectuer une action particulière lors de l’injection, mais que vous souhaitez uniquement qu’elle fonctionne sur cette méthode particulière ? (FormRequests et ValidatesUponResolved)
Solution
Injection de méthode d’introduction : c’est comme l’injection de constructeur, mais cela vous permet d’injecter des dépendances directement dans vos méthodes…quand ces méthodes sont appelées par le conteneur.
Je suppose que le cas d’utilisation le plus courant pour l’injection de méthode sera les contrôleurs. Comme je l’ai mentionné ci-dessus, les nouveaux FormRequests en sont un parfait exemple. Mais cela a déjà été documenté, alors regardons autre chose.
...
class DashboardController extends Controller
{
public function showMoneyDashboard(MoneyRepository $money)
{
$usefulMoneyStuff = $money->getUsefulStuff();
return View::make('dashboards.money')
->with('stuff', $usefulMoneyStuff);
}
public function showTasksDashboard(TasksRepository $tasks)
{
$usefulTasksStuff = $tasks->getUsefulStuff();
return View::make('dashboards.tasks')
->with('stuff', $usefulTasksStuff);
}
public function showSupervisionDashboard(SupervisionRepository $supervision)
{
$usefulSupervisionStuff = $supervision->getUsefulStuff();
return View::make('dashboards.supervision')
->with('stuff', $usefulSupervisionStuff);
}
}
Étant donné que les méthodes du contrôleur public sont appelées par le conteneur (lorsque vous leur mappez une route et que l’utilisateur visite cette route), ces dépendances seront automatiquement injectées dès que vous atteindrez cette route. Agréable et propre.
À quel autre moment le conteneur résoudra-t-il une méthode ?
Ainsi, nous savons maintenant que les méthodes de contrôleur sont résolues par le conteneur. Les fournisseurs de services boot
les méthodes le sont aussi.
Mais vous pouvez choisir arbitrairement de résoudre le conteneur n’importe quel méthode que vous souhaitez.
...
class ThingDoer
{
public function doThing($thing_key, ThingRepository $repository)
{
$thing = $repository->getThing($thing_key);
$thing->do();
}
}
… et nous pouvons l’appeler depuis notre contrôleur en utilisant App::call()
qui peut éventuellement prendre un deuxième paramètre qui est un tableau de paramètres :
<?php namespace App\Http\Controllers;
use Illuminate\Contracts\Container\Container;
use Illuminate\Routing\Controller;
class ThingController extends Controller
{
public function doThing(Container $container)
{
$thingDoer = $container->make('ThingDoer');
// Calls the $thingDoer object's doThing method with one parameter
// ($thing_key) with a value of 'awesome-parameter-here'
$container->call(
[$thingDoer, 'doThing'],
['thing_key' => 'awesome-parameter-here']
);
}
}
CONCLURE
L’injection de méthode est, à la base, un catalyseur de certaines fonctionnalités système utiles telles que FormRequest, mais ne laissez pas cela vous empêcher de l’utiliser. C’est juste une autre façon de nettoyer votre code. Et nous avons tous besoin d’un code plus propre.