Skip to content

Commit ce74151

Browse files
committed
expose domains feature
1 parent be6c7ec commit ce74151

File tree

7 files changed

+194
-19
lines changed

7 files changed

+194
-19
lines changed

Command/DumpCommand.php

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,13 @@ protected function configure()
101101
InputOption::VALUE_NONE,
102102
'Pretty print the JSON.'
103103
)
104+
->addOption(
105+
'domain',
106+
null,
107+
InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY,
108+
'Specify expose domain',
109+
array()
110+
)
104111
;
105112
}
106113

@@ -132,12 +139,15 @@ protected function execute(InputInterface $input, OutputInterface $output)
132139
*/
133140
private function doDump(InputInterface $input, OutputInterface $output)
134141
{
142+
$domain = $input->getOption('domain');
143+
135144
$extractor = $this->extractor;
136145
$serializer = $this->serializer;
137146
$targetPath = $input->getOption('target') ?:
138147
sprintf(
139-
'%s/../web/js/fos_js_routes.%s',
148+
'%s/../web/js/fos_js_routes%s.%s',
140149
$this->rootDir,
150+
empty($domain) ? '' : ('_' . implode('_', $domain)),
141151
$input->getOption('format')
142152
);
143153

@@ -168,7 +178,8 @@ private function doDump(InputInterface $input, OutputInterface $output)
168178
$extractor->getPrefix($input->getOption('locale')),
169179
$extractor->getHost(),
170180
$extractor->getPort(),
171-
$extractor->getScheme()
181+
$extractor->getScheme(),
182+
$domain
172183
),
173184
'json',
174185
$params

Command/RouterDebugExposedCommand.php

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
use Symfony\Component\Console\Output\OutputInterface;
2121
use Symfony\Component\Routing\Route;
2222
use Symfony\Component\Routing\RouterInterface;
23+
use Symfony\Component\Routing\RouteCollection;
2324

2425
/**
2526
* A console command for retrieving information about exposed routes.
@@ -54,6 +55,7 @@ protected function configure()
5455
new InputOption('show-controllers', null, InputOption::VALUE_NONE, 'Show assigned controllers in overview'),
5556
new InputOption('format', null, InputOption::VALUE_REQUIRED, 'The output format (txt, xml, json, or md)', 'txt'),
5657
new InputOption('raw', null, InputOption::VALUE_NONE, 'To output raw route(s)'),
58+
new InputOption('domain', null, InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, 'Specify expose domain', array())
5759
))
5860
->setName('fos:js-routing:debug')
5961
->setDescription('Displays currently exposed routes for an application')
@@ -96,11 +98,35 @@ protected function execute(InputInterface $input, OutputInterface $output)
9698
));
9799
} else {
98100
$helper = new DescriptorHelper();
99-
$helper->describe($output, $this->extractor->getRoutes(), array(
101+
$helper->describe($output, $this->getRoutes($input->getOption('domain')), array(
100102
'format' => $input->getOption('format'),
101103
'raw_text' => $input->getOption('raw'),
102104
'show_controllers' => $input->getOption('show-controllers'),
103105
));
104106
}
105107
}
108+
109+
protected function getRoutes($domain = array())
110+
{
111+
$routes = $this->extractor->getRoutes();
112+
113+
if (empty($domain)) {
114+
return $routes;
115+
}
116+
117+
$targetRoutes = new RouteCollection();
118+
119+
foreach ($routes as $name => $route) {
120+
121+
$expose = $route->getOption('expose');
122+
$expose = is_string($expose) ? ($expose === 'true' ? 'default' : $expose) : 'default';
123+
124+
if (in_array($expose, $domain, true)) {
125+
$targetRoutes->add($name, $route);
126+
}
127+
128+
}
129+
130+
return $targetRoutes;
131+
}
106132
}

Controller/Controller.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,8 @@ public function indexAction(Request $request, $_format)
9898
$this->exposedRoutesExtractor->getHost(),
9999
$this->exposedRoutesExtractor->getPort(),
100100
$this->exposedRoutesExtractor->getScheme(),
101-
$request->getLocale()
101+
$request->getLocale(),
102+
$request->query->has('domain') ? explode(',', $request->query->get('domain')) : array()
102103
);
103104

104105
$content = $this->serializer->serialize($routesResponse, 'json');

Extractor/ExposedRoutesExtractor.php

Lines changed: 85 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -38,25 +38,37 @@ class ExposedRoutesExtractor implements ExposedRoutesExtractorInterface
3838
*/
3939
protected $bundles;
4040

