Passed
Push — master ( 02c0f4...848e78 )
by Divine Niiquaye
08:42
created

RoutePipeline::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 1
b 0
f 0
nc 1
nop 1
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of Flight Routing.
7
 *
8
 * PHP version 7.1 and above required
9
 *
10
 * @author    Divine Niiquaye Ibok <[email protected]>
11
 * @copyright 2019 Biurad Group (https://biurad.com/)
12
 * @license   https://opensource.org/licenses/BSD-3-Clause License
13
 *
14
 * For the full copyright and license information, please view the LICENSE
15
 * file that was distributed with this source code.
16
 */
17
18
namespace Flight\Routing;
19
20
use Flight\Routing\Exceptions\InvalidMiddlewareException;
21
use Flight\Routing\Exceptions\RouteNotFoundException;
22
use Flight\Routing\Interfaces\RouteInterface;
23
use Laminas\Stratigility\MiddlewarePipe;
24
use Psr\Container\ContainerInterface;
25
use Psr\Http\Message\ResponseInterface;
26
use Psr\Http\Message\ServerRequestInterface;
27
use Psr\Http\Server\MiddlewareInterface;
28
use Psr\Http\Server\RequestHandlerInterface;
29
30
/**
31
 * Marshal middleware for use in the application.
32
 *
33
 * This class provides a number of methods for preparing and returning
34
 * middleware for use within an application.
35
 *
36
 * Middleware are organized as a stack. That means middleware
37
 * that have been added before will be executed after the newly
38
 * added one (last in, first out).
39
 *
40
 * If any middleware provided is already a MiddlewareInterface, it can be used
41
 * verbatim or decorated as-is. Other middleware types acceptable are:
42
 *
43
 * - PSR-15 RequestHandlerInterface instances; these will be decorated as
44
 *   RequestHandlerMiddleware instances.
45
 * - string service names resolving to middleware
46
 * - arrays of service names and/or MiddlewareInterface instances
47
 * - PHP callable that follow the PSR-15 signature
48
 *
49
 * @author Divine Niiquaye Ibok <[email protected]>
50
 */
51
class RoutePipeline implements RequestHandlerInterface, MiddlewareInterface
52
{
53 1
    use Traits\MiddlewareTrait;
54
55
    /** @var null|ContainerInterface */
56
    protected $container;
57
58
    /** @var null|RequestHandlerInterface */
59
    private $handler;
60
61
    /**
62
     * @param null|ContainerInterface $container
63
     */
64 42
    public function __construct(ContainerInterface $container = null)
65
    {
66 42
        $this->container = $container;
67 42
    }
68
69
    /**
70
     * Configures pipeline with target endpoint.
71
     *
72
     * @param RequestHandlerInterface $handler
73
     *
74
     * @return $this
75
     */
76 28
    public function withHandler(RequestHandlerInterface $handler): self
77
    {
78 28
        $pipeline          = clone $this;
79 28
        $pipeline->handler = $handler;
80
81 28
        return $pipeline;
82
    }
83
84
    /**
85
     * {@inheritdoc}
86
     */
87 26
    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
88
    {
89 26
        return $this->withHandler($handler)->handle($request);
90
    }
91
92
    /**
93
     * {@inheritdoc}
94
     */
95 29
    public function handle(ServerRequestInterface $request): ResponseInterface
96
    {
97 29
        if (null === $handler = $this->handler) {
98 1
            throw new InvalidMiddlewareException('Unable to run pipeline, no handler given.');
99
        }
100
101 28
        if ($handler instanceof Router) {
102
            // Get the Default Router is available and ready for dispatching
103 22
            $handler = $this->getDefaultRouter($handler, $request);
104
        }
105
106 28
        return $this->pipeline()->process($request, $handler);
107
    }
108
109
    /**
110
     * Create a middleware pipeline from an array of middleware.
111
     *
112
     * Each item is passed to prepare() before being passed to the
113
     * MiddlewarePipe instance the method returns.
114
     *
115
     * @throws InvalidMiddlewareException if middleware has not one of
116
     *                                    the specified types
117
     *
118
     * @return MiddlewarePipe
119
     */
120 28
    public function pipeline(): MiddlewarePipe
121
    {
122 28
        $pipeline    = new MiddlewarePipe();
123 28
        $middlewares = $this->getMiddlewares();
124
125 28
        foreach ($middlewares as $middleware) {
126 26
            $pipeline->pipe($this->prepare($middleware));
127
        }
128
129 25
        return $pipeline;
130
    }
131
132
    /**
133
     * Gets the middlewares from stack
134
     *
135
     * @return array<int,MiddlewareInterface|string>
136
     */
137 40
    public function getMiddlewares(): array
138
    {
139 40
        return \array_values($this->middlewares);
140
    }
141
142
    /**
143
     * Return the default router
144
     *
145
     * @throws RouteNotFoundException
146
     *
147
     * @return RequestHandlerInterface
148
     */
149 22
    private function getDefaultRouter(Router $router, ServerRequestInterface &$request): RequestHandlerInterface
150
    {
151
        // Get the Route Handler ready for dispatching
152 22
        $handler = $router->match($request);
153
154
        /** @var RouteInterface $route */
155 22
        $route   = $request->getAttribute(Route::class);
156 22
        $request = $request->withAttribute(Route::class, $route);
157
158 22
        $this->addMiddleware(...$route->getMiddlewares());
159
160 22
        return $handler;
161
    }
162
}
163