Introduction of Service Provider

Service Provider is an useful way to encapsulate logic for creating objects and services. For example, a mailer library, custom listeners or 3rd tools. Some libraries need a bootstrapping process, we should put this process in Service Provider.

Service Provider works with IoC Container, we must implement the \Windwalker\DI\ServiceProviderInterface and write all our logic in register() and boot() method then set our objects into container.

Basic Provider Example

Original Way

Take a look of this example code, in a original way, if we have a MongoDB driver want to bootstrap, we'll write an bootstrap file.

// ./import.mongodb.php

// This is a fake MongoDB connector
$conn = new MongoDBConnection($config['database']['mongodb']);

return $conn;

And include this file:

$mongo = include_once __DIR__ . '/import.mongodb.php';

This is not the best practice to include a 3rd service in our system, so we use provider to handle it.

Windwalker Way

In Windwalker, Create a MongoDBServiceProvider, and set MongoDB connection to Container.

use Windwalker\DI\Container;
use Windwalker\DI\ServiceProviderInterface;

class MongoDBServiceProvider implements ServiceProviderInterface
{
    public function register(Container $container)
    {
        $closure = function (Container $container)
       {
           $config = $container->get('config');

           return new MongoDBConnection($config->get('database.mongodb'));
       }

        $container->share(MongoDBServiceProvider::class, $closure)->alias('mongo.db', MongoDBServiceProvider::class);
    }
}

Register this provider in container:

$container->registerServiceProvider(new MongoDBServiceProvider());

Then get this object from Container, the MongoDBConnection will be lazy loading, MongoDB will connected after your first get it:

$mongo = $container->get('mongo.db');

// OR

$mongo = Ioc::get('mongo.db');

About how to use IoC (DI) Container, see: IoC Container

Registering Providers

All Service Providers are registered in config, add your own or 3rd providers in etc/app/windwalker.php or etc/app/web.php:

// etc/app/windwalker.php

// ...

    'providers' => [
        'mongodb' => MongoDBServiceProvider::class
    ]

// ...

Boot Service

If the service need to be boot when system initializing, we can add a boot() method to provider class. This is an error handler provider example, we must register error handler instantly after this provider registered.

class ErrorHandlingProvider implements ServiceProviderInterface
{
    public function boot(Container $container)
    {
        $handler = $container->get(ErrorManager::class);

        // Register error handler instantly.
        $handler->register();
    }

    public function register(Container $container)
    {
        $closure = $container->prepareSharedObject(ErrorManager::class);
    }
}

Boot Deferred

If you wish this provider boot after all providers registered, you can use bootDeferred().

class ErrorHandlingProvider implements ServiceProviderInterface
{
    public function bootDeferred(Container $container)
    {
        $handler = $container->get(ErrorManager::class);

        // Get other service.
        $handler->addHandler($container->get('other.service'))

        // Register error handler after providers registered.
        $handler->register();
    }

    // ...

Get Services From Application

Application object can easily get some main services by magic properties:

$app = Ioc::getApplication();

$this->app->container->get('...'); // Global container
$this->app->uri->path;
$this->app->dispatcher->addListener(...);
$this->app->router->route(...);
$this->app->language->translate(...);
$this->app->renderer->addGlobal(...);
$this->app->cacheManager->getCache();
$this->app->cache->set(...);
$this->app->session->get('user');
$this->app->browser->isMobile();
$this->app->platform->isLinux();
$this->app->database->getQuery(true);
$this->app->logger->debug('category', '...');
$this->app->mailer->createMessage('Subject');

If you found a typo or error, please help us improve this document.