41+
/**
42+
* @var string
43+
*/
44+
protected $pattern;
45+
4146
/**
4247
* @var array
4348
*/
44-
protected $routesToExpose;
49+
protected $availableDomains;
4550

4651
/**
4752
* Default constructor.
4853
*
49-
* @param RouterInterface $router The router.
50-
* @param array $routesToExpose Some route names to expose.
51-
* @param string $cacheDir
52-
* @param array $bundles list of loaded bundles to check when generating the prefix
54+
* @param RouterInterface $router The router.
55+
* @param array $routesToExpose Some route names to expose.
56+
* @param string $cacheDir
57+
* @param array $bundles list of loaded bundles to check when generating the prefix
58+
*
59+
* @throws \Exception
5360
*/
5461
public function __construct(RouterInterface $router, array $routesToExpose = array(), $cacheDir, $bundles = array())
5562
{
5663
$this->router = $router;
57-
$this->routesToExpose = $routesToExpose;
5864
$this->cacheDir = $cacheDir;
5965
$this->bundles = $bundles;
66+
67+
$domainPatterns = $this->extractDomainPatterns($routesToExpose);
68+
69+
$this->availableDomains = array_keys($domainPatterns);
70+
71+
$this->pattern = $this->buildPattern($domainPatterns);
6072
}
6173

