Completed
Push — master ( 238e2d...c71ea9 )
by Gabor
03:17
created

Pipeline::buildPipeline()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 12
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 3

Importance

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