Service Container
Keep on Learning!
If you liked what you've learned so far, dive in! Subscribe to get access to this tutorial plus video, code and script downloads.
Good news: we've got great flexibility! Bad news: we have to create the service objects by hand and this stuff is duplicated. We need to centralize what we've got here.
Creating a Service Container
To do that, we'll create one special class whose only job is to create these service objects. This class is called a service container, ya know, because it's basically a container for all the service objects. You'll see.
In lib/ create a new file called Container.php. Inside create a class
called Container:
| class Container | |
| { | |
| // ... lines 5 - 24 | |
| } |
In battle.php and index.php, we create a new PDO object. Let's have
Container do that instead. Create a new public function getPDO() inside
Container. Copy the code to make this and paste it here. Hmm, we need the
$configuration variable, so copy that from bootstrap.php and put it
here temporarily. Return $pdo at the bottom and perfect the method by
adding some PHPDoc:
| // ... lines 1 - 2 | |
| class Container | |
| { | |
| /** | |
| * @return PDO | |
| */ | |
| public function getPDO() | |
| { | |
| $configuration = array( | |
| 'db_dsn' => 'mysql:host=localhost;dbname=oo_battle', | |
| 'db_user' => 'root', | |
| 'db_pass' => null, | |
| ); | |
| $pdo = new PDO( | |
| $configuration['db_dsn'], | |
| $configuration['db_user'], | |
| $configuration['db_pass'] | |
| ); | |
| $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); | |
| return $pdo; | |
| } | |
| } |
Using the Container
Ok, nobody needs to do this work by hand anymore. Go to index.php. At the
top, create a $container variable and set it to new Container(). Below
that, replace the new PDO() stuff with just $container->getPDO():
| // ... lines 1 - 3 | |
| $container = new Container(); | |
| $pdo = $container->getPDO(); | |
| // ... lines 6 - 122 |
Copy those lines and repeat this in battle.php:
| // ... lines 1 - 3 | |
| $container = new Container(); | |
| $pdo = $container->getPDO(); | |
| // ... lines 6 - 110 |
Before trying this, don't forget to go to bootstrap.php: we need to require
the file so we can access the new class:
| // ... lines 1 - 8 | |
| require_once __DIR__.'/lib/Container.php'; | |
| // ... lines 10 - 14 |
Hey, let's give it a shot! Refresh! No problems.
Centralizing Configuration
Ok, we've started removing duplication. But I made us go one step backwards:
once again, our configuration is buried inside a class - I'd rather have
that somewhere central. Fix this like we always do when we want to remove
some details from a class: create a public function __construct() with
a $configuration argument. Add the $configuration property and assign
it in the construct function:
| // ... lines 1 - 2 | |
| class Container | |
| { | |
| private $configuration; | |
| public function __construct(array $configuration) | |
| { | |
| $this->configuration = $configuration; | |
| } | |
| // ... lines 11 - 25 | |
| } |
Down in getPDO(), let's celebrate! Remove the $configuration variable
and reference the property instead:
| // ... lines 1 - 2 | |
| class Container | |
| { | |
| private $configuration; | |
| // ... lines 6 - 14 | |
| public function getPDO() | |
| { | |
| $pdo = new PDO( | |
| $this->configuration['db_dsn'], | |
| $this->configuration['db_user'], | |
| $this->configuration['db_pass'] | |
| ); | |
| // ... lines 22 - 24 | |
| } | |
| } |
This is an easy change - bootstrap.php already holds the central $configuration
array. In battle.php pass $configuration to the Container:
| // ... lines 1 - 3 | |
| $container = new Container($configuration); | |
| // ... lines 5 - 110 |
And do the same thing for index.php:
| // ... lines 1 - 3 | |
| $container = new Container($configuration); | |
| $pdo = $container->getPDO(); | |
| // ... lines 6 - 122 |
Time for a sanity check! Refresh! Oh no!
PDOException on Container.php line 21
Put on your debugging cap! That's the line that creates the new PDO object.
Hmm, we didn't change anything - this is fishy. Dump $this->configuration and
refresh. Ah, it's null. Well, clearly that's not right. I see it. Silly
mistake: in __construct(), I wasn't assigning the property. Make sure you
have $this->configuration = $configuration:
| // ... lines 1 - 2 | |
| class Container | |
| { | |
| private $configuration; | |
| public function __construct(array $configuration) | |
| { | |
| $this->configuration = $configuration; | |
| } | |
| // ... lines 11 - 25 | |
| } |
We were passing in the configuration, but I had forgot to set it on my property. Try it again. Excellent!
This keeps my requirement of a centralized configuration array and centralizing where we create service objects. But we still need to move a few more service objects in here and fix one more issue. Almost there!