• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Cecilapp / Cecil / 7142649554

08 Dec 2023 02:37PM UTC coverage: 83.0% (+0.5%) from 82.534%
7142649554

push

github

web-flow
8.x (#1676)

186 of 231 new or added lines in 31 files covered. (80.52%)

17 existing lines in 6 files now uncovered.

2861 of 3447 relevant lines covered (83.0%)

0.83 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

95.83
/src/Renderer/Twig.php
1
<?php
2

3
declare(strict_types=1);
4

5
/*
6
 * This file is part of Cecil.
7
 *
8
 * Copyright (c) Arnaud Ligny <arnaud@ligny.fr>
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\Extension\Core as CoreExtension;
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;
1✔
48
        // load layouts
49
        $loader = new \Twig\Loader\FilesystemLoader($templatesPath);
1✔
50
        // default options
51
        $loaderOptions = [
1✔
52
            'debug'            => $this->builder->isDebug(),
1✔
53
            'strict_variables' => true,
1✔
54
            'autoescape'       => false,
1✔
55
            'auto_reload'      => true,
1✔
56
            'cache'            => false,
1✔
57
        ];
1✔
58
        // use Twig cache?
59
        if ((bool) $this->builder->getConfig()->get('cache.templates.enabled')) {
1✔
60
            $loaderOptions = array_replace($loaderOptions, ['cache' => $this->builder->getConfig()->getCacheTemplatesPath()]);
1✔
61
        }
62
        // create the Twig instance
63
        $this->twig = new \Twig\Environment($loader, $loaderOptions);
1✔
64
        // set date format
65
        $this->twig->getExtension(\Twig\Extension\CoreExtension::class)
1✔
66
            ->setDateFormat((string) $this->builder->getConfig()->get('date.format'));
1✔
67
        // set timezone
68
        if ($this->builder->getConfig()->has('date.timezone')) {
1✔
69
            $this->twig->getExtension(\Twig\Extension\CoreExtension::class)
×
NEW
70
                ->setTimezone((string) $this->builder->getConfig()->get('date.timezone') ?? date_default_timezone_get());
×
71
        }
72
        /*
73
         * adds extensions
74
         */
75
        // Cecil core extension
76
        $this->twig->addExtension(new CoreExtension($this->builder));
1✔
77
        // required by `template_from_string()`
78
        $this->twig->addExtension(new \Twig\Extension\StringLoaderExtension());
1✔
79
        // l10n
80
        $this->translator = new Translator(
1✔
81
            $this->builder->getConfig()->getLanguageProperty('locale'),
1✔
82
            new MessageFormatter(new IdentityTranslator()),
1✔
83
            (bool) $this->builder->getConfig()->get('cache.templates.enabled') ? $this->builder->getConfig()->getCacheTranslationsPath() : null,
1✔
84
            $this->builder->isDebug()
1✔
85
        );
1✔
86
        if (\count($this->builder->getConfig()->getLanguages()) > 0) {
1✔
87
            foreach ((array) $this->builder->getConfig()->get('layouts.translations.formats') as $format) {
1✔
88
                $loader = sprintf('Symfony\Component\Translation\Loader\%sFileLoader', ucfirst($format));
1✔
89
                if (class_exists($loader)) {
1✔
90
                    $this->translator->addLoader($format, new $loader());
1✔
91
                    $this->builder->getLogger()->debug(sprintf('Translation loader for format "%s" found', $format));
1✔
92
                }
93
            }
94
            foreach ($this->builder->getConfig()->getLanguages() as $lang) {
1✔
95
                // internal
96
                $this->addTransResource($this->builder->getConfig()->getTranslationsInternalPath(), $lang['locale']);
1✔
97
                // themes
98
                if ($themes = $this->builder->getConfig()->getTheme()) {
1✔
99
                    foreach ($themes as $theme) {
1✔
100
                        $this->addTransResource($this->builder->getConfig()->getThemeDirPath($theme, 'translations'), $lang['locale']);
1✔
101
                    }
102
                }
103
                // site
104
                $this->addTransResource($this->builder->getConfig()->getTranslationsPath(), $lang['locale']);
1✔
105
            }
106
        }
107
        $this->twig->addExtension(new TranslationExtension($this->translator));
1✔
108
        // intl
109
        $this->twig->addExtension(new IntlExtension());
1✔
110
        if (\extension_loaded('intl')) {
1✔
111
            $this->builder->getLogger()->debug('Intl extension is loaded');
1✔
112
        }
113
        // filters fallback
114
        $this->twig->registerUndefinedFilterCallback(function ($name) {
1✔
115
            switch ($name) {
116
                case 'localizeddate':
1✔
117
                    return new \Twig\TwigFilter($name, function (\DateTime $value = null) {
1✔
118
                        return date($this->builder->getConfig()->get('date.format') ?? 'F j, Y', $value->getTimestamp());
1✔
119
                    });
1✔
120
            }
121

122
            return false;
×
123
        });
1✔
124
        // debug
125
        if ($this->builder->isDebug()) {
1✔
126
            // dump()
127
            $this->twig->addExtension(new \Twig\Extension\DebugExtension());
1✔
128
            // profiler
129
            $this->profile = new \Twig\Profiler\Profile();
1✔
130
            $this->twig->addExtension(new \Twig\Extension\ProfilerExtension($this->profile));
1✔
131
        }
132
        // loads custom extensions
133
        if ($this->builder->getConfig()->has('layouts.extensions')) {
1✔
134
            Util::autoload($builder, 'extensions');
1✔
135
            foreach ((array) $this->builder->getConfig()->get('layouts.extensions') as $name => $class) {
1✔
136
                $this->twig->addExtension(new $class($this->builder));
1✔
137
                $this->builder->getLogger()->debug(sprintf('Extension "%s" (%s) added.', $name, $class));
1✔
138
            }
139
        }
140
    }
