Passed
Push — steps ( c7b5f4...d19fba )
by Tom
02:52
created

Steps::setGetIteratorFunctor()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
c 1
b 0
f 0
1
<?php
2
3
/* this file is part of pipelines */
4
5
namespace Ktomk\Pipelines\File\Pipeline;
6
7
use Ktomk\Pipelines\File\ParseException;
8
use Ktomk\Pipelines\File\Pipeline;
9
10
/**
11
 * Class Steps
12
 *
13
 * A Pipeline consist of Steps. Some of them can be parallel.
14
 */
15
class Steps implements \ArrayAccess, \Countable, \IteratorAggregate
16
{
17
    /**
18
     * @var Pipeline
19
     */
20
    private $pipeline;
21
22
    /**
23
     * @var array pipeline definition
24
     */
25
    private $array;
26
27
    /**
28
     * @var array|Step[] steps of the pipeline
29
     * @see parseSteps
30
     */
31
    private $steps;
32
33
    /**
34
     * @var callable
35
     */
36
    private $getIteratorFunctor;
37
38
    /**
39
     * Pipeline constructor.
40
     *
41
     * @param Pipeline $pipeline
42
     * @param array $definition
43
     *
44
     * @throws ParseException
45
     */
46 7
    public function __construct(Pipeline $pipeline, array $definition)
47
    {
48
        // quick validation
49 7
        if (!isset($definition[0])) {
50 1
            ParseException::__('Steps requires a tree of steps');
51
        }
52
53 7
        $this->pipeline = $pipeline;
54 7
        $this->parseSteps($definition);
55 7
    }
56
57
    /**
58
     * @return Pipeline
59
     */
60 1
    public function getPipeline()
61
    {
62 1
        return $this->pipeline;
63
    }
64
65
    /**
66
     * @return array|Step[]
67
     */
68 4
    public function getSteps()
69
    {
70 4
        return $this->steps;
71
    }
72
73
    /**
74
     * @param $functor
75
     *
76
     * @see getIterator
77
     */
78 1
    public function setGetIteratorFunctor($functor)
79
    {
80 1
        $this->getIteratorFunctor = $functor;
81 1
    }
82
83
    /**
84
     * Specify data which should be serialized to JSON
85
     *
86
     * @return array
87
     * @since 5.4.0
88
     */
89 1
    public function jsonSerialize()
90
    {
91 1
        $steps = array();
92 1
        foreach ($this->getSteps() as $step) {
93 1
            $steps[] = $step->jsonSerialize();
94
        }
95
96
        return array(
97 1
            'steps' => $steps,
98
        );
99
    }
100
101
    /* @see \ArrayAccess */
102
103 1
    public function offsetExists($offset)
104
    {
105 1
        return isset($this->steps[$offset]);
106
    }
107
108
    /**
109
     * @param mixed $offset
110
     *
111
     * @return Step
112
     */
113 1
    public function offsetGet($offset)
114
    {
115 1
        return $this->steps[$offset];
116
    }
117
118 1
    public function offsetSet($offset, $value)
119
    {
120 1
        throw new \BadMethodCallException('Steps offsets are read-only');
121
    }
122
123 1
    public function offsetUnset($offset)
124
    {
125 1
        throw new \BadMethodCallException('Steps offsets are read-only');
126
    }
127
128
    /* @see \Countable */
129
130 2
    public function count()
131
    {
132 2
        return count($this->steps);
133
    }
134
135
    /* @see \IteratorAggregate */
136
137
    /**
138
     * @return \ArrayIterator|Step[]
139
     */
140 2
    public function getIterator()
141
    {
142 2
        return is_callable($this->getIteratorFunctor)
143 1
            ? call_user_func($this->getIteratorFunctor, $this)
144 2
            : new \ArrayIterator($this->steps);
145
    }
146
147 7
    private function parseSteps(array $definition)
148
    {
149 7
        $this->array = array();
150 7
        $this->steps = array();
151
152 7
        foreach ($definition as $node) {
153 7
            if (!is_array($node)) {
154 1
                ParseException::__(sprintf('Step expected array, got %s', gettype($node)));
155
            }
156 7
            if (empty($node)) {
157 1
                ParseException::__('Step expected, got empty array');
158
            }
159
160 7
            $keys = array_keys($node);
161 7
            $name = $keys[0];
162 7
            if (!in_array($name, array('step', 'parallel'), true)) {
163 1
                ParseException::__(sprintf('Unknown pipeline step "%s", expected "step" or "parallel"', $name));
164
            }
165
166 7
            $this->node($node, $name);
167
        }
168 7
    }
169
170
    /**
171
     * @param int $index of step, from the zero based index in the list of steps
172
     * @param array $step
173
     * @param array $env [optional] environment variables in array notation for the new step
174
     *
175
     * @return Step
176
     */
177 7
    private function step($index, array $step, array $env = array())
178
    {
179 7
        return new Step($this->pipeline, $index, $step, $env);
180
    }
181
182
    /**
183
     * @param array $node
184
     * @param $name
185
     */
186 7
    private function node(array $node, $name)
187
    {
188 7
        $this->array[] = $node;
189
        switch ($name) {
190 7
            case 'step':
191 7
                $this->steps[] = $this->step(count($this->steps), $node[$name]);
192
193 7
                break;
194 3
            case 'parallel':
195 3
                $this->parallel($node[$name]);
196
197 2
                break;
198
            default:
199
                // @codeCoverageIgnoreStart
200
                throw new \BadMethodCallException(
201
                    sprintf('Unchecked name condition: "%s"', $name)
202
                );
203
            // @codeCoverageIgnoreEnd
204
        }
205 7
    }
206
207
    /**
208
     * @param $node
209
     */
210 3
    private function parallel(array $node)
211
    {
212 3
        $group = array();
213 3
        foreach ($node as $step) {
214 3
            if (!(isset($step['step']) && is_array($step['step']))) {
215 1
                ParseException::__('Parallel step must consist of steps only');
216
            }
217 2
            $group[] = $step['step'];
218
        }
219
220 2
        $total = count($group);
221 2
        foreach ($group as $index => $step) {
222 2
            $this->steps[] = $this->step(
223 2
                count($this->steps),
224 2
                $step,
225
                array(
226 2
                    'BITBUCKET_PARALLEL_STEP' => $index,
227 2
                    'BITBUCKET_PARALLEL_STEP_COUNT' => $total,
228
                )
229
            );
230
        }
231 2
    }
232
}
233