Passed
Push — master ( a5e378...69cdd1 )
by Marcio
02:39
created

Pipeline::parsePipeString()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 4
c 1
b 0
f 0
dl 0
loc 9
rs 10
cc 2
nc 2
nop 1
1
<?php
2
/**
3
 *
4
 * KNUT7 K7F (https://marciozebedeu.com/)
5
 * KNUT7 K7F (tm) : Rapid Development Framework (https://marciozebedeu.com/)
6
 *
7
 * Licensed under The MIT License
8
 * For full copyright and license information, please see the LICENSE.txt
9
 * Redistributions of files must retain the above copyright notice.
10
 *
11
 * @link      https://github.com/knut7/framework/ for the canonical source repository
12
 * @copyright (c) 2015.  KNUT7  Software Technologies AO Inc. (https://marciozebedeu.com/)
13
 * @license   MIT License
14
 * @author    Beyond Code GmbH
15
16
 * @version   1.0.7
17
 *
18
 *
19
 */
20
21
namespace Ballybran\Core\Http;
22
23
use Closure;
24
25
class Pipeline
26
{
27
28
    /**
29
     * The object being passed through the pipeline.
30
     *
31
     * @var mixed
32
     */
33
    protected $passable;
34
35
    /**
36
     * The array of class pipes.
37
     *
38
     * @var array
39
     */
40
    protected $pipes = [];
41
42
    /**
43
     * The additional parameters.
44
     *
45
     * @var array
46
     */
47
    protected $parameters = [];
48
49
    /**
50
     * The method to call on each pipe.
51
     *
52
     * @var string
53
     */
54
    protected $method = 'handle';
55
56
    /**
57
     * Set the object being sent through the pipeline.
58
     *
59
     * @param  mixed  $passable
60
     * @return $this
61
     */
62
    public function send(...$passable)
63
    {
64
        $this->passable = $passable;
65
66
        return $this;
67
    }
68
69
    /**
70
     * Set the array of pipes.
71
     *
72
     * @param  array|mixed  $pipes
73
     * @return $this
74
     */
75
    public function through($pipes)
76
    {
77
        $this->pipes = is_array($pipes) ? $pipes : func_get_args();
78
79
        return $this;
80
    }
81
82
    /**
83
     * Set the method to call on the pipes.
84
     *
85
     * @param  string  $method
86
     * @return $this
87
     */
88
    public function via($method)
89
    {
90
        $this->method = $method;
91
92
        return $this;
93
    }
94
95
    /**
96
     * Set the additional parameters to send
97
     *
98
     * @param  mixed  $parameters
99
     * @return $this
100
     */
101
    public function with(...$parameters)
102
    {
103
        $this->parameters = $parameters;
104
105
        return $this;
106
    }
107
108
    /**
109
     * Run the pipeline with a final destination callback.
110
     *
111
     * @param  \Closure  $destination
112
     * @return mixed
113
     */
114
    public function then(Closure $destination)
115
    {
116
        $pipeline = array_reduce(
117
            array_reverse($this->pipes), $this->carry(), $this->prepareDestination($destination)
118
        );
119
120
        return call_user_func_array($pipeline, $this->passable);
121
    }
122
123
    /**
124
     * Get the final piece of the Closure onion.
125
     *
126
     * @param  \Closure  $destination
127
     * @return \Closure
128
     */
129
    protected function prepareDestination(Closure $destination)
130
    {
131
        return function () use ($destination) {
132
            return call_user_func_array($destination, func_get_args());
133
        };
134
    }
135
136
    /**
137
     * Get a Closure that represents a slice of the application onion.
138
     *
139
     * @return \Closure
140
     */
141
    protected function carry()
142
    {
143
        return function ($stack, $pipe) {
144
            return function () use ($stack, $pipe) {
145
                $passable = func_get_args();
146
                $passable[] = $stack;
147
                $passable = array_merge($passable, $this->parameters);
148
149
                if (is_callable($pipe)) {
150
                    // If the pipe is an instance of a Closure, we will just call it directly but
151
                    // otherwise we'll resolve the pipes out of the container and call it with
152
                    // the appropriate method and arguments, returning the results back out.
153
                    return call_user_func_array($pipe, $passable);
154
                } elseif (! is_object($pipe)) {
155
                    list($name, $parameters) = $this->parsePipeString($pipe);
156
                    // If the pipe is a string we will parse the string and resolve the class out
157
                    // of the dependency injection container. We can then build a callable and
158
                    // execute the pipe function giving in the parameters that are required.
159
                    $pipe = new $name();
160
                    $parameters = array_merge($passable, $parameters);
161
                } else {
162
                    // If the pipe is already an object we'll just make a callable and pass it to
163
                    // the pipe as-is. There is no need to do any extra parsing and formatting
164
                    // since the object we're given was already a fully instantiated object.
165
                    $parameters = $passable;
166
                }
167
168
                return method_exists($pipe, $this->method)
169
                    ? call_user_func_array([$pipe, $this->method], $parameters)
170
                    : $pipe(...$parameters);
171
            };
172
        };
173
    }
174
175
    /**
176
     * Parse full pipe string to get name and parameters.
177
     *
178
     * @param  string $pipe
179
     * @return array
180
     */
181
    protected function parsePipeString($pipe)
182
    {
183
        list($name, $parameters) = array_pad(explode(':', $pipe, 2), 2, []);
184
185
        if (is_string($parameters)) {
186
            $parameters = explode(',', $parameters);
187
        }
188
189
        return [$name, $parameters];
190
    }
191
}