141

142
    /**
143
     * {@inheritdoc}
144
     */
145
    public function addGlobal(string $name, $value): void
146
    {
147
        $this->twig->addGlobal($name, $value);
1✔
148
    }
149

150
    /**
151
     * {@inheritdoc}
152
     */
153
    public function render(string $template, array $variables): string
154
    {
155
        return $this->twig->render($template, $variables);
1✔
156
    }
157

158
    /**
159
     * {@inheritdoc}
160
     */
161
    public function setLocale(string $locale): void
162
    {
163
        if (\extension_loaded('intl')) {
1✔
164
            \Locale::setDefault($locale);
1✔
165
        }
166
        $this->translator === null ?: $this->translator->setLocale($locale);
1✔
167
    }
168

169
    /**
170
     * {@inheritdoc}
171
     */
172
    public function addTransResource(string $translationsDir, string $locale): void
173
    {
174
        $locales = [$locale];
1✔
175
        // if locale is 'fr_FR', trying to load ['fr', 'fr_FR']
176
        if (\strlen($locale) > 2) {
1✔
177
            array_unshift($locales, substr($locale, 0, 2));
1✔
178
        }
179
        foreach ($locales as $locale) {
1✔
180
            foreach ((array) $this->builder->getConfig()->get('layouts.translations.formats') as $format) {
1✔
181
                $translationFile = Util::joinPath($translationsDir, sprintf('messages.%s.%s', $locale, $format));
1✔
182
                if (Util\File::getFS()->exists($translationFile)) {
1✔
183
                    $this->translator->addResource($format, $translationFile, $locale);
1✔
184
                    $this->builder->getLogger()->debug(sprintf('Translation file "%s" added', $translationFile));
1✔
185
                }
186
            }
187
        }
188
    }
189

190
    /**
191
     * {@inheritdoc}
192
     */
193
    public function getDebugProfile(): ?\Twig\Profiler\Profile
194
    {
195
        return $this->profile;
1✔
196
    }
197
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc