Completed
Push — master ( 4e7b0a...f8136b )
by Florian
02:06
created

Workflow::processItem()   C

Complexity

Conditions 14
Paths 19

Size

Total Lines 32
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 26
CRAP Score 14

Importance

Changes 7
Bugs 1 Features 2
Metric Value
dl 0
loc 32
ccs 26
cts 26
cp 1
rs 5.0864
c 7
b 1
f 2
cc 14
eloc 21
nc 19
nop 2
crap 14

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * This file is part of plumphp/plum.
5
 *
6
 * (c) Florian Eckerstorfer <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Plum\Plum;
13
14
use Cocur\Vale\Vale;
15
use InvalidArgumentException;
16
use Plum\Plum\Converter\ConverterInterface;
17
use Plum\Plum\Filter\FilterInterface;
18
use Plum\Plum\Pipe\ConverterPipe;
19
use Plum\Plum\Pipe\FilterPipe;
20
use Plum\Plum\Pipe\AbstractPipe;
21
use Plum\Plum\Pipe\WriterPipe;
22
use Plum\Plum\Reader\ReaderInterface;
23
use Plum\Plum\Writer\WriterInterface;
24
25
/**
26
 * Workflow.
27
 *
28
 * @author    Florian Eckerstorfer <[email protected]>
29
 * @copyright 2014-2016 Florian Eckerstorfer
30
 */
