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!