<?php
namespace Can\RestBundle\EventListener;
use Can\RestBundle\CanRestBundle;
use Can\RestBundle\Token\Generator\UUIDGenerator;
use Can\RestBundle\URI\ServiceNode;
use Can\RestBundle\URI\ServiceNodeStorage;
use Can\RestBundle\URI\URIParserInterface;
use Can\URI\Exception\MalformedURIException;
use Can\URI\URI;
use Symfony\Component\HttpFoundation\RequestMatcherInterface;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Exception;
/**
* Matches REST zones.
*
* @group service
*
* @package can/rest-bundle
* @author lechecacharro <lechecacharro@gmail.com>
*/
class ZoneMatcherListener
{
/**
* @var ServiceNodeStorage
*/
private $storage;
/**
* @var URIParserInterface
*/
private $parser;
/**
* @var UUIDGenerator
*/
private $generator;
/**
* @var RequestMatcherInterface[]
*/
private $matchers = [];
/**
* ZoneMatcherListener constructor.
*
* @param ServiceNodeStorage $storage
* @param URIParserInterface $parser
* @param UUIDGenerator $generator
*/
public function __construct(ServiceNodeStorage $storage, URIParserInterface $parser, UUIDGenerator $generator)
{
$this->storage = $storage;
$this->parser = $parser;
$this->generator = $generator;
}
/**
* @param RequestMatcherInterface $matcher
*/
public function addRequestMatcher(RequestMatcherInterface $matcher): void
{
$this->matchers[] = $matcher;
}
/**
* @param RequestEvent $event
*
* @throws Exception
*/
public function onRequest(RequestEvent $event): void
{
if (! $event->isMasterRequest()) {
return;
}
$request = $event->getRequest();
try {
$requestUri = new URI($request->getUri());
} catch (MalformedURIException $e) {
throw new BadRequestHttpException(null, $e);
}
foreach ($this->matchers as $matcher) {
if ($matcher->matches($request)) {
$node = $this->parser->parse($requestUri);
$uuid = $this->generator->uuid();
$request->attributes->set(CanRestBundle::ATTR_SERVICE_NODE, $node);
$request->attributes->set(CanRestBundle::ATTR_SERVICE_VERSION, $node->getVersionNumber());
$request->attributes->set(CanRestBundle::ATTR_SERVICE_ZONE, true);
$request->attributes->set(CanRestBundle::ATTR_REQUEST_UUID, $uuid);
// Populate also the service node storage, so all services
// which require access to the current service node (which
// use the storage) have it available from now on...
$this->storage->setServiceNode($node);
return;
}
}
$request->attributes->set(CanRestBundle::ATTR_SERVICE_ZONE, false);
}
}