Completed
Push — master ( ef610a...dc0762 )
by Gabor
24:45
created

Pipeline::sortPipeline()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 9
rs 9.6666
cc 2
eloc 5
nc 2
nop 0
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 (isset($this->index)) {
71
            throw new RuntimeException('You are forbidden to add new middleware after start.');
72
        }
73
74
        // Don't throw error if the user defines the default middleware classes.
75
        if (in_array($middleWareClass, $this->keyMiddlewareList)) {
76
            return $this;
77
        }
78
79
        if (in_array($middleWareClass, $this->pipelineList)) {
80
            throw new InvalidArgumentException(
81
                sprintf('The class "%s" is already added to the pipeline.', $middleWareClass)
82
            );
83
        }
84
85
        $interfaces = class_implements($middleWareClass);
86
87
        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...
88
            throw new InvalidArgumentException(
89
                sprintf('The class "%s" does not implement MiddlewareInterface.', $middleWareClass)
90
            );
91
        }
92
93
        if ($priority === 0 || $priority == 100) {
94
            $priority++;
95
        }
96
97
        if (!isset($this->priorityList[$priority])) {
98
            $this->priorityList[$priority] = [];
99
        }
100
101
        if (!in_array($middleWareClass, $this->priorityList[$priority])) {
102
            $this->priorityList[$priority][] = $middleWareClass;
103
        }
104
105
        return $this;
106
    }
107
108
    /**
109
     * Sorts the pipeline elements according to the priority.
110
     */
111
    private function sortPipeline()
112
    {
113
        ksort($this->priorityList);
114
        $this->pipelineList = [];
115
116
        foreach ($this->priorityList as $middlewareList) {
117
            $this->pipelineList = array_merge($this->pipelineList, $middlewareList);
118
        }
119
    }
120
121
    /**
122
     * Starts the pipeline.
123
     *
124
     * @return null|string
125
     */
126
    public function start()
127
    {
128
        $this->index = 0;
129
        $this->sortPipeline();
130
131
        return $this->next();
132
    }
133
134
    /**
135
     * Gets next element from the pipeline.
136
     *
137
     * @return null|string
138
     */
139
    public function next()
140
    {
141
        if (!isset($this->index)) {
142
            throw new RuntimeException('Unable to get the next element until the pipeline is not started.');
143
        }
144
145
        return isset($this->pipelineList[$this->index]) ? $this->pipelineList[$this->index++] : null;
146
    }
147
}
148