IncludeTag::__construct()   B
last analyzed

Complexity

Conditions 7
Paths 21

Size

Total Lines 40
Code Lines 25

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 7
eloc 25
nc 21
nop 3
dl 0
loc 40
rs 8.5866
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * Platine Template
5
 *
6
 * Platine Template is a template engine that has taken a lot of inspiration from Django.
7
 *
8
 * This content is released under the MIT License (MIT)
9
 *
10
 * Copyright (c) 2020 Platine Template
11
 * Copyright (c) 2014 Guz Alexander, http://guzalexander.com
12
 * Copyright (c) 2011, 2012 Harald Hanek, http://www.delacap.com
13
 * Copyright (c) 2006 Mateo Murphy
14
 *
15
 * Permission is hereby granted, free of charge, to any person obtaining a copy
16
 * of this software and associated documentation files (the "Software"), to deal
17
 * in the Software without restriction, including without limitation the rights
18
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
19
 * copies of the Software, and to permit persons to whom the Software is
20
 * furnished to do so, subject to the following conditions:
21
 *
22
 * The above copyright notice and this permission notice shall be included in all
23
 * copies or substantial portions of the Software.
24
 *
25
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
26
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
28
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
29
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
30
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
31
 * SOFTWARE.
32
 */
33
34
/**
35
 *  @file IncludeTag.php
36
 *
37
 *  The "include" Template tag class
38
 *
39
 *  @package    Platine\Template\Tag
40
 *  @author Platine Developers Team
41
 *  @copyright  Copyright (c) 2020
42
 *  @license    http://opensource.org/licenses/MIT  MIT License
43
 *  @link   https://www.platine-php.com
44
 *  @version 1.0.0
45
 *  @filesource
46
 */
47
48
declare(strict_types=1);
49
50
namespace Platine\Template\Tag;
51
52
use Platine\Template\Exception\ParseException;
53
use Platine\Template\Parser\AbstractTag;
54
use Platine\Template\Parser\Context;
55
use Platine\Template\Parser\Document;
56
use Platine\Template\Parser\Lexer;
57
use Platine\Template\Parser\Parser;
58
use Platine\Template\Parser\Token;
59
60
/**
61
 * @class IncludeTag
62
 * @package Platine\Template\Tag
63
 */
64
class IncludeTag extends AbstractTag
65
{
66
    /**
67
     * The name of the template
68
     * @var string
69
     */
70
    protected string $templateName;
71
72
    /**
73
     * The Document that represents the extends template
74
     * @var Document
75
     */
76
    protected Document $document;
77
78
    /**
79
     * The source template Hash
80
     * @var string
81
     */
82
    protected string $hash;
83
84
    /**
85
     * if the variable is a collection
86
     * @var bool
87
     */
88
    protected bool $isCollection = false;
89
90
    /**
91
     * The value to pass to the child
92
     * template as the template name
93
     * @var mixed
94
     */
95
    protected mixed $variable;
96
97
    /**
98
    * {@inheritdoc}
99
    */
100
    public function __construct(string $markup, array &$tokens, Parser $parser)
101
    {
102
        $lexer = new Lexer(
103
            '/("[^"]+"|\'[^\']+\'|[^\'"\s]+)(\s+(with|for)\s+('
104
            . Token::QUOTED_FRAGMENT
105
            . '+))?/'
106
        );
107
108
        if (!$lexer->match($markup)) {
109
            throw new ParseException(sprintf(
110
                'Syntax Error in "%s" - Valid syntax: include "[template]" (with|for) [object|collection]',
111
                'include'
112
            ));
113
        }
114
115
        $unquoted = (strpos($lexer->getStringMatch(1), '"') === false
116
                     && strpos($lexer->getStringMatch(1), '\'') === false
117
                    );
118
119
        $start = 1;
120
        $length = strlen($lexer->getStringMatch(1)) - 2;
121
        if ($unquoted) {
122
            $start = 0;
123
            $length = strlen($lexer->getStringMatch(1));
124
        }
125
126
        $this->templateName = substr($lexer->getStringMatch(1), $start, $length);
127
        if ($lexer->isMatchNotNull(1)) {
128
            $this->isCollection = $lexer->isMatchNotNull(3)
129
                    ? $lexer->getStringMatch(3) === 'for'
130
                    : false;
131
132
            $this->variable = $lexer->isMatchNotNull(4)
133
                    ? $lexer->getStringMatch(4)
134
                    : '';
135
        }
136
137
        $this->extractAttributes($markup);
138
139
        parent::__construct($markup, $tokens, $parser);
140
    }
141
142
    /**
143
    * {@inheritdoc}
144
    */
145
    public function parse(array &$tokens): void
146
    {
147
        $source = $this->parser->getLoader()->read($this->templateName);
148
        $cache = $this->parser->getTemplate()->getCache();
149
150
        $mainTokens = [];
0 ignored issues
show
Unused Code introduced by
The assignment to $mainTokens is dead and can be removed.
Loading history...
151
152
        $this->hash = md5($this->templateName);
153
154
        /** @var Document|false $document */
155
        $document = $cache->read($this->hash, true);
156
157
        if ($document === false || ($document->hasIncludes())) {
158
            $mainTokens = $this->parser->tokenize($source);
159
            $this->document = new Document($mainTokens, $this->parser);
160
            $cache->write($this->hash, $this->document, true);
161
        } else {
162
            $this->document = $document;
163
        }
164
    }
165
166
167
    /**
168
    * {@inheritdoc}
169
    */
170
    public function render(Context $context): string
171
    {
172
        $result = '';
173
        $variable = $context->get($this->variable);
174
175
        $context->push();
176
        foreach ($this->attributes as $key => $value) {
177
            $context->set($key, $context->get($value));
178
        }
179
180
        if ($this->isCollection && is_array($variable)) {
181
            foreach ($variable as $item) {
182
                $context->set($this->templateName, $item);
183
                $result .= $this->document->render($context);
184
            }
185
        } else {
186
            if (!empty($this->variable)) {
187
                $context->set($this->templateName, $variable);
188
            }
189
190
            $result .= $this->document->render($context);
191
        }
192
193
        $context->pop();
194
195
        return $result;
196
    }
197
198
    /**
199
     * Check for cached includes;
200
     * if there are - do not use cache
201
     * @return bool
202
     */
203
    public function hasIncludes(): bool
204
    {
205
        if ($this->document->hasIncludes()) {
206
            return true;
207
        }
208
209
        $cache = $this->parser->getTemplate()->getCache();
210
        $hash = md5($this->templateName);
211
        if ($cache->exists($hash) && $this->hash === $hash) {
212
            return false;
213
        }
214
215
        return true;
216
    }
217
}
218