Completed
Push — master ( cb46a0...974133 )
by Marc
04:34
created

src/Inigo/Tag.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
namespace Kaloa\Renderer\Inigo;
4
5
/**
6
 *
7
 */
8
final class Tag
9
{
10
    /**
11
     *
12
     * @var string
13
     */
14
    private $name;
15
16
    /**
17
     *
18
     * @var array
19
     */
20
    private $attributes;
21
22
    /**
23
     *
24
     * @var boolean
25
     */
26
    private $isClosingTag;
27
28
    /**
29
     *
30
     * @var string
31
     */
32
    private $rawData;
33
34
    /**
35
     *
36
     * @var boolean
37
     */
38
    private $isValid;
39
40
    /**
41
     *
42
     * @var array
43
     */
44
    private $myHandler;
45
46
    /**
47
     *
48
     * @param string $tagString
49
     * @param array $handlers
50
     */
51
    public function __construct($tagString, array $handlers)
52
    {
53
        $this->rawData = $tagString;
54
        $this->name    = $this->extractTagName($tagString);
55
56
        $this->myHandler = null;
57
58
        foreach ($handlers as $handler) {
59
            if ($handler['name'] === $this->name) {
60
                $this->myHandler = $handler;
61
                break;
62
            }
63
        }
64
65
        $this->isValid      = (null !== $this->myHandler);
66
        $this->isClosingTag = ('/' === mb_substr($tagString, 1, 1));
67
        $this->attributes   = $this->extractTagAttributes($tagString);
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->extractTagAttributes($tagString) can also be of type false. However, the property $attributes is declared as type array. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
68
    }
69
70
    /**
71
     *
72
     * @return string
73
     */
74
    public function getRawData()
75
    {
76
        return $this->rawData;
77
    }
78
79
    /**
80
     * Returns the tag name from a valid tag string
81
     *
82
     * "[tag=http://.../]" => "tag"
83
     * "[/TAG]"            => "tag"
84
     *
85
     * @return string
86
     */
87
    public function getName()
88
    {
89
        return $this->name;
90
    }
91
92
    /**
93
     *
94
     * @return array
95
     */
96
    public function getAttributes()
97
    {
98
        return $this->attributes;
99
    }
100
101
    /**
102
     *
103
     * @return boolean
104
     */
105
    public function isClosingTag()
106
    {
107
        return $this->isClosingTag;
108
    }
109
110
    /**
111
     *
112
     * @return boolean
113
     */
114
    public function isOfType($tagType)
115
    {
116
        return ($this->isValid && $this->myHandler['type'] & $tagType);
117
    }
118
119
    /**
120
     *
121
     * @return boolean
122
     */
123
    public function isValid()
124
    {
125
        return $this->isValid;
126
    }
127
128
    /**
129
     *
130
     *
131
     * @param string $tagString
132
     * @return string
133
     */
134
    private function extractTagName($tagString)
135
    {
136
        $name       = '';
137
        $tagPattern = '[A-Za-z][A-Za-z0-9_]*';
138
        $matches    = array();
139
140
        if (1 === preg_match('/\A\[(' . $tagPattern . ')[\s=\]]/', $tagString, $matches)) {
141
            $name = strtolower($matches[1]);
142
        } elseif (1 === preg_match('/\A\[\/(' . $tagPattern . ')\s*\]\z/', $tagString, $matches)) {
143
            $name = strtolower($matches[1]);
144
        }
145
146
        return $name;
147
    }
148
149
    /**
150
     *
151
     * @param  string $tagString
152
     * @return array
153
     */
154
    private function extractTagAttributes($tagString)
155
    {
156
        if (false === $this->isValid) {
157
            return array();
158
        }
159
160
        $ret = array();
161
162
        $tagString = str_replace('&quot;', '"', $tagString);
163
        $tagString = str_replace("\\\"", '&quot;', $tagString);
164
165
        $tagString = trim(mb_substr($tagString, 1, mb_strlen($tagString) - 2));
166
167
        $i = mb_strpos($tagString, ' ');
168
        $j = mb_strpos($tagString, '=');
169
        if ((!($j === false)) && (($j < $i) || ($i === false))) {
170
            $i = $j;
171
        }
172
173
        if ($i === false) {
174
            return false;
175
        }
176
177
        $tagString = trim(mb_substr($tagString, $i));
178
179
        if (mb_substr($tagString, 0, 1) == '=') {
180
            //if
181
            $t = ltrim(mb_substr($tagString, 1));
182
            if (mb_substr($t, 0, 1) == '"') {
183
                $i = mb_strpos($tagString, '"');
184
                $j = mb_strpos($tagString, '"', $i + 1);
185
                $ret['__default'] = mb_substr($tagString, $i + 1, $j - ($i + 1));
186
                $tagString = trim(mb_substr($tagString, $j + 1));
187
            } else {
188
                $i = mb_strpos($t, ' ');
189
                if ($i === false) {
190
                    $ret['__default'] = trim($t);
191
                    $tagString = trim(mb_substr($t, $i + 1));
192
                } else {
193
                    $ret['__default'] = mb_substr($t, 0, $i);
194
                    $tagString = trim(mb_substr($t, $i + 1));
195
                }
196
            }
197
        }
198
199
        $i = mb_strpos($tagString, '=');
200
        while (!($i === false)) {
201
            $j = mb_strpos($tagString, '"');
202
            $k = mb_strpos($tagString, '"', $j + 1);
203
            if (($k > -1) && (mb_substr($tagString, $k - 1, 1) == '\\')) {
204
                $k = mb_strpos($tagString, '"', $k + 1);
205
            }
206
            $ret[trim(mb_substr($tagString, 0, $i))] = mb_substr($tagString, $j + 1, $k - ($j + 1));
207
            $tagString = trim(mb_substr($tagString, $k + 1));
208
            $i = mb_strpos($tagString, '=');
209
        }
210
211
        $retNew = array();
212
        foreach ($ret as $key => $value) {
213
            $retNew[strtolower($key)] = $value;
214
        }
215
        $ret = $retNew;
216
        unset($retNew);
217
218
        if (isset($ret['__default'])) {
219
            $defaultParam = $this->myHandler['function']->defaultParam;
220
221
            if (!isset($ret[$defaultParam])) {
222
                $ret[$defaultParam] = $ret['__default'];
223
            }
224
225
            unset($ret['__default']);
226
        }
227
228
        ksort($ret);
229
230
        return $ret;
231
    }
232
}
233