Skip to content

Commit

Permalink
Merge pull request #347 from tugrul/expose_domains
Browse files Browse the repository at this point in the history
Expose domains
  • Loading branch information
tobias-93 committed Feb 3, 2019
2 parents be6c7ec + ce74151 commit 34f7c6c
Show file tree
Hide file tree
Showing 7 changed files with 194 additions and 19 deletions.
15 changes: 13 additions & 2 deletions Command/DumpCommand.php
Expand Up @@ -101,6 +101,13 @@ protected function configure()
InputOption::VALUE_NONE,
'Pretty print the JSON.'
)
->addOption(
'domain',
null,
InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY,
'Specify expose domain',
array()
)
;
}

Expand Down Expand Up @@ -132,12 +139,15 @@ protected function execute(InputInterface $input, OutputInterface $output)
*/
private function doDump(InputInterface $input, OutputInterface $output)
{
$domain = $input->getOption('domain');

$extractor = $this->extractor;
$serializer = $this->serializer;
$targetPath = $input->getOption('target') ?:
sprintf(
'%s/../web/js/fos_js_routes.%s',
'%s/../web/js/fos_js_routes%s.%s',
$this->rootDir,
empty($domain) ? '' : ('_' . implode('_', $domain)),
$input->getOption('format')
);

Expand Down Expand Up @@ -168,7 +178,8 @@ private function doDump(InputInterface $input, OutputInterface $output)
$extractor->getPrefix($input->getOption('locale')),
$extractor->getHost(),
$extractor->getPort(),
$extractor->getScheme()
$extractor->getScheme(),
$domain
),
'json',
$params
Expand Down
28 changes: 27 additions & 1 deletion Command/RouterDebugExposedCommand.php
Expand Up @@ -20,6 +20,7 @@
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Routing\Route;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Component\Routing\RouteCollection;

/**
* A console command for retrieving information about exposed routes.
Expand Down Expand Up @@ -54,6 +55,7 @@ protected function configure()
new InputOption('show-controllers', null, InputOption::VALUE_NONE, 'Show assigned controllers in overview'),
new InputOption('format', null, InputOption::VALUE_REQUIRED, 'The output format (txt, xml, json, or md)', 'txt'),
new InputOption('raw', null, InputOption::VALUE_NONE, 'To output raw route(s)'),
new InputOption('domain', null, InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, 'Specify expose domain', array())
))
->setName('fos:js-routing:debug')
->setDescription('Displays currently exposed routes for an application')
Expand Down Expand Up @@ -96,11 +98,35 @@ protected function execute(InputInterface $input, OutputInterface $output)
));
} else {
$helper = new DescriptorHelper();
$helper->describe($output, $this->extractor->getRoutes(), array(
$helper->describe($output, $this->getRoutes($input->getOption('domain')), array(
'format' => $input->getOption('format'),
'raw_text' => $input->getOption('raw'),
'show_controllers' => $input->getOption('show-controllers'),
));
}
}

protected function getRoutes($domain = array())
{
$routes = $this->extractor->getRoutes();

if (empty($domain)) {
return $routes;
}

$targetRoutes = new RouteCollection();

foreach ($routes as $name => $route) {

$expose = $route->getOption('expose');
$expose = is_string($expose) ? ($expose === 'true' ? 'default' : $expose) : 'default';

if (in_array($expose, $domain, true)) {
$targetRoutes->add($name, $route);
}

}

return $targetRoutes;
}
}
3 changes: 2 additions & 1 deletion Controller/Controller.php
Expand Up @@ -98,7 +98,8 @@ public function indexAction(Request $request, $_format)
$this->exposedRoutesExtractor->getHost(),
$this->exposedRoutesExtractor->getPort(),
$this->exposedRoutesExtractor->getScheme(),
$request->getLocale()
$request->getLocale(),
$request->query->has('domain') ? explode(',', $request->query->get('domain')) : array()
);

$content = $this->serializer->serialize($routesResponse, 'json');
Expand Down
99 changes: 85 additions & 14 deletions Extractor/ExposedRoutesExtractor.php
Expand Up @@ -38,25 +38,37 @@ class ExposedRoutesExtractor implements ExposedRoutesExtractorInterface
*/
protected $bundles;

/**
* @var string
*/
protected $pattern;

/**
* @var array
*/
protected $routesToExpose;
protected $availableDomains;

/**
* Default constructor.
*
* @param RouterInterface $router The router.
* @param array $routesToExpose Some route names to expose.
* @param string $cacheDir
* @param array $bundles list of loaded bundles to check when generating the prefix
* @param RouterInterface $router The router.
* @param array $routesToExpose Some route names to expose.
* @param string $cacheDir
* @param array $bundles list of loaded bundles to check when generating the prefix
*
* @throws \Exception
*/
public function __construct(RouterInterface $router, array $routesToExpose = array(), $cacheDir, $bundles = array())
{
$this->router = $router;
$this->routesToExpose = $routesToExpose;
$this->cacheDir = $cacheDir;
$this->bundles = $bundles;

$domainPatterns = $this->extractDomainPatterns($routesToExpose);

$this->availableDomains = array_keys($domainPatterns);

$this->pattern = $this->buildPattern($domainPatterns);
}

