<?php
/**
* Part of the Joomla Framework Event Package
*
* @copyright Copyright (C) 2005 - 2021 Open Source Matters, Inc. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
*/
namespace Joomla\Event;
use Psr\Container\ContainerInterface;
/**
* Decorator for an event listener to be pulled from the service container.
*
* @since 2.0.0
*/
final class LazyServiceEventListener
{
/**
* The service container to load the service from
*
* @var string
* @since 2.0.0
*/
private $container;
/**
* The ID of the service from the container to be used
*
* @var string
* @since 2.0.0
*/
private $serviceId;
/**
* The method from the service to be called
*
* @var string
* @since 2.0.0
*/
private $method;
/**
* Constructor.
*
* @param ContainerInterface $container The service container to load the service from when it shall be executed
* @param string $serviceId The ID of the service from the container to be used
* @param string $method The method from the service to be called if necessary. If left empty, the service must be a callable;
* (i.e. have an `__invoke()` method on a class)
*
* @since 2.0.0
* @throws \InvalidArgumentException if the service ID is empty
*/
public function __construct(ContainerInterface $container, string $serviceId, string $method = '')
{
if (empty($serviceId))
{
throw new \InvalidArgumentException(
sprintf(
'The $serviceId parameter cannot be empty in %s',
self::class
)
);
}
$this->container = $container;
$this->serviceId = $serviceId;
$this->method = $method;
}
/**
* Load a service from the container to listen to an event.
*
* @param EventInterface $event The event to process
*
* @return void
*
* @since 2.0.0
* @throws \InvalidArgumentException if the constructor's $method parameter is empty when not executing a callable service
* @throws \RuntimeException if the service cannot be executed
*/
public function __invoke(EventInterface $event): void
{
if (!$this->container->has($this->serviceId))
{
throw new \RuntimeException(
sprintf(
'The "%s" service has not been registered to the service container',
$this->serviceId
)
);
}
$service = $this->container->get($this->serviceId);
// If the service is callable on its own, just execute it
if (\is_callable($service))
{
\call_user_func($service, $event);
return;
}
if (empty($this->method))
{
throw new \InvalidArgumentException(
sprintf(
'The $method argument is required when creating a "%s" to call a method from the "%s" service.',
self::class,
$this->serviceId
)
);
}
if (!method_exists($service, $this->method))
{
throw new \RuntimeException(
sprintf(
'The "%s" method does not exist on "%s" (from service "%s")',
$this->method,
\get_class($service),
$this->serviceId
)
);
}
\call_user_func([$service, $this->method], $event);
}
}