Test Failed
Push — master ( c5de53...cf76ff )
by Mikael
02:00
created

ViewCollection::add()   D

Complexity

Conditions 9
Paths 11

Size

Total Lines 35
Code Lines 23

Duplication

Lines 35
Ratio 100 %

Importance

Changes 0
Metric Value
cc 9
eloc 23
nc 11
nop 4
dl 35
loc 35
rs 4.909
c 0
b 0
f 0
1
<?php
2
3
namespace Anax\View;
4
5
use \Anax\View\View2 as View;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, Anax\View\View.

Let’s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let’s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
6
use \Anax\Configure\ConfigureInterface;
7
use \Anax\Configure\ConfigureTrait;
8
use \Anax\DI\InjectionAwareInterface;
9
use \Anax\DI\InjectionAwareTrait;
10
11
/**
12
 * A view collection supporting Anax DI, store all views per region,
13
 * render at will.
14
 */
15
class ViewCollection implements
16
    ConfigureInterface,
17
    InjectionAwareInterface
18
{
19
    use InjectionAwareTrait;
20
    use ConfigureTrait {
21
        configure as protected loadConfiguration;
22
    }
23
24
25
26
    /** @var [] $views Array for all views. */
0 ignored issues
show
Documentation introduced by
The doc-type [] could not be parsed: Unknown type name "" at position 0. [(view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
27
    private $views = [];
28
29
30
31
    /**
32
     * Load and apply configurations.
33
     *
34
     * @param array|string $what is an array with key/value config options
35
     *                           or a file to be included which returns such
36
     *                           an array.
37
     *
38
     * @throws Anax\View\Exception when template file is missing
39
     *
40
     * @return string as path to the template file
41
     */
42
    public function configure($what)
43
    {
44
        $this->loadConfiguration($what);
45
46
        $includes = $this->getConfig("include", []);
47
        foreach ($includes as $include) {
48
            require $include;
49
        }
50
    }
51
52
53
54
    /**
55
     * Convert template to path to template file.
56
     *
57
     * @param string $template the name of the template file to include
58
     *
59
     * @throws Anax\View\Exception when template file is missing
60
     *
61
     * @return string as path to the template file
62
     */
63 View Code Duplication
    public function getTemplateFile($template)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
64
    {
65
        $paths  = $this->config["path"];
66
        $suffix = $this->config["suffix"];
67
68
        foreach ($paths as $path) {
69
            $file = $path . "/" . $template . $suffix;
70
            if (is_file($file)) {
71
                return $file;
72
            }
73
        }
74
75
        throw new Exception("Could not find template file '$template'.");
76
    }
77
78
79
80
    /**
81
     * Add (create) a view to be included, pass optional data and put the
82
     * view in an optional specific region (default region is "main") and
83
     * pass an optional sort value where the highest value is rendered first.
84
     * The $template can be a:
85
     *  filename (string),
86
     *  callback (array with key callback set to a callable array),
87
     *  view array (key value array with template, data, region, sort)
88
     *
89
     * @param string  $template the name of the template file to include.
90
     * @param array   $data     variables to make available to the view,
91
     *                          default is empty.
92
     * @param string  $region   which region to attach the view, default is
93
     *                          "main".
94
     * @param integer $sort     which order to display the views.
95
     *
96
     * @return self for chaining.
97
     */
98 View Code Duplication
    public function add($template, $data = [], $region = "main", $sort = 0)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
99
    {
100
        if (empty($template)) {
101
            return $this;
102
        }
103
104
        $view = new View();
105
106
        if (is_string($template)) {
107
            $tpl = $this->getTemplateFile($template);
108
            $type = "file";
109
        } elseif (is_array($template)) {
110
            // Can be array with complete view or array with callable callback
111
            $tpl = $template;
112
            $type = null;
113
            $region = isset($tpl["region"])
114
                ? $tpl["region"]
115
                : $region;
116
117
            if (isset($tpl["callback"])) {
118
                $tpl["template"] = $template;
119
                $tpl["type"] = "callback";
120
            } elseif (isset($tpl["template"])) {
121
                if (!isset($tpl["type"]) || $tpl["type"] === "file") {
122
                    $tpl["type"] = "file";
123
                    $tpl["template"] = $this->getTemplateFile($tpl["template"]);
124
                }
125
            }
126
        }
127
128
        $view->set($tpl, $data, $sort, $type);
0 ignored issues
show
Bug introduced by
The variable $tpl 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...
Bug introduced by
The variable $type 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...
129
        $this->views[$region][] = $view;
130
131
        return $this;
132
    }
133
134
135
136
    /**
137
     * Add a callback to be rendered as a view.
138
     *
139
     * @param string $callback function to call to get the content of the view
140
     * @param array  $data     variables to make available to the view, default is empty
141
     * @param string $region   which region to attach the view
142
     * @param int    $sort     which order to display the views
143
     *
144
     * @return $this
145
     */
146 View Code Duplication
    public function addCallback($callback, $data = [], $region = "main", $sort = 0)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
147
    {
148
        $view = new View();
149
        $view->set(["callback" => $callback], $data, $sort, "callback");
150
        $this->views[$region][] = $view;
151
152
        return $this;
153
    }
154
155
156
157
    /**
158
     * Add a string as a view.
159
     *
160
     * @param string $content the content
161
     * @param string $region  which region to attach the view
162
     * @param int    $sort    which order to display the views
163
     *
164
     * @return $this
165
     */
166 View Code Duplication
    public function addString($content, $region = "main", $sort = 0)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
167
    {
168
        $view = new View();
169
        $view->set($content, [], $sort, "string");
170
        $this->views[$region][] = $view;
171
        
172
        return $this;
173
    }
174
175
176
177
    /**
178
     * Check if a region has views to render.
179
     *
180
     * @param string $region which region to check
181
     *
182
     * @return $this
183
     */
184
    public function hasContent($region)
185
    {
186
        return isset($this->views[$region]);
187
    }
188
189
190
191
    /**
192
     * Render all views for a specific region.
193
     *
194
     * @param string $region which region to use
195
     *
196
     * @return void
197
     */
198 View Code Duplication
    public function render($region = "main")
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
199
    {
200
        if (!isset($this->views[$region])) {
201
            return $this;
202
        }
203
204
        mergesort($this->views[$region], function ($viewA, $viewB) {
205
            $sortA = $viewA->sortOrder();
206
            $sortB = $viewB->sortOrder();
207
208
            if ($sortA == $sortB) {
209
                return 0;
210
            }
211
212
            return $sortA < $sortB ? -1 : 1;
213
        });
214
215
        foreach ($this->views[$region] as $view) {
216
            $view->render($this->di);
217
        }
218
    }
219
220
221
    /**
222
     * Render all views for a specific region and buffer the result.
223
     *
224
     * @param string $region which region to use.
225
     *
226
     * @return string with the buffered results.
227
     */
228
    public function renderBuffered($region = "main")
229
    {
230
        ob_start();
231
        $this->render($region);
232
        $res = ob_get_contents();
233
        ob_end_clean();
234
        return $res;
235
    }
236
}
237