Passed
Push — trans ( 7edc1d )
by Arnaud
04:09
created

Twig::setLocale()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 0
Metric Value
cc 3
eloc 3
c 1
b 1
f 0
nc 2
nop 1
dl 0
loc 6
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of Cecil.
7
 *
8
 * Copyright (c) Arnaud Ligny <[email protected]>
9
 *
10
 * For the full copyright and license information, please view the LICENSE
11
 * file that was distributed with this source code.
12
 */
13
14
namespace Cecil\Renderer;
15
16
use Cecil\Builder;
17
use Cecil\Renderer\Twig\Extension as TwigExtension;
18
use Cecil\Util;
19
use Symfony\Bridge\Twig\Extension\TranslationExtension;
20
use Symfony\Component\Translation\Formatter\MessageFormatter;
21
use Symfony\Component\Translation\IdentityTranslator;
22
use Symfony\Component\Translation\Translator;
23
use Twig\Extra\Intl\IntlExtension;
24
25
/**
26
 * Class Twig.
27
 */
28
class Twig implements RendererInterface
29
{
30
    /** @var Builder */
31
    private $builder;
32
33
    /** @var \Twig\Environment */
34
    private $twig;
35
36
    /** @var Translator */
37
    private $translator = null;
38
39
    /** @var \Twig\Profiler\Profile */
40
    private $profile = null;
41
42
    /**
43
     * {@inheritdoc}
44
     */
45
    public function __construct(Builder $builder, $templatesPath)
46
    {
47
        $this->builder = $builder;
48
        // load layouts
49
        $loader = new \Twig\Loader\FilesystemLoader($templatesPath);
50
        // default options
51
        $loaderOptions = [
52
            'debug'            => $this->builder->isDebug(),
53
            'strict_variables' => true,
54
            'autoescape'       => false,
55
            'auto_reload'      => true,
56
            'cache'            => false,
57
        ];
58
        // use Twig cache?
59
        if ($this->builder->getConfig()->get('cache.templates.enabled')) {
60
            $loaderOptions = array_replace($loaderOptions, ['cache' => $this->builder->getConfig()->getCacheTemplatesPath()]);
61
        }
62
        // create the Twig instance
63
        $this->twig = new \Twig\Environment($loader, $loaderOptions);
64
        // set date format
65
        $this->twig->getExtension(\Twig\Extension\CoreExtension::class)
66
            ->setDateFormat($this->builder->getConfig()->get('date.format'));
67
        // set timezone
68
        if ($this->builder->getConfig()->has('date.timezone')) {
69
            $this->twig->getExtension(\Twig\Extension\CoreExtension::class)
70
                ->setTimezone($this->builder->getConfig()->get('date.timezone'));
71
        }
72
        // adds extensions
73
        $this->twig->addExtension(new TwigExtension($this->builder));
74
        $this->twig->addExtension(new \Twig\Extension\StringLoaderExtension());
75
        // l10n
76
        $this->translator = new Translator(
77
            $this->builder->getConfig()->getLanguageProperty('locale'),
78
            new MessageFormatter(new IdentityTranslator()),
79
            $this->builder->getConfig()->get('cache.templates.enabled') ? $this->builder->getConfig()->getCacheTranslationsPath() : null,
80
            $this->builder->isDebug()
81
        );
82
        if ($this->builder->getConfig()->getLanguages()) {
83
            foreach ($this->builder->getConfig()->get('translations.formats') as $format) {
84
                $loader = \sprintf('Symfony\Component\Translation\Loader\%sFileLoader', ucfirst($format));
85
                if (class_exists($loader)) {
86
                    $this->translator->addLoader($format, new $loader());
87
                    $this->builder->getLogger()->debug(\sprintf('Translation loader for format "%s" found.', $format));
88
                }
89
            }
90
            foreach ($this->builder->getConfig()->getLanguages() as $lang) {
91
                // themes
92
                if ($themes = $this->builder->getConfig()->getTheme()) {
93
                    foreach ($themes as $theme) {
94
                        $this->addTransResource($this->builder->getConfig()->getThemeDirPath($theme, 'translations'), $lang['locale']);
95
                    }
96
                }
97
                // site
98
                $this->addTransResource($this->builder->getConfig()->getTranslationsPath(), $lang['locale']);
99
            }
100
        }
101
        $this->twig->addExtension(new TranslationExtension($this->translator));
102
        // intl
103
        $this->twig->addExtension(new IntlExtension());
104
        if (extension_loaded('intl')) {
105
            $this->builder->getLogger()->debug('Intl extension is loaded');
106
        }
107
        // filters fallback
108
        $this->twig->registerUndefinedFilterCallback(function ($name) {
109
            switch ($name) {
110
                case 'localizeddate':
111
                    return new \Twig\TwigFilter($name, function (\DateTime $value = null) {
112
                        return date((string) $this->builder->getConfig()->get('date.format'), $value->getTimestamp());
0 ignored issues
show
Bug introduced by
The method getTimestamp() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

112
                        return date((string) $this->builder->getConfig()->get('date.format'), $value->/** @scrutinizer ignore-call */ getTimestamp());

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
113
                    });
114
            }
115
116
            return false;
117
        });
118
        // debug
119
        if ($this->builder->isDebug()) {
120
            // dump()
121
            $this->twig->addExtension(new \Twig\Extension\DebugExtension());
122
            // profiler
123
            $this->profile = new \Twig\Profiler\Profile();
124
            $this->twig->addExtension(new \Twig\Extension\ProfilerExtension($this->profile));
125
        }
126
    }
127
128
    /**
129
     * {@inheritdoc}
130
     */
131
    public function addGlobal(string $name, $value): void
132
    {
133
        $this->twig->addGlobal($name, $value);
134
    }
135
136
    /**
137
     * {@inheritdoc}
138
     */
139
    public function render(string $template, array $variables): string
140
    {
141
        return $this->twig->render($template, $variables);
142
    }
143
144
    /**
145
     * {@inheritdoc}
146
     */
147
    public function setLocale(string $locale): void
148
    {
149
        if (extension_loaded('intl')) {
150
            \Locale::setDefault($locale);
151
        }
152
        $this->translator === null ?: $this->translator->setLocale($locale);
153
    }
154
155
    /**
156
     * {@inheritdoc}
157
     */
158
    public function addTransResource(string $translationsDir, string $locale): void
159
    {
160
        foreach ($this->builder->getConfig()->get('translations.formats') as $format) {
161
            $translationFile = realpath(Util::joinFile($translationsDir, \sprintf('messages.%s.%s', $locale, $format)));
162
            if ($translationFile !== false && Util\File::getFS()->exists($translationFile)) {
163
                $this->translator->addResource($format, $translationFile, $locale);
164
                $this->builder->getLogger()->debug(\sprintf('Translation "%s" added', $translationFile));
165
            }
166
        }
167
    }
168
169
    /**
170
     * {@inheritdoc}
171
     */
172
    public function getDebugProfile(): ?\Twig\Profiler\Profile
173
    {
174
        return $this->profile;
175
    }
176
}
177