Completed
Push — master ( 5bbdfe...13b325 )
by Mihail
04:51
created

Controller::setResponse()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 4
rs 10
cc 1
eloc 2
nc 1
nop 1
1
<?php
2
3
namespace Ffcms\Core\Arch;
4
5
use Ffcms\Core\App;
6
use Ffcms\Core\Exception\NativeException;
7
use Ffcms\Core\Helper\FileSystem\File;
8
use Ffcms\Core\Helper\Type\Str;
9
use Ffcms\Core\Traits\DynamicGlobal;
10
use Ffcms\Core\Template\Variables;
11
12
/**
13
 * Class Controller. Classic carcase of controller in MVC architecture.
14
 * @package Ffcms\Core\Arch
15
 */
16
class Controller
17
{
18
19
    use DynamicGlobal;
20
21
    /**
22
     * @var string $layout
23
     */
24
    public $layout = 'main';
25
26
    /**
27
     * @var string $response
28
     */
29
    protected $response;
30
31
    public function __construct()
32
    {
33
        $this->before();
34
    }
35
36
    public function before() {}
37
    
38
    /** Global bootable method */
39
    public static function boot() {}
40
41
    /**
42
     * Build variables and display output html
43
     */
44
    public function getOutput()
45
    {
46
        $this->after();
47
48
        // if layout is not required and this is just standalone app
49
        if ($this->layout === null) {
50
            $content = $this->response;
51
        } else {
52
            $layoutPath = App::$Alias->currentViewPath . '/layout/' . $this->layout . '.php';
53
            if (!File::exist($layoutPath)) {
54
                throw new NativeException('Layout not founded: ' . $layoutPath);
55
            }
56
57
            $body = $this->response;
58
            // pass global data to config viewer
59
            if (App::$Debug !== null) {
60
                App::$Debug->bar->getCollector('config')->setData(['Global Vars' => Variables::instance()->getGlobalsArray()]);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface DebugBar\DataCollector\DataCollectorInterface as the method setData() does only exist in the following implementations of said interface: DebugBar\DataCollector\ConfigCollector.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
61
            }
62
63
            // cleanup buffer from random shits after exception throw'd
64
            ob_clean();
65
            // start buffering to render layout
66
            ob_start();
67
            include($layoutPath);
68
            $content = ob_get_clean(); // read buffer content & stop buffering
69
70
            // set custom css library's not included on static call
71
            $cssIncludeCode = App::$View->showCodeLink('css');
72
            if (!Str::likeEmpty($cssIncludeCode)) {
0 ignored issues
show
Bug introduced by
It seems like $cssIncludeCode defined by \Ffcms\Core\App::$View->showCodeLink('css') on line 71 can also be of type string; however, Ffcms\Core\Helper\Type\Str::likeEmpty() does only seem to accept null, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
73
                $content = Str::replace('</head>', $cssIncludeCode . '</head>', $content);
74
            }
75
76
            // add debug bar
77
            if (App::$Debug !== null) {
78
                $content = Str::replace(
79
                    ['</body>', '</head>'],
80
                    [App::$Debug->renderOut() . '</body>', App::$Debug->renderHead() . '</head>'],
81
                    $content);
82
            }
83
84
        }
85
86
        return $content;
87
    }
88
89
    public function after() {}
90
91
    /**
92
     * Set single global variable
93
     * @param string $var
94
     * @param string $value
95
     * @param bool $html
96
     */
97
    public function setGlobalVar($var, $value, $html = false)
98
    {
99
        Variables::instance()->setGlobal($var, $value, $html);
100
    }
101
102
    /**
103
     * Set global variables as array key=>value
104
     * @param $array
105
     */
106
    public function setGlobalVarArray(array $array)
107
    {
108
        Variables::instance()->setGlobalArray($array);
109
    }
110
111
    /**
112
     * Special method to set response of action execution
113
     * @param string $response
114
     */
115
    public function setResponse($response)
116
    {
117
        $this->response = $response;
118
    }
119
120
    /**
121
     * Get response of action rendering
122
     * @return string
123
     */
124
    public function getResponse()
125
    {
126
        return $this->response;
127
    }
128
129
}