Test Failed
Push — master ( 96ccb3...e36e05 )
by Justin
03:29
created

PluginExtends   A

Complexity

Total Complexity 31

Size/Duplication

Total Lines 170
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 31
dl 0
loc 170
rs 9.8
c 0
b 0
f 0

4 Methods

Rating   Name   Duplication   Size   Complexity  
A process() 0 2 1
D compile() 0 105 21
B replaceBlock() 0 30 6
A removeTrailingNewline() 0 3 3
1
<?php
2
/**
3
 * Copyright (c) 2013-2017
4
 *
5
 * @category  Library
6
 * @package   Dwoo\Plugins\Functions
7
 * @author    Jordi Boggiano <[email protected]>
8
 * @author    David Sanchez <[email protected]>
9
 * @copyright 2008-2013 Jordi Boggiano
10
 * @copyright 2013-2017 David Sanchez
11
 * @license   http://dwoo.org/LICENSE LGPLv3
12
 * @version   1.3.6
13
 * @date      2017-03-21
14
 * @link      http://dwoo.org/
15
 */
16
17
namespace Dwoo\Plugins\Functions;
18
19
use Dwoo\Compiler;
20
use Dwoo\ICompilable;
21
use Dwoo\Plugin;
22
use Dwoo\Exception as Exception;
23
use Dwoo\Security\Exception as SecurityException;
24
use Dwoo\Compilation\Exception as CompilationException;
25
26
/**
27
 * Extends another template, read more about template inheritance at {@link
28
 * http://wiki.dwoo.org/index.php/TemplateInheritance}
29
 * <pre>
30
 *  * file : the template to extend
31
 * </pre>
32
 * This software is provided 'as-is', without any express or implied warranty.
33
 * In no event will the authors be held liable for any damages arising from the use of this software.
34
 */
