Completed
Push — master ( 8757d5...111d7a )
by Mihail
03:00
created

Controller::after()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 1
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 4
Bugs 1 Features 0
Metric Value
c 4
b 1
f 0
dl 0
loc 1
rs 10
cc 1
eloc 1
nc 1
nop 0
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
    use DynamicGlobal;
19
20
    /** @var string */
21
    public $layout = 'main';
22
23
    /** @var string */
24
    protected $output;
25
26
    /** @var \Ffcms\Core\Network\Request */
27
    public $request;
28
    /** @var \Ffcms\Core\Network\Response */
29
    public $response;
30
    /** @var View */
31
    public $view;
32
33
    /**
34
     * Controller constructor. Set controller access data - request, response, view
35
     */
36
    public function __construct()
37
    {
38
        $this->request = App::$Request;
39
        $this->response = App::$Response;
40
        $this->view = App::$View;
41
        $this->before();
42
    }
43
44
    /** Before action call method */
45
    public function before() {}
46
    
47
    /** Global bootable method */
48
    public static function boot() {}
49
50
    /**
51
     * Build variables and display output html
52
     */
53
    public function buildOutput()
54
    {
55
        $this->after();
56
57
        // if layout is not required and this is just standalone app
58
        if ($this->layout === null) {
59
            $content = $this->output;
60
        } else {
61
            $layoutPath = App::$Alias->currentViewPath . '/layout/' . $this->layout . '.php';
62
            if (!File::exist($layoutPath)) {
63
                throw new NativeException('Layout not founded: ' . $layoutPath);
64
            }
65
66
            $body = $this->output;
67
            // pass global data to config viewer
68
            if (App::$Debug !== null) {
69
                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...
70
            }
71
72
            // cleanup buffer from random shits after exception throw'd
73
            ob_clean();
74
            // start buffering to render layout
75
            ob_start();
76
            include($layoutPath);
77
            $content = ob_get_clean(); // read buffer content & stop buffering
78
79
            // set custom css library's not included on static call
80
            $cssIncludeCode = App::$View->showCodeLink('css');
81
            if (!Str::likeEmpty($cssIncludeCode)) {
82
                $content = Str::replace('</head>', $cssIncludeCode . '</head>', $content);
83
            }
84
85
            // add debug bar
86
            if (App::$Debug !== null) {
87
                $content = Str::replace(
88
                    ['</body>', '</head>'],
89
                    [App::$Debug->renderOut() . '</body>', App::$Debug->renderHead() . '</head>'],
90
                    $content);
91
            }
92
93
        }
94
95
        return $content;
96
    }
97
98
    /** After action called method */
99
    public function after() {}
100
101
    /**
102
     * Set single global variable
103
     * @param string $var
104
     * @param string $value
105
     * @param bool $html
106
     */
107
    public function setGlobalVar($var, $value, $html = false)
108
    {
109
        Variables::instance()->setGlobal($var, $value, $html);
110
    }
111
112
    /**
113
     * Set global variables as array key=>value
114
     * @param $array
115
     */
116
    public function setGlobalVarArray(array $array)
117
    {
118
        Variables::instance()->setGlobalArray($array);
119
    }
120
121
    /**
122
     * Special method to set response of action execution
123
     * @param string $output
124
     */
125
    public function setOutput($output)
126
    {
127
        $this->output = $output;
128
    }
129
130
    /**
131
     * Get response of action rendering
132
     * @return string
133
     */
134
    public function getOutput()
135
    {
136
        return $this->output;
137
    }
138
139
}