Feed   B
last analyzed

Complexity

Total Complexity 36

Size/Duplication

Total Lines 244
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 14

Test Coverage

Coverage 90%

Importance

Changes 0
Metric Value
wmc 36
lcom 1
cbo 14
dl 0
loc 244
ccs 90
cts 100
cp 0.9
rs 8.8
c 0
b 0
f 0

14 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 2
A getReader() 0 4 1
A getEventDispatcher() 0 4 1
A getModifiers() 0 4 1
A addFilter() 0 4 1
A addMapper() 0 4 1
A addTransformer() 0 4 1
A addValidator() 0 4 1
B addModifier() 0 19 5
A removeModifier() 0 10 3
A removeModifierAt() 0 8 2
A hasModifierAt() 0 4 1
B getNextItem() 0 33 6
D modify() 0 40 10
1
<?php
2
3
namespace TreeHouse\Feeder;
4
5
use Symfony\Component\EventDispatcher\EventDispatcher;
6
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
7
use Symfony\Component\HttpFoundation\ParameterBag;
8
use TreeHouse\Feeder\Event\FailedItemModificationEvent;
9
use TreeHouse\Feeder\Event\InvalidItemEvent;
10
use TreeHouse\Feeder\Event\ItemModificationEvent;
11
use TreeHouse\Feeder\Event\ItemNotModifiedEvent;
12
use TreeHouse\Feeder\Exception\FilterException;
13
use TreeHouse\Feeder\Exception\ModificationException;
14
use TreeHouse\Feeder\Exception\ValidationException;
15
use TreeHouse\Feeder\Modifier\Item\Filter\FilterInterface;
16
use TreeHouse\Feeder\Modifier\Item\Mapper\MapperInterface;
17
use TreeHouse\Feeder\Modifier\Item\ModifierInterface;
18
use TreeHouse\Feeder\Modifier\Item\Transformer\TransformerInterface;
19
use TreeHouse\Feeder\Modifier\Item\Validator\ValidatorInterface;
20
use TreeHouse\Feeder\Reader\ReaderInterface;
21
22
class Feed
23
{
24
    /**
25
     * @var ReaderInterface
26
     */
27
    protected $reader;
28
29
    /**
30
     * @var EventDispatcherInterface
31
     */
32
    protected $eventDispatcher;
33
34
    /**
35
     * @var ModifierInterface[]
36
     */
37
    protected $modifiers = [];
38
39
    /**
40
     * @var array
41
     */
42
    protected $continues = [];
43
44
    /**
45
     * @param ReaderInterface          $reader
46
     * @param EventDispatcherInterface $eventDispatcher
47
     */
48 38
    public function __construct(ReaderInterface $reader, EventDispatcherInterface $eventDispatcher = null)
49
    {
50 38
        $this->reader = $reader;
51 38
        $this->eventDispatcher = $eventDispatcher ?: new EventDispatcher();
52 38
    }
53
54
    /**
55
     * @return ReaderInterface
56
     */
57 2
    public function getReader()
58
    {
59 2
        return $this->reader;
60
    }
61
62
    /**
63
     * @return EventDispatcherInterface
64
     */
65 4
    public function getEventDispatcher()
66
    {
67 4
        return $this->eventDispatcher;
68
    }
69
70
    /**
71
     * @return ModifierInterface[]
72
     */
73 16
    public function getModifiers()
74
    {
75 16
        return $this->modifiers;
76
    }
77
78
    /**
79
     * @param FilterInterface $filter
80
     * @param int|null        $position
81
     */
82 2
    public function addFilter(FilterInterface $filter, $position = null)
83
    {
84 2
        $this->addModifier($filter, $position);
85 2
    }
86
87
    /**
88
     * @param MapperInterface $mapper
89
     * @param int|null        $position
90
     */
91 2
    public function addMapper(MapperInterface $mapper, $position = null)
92
    {
93 2
        $this->addModifier($mapper, $position);
94 2
    }
95
96
    /**
97
     * @param TransformerInterface $transformer
98
     * @param int|null             $position
99
     */
100 2
    public function addTransformer(TransformerInterface $transformer, $position = null)
101
    {
102 2
        $this->addModifier($transformer, $position);
103 2
    }
104
105
    /**
106
     * @param ValidatorInterface $validator
107
     * @param int|null           $position
108
     */
109 2
    public function addValidator(ValidatorInterface $validator, $position = null)
110
    {
111 2
        $this->addModifier($validator, $position);
112 2
    }
113
114
    /**
115
     * @param ModifierInterface $modifier
116
     * @param int               $position
117
     * @param bool              $continueOnException
118
     *
119
     * @throws \InvalidArgumentException
120
     */
121 34
    public function addModifier(ModifierInterface $modifier, $position = null, $continueOnException = false)
122
    {
123 34
        if (null === $position) {
124 20
            $position = sizeof($this->modifiers) ? (max(array_keys($this->modifiers)) + 1) : 0;
125 20
        }
126
127 34
        if (!is_numeric($position)) {
128
            throw new \InvalidArgumentException('Position must be a number');
129
        }
130
131 34
        if (array_key_exists($position, $this->modifiers)) {
132
            throw new \InvalidArgumentException(sprintf('There already is a modifier at position %d', $position));
133
        }
134
135 34
        $this->modifiers[$position] = $modifier;
136 34
        $this->continues[$position] = $continueOnException;
137
138 34
        ksort($this->modifiers);
139 34
    }
140
141
    /**
142
     * @param ModifierInterface $modifier
143
     */
144 2
    public function removeModifier(ModifierInterface $modifier)
145
    {
146 2
        foreach ($this->modifiers as $position => $_modifier) {
147 2
            if ($_modifier === $modifier) {
148 2
                unset($this->modifiers[$position]);
149
150 2
                break;
151
            }
152 2
        }
153 2
    }
154
155
    /**
156
     * @param int $position
157
     *
158
     * @throws \OutOfBoundsException
159
     */
160 2
    public function removeModifierAt($position)
161
    {
162 2
        if (!array_key_exists($position, $this->modifiers)) {
163
            throw new \OutOfBoundsException(sprintf('There is no modifier at position %d', $position));
164
        }
165
166 2
        unset($this->modifiers[$position]);
167 2
    }
168
169
    /**
170
     * @param int $position
171
     *
172
     * @return bool
173
     */
174 4
    public function hasModifierAt($position)
175
    {
176 4
        return array_key_exists($position, $this->modifiers);
177
    }
178
179
    /**
180
     * @return ParameterBag|null
181
     */
182 16
    public function getNextItem()
183
    {
184 16
        while ($item = $this->reader->read()) {
185
            try {
186 16
                $this->eventDispatcher->dispatch(FeedEvents::ITEM_PRE_MODIFICATION, new ItemModificationEvent($item));
187 16
                $item = $this->modify($item);
188 8
                $this->eventDispatcher->dispatch(FeedEvents::ITEM_POST_MODIFICATION, new ItemModificationEvent($item));
189
190 8
                return $item;
191 8
            } catch (FilterException $e) {
192 2
                $this->eventDispatcher->dispatch(
193 2
                    FeedEvents::ITEM_FILTERED,
194 2
                    new ItemNotModifiedEvent($item, $e->getMessage())
195 2
                );
196 8
            } catch (ValidationException $e) {
197 2
                $this->eventDispatcher->dispatch(
198 2
                    FeedEvents::ITEM_INVALID,
199 2
                    new InvalidItemEvent($item, $e->getMessage())
200 2
                );
201 6
            } catch (ModificationException $e) {
202 4
                if ($e->getPrevious()) {
203
                    $e = $e->getPrevious();
204
                }
205
206 4
                $this->eventDispatcher->dispatch(
207 4
                    FeedEvents::ITEM_FAILED,
208 4
                    new ItemNotModifiedEvent($item, $e->getMessage())
209 4
                );
210
            }
211 8
        }
212
213 10
        return null;
214
    }
215
216
    /**
217
     * @param ParameterBag $item
218
     *
219
     * @throws FilterException
220
     * @throws ModificationException
221
     * @throws ValidationException
222
     *
223
     * @return ParameterBag
224
     */
225 16
    protected function modify(ParameterBag &$item)
226
    {
227 16
        foreach ($this->modifiers as $position => $modifier) {
228
            try {
229 14
                if ($modifier instanceof FilterInterface) {
230 4
                    $modifier->filter($item);
231
                }
232
233 10
                if ($modifier instanceof MapperInterface) {
234
                    $item = $modifier->map($item);
235
                }
236
237 10
                if ($modifier instanceof TransformerInterface) {
238 10
                    $modifier->transform($item);
239 4
                }
240
241 4
                if ($modifier instanceof ValidatorInterface) {
242
                    $modifier->validate($item);
243
                }
244 14
            } catch (FilterException $e) {
245
                // filter exceptions don't get to continue
246 2
                throw $e;
247 8
            } catch (ValidationException $e) {
248
                // validation exceptions don't get to continue
249 2
                throw $e;
250 6
            } catch (ModificationException $e) {
251
                // notify listeners of this failure, give them the option to stop propagation
252 6
                $event = new FailedItemModificationEvent($item, $modifier, $e);
253 6
                $event->setContinue($this->continues[$position]);
254
255 6
                $this->eventDispatcher->dispatch(FeedEvents::ITEM_MODIFICATION_FAILED, $event);
256
257 6
                if (!$event->getContinue()) {
258 4
                    throw $e;
259
                }
260
            }
261 8
        }
262
263 8
        return $item;
264
    }
265
}
266