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.

Start your All-Access Pass
Buy just this tutorial for $6.00

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:

<?php
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():

122 lines index.php
... lines 1 - 3
$container = new Container();
$pdo = $container->getPDO();
... lines 6 - 122

Copy those lines and repeat this in battle.php:

110 lines 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:

14 lines bootstrap.php
... 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:

110 lines battle.php
... lines 1 - 3
$container = new Container($configuration);
... lines 5 - 110

And do the same thing for index.php:

122 lines 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!

Leave a comment!

  • 2017-01-19 Victor Bocharsky

    Ah, I already found it, you're right! It should be require_once __DIR__.'/lib/Container.php';.

    I just fixed it, thank you!

    Cheers!

  • 2017-01-19 Victor Bocharsky

    Hey Ivan,

    Could you provide a bit more information? What exactly code block looks wrong?

    Cheers!

  • 2017-01-19 Ivan

    I think that you highlighted wrong file in bootstrap.php code sample :)