Passed
Pull Request — master (#3)
by Jitendra
01:57
created

Parser::doLazyload()   B

Complexity

Conditions 10
Paths 1

Size

Total Lines 27
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 2
Metric Value
cc 10
eloc 14
c 2
b 0
f 2
nc 1
nop 1
dl 0
loc 27
rs 7.6666

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/*
4
 * This file is part of the TWIG-YALL package.
5
 *
6
 * (c) Jitendra Adhikari <[email protected]>
7
 *     <https://github.com/adhocore>
8
 *
9
 * Licensed under MIT license.
10
 */
11
12
namespace Ahc\TwigYall;
13
14
use Twig\Node\Node;
15
use Twig\Node\TextNode;
16
use Twig\Token;
17
use Twig\TokenParser\AbstractTokenParser;
18
19
class Parser extends AbstractTokenParser
20
{
21
    /** @var string yall lazyClass */
22
    protected $lazyClass;
23
24
    /** @var string URI for placeholder image */
25
    protected $placeholder;
26
27
    /**
28
     * Constructor
29
     *
30
     * @param string $lazyClass
31
     * @param string $placeholder
32
     */
33
    public function __construct(string $lazyClass, string $placeholder)
34
    {
35
        $this->lazyClass   = $lazyClass;
36
        $this->placeholder = $placeholder;
37
    }
38
39
    /**
40
     * Parse `{% lazyload %}...{% endlazyload %}` block.
41
     *
42
     * @param Token  $token
43
     *
44
     * @return Node
45
     */
46
    public function parse(Token $token): Node
47
    {
48
        $stream = $this->parser->getStream();
49
50
        $stream->expect(Token::BLOCK_END_TYPE);
51
        $body = $this->parser->subparse([$this, 'isLazyloadEnd'], true);
52
        $stream->expect(Token::BLOCK_END_TYPE);
53
54
        return $this->traverse($body);
55
    }
56
57
    protected function traverse(Node $node)
58
    {
59
        if ($node instanceof TextNode) {
60
            $node->setAttribute('data', $this->doLazyload($node->getAttribute('data')));
61
        }
62
63
        foreach ($node as $sub) {
64
            $this->traverse($sub);
65
        }
66
67
        return $node;
68
    }
69
70
    protected function doLazyload(string $html): string
71
    {
72
        return \preg_replace_callback('/<(img|source|video)([^>]+)>/m', function ($match) {
73
            list($all, $tag, $props) = $match;
74
75
            if (empty(\trim($props, ' /')) || \strpos($props, "no-{$this->lazyClass}") !== false) {
76
                return $all;
77
            }
78
79
            if (\stripos($props, 'data-src') !== false || \stripos($props, 'data-poster') !== false) {
80
                return $all;
81
            }
82
83
            // For source no need src, for video no need src if not already there!
84
            $needSrc = $tag !== 'source' && ($tag !== 'video' || \stripos($props, 'src') !== false);
85
86
            if (\stripos($props, ' class') === false) {
87
                $tag .= " class=\"{$this->lazyClass} yall\"";
88
            }
89
            if (\stripos($props, ' poster') !== false) {
90
                $tag .= " poster=\"{$this->placeholder}\"";
91
            }
92
93
            $src = $needSrc ? " src=\"{$this->placeholder}\"" : '';
94
95
            return "<$tag$src" . $this->doReplacements($props) . '>';
96
        }, $html);
97
    }
98
99
    protected function doReplacements(string $props): string
100
    {
101
        $replacements = [
102
            ' src='      => ' data-src=',
103
            ' src ='     => ' data-src=',
104
            ' srcset='   => ' data-srcset=',
105
            ' srcset ='  => ' data-srcset=',
106
            ' class="'   => " class=\"{$this->lazyClass} yall ",
107
            ' class ="'  => " class=\"{$this->lazyClass} yall ",
108
            ' class = "' => " class=\"{$this->lazyClass} yall ",
109
            " class='"   => " class='{$this->lazyClass} yall ",
110
            " class ='"  => " class='{$this->lazyClass} yall ",
111
            " class = '" => " class='{$this->lazyClass} yall ",
112
            ' poster='   => ' data-poster=',
113
            ' poster ='  => ' data-poster=',
114
        ];
115
116
        return \strtr($props, $replacements);
117
    }
118
119
    /**
120
     * @internal
121
     */
122
    public function isLazyloadEnd(Token $token): bool
123
    {
124
        return $token->test('endlazyload');
125
    }
126
127
    /**
128
     * Gets the tag name used in block.
129
     *
130
     * @return string
131
     */
132
    public function getTag(): string
133
    {
134
        return 'lazyload';
135
    }
136
}
137