AbstractReader   A
last analyzed

Complexity

Total Complexity 23

Size/Duplication

Total Lines 258
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 5

Test Coverage

Coverage 76.25%

Importance

Changes 0
Metric Value
wmc 23
lcom 1
cbo 5
dl 0
loc 258
ccs 61
cts 80
cp 0.7625
rs 10
c 0
b 0
f 0

20 Methods

Rating   Name   Duplication   Size   Complexity  
B __construct() 0 23 6
A current() 0 6 1
A key() 0 6 1
A next() 0 11 2
A rewind() 0 6 1
A valid() 0 6 1
A read() 0 20 2
A setResources() 0 7 1
A getResources() 0 4 1
A getCurrentResource() 0 4 1
A getEventDispatcher() 0 4 1
B createNextReader() 0 26 3
A initialize() 0 12 2
serialize() 0 1 ?
createReader() 0 1 ?
doKey() 0 1 ?
doCurrent() 0 1 ?
doNext() 0 1 ?
doValid() 0 1 ?
doRewind() 0 1 ?
1
<?php
2
3
namespace TreeHouse\Feeder\Reader;
4
5
use Symfony\Component\EventDispatcher\EventDispatcher;
6
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
7
use Symfony\Component\HttpFoundation\ParameterBag;
8
use TreeHouse\Feeder\Event\ResourceEvent;
9
use TreeHouse\Feeder\Event\ResourceSerializeEvent;
10
use TreeHouse\Feeder\FeedEvents;
11
use TreeHouse\Feeder\Resource\ResourceCollection;
12
use TreeHouse\Feeder\Resource\ResourceInterface;
13
14
abstract class AbstractReader implements ReaderInterface
15
{
16
    /**
17
     * @var ResourceCollection
18
     */
19
    protected $resources;
20
21
    /**
22
     * @var ResourceInterface
23
     */
24
    protected $resource;
25
26
    /**
27
     * @var EventDispatcherInterface
28
     */
29
    protected $eventDispatcher;
30
31
    /**
32
     * @var bool
33
     */
34
    protected $initialized;
35
36
    /**
37
     * @param mixed                    $resources  Optional resource collection. Can be a Resource, an array of
38
     *                                             Resource's, or a ResourceCollection. When empty, a new collection
39
     *                                             will be created.
40
     * @param EventDispatcherInterface $dispatcher Optional event dispatcher.
41
     *
42
     * @throws \InvalidArgumentException
43
     */
44 74
    public function __construct($resources = null, EventDispatcherInterface $dispatcher = null)
45
    {
46 74
        if ($resources instanceof ResourceInterface) {
47 74
            $resources = [$resources];
48 74
        }
49
50 74
        if (is_array($resources)) {
51 74
            $resources = new ResourceCollection($resources);
52 74
        }
53
54 74
        if ($resources === null) {
55
            $resources = new ResourceCollection();
56
        }
57
58 74
        if (!$resources instanceof ResourceCollection) {
59
            throw new \InvalidArgumentException(
60
                'Second argument must be a Resource object, an array of Resource objects, or null'
61
            );
62
        }
63
64 74
        $this->resources = $resources;
65 74
        $this->eventDispatcher = $dispatcher ?: new EventDispatcher();
66 74
    }
67
68
    /**
69
     * @inheritdoc
70
     */
71 48
    public function current()
72
    {
73 48
        $this->initialize();
74
75 46
        return $this->doCurrent();
76
    }
77
78
    /**
79
     * @inheritdoc
80
     */
81
    public function key()
82
    {
83
        $this->initialize();
84
85
        return $this->doKey();
86
    }
87
88
    /**
89
     * @inheritdoc
90
     */
91 52
    public function next()
92
    {
93 52
        $this->initialize();
94
95 52
        $this->doNext();
96
97
        // if the current reader is not valid, create a reader for the next resource
98 46
        if (!$this->valid()) {
99 44
            $this->createNextReader();
100 44
        }
101 46
    }
102
103
    /**
104
     * @inheritdoc
105
     */
106
    public function rewind()
107
    {
108
        $this->initialize();
109
110
        $this->doRewind();
111
    }
112
113
    /**
114
     * @inheritdoc
115
     */
116 48
    public function valid()
117
    {
118 48
        $this->initialize();
119
120 46
        return $this->doValid();
121
    }
122
123
    /**
124
     * Wrapper that implements various calls, so you can use the iterator in a
125
     * simple while loop.
126
     *
127
     * @return ParameterBag
128
     */
129 46
    public function read()
130
    {
131 46
        if (!$this->valid()) {
132 16
            return null;
133
        }
134
135
        // keep a local copy of the resource; the next() call could change the cached one
136 44
        $resource = $this->resource;
137
138 44
        $item = $this->current();
139 44
        $this->next();
140
141
        // serialize the item
142 44
        $event = new ResourceSerializeEvent($resource, $item);
143 44
        $this->eventDispatcher->dispatch(FeedEvents::RESOURCE_PRE_SERIALIZE, $event);
144 44
        $item = $this->serialize($item);
145 42
        $this->eventDispatcher->dispatch(FeedEvents::RESOURCE_POST_SERIALIZE, $event);
146
147 42
        return $item;
148
    }
149
150
    /**
151
     * @inheritdoc
152
     */
153 2
    public function setResources(ResourceCollection $resources)
154
    {
155
        $this->resources = $resources;
156
157
        // must reinitialize, because we basically start over at this point
158
        $this->initialized = false;
159 2
    }
160
161
    /**
162
     * @inheritdoc
163
     */
164
    public function getResources()
165
    {
166
        return $this->resources;
167
    }
168
169
    /**
170
     * @return ResourceInterface
171
     */
172
    public function getCurrentResource()
173
    {
174
        return $this->resource;
175
    }
176
177
    /**
178
     * @return EventDispatcherInterface
179
     */
180
    public function getEventDispatcher()
181
    {
182
        return $this->eventDispatcher;
183
    }
184
185
    /**
186
     *
187
     */
188 52
    protected function createNextReader()
189
    {
190 52
        if ($this->resource) {
191
            // end existing resource first
192 44
            $this->eventDispatcher->dispatch(
193 44
                FeedEvents::RESOURCE_END,
194 44
                new ResourceEvent($this->resource, $this->resources)
195 44
            );
196 44
        }
197
198 52
        if ($this->resources->isEmpty()) {
199 44
            return;
200
        }
201
202
        // get the next resource
203 52
        $this->resource = $this->resources->shift();
204
205
        // dispatch start event
206 52
        $this->eventDispatcher->dispatch(
207 52
            FeedEvents::RESOURCE_START,
208 52
            new ResourceEvent($this->resource, $this->resources)
209 52
        );
210
211
        // create a reader for this new resource
212 52
        $this->createReader($this->resource);
213 46
    }
214
215
    /**
216
     *
217
     */
218 52
    protected function initialize()
219
    {
220 52
        if ($this->initialized) {
221 52
            return;
222
        }
223
224
        // mark initialized first, to prevent recursive calls
225 52
        $this->initialized = true;
226
227 52
        $this->resources->rewind();
228 52
        $this->createNextReader();
229 46
    }
230
231
    /**
232
     * Serializes a read item into a ParameterBag.
233
     *
234
     * @param string $data
235
     *
236
     * @return ParameterBag
237
     */
238
    abstract protected function serialize($data);
239
240
    /**
241
     * Creates a reader for a resource.
242
     *
243
     * @param ResourceInterface $resource
244
     */
245
    abstract protected function createReader(ResourceInterface $resource);
246
247
    /**
248
     * @see \Iterator::key()
249
     */
250
    abstract protected function doKey();
251
252
    /**
253
     * @see \Iterator::current()
254
     */
255
    abstract protected function doCurrent();
256
257
    /**
258
     * @see \Iterator::next()
259
     */
260
    abstract protected function doNext();
261
262
    /**
263
     * @see \Iterator::valid()
264
     */
265
    abstract protected function doValid();
266
267
    /**
268
     * @see \Iterator::rewind()
269
     */
270
    abstract protected function doRewind();
271
}
272