31
class Workflow
32
{
33
    const APPEND  = 1;
34
    const PREPEND = 2;
35
36
    /**
37
     * @var AbstractPipe[]
38
     */
39
    private $pipeline = [];
40
41
    /**
42
     * @var array
43
     */
44
    private $options = [
45
        'resumeOnError' => false,
46
    ];
47
48
    /**
49
     * @param array $options
50
     *
51
     * @codeCoverageIgnore
52
     */
53
    public function __construct(array $options = [])
54
    {
55
        $this->options = array_merge($this->options, $options);
56
    }
57
58
    /**
59
     * @param string|null $type
60
     *
61
     * @return AbstractPipe[]
62
     */
63 2
    public function getPipeline($type = null)
64
    {
65 2
        $pipeline = [];
66
67 2
        foreach ($this->pipeline as $element) {
68 2
            if ($type === null || get_class($element) === $type) {
69 2
                $pipeline[] = $element;
70 2
            }
71 2
        }
72
73 2
        return $pipeline;
74
    }
75
76
    /**
77
     * Inserts an element into the pipeline at the given position.
78
     *
79
     * @param AbstractPipe $pipe
80
     *
81
     * @return Workflow
82
     */
83 13
    protected function addPipe(AbstractPipe $pipe)
84
    {
85 13
        if ($pipe->getPosition() === self::PREPEND) {
86 5
            array_unshift($this->pipeline, $pipe);
87 5
        } else {
88 13
            $this->pipeline[] = $pipe;
89
        }
90
91 13
        return $this;
92
    }
93
94
    /**
95
     * @param array|callable|FilterInterface $element
96
     *
97
     * @return Workflow
98
     *
99
     * @throws InvalidArgumentException
100
     */
101 11
    public function addFilter($element)
102
    {
103 11
        $pipe = FilterPipe::createFilter($element);
104
105 8
        return $this->addPipe($pipe);
106
    }
107
108
    /**
109
     * @return FilterPipe[]
110
     */
111 5
    public function getFilters()
112
    {
113 5
        return $this->getPipeline('Plum\Plum\Pipe\FilterPipe');
114
    }
115
116
    /**
117
     * @param ConverterInterface|callable|array $element
118
     *
119
     * @return Workflow $this
120
     */
121 13
    public function addConverter($element)
122
    {
123 13
        $pipe = ConverterPipe::createConverter($element);
124
125 10
        return $this->addPipe($pipe);
126
    }
127
128
    /**
129
     * @return ConverterPipe[]
130
     */
131 5
    public function getConverters()
132
    {
133 5
        return $this->getPipeline('Plum\Plum\Pipe\ConverterPipe');
134
    }
135
136
    /**
137
     * @param WriterInterface|array $element
138
     *
139
     * @return Workflow
140
     */
141 7
    public function addWriter($element)
142
    {
143 7
        $pipe = WriterPipe::createWriter($element);
144
145 4
        return $this->addPipe($pipe);
146
    }
147
148
    /**
149
     * @return WriterPipe[]
150
     */
151 3
    public function getWriters()
152
    {
153 3
        return $this->getPipeline('Plum\Plum\Pipe\WriterPipe');
154
    }
155
156
    /**
157
     * @param ReaderInterface[]|ReaderInterface $readers
158
     *
159
     * @return Result
160
     */
161 19
    public function process($readers)
162
    {
163 19
        if (!is_array($readers)) {
164 18
            $readers = [$readers];
165 18
        }
166
167 19
        $result = new Result();
168
169 19
        $this->prepareWriters($this->getWriters());
170
171 19
        foreach ($readers as $reader) {
172 19
            $this->processReader($reader, $result);
173 18
        }
174
175 18
        $this->finishWriters($this->getWriters());
176
177 18
        return $result;
178
    }
179
180
    /**
181
     * @param ReaderInterface $reader
182
     * @param Result          $result
183
     */
184 16
    protected function processReader(ReaderInterface $reader, Result $result)
185
    {
186 16
        foreach ($reader as $item) {
187 15
            $result->incReadCount();
188
            try {
189 15
                $this->processItem($item, $result);
190 15
            } catch (\Exception $e) {
191 2
                $result->addException($e);
192 2
                if (!$this->options['resumeOnError']) {
193 1
                    throw $e;
194
                }
195
            }
196 15
        }
197 15
    }
198
199
    /**
200
     * @param WriterPipe[] $writers
201
     */
202 5
    protected function prepareWriters($writers)
203
    {
204 5
        foreach ($writers as $element) {
205 5
            $element->getWriter()->prepare();
206 5
        }
207 5
    }
208
209
    /**
210
     * @param WriterPipe[] $writers
211
     */
212 5
    protected function finishWriters($writers)
213
    {
214 5
        foreach ($writers as $element) {
215 5
            $element->getWriter()->finish();
216 5
        }
217 5
    }
218
219
    /**
220
     * @param mixed  $item
221
     * @param Result $result
222
     */
223 18
    protected function processItem($item, Result $result)
224
    {
225 18
        $written = false;
226
227 18
        foreach ($this->pipeline as $element) {
228 18
            if ($element instanceof FilterPipe && $element->getField()) {
229 1
                if ($element->getFilter()->filter(Vale::get($item, $element->getField())) === false) {
230 1
                    return;
231
                }
232 18
            } elseif ($element instanceof FilterPipe) {
233 1
                if ($element->getFilter()->filter($item) === false) {
234 1
                    return;
235
                }
236 18
            } elseif ($element instanceof ConverterPipe && $element->getField()) {
237 4
                $item = $this->convertItemValue($item, $element);
238 18
            } elseif ($element instanceof ConverterPipe) {
239 7
                $item = $this->convertItem($item, $element);
240 5
                if ($item === null) {
241 1
                    return;
242
                }
243 15
            } elseif ($element instanceof WriterPipe) {
244 11
                if ($this->writeItem($item, $element) === true) {
245 10
                    $result->incWriteCount();
246 10
                    $written = true;
247 10
                }
248 11
            }
249 16
        }
250
251 16
        if ($written === true) {
252 10
            $result->incItemWriteCount();
253 10
        }
254 16
    }
255
256
    /**
257
     * Applies the given converter to the given item either if no filter is given or if the filter returns `true`.
258
     *
259
     * @param mixed         $item
260
     * @param ConverterPipe $pipe
261
     *
262
     * @return mixed
263
     */
264 5
    protected function convertItem($item, ConverterPipe $pipe)
265
    {
266 5
        $filterValue = $pipe->getFilterField() ? Vale::get($item, $pipe->getFilterField()) : $item;
267 5
        if ($pipe->getFilter() === null || $pipe->getFilter()->filter($filterValue) === true) {
268 4
            return $pipe->getConverter()->convert($item);
269
        }
270
271 2
        return $item;
272
    }
273
274
    /**
275
     * Applies the given converter to the given field in the given item if no filter is given or if the filters returns
276
     * `true` for the field.
277
     *
278
     * @param mixed         $item
279
     * @param ConverterPipe $pipe
280
     *
281
     * @return mixed
282
     */
283 4
    protected function convertItemValue($item, ConverterPipe $pipe)
284
    {
285 4
        $value       = Vale::get($item, $pipe->getField());
286 4
        $filterValue = $pipe->getFilterField() ? Vale::get($item, $pipe->getFilterField()) : $item;
287
288 4
        if ($pipe->getFilter() === null || $pipe->getFilter()->filter($filterValue) === true) {
289 3
            $item = Vale::set($item, $pipe->getField(), $pipe->getConverter()->convert($value));
290 3
        }
291
292 4
        return $item;
293
    }
294
295
    /**
296
     * Writes the given item to the given writer if the no filter is given or the filter returns `true`.
297
     *
298
     * @param mixed      $item
299
     * @param WriterPipe $pipe
300
     *
301
     * @return bool `true` if the item has been written, `false` if not.
302
     */
303 4
    protected function writeItem($item, WriterPipe $pipe)
304
    {
305 4
        if ($pipe->getFilter() === null || $pipe->getFilter()->filter($item) === true) {
306 3
            $pipe->getWriter()->writeItem($item);
307
308 3
            return true;
309
        }
310
311 1
        return false;
312
    }
313
}
314