Service Location - rawebone/Wilson GitHub Wiki

When working on an application you quickly find yourself needing to share configured object instances between different parts of your codebase. Some systems like Laravel and Symfony provide Dependency Injection where your configured object is passed either to the constructor or a setter of the object dependent upon it.

Other systems like Slim and Silex use a system called Service Location and let the code being called pull in any dependencies it needs. Wilson uses a variation of this optimised for performance.

The Service Container

The framework provides an object called Wilson\Services which provides the basic Service Container mechanism. Essentially, you extend out from this object and create methods, called Factories, which return configured object instances. The underlying Services object then handles creation and caching of these objects. For example, say we want to share a Database Connection around:


class Services extends Wilson\Services
{
    protected function getConnection()
    {
        return new PDO(/* ... */);
    }
}

You can then access this connection as follows:


$services = new Services();
$connection = $services->connection;

It is recommended that the Factory be made protected to avoid them being called directly. Additionally, it is recommended that you use @property annotations for the class to document what services are available in your IDE:


/**
 * @property PDO $connection
 */
class Services extends Wilson\Services
{
    protected function getConnection()
    {
        return new PDO(/* ... */);
    }
}

Using the Service Container

The framework needs to know to use your instance of the Service Container. To do this, we give an instance to the Api object that we created initially in our index.php:

<?php

require_once "vendor/autoload.php";

$api = new Wilson\Api();
$api->resources = array("Users");
$api->services  = new Services();
$api->dispatch();

Great, but now you might be wondering how your Controllers get access to these services you've created. If you think back to the Lifecycle document you'll remember that every Controller and Middleware Controller is automatically passed an instance of the Request and Response objects. They also receive an instance of the Service object automatically:


    /**
     * @route GET /users/{id}
     * @where id \d+
     * @through authenticate
     */
    function getUser(Request $request, Response $response, Services $services)
    {
        $connection = $services->connection;
        $data = $this->magicallyReturnData($request->getParam("id"));
        
        // ...
    }

Next: Testing