PluginExtends   A
last analyzed

Complexity

Total Complexity 31

Size/Duplication

Total Lines 172
Duplicated Lines 2.91 %

Coupling/Cohesion

Components 1
Dependencies 5

Importance

Changes 0
Metric Value
wmc 31
lcom 1
cbo 5
dl 5
loc 172
rs 9.92
c 0
b 0
f 0

4 Methods

Rating   Name   Duplication   Size   Complexity  
A process() 0 3 1
F compile() 5 106 21
B replaceBlock() 0 31 6
A removeTrailingNewline() 0 4 3

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

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
Unused Code introduced by DSanchez
$curPath is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

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');
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 View Code Duplication
            if ($parent === null) {
0 ignored issues
show
Duplication introduced by DSanchez
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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;
0 ignored issues
show
Unused Code introduced by DSanchez
$curPath is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
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
Bug introduced by DSanchez
The variable $newSource does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
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