Completed
Push — master ( 9c0667...3631d5 )
by Jeroen
8s
created

Importer::handleItem()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 15
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 1

Importance

Changes 1
Bugs 1 Features 0
Metric Value
c 1
b 1
f 0
dl 0
loc 15
ccs 5
cts 5
cp 1
rs 9.4285
cc 1
eloc 9
nc 1
nop 1
crap 1
1
<?php
2
3
namespace TreeHouse\IoBundle\Import\Importer;
4
5
use Symfony\Component\EventDispatcher\Event;
6
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
7
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
8
use TreeHouse\Feeder\Event\InvalidItemEvent;
9
use TreeHouse\Feeder\Event\ItemNotModifiedEvent;
10
use TreeHouse\Feeder\Feed;
11
use TreeHouse\Feeder\FeedEvents;
12
use TreeHouse\IoBundle\Entity\Import;
13
use TreeHouse\IoBundle\Import\Event\ExceptionEvent;
14
use TreeHouse\IoBundle\Import\Event\FailedItemEvent;
15
use TreeHouse\IoBundle\Import\Event\HandledItemEvent;
16
use TreeHouse\IoBundle\Import\Event\ItemEvent;
17
use TreeHouse\IoBundle\Import\Event\SkippedItemEvent;
18
use TreeHouse\IoBundle\Import\Event\SuccessItemEvent;
19
use TreeHouse\IoBundle\Import\Exception\FailedItemException;
20
use TreeHouse\IoBundle\Import\Feed\FeedItemBag;
21
use TreeHouse\IoBundle\Import\Handler\HandlerInterface;
22
use TreeHouse\IoBundle\Import\ImportEvents;
23
use TreeHouse\IoBundle\Import\ImportResult;
24
use TreeHouse\IoBundle\Model\SourceInterface;
25
26
class Importer implements EventSubscriberInterface
27
{
28
    /**
29
     * @var Import
30
     */
31
    protected $import;
32
33
    /**
34
     * @var HandlerInterface
35
     */
36
    protected $handler;
37
38
    /**
39
     * @var EventDispatcherInterface
40
     */
41
    protected $eventDispatcher;
42
43
    /**
44
     * @var ImportResult
45
     */
46
    protected $result;
47
48
    /**
49
     * @var int
50
     */
51
    protected $batchSize = 20;
52
53
    /**
54
     * @param Import                   $import
55
     * @param HandlerInterface         $handler
56
     * @param EventDispatcherInterface $dispatcher
57
     * @param int                      $batchSize
58 6
     */
59
    public function __construct(Import $import, HandlerInterface $handler, EventDispatcherInterface $dispatcher, $batchSize = 20)
60 6
    {
61 6
        $this->import = $import;
62 6
        $this->handler = $handler;
63 6
        $this->eventDispatcher = $dispatcher;
64
        $this->result = new ImportResult();
65 6
66 6
        $this->setBatchSize($batchSize);
67 6
        $this->eventDispatcher->addSubscriber($this);
68
    }
69
70
    /**
71
     * @return Import
72 4
     */
73
    public function getImport()
74 4
    {
75
        return $this->import;
76
    }
77
78
    /**
79
     * @return ImportResult
80 4
     */
81
    public function getResult()
82 4
    {
83
        return $this->result;
84
    }
85
86
    /**
87
     * @inheritdoc
88 4
     */
89
    public static function getSubscribedEvents()
90
    {
91 4
        return [
92 4
            FeedEvents::ITEM_FILTERED => [['onItemFiltered']],
93 4
            FeedEvents::ITEM_INVALID => [['onItemInvalid']],
94 4
            FeedEvents::ITEM_FAILED => [['onItemFailed']],
95
        ];
96
    }
97
98
    /**
99
     * @return EventDispatcherInterface
100
     */
101
    public function getEventDispatcher()
102
    {
103
        return $this->eventDispatcher;
104
    }
105
106
    /**
107
     * @param int $size
108
     *
109
     * @throws \InvalidArgumentException When size is not a positive number
110 6
     */
111
    public function setBatchSize($size)
112 6
    {
113
        $batchSize = intval($size);
114 6
115
        if ($batchSize < 1) {
116
            throw new \InvalidArgumentException('Batch size needs to be higher than 0');
117
        }
118 6
119 6
        $this->batchSize = $batchSize;
120
    }
121
122
    /**
123
     * Dispatched when item is filtered from the feed.
124
     *
125
     * @param ItemNotModifiedEvent $event
126 4
     */
127
    public function onItemFiltered(ItemNotModifiedEvent $event)
128 4
    {
129 4
        $this->skipItem($event->getItem(), $event->getReason());
0 ignored issues
show
Compatibility introduced by
$event->getItem() of type object<Symfony\Component...oundation\ParameterBag> is not a sub-type of object<TreeHouse\IoBundl...mport\Feed\FeedItemBag>. It seems like you assume a child class of the class Symfony\Component\HttpFoundation\ParameterBag to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
130
    }
131
132
    /**
133
     * Dispatched when item failed during modification.
134
     *
135
     * @param ItemNotModifiedEvent $event
136
     */
137
    public function onItemFailed(ItemNotModifiedEvent $event)
138
    {
139
        $this->failItem($event->getItem(), $event->getReason());
0 ignored issues
show
Compatibility introduced by
$event->getItem() of type object<Symfony\Component...oundation\ParameterBag> is not a sub-type of object<TreeHouse\IoBundl...mport\Feed\FeedItemBag>. It seems like you assume a child class of the class Symfony\Component\HttpFoundation\ParameterBag to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
140
    }
141
142
    /**
143
     * Dispatched when item is processed but found invalid.
144
     *
145
     * @param InvalidItemEvent $event
146
     */
147
    public function onItemInvalid(InvalidItemEvent $event)
148
    {
149
        $this->failItem($event->getItem(), $event->getReason());
0 ignored issues
show
Compatibility introduced by
$event->getItem() of type object<Symfony\Component...oundation\ParameterBag> is not a sub-type of object<TreeHouse\IoBundl...mport\Feed\FeedItemBag>. It seems like you assume a child class of the class Symfony\Component\HttpFoundation\ParameterBag to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
150
    }
151
152
    /**
153
     * @param string $name
154
     * @param Event  $event
155 4
     */
156
    public function dispatchEvent($name, Event $event)
157 4
    {
158 4
        $this->eventDispatcher->dispatch($name, $event);
159
    }
160
161
    /**
162
     * Runs the import.
163
     *
164
     * @param Feed $feed
165 4
     */
166
    public function run(Feed $feed)
167 4
    {
168
        while ($item = $this->getNextItem($feed)) {
169 4
            // dispatch event for next item
170 4
            $event = new ItemEvent($this, $item);
0 ignored issues
show
Compatibility introduced by
$item of type object<Symfony\Component...oundation\ParameterBag> is not a sub-type of object<TreeHouse\IoBundle\Item\ItemBag>. It seems like you assume a child class of the class Symfony\Component\HttpFoundation\ParameterBag to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
171
            $this->eventDispatcher->dispatch(ImportEvents::ITEM_START, $event);
172
            // import the item
173 4
            try {
174 4
                $source = $this->handleItem($item);
0 ignored issues
show
Compatibility introduced by
$item of type object<Symfony\Component...oundation\ParameterBag> is not a sub-type of object<TreeHouse\IoBundl...mport\Feed\FeedItemBag>. It seems like you assume a child class of the class Symfony\Component\HttpFoundation\ParameterBag to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
175 4
176 4
                $this->successItem($item, $source);
0 ignored issues
show
Compatibility introduced by
$item of type object<Symfony\Component...oundation\ParameterBag> is not a sub-type of object<TreeHouse\IoBundl...mport\Feed\FeedItemBag>. It seems like you assume a child class of the class Symfony\Component\HttpFoundation\ParameterBag to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
177
            } catch (FailedItemException $e) {
178
                $this->failItem($item, $e->getMessage());
0 ignored issues
show
Compatibility introduced by
$item of type object<Symfony\Component...oundation\ParameterBag> is not a sub-type of object<TreeHouse\IoBundl...mport\Feed\FeedItemBag>. It seems like you assume a child class of the class Symfony\Component\HttpFoundation\ParameterBag to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
179
            }
180 4
181
            // item done
182
            $this->eventDispatcher->dispatch(ImportEvents::ITEM_FINISH, $event);
183 4
184
            // clear entitymanager after batch
185
            if (($this->result->getProcessed() % $this->batchSize) === 0) {
186 2
                $this->flush();
187 4
                $this->clear();
188
            }
189
        }
190 4
191 4
        // flush remaining changes
192 4
        $this->flush();
193
        $this->clear();
194
    }
195
196
    /**
197
     * Returns the next item in the feed, or null if no more items are left.
198
     * Use this when iterating over the feed.
199
     *
200
     * @param Feed $feed
201
     *
202 4
     * @return FeedItemBag|null
203
     */
204
    protected function getNextItem(Feed $feed)
205 4
    {
206
        try {
207
            return $feed->getNextItem();
208
        } catch (\Exception $exception) {
209
            $this->handleException($exception);
210
        }
211
212
        return null;
213
    }
214
215
    /**
216
     * @param FeedItemBag $item
217
     *
218
     * @return SourceInterface
219 4
     */
220
    protected function handleItem(FeedItemBag $item)
221 4
    {
222
        $source = $this->handler->handle($item);
223 4
224 4
        $this->eventDispatcher->dispatch(
225 4
            ImportEvents::ITEM_HANDLED,
226
            new HandledItemEvent(
227
                $this,
228
                $item,
229
                $source
230
            )
231
        );
232
233 4
        return $source;
234
    }
235 4
236
    /**
237 4
     * Dispatches an event indicating a successfully handled item.
238 4
     *
239 4
     * @param FeedItemBag     $item
240
     * @param SourceInterface $result
241
     */
242
    protected function successItem(FeedItemBag $item, SourceInterface $result)
243
    {
244
        $this->result->incrementSuccess();
245
246
        $event = new SuccessItemEvent($this, $item, $result);
247 4
        $this->eventDispatcher->dispatch(ImportEvents::ITEM_SUCCESS, $event);
248
    }
249 4
250
    /**
251 4
     * Dispatches an event indicating a skipped item.
252 4
     *
253 4
     * @param FeedItemBag $item
254
     * @param string      $reason
255
     */
256
    protected function skipItem(FeedItemBag $item, $reason = '')
257
    {
258
        $this->result->incrementSkipped();
259
260
        $event = new SkippedItemEvent($this, $item, $reason);
261
        $this->eventDispatcher->dispatch(ImportEvents::ITEM_SKIPPED, $event);
262
    }
263
264
    /**
265
     * Dispatches an event indicating a failed item.
266
     *
267
     * @param FeedItemBag $item
268 4
     * @param string      $reason
269
     */
270 4
    protected function failItem(FeedItemBag $item, $reason)
271 4
    {
272
        $this->result->incrementFailed();
273 4
274
        $event = new FailedItemEvent($this, $item, $reason);
275 4
        $this->eventDispatcher->dispatch(ImportEvents::ITEM_FAILED, $event);
276 4
    }
277
278
    /**
279
     * Dispatches exception event.
280
     *
281
     * @param \Exception $exception
282
     */
283
    protected function handleException(\Exception $exception)
284
    {
285
        $this->eventDispatcher->dispatch(ImportEvents::EXCEPTION, new ExceptionEvent($this, $exception));
286
    }
287
288
    /**
289
     * Flushes outstanding changes.
290
     */
291
    protected function flush()
292
    {
293
        $this->handler->flush();
294
    }
295
296
    protected function clear()
297
    {
298
        $this->handler->clear();
299
    }
300
}
301