Defer   A
last analyzed

Complexity

Total Complexity 16

Size/Duplication

Total Lines 122
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 8

Test Coverage

Coverage 91.53%

Importance

Changes 12
Bugs 6 Features 4
Metric Value
wmc 16
c 12
b 6
f 4
lcom 1
cbo 8
dl 0
loc 122
ccs 54
cts 59
cp 0.9153
rs 10

6 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A decideBlockEnd() 0 4 1
A getTag() 0 4 1
B parse() 0 38 6
B bodyParse() 0 26 4
A createUniqueBlockName() 0 14 3
1
<?php
2
namespace Boekkooi\Bundle\TwigJackBundle\Twig\TokenParser;
3
4
use Boekkooi\Bundle\TwigJackBundle\Twig\Node;
5
use Twig_Error_Syntax;
6
use Twig_Node;
7
use Twig_Token;
8
use Twig_TokenParser;
9
use Twig_TokenStream;
10
11
/**
12
 * Marks a section of a template as being usable in a later stage.
13
 *
14
 * <pre>
15
 *  {% defer javascript %}
16
 *    {% javascripts 'my.js' %}
17
 *      <script src="{{ asset_url }}"></script>
18
 *    {% endjavascripts %}
19
 *  {% enddefer %}
20
 * </pre>
21
 *
22
 * @author Warnar Boekkooi <[email protected]>
23
 */
24
class Defer extends Twig_TokenParser
25
{
26
    protected $blockPrefix;
27
28
    /**
29
     * @param string $blockPrefix
30
     */
31 9
    public function __construct($blockPrefix)
32
    {
33 9
        $this->blockPrefix = $blockPrefix;
34 9
    }
35
36
    /**
37
     * Parses a token and returns a node.
38
     *
39
     * @param Twig_Token $token A Twig_Token instance
40
     * @return null|Twig_Token A Twig_NodeInterface instance
41
     */
42 8
    public function parse(Twig_Token $token)
43
    {
44 8
        $lineno = $token->getLine();
45 8
        $stream = $this->parser->getStream();
46 8
        $reference = $stream->expect(Twig_Token::NAME_TYPE)->getValue();
47
48 8
        $name = $stream->nextIf(\Twig_Token::STRING_TYPE);
49 8
        $name = $name !== null ? $name->getValue() : false;
50
51 8
        $unique = $name !== false;
52
53 8
        $variableName = $stream->nextIf(\Twig_Token::NAME_TYPE);
54 8
        $variableName = $variableName !== null ? $variableName->getValue() : false;
55
56 8
        $offset = $stream->nextIf(\Twig_Token::NUMBER_TYPE);
57 8
        $offset = $offset !== null ? $offset->getValue() : false;
58
59 8
        if ($name) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $name of type string|false is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
60 3
            $name = $this->blockPrefix . $reference . $name;
61 3
            if ($this->parser->hasBlock($name)) {
62 1
                $this->bodyParse($stream, $name);
63
64 1
                return null;
65
            }
66 3
        } else {
67 6
            $name = $this->createUniqueBlockName($token, $reference);
68
        }
69
70 8
        $this->parser->setBlock($name, $block = new Node\Defer($name, new Twig_Node(array()), $lineno));
71 8
        $this->parser->pushLocalScope();
72
73 8
        $body = $this->bodyParse($stream, $name);
74
75 5
        $block->setNode('body', $body);
76 5
        $this->parser->popLocalScope();
77
78 5
        return new Node\DeferReference($name, $variableName, $unique, $reference, $offset, $lineno, $this->getTag());
0 ignored issues
show
Documentation introduced by
$offset is of type string|false, but the function expects a integer|null.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
79
    }
80
81 7
    public function decideBlockEnd(Twig_Token $token)
82
    {
83 7
        return $token->test('enddefer');
84
    }
85
86
    /**
87
     * {@inheritdoc}
88
     */
89 8
    public function getTag()
90
    {
91 8
        return 'defer';
92
    }
93
94
    /**
95
     * @param Twig_TokenStream $stream
96
     * @param string $name
97
     * @return Twig_Node
98
     */
99 8
    protected function bodyParse(Twig_TokenStream $stream, $name)
100
    {
101 8
        if ($stream->nextIf(Twig_Token::BLOCK_END_TYPE)) {
102 7
            $body = $this->parser->subparse(array($this, 'decideBlockEnd'), true);
103 6
            if ($token = $stream->nextIf(Twig_Token::NAME_TYPE)) {
104 1
                $value = $token->getValue();
105
106 1
                if ($value != $name) {
107 1
                    throw new Twig_Error_Syntax(
108 1
                        sprintf("Expected enddefer for defer '$name' (but %s given)", $value),
109 1
                        $stream->getCurrent()->getLine(),
110 1
                        $stream->getFilename()
111 1
                    );
112
                }
113
            }
114 5
        } else {
115 1
            throw new Twig_Error_Syntax(
116 1
                "Expected enddefer for defer '$name'",
117 1
                $stream->getCurrent()->getLine(),
118 1
                $stream->getFilename()
119 1
            );
120
        }
121 5
        $stream->expect(Twig_Token::BLOCK_END_TYPE);
122
123 5
        return $body;
124
    }
125
126
    /**
127
     * @param Twig_Token $token
128
     * @param $reference
129
     * @return string
130
     */
131 6
    private function createUniqueBlockName(Twig_Token $token, $reference)
132
    {
133 6
        $name = $this->blockPrefix . $reference . sha1($this->parser->getFilename() . $token->getLine());
134 6
        if (!$this->parser->hasBlock($name)) {
135 6
            return $name;
136
        }
137
138
        $i = 0;
139
        do {
140
            $tmpName = $name . '_' . ($i++);
141
        } while ($this->parser->hasBlock($tmpName));
142
143
        return $tmpName;
144
    }
145
}
146