Passed
Push — develop ( df587f...f7c208 )
by Schlaefer
34s
created

Phile::middleware()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 7
ccs 4
cts 4
cp 1
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 4
nc 2
nop 1
crap 2
1
<?php
2
/**
3
 * @author  PhileCMS
4
 * @link    https://philecms.com
5
 * @license http://opensource.org/licenses/MIT
6
 */
7
8
namespace Phile;
9
10
use Phile\Core\Config;
11
use Phile\Core\Container;
12
use Phile\Core\Event;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, Phile\Event.

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...
13
use Phile\Core\Response;
14
use Phile\Core\Router;
15
use Phile\Http\MiddlewareQueue;
16
use Phile\Model\Page;
17
use Phile\Repository\Page as Repository;
18
use Psr\Http\Message\ResponseInterface;
19
use Psr\Http\Message\ServerRequestInterface;
20
use Psr\Http\Server\MiddlewareInterface;
21
use Psr\Http\Server\RequestHandlerInterface;
22
23
/**
24
 * Phile Core class
25
 */
26
class Phile implements MiddlewareInterface
27
{
28
    /** @var Config Phile configuration */
29
    protected $config;
30
31
    /** @var Event event-bus */
32
    protected $eventBus;
33
34
    /** @var array callbacks run at bootstrap */
35
    protected $bootstrapConfigs = [];
36
37
    /** @var array callbacks run on middleware-setup */
38
    protected $middlewareConfigs = [];
39
40
    /**
41
     * Constructor sets-up base Phile environment
42
     *
43
     * @param Event $eventBus
44
     * @param Config $config
45
     */
46 28
    public function __construct(Event $eventBus, Config $config)
47
    {
48 28
        $this->eventBus = $eventBus;
49 28
        $this->config = $config;
50 28
    }
51
52
    /**
53
     * Adds bootstrap-setup
54
     */
55 28
    public function addBootstrap(callable $bootstrap): self
56
    {
57 28
        $this->bootstrapConfigs[] = $bootstrap;
58 28
        return $this;
59
    }
60
61
    /**
62
     * Adds middleware-setup
63
     */
64 28
    public function addMiddleware(callable $middleware): self
65
    {
66 28
        $this->middlewareConfigs[] = $middleware;
67 28
        return $this;
68
    }
69
70
    /**
71
     * Performs bootstrap
72
     */
73 27
    public function bootstrap(): self
74
    {
75 27
        foreach ($this->bootstrapConfigs as $config) {
76 27
            call_user_func_array($config, [$this->eventBus, $this->config]);
77
        }
78 27
        return $this;
79
    }
80
81
    /**
82
     * Populates Phile controlled middle-ware-queue
83
     */
84 4
    public function middleware(MiddlewareQueue $queue): MiddlewareQueue
85
    {
86 4
        foreach ($this->middlewareConfigs as $config) {
87 4
            call_user_func_array($config, [$queue, $this->eventBus, $this->config]);
88
        }
89 4
        return $queue;
90
    }
91
92
    /**
93
     * Run a request through Phile and create a response
94
     *
95
     * @param ServerRequestInterface $request
96
     * @return ResponseInterface
97
     */
98 4
    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
99
    {
100 4
        $this->config->lock();
101
102 4
        $router = new Router($request->getServerParams());
103 4
        Container::getInstance()->set('Phile_Router', $router);
104
105
        // BC: send response in after_init_core event
106 4
        $response = new Response;
107 4
        $response->setCharset($this->config->get('charset'));
108 4
        $this->eventBus->trigger('after_init_core', ['response' => &$response]);
109 4
        if ($response instanceof ResponseInterface) {
110 1
            return $response;
111
        }
112
113 4
        $page = $this->resolveCurrentPage($router);
114 4
        if ($page instanceof ResponseInterface) {
115 2
            return $page;
116
        }
117
118 3
        $html = $this->renderHtml($page);
0 ignored issues
show
Bug introduced by
It seems like $page defined by $this->resolveCurrentPage($router) on line 113 can be null; however, Phile\Phile::renderHtml() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
119 3
        if ($html instanceof ResponseInterface) {
120 1
            return $html;
121
        }
122
123 2
        $charset = $this->config->get('charset');
124 2
        $response = (new Response)->createHtmlResponse($html)
125 2
            ->withHeader('Content-Type', 'text/html; charset=' . $charset);
126
127 2
        if ($page->getPageId() == $this->config->get('not_found_page')) {
128 1
            $response = $response->withStatus(404);
129
        }
130
131 2
        return $response;
132
    }
133
134
    /**
135
     * Resolves request into the current page
136
     */
137 4
    protected function resolveCurrentPage(Router $router)
138
    {
139 4
        $pageId = $router->getCurrentUrl();
140 4
        $response = null;
141 4
        $this->eventBus->trigger(
142 4
            'request_uri',
143 4
            ['uri' => $pageId, 'response' => &$response]
144
        );
145 4
        if ($response instanceof ResponseInterface) {
146 1
            return $response;
147
        }
148
149 4
        $repository = new Repository();
150 4
        $page = $repository->findByPath($pageId);
151 4
        $found = $page instanceof Page;
152
153 4
        if ($found && $pageId !== $page->getPageId()) {
154 1
            $url = $router->urlForPage($page->getPageId());
155 1
            return (new Response)->createRedirectResponse($url, 301);
156
        }
157
158 3
        if (!$found) {
159 2
            $page = $repository->findByPath($this->config->get('not_found_page'));
160 2
            $this->eventBus->trigger('after_404');
161
        }
162
163 3
        $this->eventBus->trigger(
164 3
            'after_resolve_page',
165 3
            ['pageId' => $pageId, 'page' => &$page, 'response' => &$response]
166
        );
167 3
        if ($response instanceof ResponseInterface) {
168 1
            return $response;
169
        }
170
171 3
        return $page;
172
    }
173
174
    /**
175
     * Renders page into output format (HTML)
176
     */
177 3
    protected function renderHtml(Page $page)
178
    {
179 3
        $this->eventBus->trigger('before_init_template');
180 3
        $engine = ServiceLocator::getService('Phile_Template');
181
182 3
        $coreVars = $this->config->getTemplateVars();
183 3
        $templateVars = Registry::get('templateVars') + $coreVars;
184 3
        Registry::set('templateVars', $templateVars);
185
186 3
        $response = null;
187 3
        $this->eventBus->trigger(
188 3
            'before_render_template',
189 3
            ['templateEngine' => &$engine, 'response' => &$response]
190
        );
191 3
        if ($response instanceof ResponseInterface) {
192 1
            return $response;
193
        }
194
195 2
        $engine->setCurrentPage($page);
196 2
        $html = $engine->render();
197
198 2
        $this->eventBus->trigger(
199 2
            'after_render_template',
200 2
            ['templateEngine' => &$engine, 'output' => &$html]
201
        );
202
203 2
        return $html;
204
    }
205
}
206