AppExtension   A
last analyzed

Complexity

Total Complexity 32

Size/Duplication

Total Lines 270
Duplicated Lines 0 %

Test Coverage

Coverage 0%

Importance

Changes 27
Bugs 8 Features 4
Metric Value
eloc 134
dl 0
loc 270
rs 9.84
c 27
b 8
f 4
ccs 0
cts 178
cp 0
wmc 32

20 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 1
A slugify() 0 3 1
A pregReplace() 0 3 1
A getFilters() 0 11 1
A isCurrentPage() 0 6 3
A renderJavascriptLink() 0 19 4
A getYoutubeVideo() 0 4 2
A renderPhoneNumber() 0 6 1
A renderPagesList() 0 15 1
A renderTxtAnchor() 0 6 1
A getFunctions() 0 59 1
A getEmbedCode() 0 9 2
A loadClassForJSLink() 0 7 3
A readableEncodedMail() 0 11 1
A renderEncodedMail() 0 7 1
A renderGallery() 0 6 1
A encode() 0 3 1
A renderVideo() 0 24 3
A transformInlineImageToMedia() 0 3 2
A isInternalImage() 0 3 1
1
<?php
2
3
namespace PiedWeb\CMSBundle\Twig;
4
5
use Cocur\Slugify\Slugify;
6
use Doctrine\ORM\EntityManager;
7
use Doctrine\ORM\EntityManagerInterface;
8
use PiedWeb\CMSBundle\Entity\Media;
9
use PiedWeb\CMSBundle\Entity\MediaExternal;
10
use PiedWeb\CMSBundle\Entity\PageInterface as Page;
11
use PiedWeb\CMSBundle\Service\PageCanonicalService;
12
use PiedWeb\CMSBundle\Service\Repository;
13
use PiedWeb\CMSBundle\Utils\HtmlBeautifer;
14
use PiedWeb\RenderAttributes\AttributesTrait;
15
use Twig\Environment as Twig;
16
use Twig\Extension\AbstractExtension;
17
use Twig\TwigFilter;
18
use Twig\TwigFunction;
19
20
class AppExtension extends AbstractExtension
21
{
22
    use AttributesTrait;
23
24
    /** @var PageCanonicalService */
25
    protected $pageCanonical;
26
27
    /** @var EntityManagerInterface */
28
    private $em;
29
30
    /** @var string */
31
    private $page_class;
32
33
    public function __construct(EntityManager $em, string $page_class, PageCanonicalService $pageCanonical)
34
    {
35
        $this->em = $em;
36
        $this->pageCanonical = $pageCanonical;
37
        $this->page_class = $page_class;
38
    }
39
40
    public function getFilters()
41
    {
42
        return [
43
            //new TwigFilter('markdown', [AppExtension::class, 'markdownToHtml'], ['is_safe' => ['all']]),
44
            new TwigFilter('html_entity_decode', 'html_entity_decode'),
45
            new TwigFilter('preg_replace', [self::class, 'pregReplace']),
46
            new TwigFilter('slugify', [self::class, 'slugify']),
47
            new TwigFilter(
48
                'punctuation_beautifer',
49
                [HtmlBeautifer::class, 'punctuationBeautifer'],
50
                ['is_safe' => ['html']]
51
            ),
52
        ];
53
    }
54
55
    public static function slugify($string)
56
    {
57
        return (new Slugify())->slugify($string);
58
    }
59
60
    public static function pregReplace($subject, $pattern, $replacement)
61
    {
62
        return preg_replace($pattern, $replacement, $subject);
63
    }
64
65
    public function getFunctions()
66
    {
67
        return [
68
            new TwigFunction('homepage', [$this->pageCanonical, 'generatePathForHomepage']),
69
            new TwigFunction('page', [$this->pageCanonical, 'generatePathForPage']),
70
            new TwigFunction('jslink', [self::class, 'renderJavascriptLink'], [
71
                'is_safe' => ['html'],
72
                'needs_environment' => true,
73
            ]),
74
            new TwigFunction('link', [self::class, 'renderJavascriptLink'], [
75
                'is_safe' => ['html'],
76
                'needs_environment' => true,
77
            ]),
78
            new TwigFunction('mail', [self::class, 'renderEncodedMail'], [
79
                'is_safe' => ['html'],
80
                'needs_environment' => true,
81
            ]),
82
            new TwigFunction('tel', [self::class, 'renderPhoneNumber'], [
83
                'is_safe' => ['html'],
84
                'needs_environment' => true,
85
            ]),
86
            new TwigFunction(
87
                'bookmark', // = anchor
88
                [self::class, 'renderTxtAnchor'],
89
                ['is_safe' => ['html'], 'needs_environment' => true]
90
            ),
91
            new TwigFunction(
92
                'anchor', // = bookmark
93
                [self::class, 'renderTxtAnchor'],
94
                ['is_safe' => ['html'], 'needs_environment' => true]
95
            ),
96
            new TwigFunction(
97
                'isCurrentPage',
98
                [$this, 'isCurrentPage'],
99
                ['is_safe' => ['html'], 'needs_environment' => false]
100
            ),
101
            new TwigFunction(
102
                'gallery',
103
                [$this, 'renderGallery'],
104
                ['is_safe' => ['html'], 'needs_environment' => true]
105
            ),
106
            new TwigFunction(
107
                'video',
108
                [$this, 'renderVideo'],
109
                ['is_safe' => ['html'], 'needs_environment' => true]
110
            ),
111
            new TwigFunction(
112
                'encode',
113
                [self::class, 'encode'],
114
                ['is_safe' => ['html']]
115
            ),
116
            new TwigFunction(
117
                'list',
118
                [$this, 'renderPagesList'],
119
                ['is_safe' => ['html'], 'needs_environment' => true]
120
            ),
121
            new TwigFunction('isInternalImage', [self::class, 'isInternalImage']),
122
            new TwigFunction('getImageFrom', [self::class, 'transformInlineImageToMedia']),
123
            new TwigFunction('getEmbedCode', [self::class, 'getEmbedCode']),
124
        ];
125
    }
126
127
    public static function getEmbedCode(
128
        $embed_code
129
    ) {
130
        if ($id = self::getYoutubeVideo($embed_code)) {
131
            $embed_code = '<iframe src=https://www.youtube-nocookie.com/embed/'.$id.' frameborder=0'
132
                    .' allow=autoplay;encrypted-media allowfullscreen class=w-100></iframe>';
133
        }
134
135
        return $embed_code;
136
    }
137
138
    public function renderVideo(
139
        Twig $env,
140
        $embed_code,
141
        $image,
142
        $alt,
143
        $btn_title = null,
144
        $btn_style = null
145
    ) {
146
        $embed_code = self::getEmbedCode($embed_code);
147
148
        $params = [
149
            'embed_code' => $embed_code,
150
            'image' => $image,
151
            'alt' => $alt,
152
        ];
153
154
        if (null !== $btn_title) {
155
            $params['btn_title'] = $btn_title;
156
        }
157
        if (null !== $btn_style) {
158
            $params['btn_style'] = $btn_style;
159
        }
160
161
        return $env->render('@PiedWebCMS/component/_video.html.twig', $params);
162
    }
163
164
    protected static function getYoutubeVideo($url)
165
    {
166
        if (preg_match('~^(?:https?://)?(?:www[.])?(?:youtube[.]com/watch[?]v=|youtu[.]be/)([^&]{11})~', $url, $m)) {
167
            return $m[1];
168
        }
169
    }
170
171
    public function renderPagesList(
172
        Twig $env,
173
        string $containing = '',
174
        int $number = 3,
175
        string $orderBy = 'createdAt',
176
        string $template = '@PiedWebCMS/page/_pages_list.html.twig'
177
    ) {
178
        $qb = Repository::getPageRepository($this->em, $this->page_class)->getQueryToFindPublished('p');
179
        $qb->andWhere('p.mainContent LIKE :containing')->setParameter('containing', '%'.$containing.'%');
180
        $qb->orderBy('p.'.$orderBy, 'DESC');
181
        $qb->setMaxResults($number);
182
183
        $pages = $qb->getQuery()->getResult();
184
185
        return $env->render($template, ['pages' => $pages]);
186
    }
187
188
    public static function isInternalImage(string $media): bool
189
    {
190
        return 0 === strpos($media, '/media/default/');
191
    }
192
193
    public static function transformInlineImageToMedia(string $src)
194
    {
195
        return self::isInternalImage($src) ? Media::loadFromSrc($src) : MediaExternal::load($src);
196
    }
197
198
    public function renderGallery(Twig $env, Page $currentPage, $filterImageFrom = 1, $length = 1001)
199
    {
200
        return $env->render('@PiedWebCMS/page/_gallery.html.twig', [
201
            'page' => $currentPage,
202
            'galleryFilterFrom' => $filterImageFrom - 1,
203
            'length' => $length,
204
        ]);
205
    }
206
207
    public function isCurrentPage(string $uri, ?Page $currentPage)
208
    {
209
        return
210
            null === $currentPage || $uri != $this->pageCanonical->generatePathForPage($currentPage->getRealSlug())
211
            ? false
212
            : true;
213
    }
214
215
    public static function renderTxtAnchor(Twig $env, $name)
216
    {
217
        $slugify = new Slugify();
218
        $name = $slugify->slugify($name);
219
220
        return $env->render('@PiedWebCMS/component/_txt_anchor.html.twig', ['name' => $name]);
221
    }
222
223
    public static function renderEncodedMail(Twig $env, $mail, $class = '')
224
    {
225
        return trim($env->render('@PiedWebCMS/component/_encoded_mail.html.twig', [
226
            'mail_readable' => self::readableEncodedMail($mail),
227
            'mail_encoded' => str_rot13($mail),
228
            'mail' => $mail,
229
            'class' => $class,
230
        ]));
231
    }
232
233
    public static function renderPhoneNumber(Twig $env, $number, $class = '')
234
    {
235
        return trim($env->render('@PiedWebCMS/component/_phone_number.html.twig', [
236
            'number' => str_replace([' ', '&nbsp;', '.'], '', $number),
237
            'number_readable' => str_replace(' ', '&nbsp;', preg_replace('#^\+33 ?#', '0', $number)),
238
            'class' => $class,
239
        ]));
240
    }
241
242
    public static function readableEncodedMail($mail)
243
    {
244
        return str_replace('@', '<svg width="1em" height="1em" viewBox="0 0 16 16" class="bi bi-at" '
245
        .'fill="currentColor" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M13.106 '
246
        .'7.222c0-2.967-2.249-5.032-5.482-5.032-3.35 0-5.646 2.318-5.646 5.702 0 3.493 2.235 5.708 5.762'
247
        .' 5.708.862 0 1.689-.123 2.304-.335v-.862c-.43.199-1.354.328-2.29.328-2.926 0-4.813-1.88-4.813-4.798'
248
        .' 0-2.844 1.921-4.881 4.594-4.881 2.735 0 4.608 1.688 4.608 4.156 0 1.682-.554 2.769-1.416 2.769-.492'
249
        .' 0-.772-.28-.772-.76V5.206H8.923v.834h-.11c-.266-.595-.881-.964-1.6-.964-1.4 0-2.378 1.162-2.378 2.823 0'
250
        .' 1.737.957 2.906 2.379 2.906.8 0 1.415-.39 1.709-1.087h.11c.081.67.703 1.148 1.503 1.148 1.572 0 2.57-1.415'
251
        .' 2.57-3.643zm-7.177.704c0-1.197.54-1.907 1.456-1.907.93 0 1.524.738 1.524 1.907S8.308 9.84 7.371 9.84c-.895'
252
        .' 0-1.442-.725-1.442-1.914z"/></svg>', $mail);
253
    }
254
255
    public static function renderJavascriptLink(Twig $env, $anchor, $path, $attr = [])
256
    {
257
        if (0 === strpos($path, 'http://')) {
258
            $path = '-'.substr($path, 7);
259
        } elseif (0 === strpos($path, 'https://')) {
260
            $path = '_'.substr($path, 8);
261
        } elseif (0 === strpos($path, 'mailto:')) {
262
            $path = '@'.substr($path, 7);
263
        }
264
265
        return $env->render(
266
            '@PiedWebCMS/component/_javascript_link.html.twig',
267
            [
268
            'attr' => self::mergeAndMapAttributes(
269
                $attr,
270
                self::loadClassForJSLink($attr),
271
                ['data-rot' => str_rot13($path)]
272
            ),
273
            'anchor' => $anchor,
274
            ]
275
        );
276
    }
277
278
    protected static function loadClassForJSLink($attr): array
279
    {
280
        if (isset($attr['class']) && false !== strpos($attr['class'], 'btn')) {
281
            return [];
282
        }
283
284
        return ['class' => 'a'];
285
    }
286
287
    public static function encode($string)
288
    {
289
        return str_rot13($string);
290
    }
291
}
292