1<?php
2
3/**
4 * 2007-2016 PrestaShop.
5 *
6 * NOTICE OF LICENSE
7 *
8 * This source file is subject to the Open Software License (OSL 3.0)
9 * that is bundled with this package in the file LICENSE.txt.
10 * It is also available through the world-wide-web at this URL:
11 * http://opensource.org/licenses/osl-3.0.php
12 * If you did not receive a copy of the license and are unable to
13 * obtain it through the world-wide-web, please send an email
14 * to license@prestashop.com so we can send you a copy immediately.
15 *
16 * DISCLAIMER
17 *
18 * Do not edit or add to this file if you wish to upgrade PrestaShop to newer
19 * versions in the future. If you wish to customize PrestaShop for your
20 * needs please refer to http://www.prestashop.com for more information.
21 *
22 * @author    PrestaShop SA <contact@prestashop.com>
23 * @copyright 2007-2015 PrestaShop SA
24 * @license   http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
25 * International Registered Trademark & Property of PrestaShop SA
26 */
27
28namespace PrestaShop\TranslationToolsBundle\Translation\Extractor;
29
30use Twig_Source;
31use Twig_Environment;
32use Twig_Error;
33use PrestaShop\TranslationToolsBundle\Twig\Lexer;
34use Symfony\Bridge\Twig\Translation\TwigExtractor as BaseTwigExtractor;
35use Symfony\Component\Finder\SplFileInfo;
36use Symfony\Component\Translation\MessageCatalogue;
37use Symfony\Component\Translation\Extractor\ExtractorInterface;
38use Symfony\Bridge\Twig\Extension\TranslationExtension;
39
40class TwigExtractor extends BaseTwigExtractor implements ExtractorInterface
41{
42    use TraitExtractor;
43
44    /**
45     * Prefix for found message.
46     *
47     * @var string
48     */
49    private $prefix = '';
50
51    /**
52     * The twig environment.
53     *
54     * @var Twig_Environment
55     */
56    private $twig;
57
58    /**
59     * @var Lexer
60     */
61    private $twigLexer;
62
63    /**
64     * The twig environment.
65     *
66     * @var Twig_Environment
67     */
68    public function __construct(Twig_Environment $twig)
69    {
70        $this->twig = $twig;
71        $this->twigLexer = new Lexer($this->twig);
72    }
73
74    /**
75     * {@inheritdoc}
76     */
77    public function extract($resource, MessageCatalogue $catalogue)
78    {
79        $files = $this->extractFiles($resource);
80        foreach ($files as $file) {
81            if (!$this->canBeExtracted($file->getRealpath())) {
82                continue;
83            }
84
85            try {
86                $this->extractTemplateFile($file, $catalogue);
87            } catch (Twig_Error $e) {
88                if ($file instanceof SplFileInfo) {
89                    $e->setSourceContext(new Twig_Source(
90                        $e->getSourceContext()->getCode(),
91                        $e->getSourceContext()->getName(),
92                        $file->getRelativePathname()
93                    ));
94                } elseif ($file instanceof \SplFileInfo) {
95                    $e->setSourceContext(new Twig_Source(
96                        $e->getSourceContext()->getCode(),
97                        $e->getSourceContext()->getName(),
98                        $file->getRealPath()
99                    ));
100                }
101
102                throw $e;
103            }
104        }
105    }
106
107    /**
108     * {@inheritdoc}
109     */
110    protected function extractTemplateFile($file, MessageCatalogue $catalogue)
111    {
112        if (!$file instanceof \SplFileInfo) {
113            $file = new \SplFileInfo($file);
114        }
115
116        $visitor = $this->twig->getExtension(TranslationExtension::class)->getTranslationNodeVisitor();
117        $visitor->enable();
118
119        $this->twig->setLexer(new Lexer($this->twig));
120
121        $tokens = $this->twig->tokenize(new Twig_Source(file_get_contents($file->getPathname()), $file->getFilename()));
122        $this->twig->parse($tokens);
123
124        $comments = $this->twigLexer->getComments();
125
126        foreach ($visitor->getMessages() as $message) {
127            $domain = $this->resolveDomain(isset($message[1]) ? $message[1] : null);
128
129            $catalogue->set(
130                $message[0],
131                $this->prefix.trim($message[0]),
132                $domain
133            );
134
135            $metadata = [
136                'file' => $file->getRealpath(),
137                'line' => $message['line'],
138            ];
139
140            $comment = $this->getEntryComment($comments, $file->getFilename(), ($message['line'] - 1));
141
142            if (null != $comment) {
143                $metadata['comment'] = $comment;
144            }
145
146            if (isset($message['line'])) {
147                $metadata['comment'] = $this->getEntryComment($comments, $file->getFilename(), ($message['line'] - 1));
148            }
149
150            $catalogue->setMetadata($message[0], $metadata, $domain);
151        }
152
153        $visitor->disable();
154    }
155
156    /**
157     * @param $comments
158     * @param $file
159     * @param $line
160     *
161     * @return array
162     */
163    public function getEntryComment($comments, $file, $line)
164    {
165        foreach ($comments as $comment) {
166            if ($comment['file'] == $file && $comment['line'] == $line) {
167                return $comment['comment'];
168            }
169        }
170    }
171
172    /**
173     * @param string $directory
174     *
175     * @return Finder
176     */
177    protected function extractFromDirectory($directory)
178    {
179        return $this->getFinder()->files()->name('*.twig')->in($directory);
180    }
181}
182