Completed
Push — master ( dc0762...6e4967 )
by Gabor
03:32
created

Pipeline::checkClassType()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 1
Bugs 1 Features 0
Metric Value
c 1
b 1
f 0
dl 0
loc 10
ccs 0
cts 9
cp 0
rs 9.4285
cc 3
eloc 5
nc 2
nop 1
crap 12
1
<?php
2
/**
3
 * WebHemi.
4
 *
5
 * PHP version 5.6
6
 *
7
 * @copyright 2012 - 2016 Gixx-web (http://www.gixx-web.com)
8
 * @license   https://opensource.org/licenses/MIT The MIT License (MIT)
9
 *
10
 * @link      http://www.gixx-web.com
11
 */
12
namespace WebHemi\Middleware\Pipeline;
13
14
use InvalidArgumentException;
15
use RuntimeException;
16
use WebHemi\Middleware\MiddlewareInterface;
17
use WebHemi\Middleware\DispatcherMiddleware;
18
use WebHemi\Middleware\FinalMiddleware;
19
use WebHemi\Middleware\RoutingMiddleware;
20
21
/**
22
 * Class Pipeline.
23
 */
24
class Pipeline implements MiddlewarePipelineInterface
25
{
26
    /** @var array */
27
    private $priorityList;
28
    /** @var array */
29
    private $pipelineList;
30
    /** @var array */
31
    private $keyMiddlewareList;
32
    /** @var int */
33
    private $index;
34
35
    /**
36
     * Pipeline constructor.
37
     */
38
    public function __construct()
39
    {
40
        $this->keyMiddlewareList = [
41
            RoutingMiddleware::class,
42
            DispatcherMiddleware::class,
43
            FinalMiddleware::class
44
        ];
45
46
        // The FinalMiddleware should not be part of the queue.
47
        $this->priorityList = [
48
            0   => [RoutingMiddleware::class],
49
            100 => [DispatcherMiddleware::class]
50
        ];
51
52
        $this->pipelineList = [
53
            RoutingMiddleware::class,
54
            DispatcherMiddleware::class,
55
        ];
56
    }
57
58
    /**
59
     * Adds a new middleware to the pipeline queue.
60
     *
61
     * @param string $middleWareClass
62
     * @param int    $priority
63
     *
64
     * @throws RuntimeException
65
     *
66
     * @return $this
67
     */
68
    public function queueMiddleware($middleWareClass, $priority = 50)
69
    {
70
        if (in_array($middleWareClass, $this->keyMiddlewareList)) {
71
            // Don't throw error if the user defines the default middleware classes.
72
            return $this;
73
        }
74
75
        $this->checkPipelineIsStarted();
76
        $this->checkDuplicates($middleWareClass);
77
        $this->checkClassType($middleWareClass);
78
79
        if ($priority === 0 || $priority == 100) {
80
            $priority++;
81
        }
82
83
        if (!isset($this->priorityList[$priority])) {
84
            $this->priorityList[$priority] = [];
85
        }
86
87
        if (!in_array($middleWareClass, $this->priorityList[$priority])) {
88
            $this->priorityList[$priority][] = $middleWareClass;
89
        }
90
91
        return $this;
92
    }
93
94
    /**
95
     * Checks if the pipline is already being processed.
96
     *
97
     * @throws RuntimeException
98
     */
99
    private function checkPipelineIsStarted()
100
    {
101
        if (isset($this->index)) {
102
            throw new RuntimeException('You are forbidden to add new middleware after start.');
103
        }
104
    }
105
106
    /**
107
     * Checks if the given middleware is already added to the list.
108
     *
109
     * @param string $middleWareClass
110
     *
111
     * @throws RuntimeException
112
     */
113
    private function checkDuplicates($middleWareClass)
114
    {
115
        if (in_array($middleWareClass, $this->pipelineList)) {
116
            throw new InvalidArgumentException(
117
                sprintf('The class "%s" is already added to the pipeline.', $middleWareClass)
118
            );
119
        }
120
    }
121
122
    /**
123
     * Checks if the given class is a middleware.
124
     *
125
     * @param string $middleWareClass
126
     *
127
     * @throws RuntimeException
128
     */
129
    private function checkClassType($middleWareClass)
130
    {
131
        $interfaces = class_implements($middleWareClass);
132
133
        if ($interfaces && !in_array(MiddlewareInterface::class, $interfaces)) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $interfaces of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
134
            throw new InvalidArgumentException(
135
                sprintf('The class "%s" does not implement MiddlewareInterface.', $middleWareClass)
136
            );
137
        }
138
    }
139
140
    /**
141
     * Sorts the pipeline elements according to the priority.
142
     */
143
    private function sortPipeline()
144
    {
145
        ksort($this->priorityList);
146
        $this->pipelineList = [];
147
148
        foreach ($this->priorityList as $middlewareList) {
149
            $this->pipelineList = array_merge($this->pipelineList, $middlewareList);
150
        }
151
    }
152
153
    /**
154
     * Starts the pipeline.
155
     *
156
     * @return null|string
157
     */
158
    public function start()
159
    {
160
        $this->index = 0;
161
        $this->sortPipeline();
162
163
        return $this->next();
164
    }
165
166
    /**
167
     * Gets next element from the pipeline.
168
     *
169
     * @return null|string
170
     */
171
    public function next()
172
    {
173
        if (!isset($this->index)) {
174
            throw new RuntimeException('Unable to get the next element until the pipeline is not started.');
175
        }
176
177
        return isset($this->pipelineList[$this->index]) ? $this->pipelineList[$this->index++] : null;
178
    }
179
}
180