Services

Each of your features (modules) wants to be self-contained, isolated and in control of its own destiny. To keep such separation is a good thing (Separation of Responsibility principal). Once you’ve got that nailed then you want to begin exposing information out of your module. A popular architectural pattern is Service Oriented Architecture (SOA).

Services in PPI have names that you define. This can be something simple like user.search or cache.driver or it’s even somewhat popular to use the Fully Qualified Class Name (FQCN) as the name of the service like this: MyService::class. With that in mind it’s just a string and it’s up to you what convention you use just make sure it’s consistent.

Defining the Service in our Module

This is of course optional for your module but if you want to begin doing services then the method is getServiceConfig. This will be called on all modules upon boot() of PPI. Boot should be almost instantaneous and non-blocking, so be sure not to do anything expensive here such as make network connections, as that’ll slow down your boot process.

<?php
namespace MyModule;

use PPI\Framework\Module\AbstractModule;
use MyModule\Factory\UserSearchFactory;
use MyModule\Factory\UserCreateFactory;
use MyModule\Factory\UserImportService;

class Module extends AbstractModule
{

    public function getServiceConfig()
    {
        return ['factories' => [
            'user.search' => UserSearchFactory::class,
            'user.create' => UserCreateFactory::class,
            'user.import' => function ($sm) {
               return new UserImportService($sm->get('Doctrine\ORM\EntityManager'));
            }
        ]];
    }
}

Above you’ll see two types of ways to create a service. One is a Factory class and one is an inline factory closure. It’s recommended to use a Factory class but each to their own.

Creating a Service Factory

<?php
namespace MyModule\Factory;

use Zend\ServiceManager\ServiceLocatorInterface;
use Zend\ServiceManager\FactoryInterface;
use MyModule\Service\UserSearchService;

class UserSearchFactory implements FactoryInterface
{
    public function createService(ServiceLocatorInterface $sm)
    {
        $config = $sm->get('config');
        if(!isset($config['usersearch']['search_key']) {
            throw new \RuntimeException('Missing user search configuration');
        }

        return new UserSearchService(
            $config['usersearch']['search_key'],
            $sm->get('Doctrine\ORM\EntityManager')
        );
    }

}

Using services in our Controllers

To use the services in our Controllers, we just need to call $this->getService('service.name')

<?php
public function searchUsersAction(Request $request, $lat, $long)
{
    $userSearchService = $this->getService('user.search');
    $users = $userSearchService->getUsersFromLatLong($lat, $long);

    return $this->render('MyModule:search:searchUsers.twig', compact('users'));
}