no-framework-tutorial/08-dependency-injector.md

98 lines
3.2 KiB
Markdown
Raw Normal View History

[<< previous](07-inversion-of-control.md) | [next >>](09-templating.md)
2014-09-16 19:48:41 +00:00
2014-09-16 19:52:08 +00:00
### Dependency Injector
2014-09-16 19:48:41 +00:00
2014-09-17 19:22:11 +00:00
A dependency injector resolves the dependencies of your class and makes sure that the correct objects are injected when the class is instantiated.
2014-09-19 13:50:19 +00:00
There is only one injector that I can recommend: [Auryn](https://github.com/rdlowrey/Auryn). Sadly all the alternatives that I am aware of are using the [service locator antipattern](http://blog.ploeh.dk/2010/02/03/ServiceLocatorisanAnti-Pattern/).
2014-09-17 19:22:11 +00:00
2014-10-09 17:18:45 +00:00
Install the Auryn package and then create a new file called `Dependencies.php` in your `src/` folder. In there add the following content:
2014-09-17 19:46:06 +00:00
2014-09-17 20:05:09 +00:00
```php
2014-09-17 19:46:06 +00:00
<?php
$injector = new \Auryn\Injector;
2014-09-17 19:46:06 +00:00
$injector->alias('Http\Response', 'Http\HttpResponse');
$injector->share('Http\HttpRequest');
$injector->define('Http\HttpRequest', [
':get' => $_GET,
':post' => $_POST,
':cookies' => $_COOKIE,
':files' => $_FILES,
':server' => $_SERVER,
]);
$injector->alias('Http\Request', 'Http\HttpRequest');
$injector->share('Http\HttpResponse');
return $injector;
```
Make sure you understand what `alias`, `share` and `define` are doing before you continue. You can read about them in the [Auryn documentation](https://github.com/rdlowrey/Auryn).
You are sharing the HTTP objects because there would not be much point in adding content to one object and then returning another one. So by sharing it you always get the same instance.
The alias allows you to type hint the interface instead of the class name. This makes it easy to switch the implementation without having to go back and edit all your classes that use the old implementation.
2014-09-17 20:05:09 +00:00
Of course your `Bootstrap.php` will also need to be changed. Before you were setting up `$request` and `$response` with `new` calls. Switch that to the injector now so that we are using the same instance of those objects everywhere.
```php
$injector = include('Dependencies.php');
$request = $injector->make('Http\HttpRequest');
$response = $injector->make('Http\HttpResponse');
```
The other part that has to be changed is the dispatching of the route. Before you had the following code:
```php
$class = new $className($response);
$class->$method($vars);
```
Change that to the following:
```php
$class = $injector->make($className);
$class->$method($vars);
```
Now all your controller constructor dependencies will be automatically resolved with Auryn.
2014-11-30 20:06:11 +00:00
Go back to your `Homepage` controller and change it to the following:
2014-09-18 19:53:50 +00:00
```php
<?php
2014-11-30 20:06:11 +00:00
namespace Example\Controllers;
2014-09-18 19:53:50 +00:00
use Http\Request;
use Http\Response;
2014-11-30 20:06:11 +00:00
class Homepage
2014-09-18 19:53:50 +00:00
{
private $request;
private $response;
public function __construct(Request $request, Response $response)
{
$this->request = $request;
$this->response = $response;
}
2014-11-30 20:06:11 +00:00
public function show()
2014-09-18 19:53:50 +00:00
{
$content = '<h1>Hello World</h1>';
$content .= 'Hello ' . $this->request->getParameter('name', 'stranger');
$this->response->setContent($content);
}
}
```
2014-11-30 20:06:11 +00:00
As you can see now the class has two dependencies. Try to access the page with a GET parameter like this `http://localhost:8000/?name=Arthur%20Dent`.
2014-09-18 19:53:50 +00:00
Congratulations, you have now successfully laid the groundwork for your application.
[<< previous](07-inversion-of-control.md) | [next >>](09-templating.md)