Completed
Push — master ( a09c74...b4437a )
by Gabor
03:33
created

Pipeline::getPipelineList()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 1
Bugs 1 Features 0
Metric Value
c 1
b 1
f 0
dl 0
loc 4
ccs 0
cts 2
cp 0
rs 10
cc 1
eloc 2
nc 1
nop 0
crap 2
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\Config\ConfigInterface;
17
use WebHemi\Middleware\MiddlewareInterface;
18
use WebHemi\Middleware\DispatcherMiddleware;
19
use WebHemi\Middleware\FinalMiddleware;
20
use WebHemi\Middleware\RoutingMiddleware;
21
22
/**
23
 * Class Pipeline.
24
 */
25
class Pipeline implements MiddlewarePipelineInterface
26
{
27
    /** @var ConfigInterface */
28
    private $config;
29
    /** @var array */
30
    private $priorityList;
31
    /** @var array */
32
    private $pipelineList;
33
    /** @var array */
34
    private $keyMiddlewareList;
35
    /** @var int */
36
    private $index;
37
38
    /**
39
     * Pipeline constructor.
40
     *
41
     * @param ConfigInterface $pipelineConfig
42
     */
43 3
    public function __construct(ConfigInterface $pipelineConfig)
44
    {
45 3
        $this->config = $pipelineConfig;
46
47 3
        $this->keyMiddlewareList = [
48
            RoutingMiddleware::class,
49
            DispatcherMiddleware::class,
50
            FinalMiddleware::class
51
        ];
52
53
        // The FinalMiddleware should not be part of the queue.
54 3
        $this->priorityList = [
55
            0   => [RoutingMiddleware::class],
56
            100 => [DispatcherMiddleware::class]
57
        ];
58
59 3
        $this->pipelineList = [
60
            RoutingMiddleware::class,
61
            DispatcherMiddleware::class,
62
        ];
63
64 3
        $this->buildPipeline();
65 3
    }
66
67
    /**
68
     * Add middleware definitions to the pipeline.
69
     */
70 3
    private function buildPipeline()
71
    {
72 3
        $pipelineConfig = $this->config->toArray();
73
74 3
        foreach ($pipelineConfig as $middlewareData) {
75 3
            if (!isset($middlewareData['priority'])) {
76 3
                $middlewareData['priority'] = 50;
77
            }
78
79 3
            $this->queueMiddleware($middlewareData['class'], $middlewareData['priority']);
80
        }
81 3
    }
82
83
    /**
84
     * Checks the given class against Middleware Criterias.
85
     *
86
     * @param $middleWareClass
87
     *
88
     * @throws RuntimeException
89
     *
90
     * @return bool
91
     */
92 3
    private function checkMiddleware($middleWareClass)
93
    {
94 3
        if (isset($this->index)) {
95
            throw new RuntimeException('You are forbidden to add new middleware after start.');
96
        }
97
98 3
        if (in_array($middleWareClass, $this->pipelineList)) {
99
            throw new RuntimeException(
100
                sprintf('The class "%s" is already added to the pipeline.', $middleWareClass)
101
            );
102
        }
103
104 3
        return true;
105
    }
106
107
    /**
108
     * Adds a new middleware to the pipeline queue.
109
     *
110
     * @param string $middleWareClass
111
     * @param int    $priority
112
     *
113
     * @throws RuntimeException
114
     *
115
     * @return $this
116
     */
117 3
    public function queueMiddleware($middleWareClass, $priority = 50)
118
    {
119 3
        $this->checkMiddleware($middleWareClass);
120
121 3
        if (in_array($middleWareClass, $this->keyMiddlewareList)) {
122
            // Don't throw error if the user defines the default middleware classes.
123
            return $this;
124
        }
125
126 3
        if ($priority === 0 || $priority == 100) {
127
            $priority++;
128
        }
129
130 3
        if (!isset($this->priorityList[$priority])) {
131 3
            $this->priorityList[$priority] = [];
132
        }
133
134 3
        if (!in_array($middleWareClass, $this->priorityList[$priority])) {
135 3
            $this->priorityList[$priority][] = $middleWareClass;
136
        }
137
138 3
        return $this;
139
    }
140
141
    /**
142
     * Sorts the pipeline elements according to the priority.
143
     */
144 2
    private function sortPipeline()
145
    {
146 2
        ksort($this->priorityList);
147 2
        $this->pipelineList = [];
148
149 2
        foreach ($this->priorityList as $middlewareList) {
150 2
            $this->pipelineList = array_merge($this->pipelineList, $middlewareList);
151
        }
152 2
    }
153
154
    /**
155
     * Starts the pipeline.
156
     *
157
     * @return null|string
158
     */
159 2
    public function start()
160
    {
161 2
        $this->index = 0;
162 2
        $this->sortPipeline();
163
164 2
        return $this->next();
165
    }
166
167
    /**
168
     * Gets next element from the pipeline.
169
     *
170
     * @return null|string
171
     */
172 2
    public function next()
173
    {
174 2
        if (!isset($this->index)) {
175
            throw new RuntimeException('Unable to get the next element until the pipeline is not started.');
176
        }
177
178 2
        return isset($this->pipelineList[$this->index]) ? $this->pipelineList[$this->index++] : null;
179
    }
180
181
    /**
182
     * Gets the full pipeline list.
183
     *
184
     * @return array
185
     */
186
    public function getPipelineList()
187
    {
188
        return $this->pipelineList;
189
    }
190
}
191