Passed
Branch master (30ae21)
by Gabor
03:15
created

PipelineManager::getPipelineList()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

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