Completed
Push — master ( 3b3e78...78cfc1 )
by Alexander
03:21
created

Dispatch::session()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 4
nc 2
nop 1
dl 0
loc 7
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
namespace alkemann\h2l;
4
5
use alkemann\h2l\exceptions\InvalidUrl;
6
use alkemann\h2l\exceptions\NoRouteSetError;
7
use alkemann\h2l\util\Chain;
8
9
/**
10
 * Class Request
11
 *
12
 * @package alkemann\h2l
13
 */
14
class Dispatch
15
{
16
    private $middlewares = [];
17
18
    /**
19
     * @var interfaces\Session
20
     */
21
    private $session;
22
23
    /**
24
     * @var Request
25
     */
26
    protected $request;
27
28
    /**
29
     * Analyze request, provided $_REQUEST, $_SERVER [, $_GET, $_POST] to identify Route
30
     *
31
     * Response type can be set from HTTP_ACCEPT header
32
     * Call setRoute or setRouteFromRouter to set a route
33
     *
34
     * @param array $request $_REQUEST
35
     * @param array $server $_SERVER
36
     * @param array $get $_GET
37
     * @param array $post $_POST
38
     * @param null|interfaces\Session $session if null, a default Session with $_SESSION will be created
39
     */
40
    public function __construct(
41
        array $request = [],
42
        array $server = [],
43
        array $get = [],
44
        array $post = [],
45
        interfaces\Session $session = null
46
    ) {
47
        unset($get['url']); // @TODO Use a less important keyword, as it blocks that _GET param?
48
49
        if (is_null($session)) {
50
            $session = new Session;
51
        }
52
53
        $this->request = (new Request)
54
            ->withRequestParams($request)
55
            ->withServerParams($server)
56
            ->withGetData($get)
57
            ->withPostData($post)
58
            ->withSession($session)
59
60
            // @TODO Always do this? Can we know from $_SERVER or $_REQUEST ?
61
            ->withBody(file_get_contents('php://input'));
62
        ;
63
    }
64
65
    public function setRouteFromRouter(string $router = Router::class): bool
66
    {
67
        /**
68
         * @var Router $router
69
         */
70
        $route = $router::match($this->request->url(), $this->request->method());
71
        if (is_null($route)) {
72
            return false;
73
        }
74
        $this->request = $this->request->withRoute($route);
75
        return true;
76
    }
77
78
    /**
79
     * @return interfaces\Route|null Route identified for request if set
80
     */
81
    public function route(): ?interfaces\Route
82
    {
83
        return $this->request->route();
84
    }
85
86
    /**
87
     * @param interfaces\Route $route
88
     */
89
    public function setRoute(interfaces\Route $route): void
90
    {
91
        if (!$this->request) {
92
            $this->request = new Request;
93
        }
94
        $this->request = $this->request->withRoute($route);
95
    }
96
97
    /**
98
     * Execute the Route's callback and return the Response object that the callback is required to return
99
     *
100
     * Catches InvalidUrl exceptions and returns a response\Error with 404 instead
101
     *
102
     * @return Response|null
103
     * @throws NoRouteSetError if a route has not been set prior to calling this, or by a middleware
104
     */
105
    public function response(): ?Response
106
    {
107
        $cbs = $this->middlewares;
108
        $call_eventual_route_at_end_of_chain = function (Request $request, Chain $chain): ?Response {
0 ignored issues
show
Unused Code introduced by
The parameter $chain is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

108
        $call_eventual_route_at_end_of_chain = function (Request $request, /** @scrutinizer ignore-unused */ Chain $chain): ?Response {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
109
            $route = $request->route();
110
            if (is_null($route)) {
111
                throw new NoRouteSetError("Response called without Route set");
0 ignored issues
show
Unused Code introduced by
The call to alkemann\h2l\exceptions\...SetError::__construct() has too many arguments starting with 'Response called without Route set'. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

111
                throw /** @scrutinizer ignore-call */ new NoRouteSetError("Response called without Route set");

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
112
            }
113
            try {
114
                return $route($request);
115
            } catch (InvalidUrl $e) {
116
                return new response\Error(['message' => $e->getMessage()],
117
                    ['code' => 404, 'request' => $this->request]);
118
            }
119
        };
120
        array_push($cbs, $call_eventual_route_at_end_of_chain);
121
        $response = (new Chain($cbs))->next($this->request);
122
        return ($response instanceof Response) ? $response : null;
123
    }
124
125
    /**
126
     * Add a closure to wrap the Route callback in to be called during Request::response
127
     *
128
     * @param callable|callable[] ...$cbs
129
     */
130
    public function registerMiddle(callable ...$cbs): void
131
    {
132
        foreach ($cbs as $cb) {
133
            $this->middlewares[] = $cb;
134
        }
135
    }
136
}
137