Passed
Push — master ( a14261...5f8bab )
by Gabor
05:22
created

AbstractAdapter::buildPipeline()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 12
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 3

Importance

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