Passed
Push — feat_i18n ( c4f2d5...2092c2 )
by Arnaud
03:41
created

Twig   A

Complexity

Total Complexity 16

Size/Duplication

Total Lines 124
Duplicated Lines 0 %

Test Coverage

Coverage 93.33%

Importance

Changes 6
Bugs 2 Features 1
Metric Value
eloc 55
c 6
b 2
f 1
dl 0
loc 124
ccs 42
cts 45
cp 0.9333
rs 10
wmc 16

5 Methods

Rating   Name   Duplication   Size   Complexity  
A setLocale() 0 4 3
A addGlobal() 0 3 1
A addTransResource() 0 5 2
A render() 0 3 1
B __construct() 0 74 9
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\Loader\MoFileLoader;
23
use Symfony\Component\Translation\Translator;
24
use Twig\Extra\Intl\IntlExtension;
25
26
/**
27
 * Class Twig.
28
 */
29
class Twig implements RendererInterface
30
{
31
    /** @var \Twig\Profiler\Profile */
32
    public $profile;
33
34
    /** @var \Twig\Environment */
35
    private $twig;
36
37
    /** @var Translator */
38
    private $translator;
39
40
    /**
41
     * {@inheritdoc}
42
     */
43 1
    public function __construct(Builder $builder, $templatesPath)
44
    {
45
        // load layouts
46 1
        $loader = new \Twig\Loader\FilesystemLoader($templatesPath);
47
        // default options
48
        $loaderOptions = [
49 1
            'debug'            => $builder->isDebug(),
50
            'strict_variables' => true,
51
            'autoescape'       => false,
52
            'auto_reload'      => true,
53
            'cache'            => false,
54
        ];
55
        // use Twig cache?
56 1
        if ($builder->getConfig()->get('cache.templates.enabled')) {
57 1
            $templatesCachePath = \Cecil\Util::joinFile(
58 1
                $builder->getConfig()->getCachePath(),
59 1
                (string) $builder->getConfig()->get('cache.templates.dir')
60
            );
61 1
            $loaderOptions = array_replace($loaderOptions, ['cache' => $templatesCachePath]);
62
        }
63
        // create the Twig instance
64 1
        $this->twig = new \Twig\Environment($loader, $loaderOptions);
65
        // set date format
66 1
        $this->twig->getExtension(\Twig\Extension\CoreExtension::class)
67 1
            ->setDateFormat($builder->getConfig()->get('date.format'));
68
        // set timezone
69 1
        if ($builder->getConfig()->has('date.timezone')) {
70
            $this->twig->getExtension(\Twig\Extension\CoreExtension::class)
71
                ->setTimezone($builder->getConfig()->get('date.timezone'));
72
        }
73
        // adds extensions
74 1
        $this->twig->addExtension(new TwigExtension($builder));
75 1
        $this->twig->addExtension(new \Twig\Extension\StringLoaderExtension());
76
        // i18n
77 1
        $this->twig->addExtension(new IntlExtension());
78
        // filters fallback
79 1
        $this->twig->registerUndefinedFilterCallback(function ($name) use ($builder) {
80
            switch ($name) {
81 1
                case 'localizeddate':
82 1
                    return new \Twig\TwigFilter($name, function (\DateTime $value = null) use ($builder) {
83 1
                        return date((string) $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

83
                        return date((string) $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...
84
                    });
85
            }
86
87
            return false;
88
        });
89
        // l10n
90 1
        if (count($builder->getConfig()->getLanguages()) > 1) {
91 1
            $this->translator = new Translator(
92 1
                $builder->getConfig()->getLanguageProperty('locale'),
93 1
                new MessageFormatter(new IdentityTranslator()),
94 1
                Util::joinFile($builder->getConfig()->getCachePath(), 'translations'),
95 1
                $builder->isDebug()
96
            );
97 1
            $this->translator->addLoader('mo', new MoFileLoader());
98 1
            foreach ($builder->getConfig()->getLanguages() as $lang) {
99 1
                // themes
100 1
                if ($themes = $builder->getConfig()->getTheme()) {
101 1
                    foreach ($themes as $theme) {
102
                        $this->addTransResource($builder->getConfig()->getThemeDirPath($theme, 'translations'), $lang['locale']);
103
                    }
104 1
                }
105
                // site
106
                $this->addTransResource($builder->getConfig()->getTranslationsPath(), $lang['locale']);
107 1
            }
108
            $this->twig->addExtension(new TranslationExtension($this->translator));
109 1
        }
110
        // debug
111 1
        if ($builder->isDebug()) {
112 1
            // dump()
113
            $this->twig->addExtension(new \Twig\Extension\DebugExtension());
114
            // profiler
115
            $this->profile = new \Twig\Profiler\Profile();
116
            $this->twig->addExtension(new \Twig\Extension\ProfilerExtension($this->profile));
117
        }
118
    }
119 1
120
    /**
121 1
     * {@inheritdoc}
122 1
     */
123
    public function addGlobal(string $name, $value): void
124
    {
125
        $this->twig->addGlobal($name, $value);
126
    }
127
128 1
    /**
129
     * {@inheritdoc}
130 1
     */
131
    public function render(string $template, array $variables): string
132
    {
133
        return $this->twig->render($template, $variables);
134
    }
135
136 1
    /**
137
     * {@inheritdoc}
138 1
     */
139
    public function setLocale(string $locale): void
140
    {
141
        !class_exists(\Locale::class) ?: \Locale::setDefault($locale);
142
        !$this->translator instanceof Translator ?: $this->translator->setLocale($locale);
0 ignored issues
show
introduced by
$this->translator is always a sub-type of Symfony\Component\Translation\Translator.
Loading history...
143
    }
144
145
    /**
146
     * {@inheritdoc}
147
     */
148
    public function addTransResource(string $translationsDir, string $locale): void
149
    {
150
        $translationFile = realpath(Util::joinFile($translationsDir, \sprintf('messages.%s.mo', $locale)));
151
        if (Util\File::getFS()->exists($translationFile)) {
152
            $this->translator->addResource('mo', $translationFile, $locale);
153
        }
154
    }
155
}
156