6274
/**
@@ -69,9 +81,27 @@ public function getRoutes()
6981

7082
/** @var Route $route */
7183
foreach ($collection->all() as $name => $route) {
72-
if ($this->isRouteExposed($route, $name)) {
84+
85+
if ($route->hasOption('expose')) {
7386
$routes->add($name, $route);
87+
continue;
7488
}
89+
90+
preg_match('#' . $this->pattern . '#', $name, $matches);
91+
92+
if (count($matches) === 0) {
93+
continue;
94+
}
95+
96+
$domain = $this->getDomainByRouteMatches($matches, $name);
97+
98+
if (is_null($domain)) {
99+
continue;
100+
}
101+
102+
$route = clone $route;
103+
$route->setOption('expose', $domain);
104+
$routes->add($name, $route);
75105
}
76106

77107
return $routes;
@@ -166,23 +196,64 @@ public function getResources()
166196
*/
167197
public function isRouteExposed(Route $route, $name)
168198
{
169-
$pattern = $this->buildPattern();
199+
return true === $route->hasOption('expose') ||
200+
('' !== $this->pattern && preg_match('#' . $this->pattern . '#', $name));
201+
}
170202

171-
return true === $route->getOption('expose')
172-
|| 'true' === $route->getOption('expose')
173-
|| ('' !== $pattern && preg_match('#' . $pattern . '#', $name));
203+
protected function getDomainByRouteMatches($matches, $name)
204+
{
205+
$matches = array_filter($matches, function($match) {
206+
return !empty($match);
207+
});
208+
209+
$matches = array_flip(array_intersect_key($matches, array_flip($this->availableDomains)));
210+
211+
return isset($matches[$name]) ? $matches[$name] : null;
212+
}
213+
214+
protected function extractDomainPatterns($routesToExpose)
215+
{
216+
$domainPatterns = array();
217+
218+
foreach ($routesToExpose as $item) {
219+
220+
if (is_string($item)) {
221+
$domainPatterns['default'][] = $item;
222+
continue;
223+
}
224+
225+
if (is_array($item) && is_string($item['pattern'])) {
226+
227+
if (!isset($item['domain'])) {
228+
$domainPatterns['default'][] = $item['pattern'];
229+
continue;
230+
} elseif (is_string($item['domain'])) {
231+
$domainPatterns[$item['domain']][] = $item['pattern'];
232+
continue;
233+
}
234+
235+
}
236+
237+
throw new \Exception('routes_to_expose definition is invalid');
238+
}
239+
240+
return $domainPatterns;
174241
}
175242

176243
/**
177244
* Convert the routesToExpose array in a regular expression pattern
178245
*
246+
* @param $domainPatterns
179247
* @return string
248+
* @throws \Exception
180249
*/
181-
protected function buildPattern()
250+
protected function buildPattern($domainPatterns)
182251
{
183252
$patterns = array();
184-
foreach ($this->routesToExpose as $toExpose) {
185-
$patterns[] = '(' . $toExpose . ')';
253+
254+
foreach ($domainPatterns as $domain => $items) {
255+
256+
$patterns[] = '(?P<' . $domain . '>' . implode($items, '|') . ')';
186257
}
187258

188259
return implode($patterns, '|');

Response/RoutesResponse.php

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,10 @@ class RoutesResponse
2222
private $port;
2323
private $scheme;
2424
private $locale;
25+
private $domains;
2526

26-
public function __construct($baseUrl, RouteCollection $routes = null, $prefix = null, $host = null, $port = null, $scheme = null, $locale = null)
27+
public function __construct($baseUrl, RouteCollection $routes = null, $prefix = null, $host = null, $port = null,
28+
$scheme = null, $locale = null, $domains = array())
2729
{
2830
$this->baseUrl = $baseUrl;
2931
$this->routes = $routes ?: new RouteCollection();
@@ -32,6 +34,7 @@ public function __construct($baseUrl, RouteCollection $routes = null, $prefix =
3234
$this->port = $port;
3335
$this->scheme = $scheme;
3436
$this->locale = $locale;
37+
$this->domains = $domains;
3538
}
3639

3740
public function getBaseUrl()
@@ -43,6 +46,23 @@ public function getRoutes()
4346
{
4447
$exposedRoutes = array();
4548
foreach ($this->routes->all() as $name => $route) {
49+
50+
if (!$route->hasOption('expose')) {
51+
$domain = 'default';
52+
} else {
53+
$domain = $route->getOption('expose');
54+
$domain = is_string($domain) ? ($domain === 'true' ? 'default' : $domain) : 'default';
55+
}
56+
57+
58+
if (count($this->domains) === 0) {
59+
if ($domain !== 'default') {
60+
continue;
61+
}
62+
} elseif (!in_array($domain, $this->domains, true)) {
63+
continue;
64+
}
65+
4666
$compiledRoute = $route->compile();
4767
$defaults = array_intersect_key(
4868
$route->getDefaults(),

Tests/Controller/ControllerTest.php

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,49 @@ public function testCacheControl()
157157
$this->assertEquals(456, $response->headers->getCacheControlDirective('s-maxage'));
158158
}
159159

160+
public function testExposeDomain()
161+
{
162+
$routes = new RouteCollection();
163+
$routes->add('homepage', new Route('/'));
164+
$routes->add('admin_index', new Route('/admin', array(), array(),
165+
array('expose' => 'admin')));
166+
$routes->add('admin_pages', new Route('/admin/path', array(), array(),
167+
array('expose' => 'admin')));
168+
$routes->add('blog_index', new Route('/blog', array(), array(),
169+
array('expose' => 'blog'), 'localhost'));
170+
$routes->add('blog_post', new Route('/blog/{slug}', array(), array(),
171+
array('expose' => 'blog'), 'localhost'));
172+
173+
$controller = new Controller(
174+
$this->getSerializer(),
175+
$this->getExtractor($routes)
176+
);
177+
178+
$response = $controller->indexAction($this->getRequest('/'), 'json');
179+
180+
$this->assertEquals('{"base_url":"","routes":{"homepage":{"tokens":[["text","\/"]],"defaults":[],"requirements":[],"hosttokens":[],"methods":[],"schemes":[]}},"prefix":"","host":"","port":null,"scheme":""}', $response->getContent());
181+
182+
$response = $controller->indexAction($this->getRequest('/',
183+
'GET', array('domain' => 'admin')), 'json');
184+
185+
$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());
186+
187+
$response = $controller->indexAction($this->getRequest('/',
188+
'GET', array('domain' => 'blog')), 'json');
189+
190+
$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());
191+
192+
$response = $controller->indexAction($this->getRequest('/',
193+
'GET', array('domain' => 'admin,blog')), 'json');
194+
195+
$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());
196+
197+
$response = $controller->indexAction($this->getRequest('/',
198+
'GET', array('domain' => 'default,admin,blog')), 'json');
199+
200+
$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());
201+
}
202+
160203
private function getExtractor(RouteCollection $exposedRoutes = null, $baseUrl = '')
161204
{
162205
if (null === $exposedRoutes) {

Tests/Extractor/ExposedRoutesExtractorTest.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ public function testGetRoutes()
4444

4545
$router = $this->getRouter($expected);
4646
$extractor = new ExposedRoutesExtractor($router, array('.*'), $this->cacheDir, array());
47+
48+
$expected->addOptions(array('expose' => 'default'));
49+
4750
$this->assertEquals($expected, $extractor->getRoutes());
4851
}
4952

0 commit comments

Comments
 (0)