35
class PluginExtends extends Plugin implements ICompilable
36
{
37
    protected static $childSource;
38
    protected static $regex;
39
    protected static $l;
40
    protected static $r;
41
    protected static $lastReplacement;
42
43
    public function process()
44
    {
45
    }
46
47
    /**
48
     * @param Compiler $compiler
49
     * @param          $file
50
     *
51
     * @throws CompilationException
52
     */
53
    public static function compile(Compiler $compiler, $file)
54
    {
55
        list($l, $r) = $compiler->getDelimiters();
56
        self::$l     = preg_quote($l, '/');
57
        self::$r     = preg_quote($r, '/');
58
        self::$regex = '/
59
			' . self::$l . 'block\s(["\']?)(.+?)\1' . self::$r . '(?:\r?\n?)
60
			((?:
61
				(?R)
62
				|
63
				[^' . self::$l . ']*
64
				(?:
65
					(?! ' . self::$l . '\/?block\b )
66
					' . self::$l . '
67
					[^' . self::$l . ']*+
68
				)*
69
			)*)
70
			' . self::$l . '\/block' . self::$r . '
71
			/six';
72
73
        if ($compiler->getLooseOpeningHandling()) {
74
            self::$l .= '\s*';
75
            self::$r = '\s*' . self::$r;
76
        }
77
        $inheritanceTree = array(array('source' => $compiler->getTemplateSource()));
78
        $curPath         = dirname($compiler->getCore()->getTemplate()->getResourceIdentifier()) . DIRECTORY_SEPARATOR;
0 ignored issues
show
Bug introduced by
It seems like $compiler->getCore()->ge...getResourceIdentifier() can also be of type false; however, parameter $path of dirname() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

78
        $curPath         = dirname(/** @scrutinizer ignore-type */ $compiler->getCore()->getTemplate()->getResourceIdentifier()) . DIRECTORY_SEPARATOR;
Loading history...
Unused Code introduced by
The assignment to $curPath is dead and can be removed.
Loading history...
79
        $curTpl          = $compiler->getCore()->getTemplate();
80
81
        while (!empty($file)) {
82
            if ($file === '""' || $file === "''" || (substr($file, 0, 1) !== '"' && substr($file, 0, 1) !== '\'')) {
83
                throw new CompilationException($compiler, 'Extends : The file name must be a non-empty string');
0 ignored issues
show
Bug introduced by
'Extends : The file name... be a non-empty string' of type string is incompatible with the type integer expected by parameter $message of Dwoo\Compilation\Exception::__construct(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

83
                throw new CompilationException($compiler, /** @scrutinizer ignore-type */ 'Extends : The file name must be a non-empty string');
Loading history...
84
            }
85
86
            if (preg_match('#^["\']([a-z]{2,}):(.*?)["\']$#i', $file, $m)) {
87
                // resource:identifier given, extract them
88
                $resource   = $m[1];
89
                $identifier = $m[2];
90
            } else {
91
                // get the current template's resource
92
                $resource   = $curTpl->getResourceName();
93
                $identifier = substr($file, 1, - 1);
94
            }
95
96
            try {
97
                $parent = $compiler->getCore()->templateFactory($resource, $identifier, null, null, null, $curTpl);
98
            }
99
            catch (SecurityException $e) {
100
                throw new CompilationException($compiler, 'Extends : Security restriction : ' . $e->getMessage());
101
            }
102
            catch (Exception $e) {
103
                throw new CompilationException($compiler, 'Extends : ' . $e->getMessage());
104
            }
105
106
            if ($parent === null) {
107
                throw new CompilationException($compiler, 'Extends : Resource "' . $resource . ':' . $identifier . '" not found.');
108
            } elseif ($parent === false) {
109
                throw new CompilationException($compiler, 'Extends : Resource "' . $resource . '" does not support extends.');
110
            }
111
112
            $curTpl    = $parent;
113
            $newParent = array(
114
                'source'     => $parent->getSource(),
115
                'resource'   => $resource,
116
                'identifier' => $parent->getResourceIdentifier(),
117
                'uid'        => $parent->getUid()
118
            );
119
            if (array_search($newParent, $inheritanceTree, true) !== false) {
120
                throw new CompilationException($compiler, 'Extends : Recursive template inheritance detected');
121
            }
122
            $inheritanceTree[] = $newParent;
123
124
            if (preg_match('/^' . self::$l . 'extends(?:\(?\s*|\s+)(?:file=)?\s*((["\']).+?\2|\S+?)\s*\)?\s*?' . self::$r . '/i', $parent->getSource(), $match)) {
125
                $curPath = dirname($identifier) . DIRECTORY_SEPARATOR;
126
                if (isset($match[2]) && $match[2] == '"') {
127
                    $file = '"' . str_replace('"', '\\"', substr($match[1], 1, - 1)) . '"';
128
                } elseif (isset($match[2]) && $match[2] == "'") {
129
                    $file = '"' . substr($match[1], 1, - 1) . '"';
130
                } else {
131
                    $file = '"' . $match[1] . '"';
132
                }
133
            } else {
134
                $file = false;
135
            }
136
        }
137
138
        while (true) {
139
            $parent                = array_pop($inheritanceTree);
140
            $child                 = end($inheritanceTree);
141
            self::$childSource     = $child['source'];
142
            self::$lastReplacement = count($inheritanceTree) === 1;
143
            if (!isset($newSource)) {
144
                $newSource = $parent['source'];
145
            }
146
            $newSource = preg_replace_callback(self::$regex, array(
147
                'Dwoo\Plugins\Functions\PluginExtends',
148
                'replaceBlock'
149
            ), $newSource);
150
            $newSource = $l . 'do extendsCheck(' . var_export($parent['resource'] . ':' . $parent['identifier'], true) . ')' . $r . $newSource;
151
152
            if (self::$lastReplacement) {
153
                break;
154
            }
155
        }
156
        $compiler->setTemplateSource($newSource);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $newSource does not seem to be defined for all execution paths leading up to this point.
Loading history...
157
        $compiler->recompile();
158
    }
159
160
    /**
161
     * @param array $matches
162
     *
163
     * @return mixed|string
164
     */
165
    protected static function replaceBlock(array $matches)
166
    {
167
        $matches[3] = self::removeTrailingNewline($matches[3]);
168
169
        if (preg_match_all(self::$regex, self::$childSource, $override) && in_array($matches[2], $override[2])) {
170
            $key      = array_search($matches[2], $override[2]);
171
            $override = self::removeTrailingNewline($override[3][$key]);
172
173
            $l = stripslashes(self::$l);
174
            $r = stripslashes(self::$r);
175
176
            if (self::$lastReplacement) {
177
                return preg_replace('/' . self::$l . '\$dwoo\.parent' . self::$r . '/is', $matches[3], $override);
178
            }
179
180
            return $l . 'block ' . $matches[1] . $matches[2] . $matches[1] . $r . preg_replace('/' . self::$l . '\$dwoo\.parent' . self::$r . '/is', $matches[3], $override) . $l . '/block' . $r;
181
        }
182
183
        if (preg_match(self::$regex, $matches[3])) {
184
            return preg_replace_callback(self::$regex, array(
185
                'Dwoo\Plugins\Functions\PluginExtends',
186
                'replaceBlock'
187
            ), $matches[3]);
188
        }
189
190
        if (self::$lastReplacement) {
191
            return $matches[3];
192
        }
193
194
        return $matches[0];
195
    }
196
197
    /**
198
     * @param $text
199
     *
200
     * @return string
201
     */
202
    protected static function removeTrailingNewline($text)
203
    {
204
        return substr($text, - 1) === "\n" ? substr($text, - 2, 1) === "\r" ? substr($text, 0, - 2) : substr($text, 0, - 1) : $text;
205
    }
206
}
207