/**
Expand All @@ -69,9 +81,27 @@ public function getRoutes()

/** @var Route $route */
foreach ($collection->all() as $name => $route) {
if ($this->isRouteExposed($route, $name)) {

if ($route->hasOption('expose')) {
$routes->add($name, $route);
continue;
}

preg_match('#' . $this->pattern . '#', $name, $matches);

if (count($matches) === 0) {
continue;
}

$domain = $this->getDomainByRouteMatches($matches, $name);

if (is_null($domain)) {
continue;
}

$route = clone $route;
$route->setOption('expose', $domain);
$routes->add($name, $route);
}

return $routes;
Expand Down Expand Up @@ -166,23 +196,64 @@ public function getResources()
*/
public function isRouteExposed(Route $route, $name)
{
$pattern = $this->buildPattern();
return true === $route->hasOption('expose') ||
('' !== $this->pattern && preg_match('#' . $this->pattern . '#', $name));
}

return true === $route->getOption('expose')
|| 'true' === $route->getOption('expose')
|| ('' !== $pattern && preg_match('#' . $pattern . '#', $name));
protected function getDomainByRouteMatches($matches, $name)
{
$matches = array_filter($matches, function($match) {
return !empty($match);
});

$matches = array_flip(array_intersect_key($matches, array_flip($this->availableDomains)));

return isset($matches[$name]) ? $matches[$name] : null;
}

protected function extractDomainPatterns($routesToExpose)
{
$domainPatterns = array();

foreach ($routesToExpose as $item) {

if (is_string($item)) {
$domainPatterns['default'][] = $item;
continue;
}

if (is_array($item) && is_string($item['pattern'])) {

if (!isset($item['domain'])) {
$domainPatterns['default'][] = $item['pattern'];
continue;
} elseif (is_string($item['domain'])) {
$domainPatterns[$item['domain']][] = $item['pattern'];
continue;
}

}

throw new \Exception('routes_to_expose definition is invalid');
}

return $domainPatterns;
}

/**
* Convert the routesToExpose array in a regular expression pattern
*
* @param $domainPatterns
* @return string
* @throws \Exception
*/
protected function buildPattern()
protected function buildPattern($domainPatterns)
{
$patterns = array();
foreach ($this->routesToExpose as $toExpose) {
$patterns[] = '(' . $toExpose . ')';

foreach ($domainPatterns as $domain => $items) {

$patterns[] = '(?P<' . $domain . '>' . implode($items, '|') . ')';
}

return implode($patterns, '|');
Expand Down
22 changes: 21 additions & 1 deletion Response/RoutesResponse.php
Expand Up @@ -22,8 +22,10 @@ class RoutesResponse
private $port;
private $scheme;
private $locale;
private $domains;

public function __construct($baseUrl, RouteCollection $routes = null, $prefix = null, $host = null, $port = null, $scheme = null, $locale = null)
public function __construct($baseUrl, RouteCollection $routes = null, $prefix = null, $host = null, $port = null,
$scheme = null, $locale = null, $domains = array())
{
$this->baseUrl = $baseUrl;
$this->routes = $routes ?: new RouteCollection();
Expand All @@ -32,6 +34,7 @@ public function __construct($baseUrl, RouteCollection $routes = null, $prefix =
$this->port = $port;
$this->scheme = $scheme;
$this->locale = $locale;
$this->domains = $domains;
}

public function getBaseUrl()
Expand All @@ -43,6 +46,23 @@ public function getRoutes()
{
$exposedRoutes = array();
foreach ($this->routes->all() as $name => $route) {

if (!$route->hasOption('expose')) {
$domain = 'default';
} else {
$domain = $route->getOption('expose');
$domain = is_string($domain) ? ($domain === 'true' ? 'default' : $domain) : 'default';
}


if (count($this->domains) === 0) {
if ($domain !== 'default') {
continue;
}
} elseif (!in_array($domain, $this->domains, true)) {
continue;
}

$compiledRoute = $route->compile();
$defaults = array_intersect_key(
$route->getDefaults(),
Expand Down
43 changes: 43 additions & 0 deletions Tests/Controller/ControllerTest.php
Expand Up @@ -157,6 +157,49 @@ public function testCacheControl()
$this->assertEquals(456, $response->headers->getCacheControlDirective('s-maxage'));
}

public function testExposeDomain()
{
$routes = new RouteCollection();
$routes->add('homepage', new Route('/'));
$routes->add('admin_index', new Route('/admin', array(), array(),
array('expose' => 'admin')));
$routes->add('admin_pages', new Route('/admin/path', array(), array(),
array('expose' => 'admin')));
$routes->add('blog_index', new Route('/blog', array(), array(),
array('expose' => 'blog'), 'localhost'));
$routes->add('blog_post', new Route('/blog/{slug}', array(), array(),
array('expose' => 'blog'), 'localhost'));

$controller = new Controller(
$this->getSerializer(),
$this->getExtractor($routes)
);

$response = $controller->indexAction($this->getRequest('/'), 'json');

$this->assertEquals('{"base_url":"","routes":{"homepage":{"tokens":[["text","\/"]],"defaults":[],"requirements":[],"hosttokens":[],"methods":[],"schemes":[]}},"prefix":"","host":"","port":null,"scheme":""}', $response->getContent());

$response = $controller->indexAction($this->getRequest('/',
'GET', array('domain' => 'admin')), 'json');

$this->assertEquals('{"base_url":"","routes":{"admin_index":{"tokens":[["text","\/admin"]],"defaults":[],"requirements":[],"hosttokens":[],"methods":[],"schemes":[]},"admin_pages":{"tokens":[["text","\/admin\/path"]],"defaults":[],"requirements":[],"hosttokens":[],"methods":[],"schemes":[]}},"prefix":"","host":"","port":null,"scheme":""}', $response->getContent());

$response = $controller->indexAction($this->getRequest('/',
'GET', array('domain' => 'blog')), 'json');

$this->assertEquals('{"base_url":"","routes":{"blog_index":{"tokens":[["text","\/blog"]],"defaults":[],"requirements":[],"hosttokens":[["text","localhost"]],"methods":[],"schemes":[]},"blog_post":{"tokens":[["variable","\/","[^\/]++","slug"],["text","\/blog"]],"defaults":[],"requirements":[],"hosttokens":[["text","localhost"]],"methods":[],"schemes":[]}},"prefix":"","host":"","port":null,"scheme":""}', $response->getContent());

$response = $controller->indexAction($this->getRequest('/',
'GET', array('domain' => 'admin,blog')), 'json');

$this->assertEquals('{"base_url":"","routes":{"admin_index":{"tokens":[["text","\/admin"]],"defaults":[],"requirements":[],"hosttokens":[],"methods":[],"schemes":[]},"admin_pages":{"tokens":[["text","\/admin\/path"]],"defaults":[],"requirements":[],"hosttokens":[],"methods":[],"schemes":[]},"blog_index":{"tokens":[["text","\/blog"]],"defaults":[],"requirements":[],"hosttokens":[["text","localhost"]],"methods":[],"schemes":[]},"blog_post":{"tokens":[["variable","\/","[^\/]++","slug"],["text","\/blog"]],"defaults":[],"requirements":[],"hosttokens":[["text","localhost"]],"methods":[],"schemes":[]}},"prefix":"","host":"","port":null,"scheme":""}', $response->getContent());

$response = $controller->indexAction($this->getRequest('/',
'GET', array('domain' => 'default,admin,blog')), 'json');

$this->assertEquals('{"base_url":"","routes":{"homepage":{"tokens":[["text","\/"]],"defaults":[],"requirements":[],"hosttokens":[],"methods":[],"schemes":[]},"admin_index":{"tokens":[["text","\/admin"]],"defaults":[],"requirements":[],"hosttokens":[],"methods":[],"schemes":[]},"admin_pages":{"tokens":[["text","\/admin\/path"]],"defaults":[],"requirements":[],"hosttokens":[],"methods":[],"schemes":[]},"blog_index":{"tokens":[["text","\/blog"]],"defaults":[],"requirements":[],"hosttokens":[["text","localhost"]],"methods":[],"schemes":[]},"blog_post":{"tokens":[["variable","\/","[^\/]++","slug"],["text","\/blog"]],"defaults":[],"requirements":[],"hosttokens":[["text","localhost"]],"methods":[],"schemes":[]}},"prefix":"","host":"","port":null,"scheme":""}', $response->getContent());
}

private function getExtractor(RouteCollection $exposedRoutes = null, $baseUrl = '')
{
if (null === $exposedRoutes) {
Expand Down
3 changes: 3 additions & 0 deletions Tests/Extractor/ExposedRoutesExtractorTest.php
Expand Up @@ -44,6 +44,9 @@ public function testGetRoutes()

$router = $this->getRouter($expected);
$extractor = new ExposedRoutesExtractor($router, array('.*'), $this->cacheDir, array());

$expected->addOptions(array('expose' => 'default'));

$this->assertEquals($expected, $extractor->getRoutes());
}

Expand Down

0 comments on commit 34f7c6c

Please sign in to comment.