The Service Layer

My Service Layer provides whatever public methods are required by the controllers and occasionally views. To maximise the utility of the Service Layer, each of its classes is service-locator-aware, and each has its own event listener.

Core\Service\ServiceLoader is the abstract factory responsible for creating Service Layer services and you can see there how it creates and injects the event listener.

Here is the code for a sample Bar Service.

namespace Core\Service;

class Bar extends AbstractService
{
    public function updateBaz($bar, $baz)
    {
        $bar = $this->serviceLocator->get('Mapper\Bar')->find($bar);
        $baz = $this->serviceLocator->get('Mapper\Baz')->find($baz);

        $bar->baz = $baz;
        $this->serviceLocator->get('Mapper\Bar')->update($bar);

        // optional: trigger an event
        $this->eventManager->trigger(__FUNCTION__ . '.post', $this, array(
            'bar' => $bar,
            'baz' => $baz
        ));

        return $baz;
    }
}

As a general rule, all calls to Mappers to persist changes are made from the Service Layer. If this becomes difficult to manage, you might consider extending the Domain Watcher, and using the Unit of Work patten for persistence.

Service Layer Events

Service Layer Events can be used to separate out entire aspects of the application, such as logging or authentication, from the main workflow. Alternatively they may be used for one-off tasks such as triggering an email.

Events which are triggered by a range of workflows are best placed in the AbstractListener base class. Those that apply only to a particular Service Layer service may be placed in the concrete listener that belongs to that particular service. All listeners are stored in the Core\Service\Event namespace.

Here's an example of a listener that should be activated when Bar::updateBaz has executed.

namespace Core\Service\Event;

use Zend\EventManager\EventInterface;
use Zend\EventManager\EventManagerInterface;

class BarService extends AbstractListener 
{
    public function attach(EventManagerInterface $em)
    {
        $em->attach('updateBaz.post', array($this, 'emailAdmin'));
    }

    public function emailAdmin(EventInterface $e)
    {
        // do some stuff here
    }
}