Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 1abbd58

Browse files
committed
[Routing] Convert the PhpGeneratorDumper to an AstGeneratorInterface
1 parent 86f5150 commit 1abbd58

File tree

5 files changed

+234
-105
lines changed

5 files changed

+234
-105
lines changed

src/Symfony/Component/AstGenerator/Util/AstHelper.php

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,50 @@
1111

1212
namespace Symfony\Component\AstGenerator\Util;
1313

14+
use PhpParser\Node;
1415
use PhpParser\Node\Expr;
16+
use PhpParser\Node\Name;
1517
use PhpParser\Node\Scalar;
18+
use PhpParser\ParserFactory;
19+
use PhpParser\PrettyPrinter\Standard;
1620

21+
/**
22+
* @internal
23+
*/
1724
final class AstHelper
1825
{
26+
private static $parser;
27+
28+
/**
29+
* @param Node[] $stmts
30+
*
31+
* @return string the php code
32+
*/
33+
public static function dump(array $stmts)
34+
{
35+
$printer = new Standard();
36+
37+
return $printer->prettyPrintFile($stmts);
38+
}
39+
40+
/**
41+
* Transforms php code into an ast node.
42+
*
43+
* @param string $code the php code
44+
*
45+
* @return Node[]
46+
*/
47+
public static function raw($code)
48+
{
49+
$code = "<?php \n".$code;
50+
if (null === self::$parser) {
51+
$parserFactory = new ParserFactory();
52+
self::$parser = $parserFactory->create(ParserFactory::ONLY_PHP5);
53+
}
54+
55+
return self::$parser->parse($code);
56+
}
57+
1958
/**
2059
* Transforms a php value into an AST node.
2160
*
@@ -46,13 +85,13 @@ public static function value($value)
4685
// for consecutive, numeric keys don't generate keys
4786
if (null !== $lastKey && ++$lastKey === $itemKey) {
4887
$items[] = new Expr\ArrayItem(
49-
$this->normalizeValue($itemValue)
88+
self::value($itemValue)
5089
);
5190
} else {
5291
$lastKey = null;
5392
$items[] = new Expr\ArrayItem(
54-
$this->normalizeValue($itemValue),
55-
$this->normalizeValue($itemKey)
93+
self::value($itemValue),
94+
self::value($itemKey)
5695
);
5796
}
5897
}
@@ -61,7 +100,6 @@ public static function value($value)
61100
} else {
62101
throw new \LogicException('Invalid value');
63102
}
64-
65103
}
66104

67105
private function __construct()
Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Routing\Generator\AstGenerator;
13+
14+
use PhpParser\BuilderFactory;
15+
use PhpParser\Comment;
16+
use PhpParser\Node\Arg;
17+
use PhpParser\Node\Name;
18+
use PhpParser\Node\Param;
19+
use PhpParser\Node\Stmt;
20+
use PhpParser\Node\Expr;
21+
use PhpParser\Node\Scalar;
22+
use Psr\Log\LoggerInterface;
23+
use Symfony\Component\AstGenerator\AstGeneratorInterface;
24+
use Symfony\Component\AstGenerator\Util\AstHelper;
25+
use Symfony\Component\ExpressionLanguage\ExpressionFunctionProviderInterface;
26+
use Symfony\Component\Routing\Exception\MethodNotAllowedException;
27+
use Symfony\Component\Routing\Exception\ResourceNotFoundException;
28+
use Symfony\Component\Routing\Exception\RouteNotFoundException;
29+
use Symfony\Component\Routing\Generator\UrlGenerator;
30+
use Symfony\Component\Routing\RequestContext;
31+
32+
/**
33+
* @author Guilhem N. <[email protected]>
34+
*/
35+
class UrlGeneratorGenerator implements AstGeneratorInterface
36+
{
37+
public function __construct()
38+
{
39+
$this->factory = new BuilderFactory();
40+
}
41+
42+
/**
43+
* {@inheritdoc}
44+
*/
45+
public function generate($object, array $context = array())
46+
{
47+
$context = array_replace(array(
48+
'class' => 'ProjectUrlGenerator',
49+
'base_class' => UrlGenerator::class,
50+
), $context);
51+
52+
return array($this->generateClass($object, $context)->getNode());
53+
}
54+
55+
/**
56+
* {@inheritdoc}
57+
*/
58+
public function supportsGeneration($object)
59+
{
60+
return is_string($object) && class_exists($object);
61+
}
62+
63+
private function generateClass($object, array $context)
64+
{
65+
$docComment = <<<COMMENT
66+
/**
67+
* {$context['class']}.
68+
*
69+
* This class has been auto-generated
70+
* by the Symfony Routing Component.
71+
*/
72+
COMMENT;
73+
74+
return $this->factory->class($context['class'])
75+
->setDocComment($docComment)
76+
->extend($context['base_class'])
77+
->addStmt($this->factory->property('declaredRoutes')->makePrivate()->makeStatic())
78+
->addStmt($this->generateConstructor($object, $context))
79+
->addStmt($this->generateGenerateMethod($object, $context));
80+
}
81+
82+
private function generateConstructor($object, array $context)
83+
{
84+
$constructor = $this->factory->method('__construct')
85+
->makePublic()
86+
->addParam($this->factory->param('context')->setTypeHint(RequestContext::class))
87+
->addParam($this->factory->param('logger')->setTypeHint(LoggerInterface::class)->setDefault(null));
88+
89+
$code = <<<'EOF'
90+
$this->context = $context;
91+
$this->logger = $logger;
92+
EOF;
93+
foreach (AstHelper::raw($code) as $stmt) {
94+
$constructor->addStmt($stmt);
95+
}
96+
97+
$constructor->addStmt(new Stmt\If_(
98+
new Expr\BinaryOp\Equal(
99+
AstHelper::value(null),
100+
new Expr\StaticPropertyFetch(new Name('self'), 'declaredRoutes')
101+
),
102+
array(
103+
'stmts' => array(
104+
new Expr\Assign(
105+
new Expr\StaticPropertyFetch(new Name('self'), 'declaredRoutes'),
106+
$this->generateDeclaredRoutes($object, $context)
107+
)
108+
)
109+
)
110+
));
111+
112+
return $constructor;
113+
}
114+
115+
/**
116+
* Generates an AST node representing an array of defined routes
117+
* together with the routes properties (e.g. requirements).
118+
*
119+
* @return Expr\Array_
120+
*/
121+
private function generateDeclaredRoutes($object, array $context)
122+
{
123+
$routes = array();
124+
foreach ($object->all() as $name => $route) {
125+
$compiledRoute = $route->compile();
126+
127+
$properties = array();
128+
$properties[] = $compiledRoute->getVariables();
129+
$properties[] = $route->getDefaults();
130+
$properties[] = $route->getRequirements();
131+
$properties[] = $compiledRoute->getTokens();
132+
$properties[] = $compiledRoute->getHostTokens();
133+
$properties[] = $route->getSchemes();
134+
135+
$routes[$name] = $properties;
136+
}
137+
138+
return AstHelper::value($routes);
139+
}
140+
141+
/**
142+
* Generates an AST node representing the `generate` method that implements the UrlGeneratorInterface.
143+
*
144+
* @return string PHP code
145+
*/
146+
private function generateGenerateMethod()
147+
{
148+
$generateMethod = $this->factory
149+
->method('generate')
150+
->makePublic()
151+
->addParam($this->factory->param('name'))
152+
->addParam($this->factory->param('parameters')->setDefault(array()))
153+
->addParam($this->factory->param('referenceType')->setDefault(UrlGenerator::ABSOLUTE_PATH));
154+
155+
$exception = RouteNotFoundException::class;
156+
$code = <<<EOF
157+
if (!isset(self::\$declaredRoutes[\$name])) {
158+
throw new {$exception}(sprintf('Unable to generate a URL for the named route "%s" as such route does not exist.', \$name));
159+
}
160+
161+
list(\$variables, \$defaults, \$requirements, \$tokens, \$hostTokens, \$requiredSchemes) = self::\$declaredRoutes[\$name];
162+
163+
return \$this->doGenerate(\$variables, \$defaults, \$requirements, \$tokens, \$parameters, \$name, \$referenceType, \$hostTokens, \$requiredSchemes);
164+
EOF;
165+
166+
foreach (AstHelper::raw($code) as $stmt) {
167+
$generateMethod->addStmt($stmt);
168+
}
169+
170+
return $generateMethod;
171+
}
172+
}

src/Symfony/Component/Routing/Generator/Dumper/PhpGeneratorDumper.php

Lines changed: 6 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111

1212
namespace Symfony\Component\Routing\Generator\Dumper;
1313

14+
use Symfony\Component\AstGenerator\Util\AstHelper;
15+
use Symfony\Component\Routing\Generator\AstGenerator\UrlGeneratorGenerator;
16+
1417
/**
1518
* PhpGeneratorDumper creates a PHP class able to generate URLs for a given set of routes.
1619
*
@@ -33,91 +36,10 @@ class PhpGeneratorDumper extends GeneratorDumper
3336
*/
3437
public function dump(array $options = array())
3538
{
36-
$options = array_merge(array(
37-
'class' => 'ProjectUrlGenerator',
38-
'base_class' => 'Symfony\\Component\\Routing\\Generator\\UrlGenerator',
39-
), $options);
40-
41-
return <<<EOF
42-
<?php
43-
44-
use Symfony\Component\Routing\RequestContext;
45-
use Symfony\Component\Routing\Exception\RouteNotFoundException;
46-
use Psr\Log\LoggerInterface;
47-
48-
/**
49-
* {$options['class']}
50-
*
51-
* This class has been auto-generated
52-
* by the Symfony Routing Component.
53-
*/
54-
class {$options['class']} extends {$options['base_class']}
55-
{
56-
private static \$declaredRoutes;
57-
58-
/**
59-
* Constructor.
60-
*/
61-
public function __construct(RequestContext \$context, LoggerInterface \$logger = null)
62-
{
63-
\$this->context = \$context;
64-
\$this->logger = \$logger;
65-
if (null === self::\$declaredRoutes) {
66-
self::\$declaredRoutes = {$this->generateDeclaredRoutes()};
67-
}
68-
}
69-
70-
{$this->generateGenerateMethod()}
71-
}
72-
73-
EOF;
74-
}
75-
76-
/**
77-
* Generates PHP code representing an array of defined routes
78-
* together with the routes properties (e.g. requirements).
79-
*
80-
* @return string PHP code
81-
*/
82-
private function generateDeclaredRoutes()
83-
{
84-
$routes = "array(\n";
85-
foreach ($this->getRoutes()->all() as $name => $route) {
86-
$compiledRoute = $route->compile();
87-
88-
$properties = array();
89-
$properties[] = $compiledRoute->getVariables();
90-
$properties[] = $route->getDefaults();
91-
$properties[] = $route->getRequirements();
92-
$properties[] = $compiledRoute->getTokens();
93-
$properties[] = $compiledRoute->getHostTokens();
94-
$properties[] = $route->getSchemes();
39+
$generator = new UrlGeneratorGenerator();
9540

96-
$routes .= sprintf(" '%s' => %s,\n", $name, str_replace("\n", '', var_export($properties, true)));
97-
}
98-
$routes .= ' )';
99-
100-
return $routes;
101-
}
41+
$code = AstHelper::dump($generator->generate($this->getRoutes(), $options));
10242

103-
/**
104-
* Generates PHP code representing the `generate` method that implements the UrlGeneratorInterface.
105-
*
106-
* @return string PHP code
107-
*/
108-
private function generateGenerateMethod()
109-
{
110-
return <<<'EOF'
111-
public function generate($name, $parameters = array(), $referenceType = self::ABSOLUTE_PATH)
112-
{
113-
if (!isset(self::$declaredRoutes[$name])) {
114-
throw new RouteNotFoundException(sprintf('Unable to generate a URL for the named route "%s" as such route does not exist.', $name));
115-
}
116-
117-
list($variables, $defaults, $requirements, $tokens, $hostTokens, $requiredSchemes) = self::$declaredRoutes[$name];
118-
119-
return $this->doGenerate($variables, $defaults, $requirements, $tokens, $parameters, $name, $referenceType, $hostTokens, $requiredSchemes);
120-
}
121-
EOF;
43+
return $code;
12244
}
12345
}

src/Symfony/Component/Routing/Matcher/Dumper/PhpMatcherDumper.php

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,8 @@ class PhpMatcherDumper extends MatcherDumper
5050
public function dump(array $options = array())
5151
{
5252
$generator = new PhpMatcherGenerator();
53-
$ast = $generator->generate($this->getRoutes(), $options);
5453

55-
$printer = new Standard();
56-
57-
return $printer->prettyPrintFile($ast);
54+
return AstHelper::dump($generator->generate($this->getRoutes(), $options));
5855
}
5956

6057
public function addExpressionLanguageProvider(ExpressionFunctionProviderInterface $provider)

0 commit comments

Comments
 (0)