Skip to content

Commit 0bf5b83

Browse files
author
Olivier Dolbeau
authored
Merge pull request #152 from Guite/master
added Knp extractors
2 parents 8009cb4 + 212cbd2 commit 0bf5b83

File tree

7 files changed

+324
-1
lines changed

7 files changed

+324
-1
lines changed

composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@
2020
"symfony/translation": "^3.4 || ^4.3 || ^5.0",
2121
"symfony/validator": "^3.4 || ^4.3 || ^5.0",
2222
"symfony/twig-bridge": "^3.4 || ^4.3 || ^5.0",
23-
"phpunit/phpunit": "^8.4"
23+
"phpunit/phpunit": "^8.4",
24+
"knplabs/knp-menu": "^3.1"
2425
},
2526
"autoload": {
2627
"psr-4": {
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the PHP Translation package.
5+
*
6+
* (c) PHP Translation team <[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 Translation\Extractor\Visitor\Php\Knp\Menu;
13+
14+
use PhpParser\Node;
15+
use PhpParser\NodeVisitor;
16+
use Translation\Extractor\Model\SourceLocation;
17+
use Translation\Extractor\Visitor\Php\BasePHPVisitor;
18+
19+
/**
20+
* This class provides common functionality for KnpMenu extractors.
21+
*/
22+
abstract class AbstractKnpMenuVisitor extends BasePHPVisitor implements NodeVisitor
23+
{
24+
/**
25+
* @var bool
26+
*/
27+
private $isKnpMenuBuildingMethod = false;
28+
29+
/**
30+
* @var string|bool
31+
*/
32+
private $domain;
33+
34+
/**
35+
* @var SourceLocation[]
36+
*/
37+
private $sourceLocations = [];
38+
39+
public function beforeTraverse(array $nodes): ?Node
40+
{
41+
$this->sourceLocations = [];
42+
43+
return null;
44+
}
45+
46+
public function enterNode(Node $node): ?Node
47+
{
48+
if (!$this->isKnpMenuBuildingMethod($node)) {
49+
return null;
50+
}
51+
52+
if (!$node instanceof Node\Expr\MethodCall) {
53+
return null;
54+
}
55+
56+
if (!\is_string($node->name) && !$node->name instanceof Node\Identifier) {
57+
return null;
58+
}
59+
60+
$methodName = (string) $node->name;
61+
if ('setExtra' !== $methodName) {
62+
return null;
63+
}
64+
65+
$extraKey = $this->getStringArgument($node, 0);
66+
if ('translation_domain' === $extraKey) {
67+
if (
68+
$node->args[1]->value instanceof Node\Expr\ConstFetch
69+
&& 'false' === $node->args[1]->value->name->toString()
70+
) {
71+
// translation disabled
72+
$this->domain = false;
73+
} else {
74+
$extraValue = $this->getStringArgument($node, 1);
75+
if (null !== $extraValue) {
76+
$this->domain = $extraValue;
77+
}
78+
}
79+
}
80+
81+
return null;
82+
}
83+
84+
/**
85+
* Checks if the given node is a class method returning a knp menu.
86+
*/
87+
protected function isKnpMenuBuildingMethod(Node $node): bool
88+
{
89+
if ($node instanceof Node\Stmt\ClassMethod) {
90+
if (null === $node->returnType) {
91+
$this->isKnpMenuBuildingMethod = false;
92+
}
93+
if ($node->returnType instanceof Node\Identifier) {
94+
$this->isKnpMenuBuildingMethod = false;
95+
}
96+
97+
$returnType = $node->returnType;
98+
if ($returnType instanceof Node\NullableType) {
99+
$returnType = $returnType->type;
100+
}
101+
102+
if (!$returnType instanceof Node\Name) {
103+
$this->isKnpMenuBuildingMethod = false;
104+
} else {
105+
$this->isKnpMenuBuildingMethod = 'ItemInterface' === $returnType->toString();
106+
}
107+
}
108+
109+
return $this->isKnpMenuBuildingMethod;
110+
}
111+
112+
protected function lateCollect(SourceLocation $location): void
113+
{
114+
$this->sourceLocations[] = $location;
115+
}
116+
117+
public function leaveNode(Node $node): ?Node
118+
{
119+
return null;
120+
}
121+
122+
public function afterTraverse(array $nodes): ?Node
123+
{
124+
if (false === $this->domain) {
125+
// translation disabled
126+
return null;
127+
}
128+
129+
/** @var SourceLocation $location */
130+
foreach ($this->sourceLocations as $location) {
131+
if (null !== $this->domain) {
132+
$context = $location->getContext();
133+
$context['domain'] = $this->domain;
134+
$location = new SourceLocation($location->getMessage(), $location->getPath(), $location->getLine(), $context);
135+
}
136+
$this->collection->addLocation($location);
137+
}
138+
$this->sourceLocations = [];
139+
140+
return null;
141+
}
142+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the PHP Translation package.
5+
*
6+
* (c) PHP Translation team <[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 Translation\Extractor\Visitor\Php\Knp\Menu;
13+
14+
use PhpParser\Node;
15+
use PhpParser\NodeVisitor;
16+
17+
/**
18+
* This class extracts knp menu item labels:
19+
* - $menu->addChild('foo')
20+
* - $menu['foo']->setLabel('bar').
21+
*/
22+
final class ItemLabel extends AbstractKnpMenuVisitor implements NodeVisitor
23+
{
24+
public function enterNode(Node $node): ?Node
25+
{
26+
if (!$this->isKnpMenuBuildingMethod($node)) {
27+
return null;
28+
}
29+
30+
parent::enterNode($node);
31+
32+
if (!$node instanceof Node\Expr\MethodCall) {
33+
return null;
34+
}
35+
36+
if (!\is_string($node->name) && !$node->name instanceof Node\Identifier) {
37+
return null;
38+
}
39+
40+
$methodName = (string) $node->name;
41+
if (!\in_array($methodName, ['addChild', 'setLabel'], true)) {
42+
return null;
43+
}
44+
45+
if (null !== $label = $this->getStringArgument($node, 0)) {
46+
$line = $node->getAttribute('startLine');
47+
if (null !== $location = $this->getLocation($label, $line, $node)) {
48+
$this->lateCollect($location);
49+
}
50+
}
51+
52+
return null;
53+
}
54+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the PHP Translation package.
5+
*
6+
* (c) PHP Translation team <[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 Translation\Extractor\Visitor\Php\Knp\Menu;
13+
14+
use PhpParser\Node;
15+
use PhpParser\NodeVisitor;
16+
17+
/**
18+
* This class extracts knp menu item link titles:
19+
* - $menu['foo']->setLinkAttribute('title', 'my.title').
20+
*/
21+
final class LinkTitle extends AbstractKnpMenuVisitor implements NodeVisitor
22+
{
23+
public function enterNode(Node $node): ?Node
24+
{
25+
if (!$this->isKnpMenuBuildingMethod($node)) {
26+
return null;
27+
}
28+
29+
parent::enterNode($node);
30+
31+
if (!$node instanceof Node\Expr\MethodCall) {
32+
return null;
33+
}
34+
35+
if (!\is_string($node->name) && !$node->name instanceof Node\Identifier) {
36+
return null;
37+
}
38+
39+
$methodName = (string) $node->name;
40+
if ('setLinkAttribute' !== $methodName) {
41+
return null;
42+
}
43+
44+
$attributeKey = $this->getStringArgument($node, 0);
45+
$attributeValue = $this->getStringArgument($node, 1);
46+
if ('title' === $attributeKey && null !== $attributeValue) {
47+
$line = $node->getAttribute('startLine');
48+
if (null !== $location = $this->getLocation($attributeValue, $line, $node)) {
49+
$this->lateCollect($location);
50+
}
51+
}
52+
53+
return null;
54+
}
55+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the PHP Translation package.
5+
*
6+
* (c) PHP Translation team <[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 Translation\Extractor\Tests\Functional\Visitor\Php\Knp;
13+
14+
use Translation\Extractor\Tests\Functional\Visitor\Php\BasePHPVisitorTest;
15+
use Translation\Extractor\Tests\Resources;
16+
use Translation\Extractor\Visitor\Php\Knp\Menu\ItemLabel;
17+
use Translation\Extractor\Visitor\Php\Knp\Menu\LinkTitle;
18+
19+
final class MenuTest extends BasePHPVisitorTest
20+
{
21+
public function testExtractOne()
22+
{
23+
$collection = $this->getSourceLocations(new ItemLabel(),
24+
Resources\Php\Knp\Menu::class);
25+
26+
$this->assertCount(4, $collection);
27+
$this->assertEquals('my.first.label', $collection->get(0)->getMessage());
28+
$this->assertEquals('foo', $collection->get(1)->getMessage());
29+
$this->assertEquals('foo.first.label', $collection->get(2)->getMessage());
30+
$this->assertEquals('foo.second.label', $collection->get(3)->getMessage());
31+
}
32+
33+
public function testExtractTwo()
34+
{
35+
$collection = $this->getSourceLocations(new LinkTitle(),
36+
Resources\Php\Knp\Menu::class);
37+
38+
$this->assertCount(2, $collection);
39+
$this->assertEquals('my.first.title', $collection->get(0)->getMessage());
40+
$this->assertEquals('my.second.title', $collection->get(1)->getMessage());
41+
}
42+
}

tests/Resources/Php/Knp/Menu.php

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php
2+
3+
namespace Translation\Extractor\Tests\Resources\Php\Knp;
4+
5+
use Knp\Menu\MenuFactory;
6+
use Knp\Menu\ItemInterface;
7+
8+
class Menu
9+
{
10+
public function buildMenu(): ItemInterface
11+
{
12+
$factory = new MenuFactory();
13+
$menu = $factory->createItem('A menu');
14+
$menu->addChild('my.first.label', ['uri' => '/']);
15+
16+
$menu->addChild('foo', ['uri' => '/']);
17+
$menu['foo']->setLabel('foo.first.label');
18+
$menu->getChild('foo')->setLabel('foo.second.label');
19+
20+
$menu['foo']->setLinkAttribute('title', 'my.first.title');
21+
$menu->getChild('foo')->setLinkAttribute('title', 'my.second.title');
22+
23+
return $menu;
24+
}
25+
}

tests/Smoke/AllExtractorsTest.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
use Translation\Extractor\Model\SourceCollection;
2121
use Translation\Extractor\Model\SourceLocation;
2222
use Translation\Extractor\Tests\Functional\Visitor\Twig\TwigEnvironmentFactory;
23+
use Translation\Extractor\Visitor\Php\Knp\Menu\ItemLabel;
24+
use Translation\Extractor\Visitor\Php\Knp\Menu\LinkTitle;
2325
use Translation\Extractor\Visitor\Php\SourceLocationContainerVisitor;
2426
use Translation\Extractor\Visitor\Php\Symfony\ContainerAwareTrans;
2527
use Translation\Extractor\Visitor\Php\Symfony\ContainerAwareTransChoice;
@@ -153,6 +155,8 @@ private function getPHPFileExtractor(): PHPFileExtractor
153155
$file->addVisitor(new FormTypeTitle());
154156
$file->addVisitor(new SourceLocationContainerVisitor());
155157
$file->addVisitor(new TranslateAnnotationVisitor());
158+
$file->addVisitor(new ItemLabel());
159+
$file->addVisitor(new LinkTitle());
156160

157161
return $file;
158162
}

0 commit comments

Comments
 (0)