Completed
Push — master ( 70ef2d...0e5aaa )
by Alex
16s queued 10s
created

FeedIo   B

Complexity

Total Complexity 33

Size/Duplication

Total Lines 361
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 16

Test Coverage

Coverage 95.05%

Importance

Changes 0
Metric Value
wmc 33
lcom 2
cbo 16
dl 0
loc 361
ccs 96
cts 101
cp 0.9505
rs 7.9538
c 0
b 0
f 0

26 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 9 1
A loadCommonStandards() 0 9 2
A addFilter() 0 6 1
A getCommonStandards() 0 6 1
A addStandard() 0 9 1
A newParser() 0 10 2
A getFixerSet() 0 4 1
A loadFixerSet() 0 11 2
A addFixer() 0 7 1
A getBaseFixers() 0 7 1
A addDateFormats() 0 8 2
A getDateTimeBuilder() 0 4 1
A getReader() 0 4 1
A setReader() 0 6 1
A discover() 0 6 1
A readAsync() 0 6 1
A read() 0 17 3
A readSince() 0 4 1
A resetFilters() 0 6 1
A getPsrResponse() 0 9 1
A format() 0 8 1
A toRss() 0 4 1
A toAtom() 0 4 1
A toJson() 0 4 1
A getStandard() 0 9 2
A logAction() 0 7 1
1
<?php declare(strict_types=1);
2
/*
3
 * This file is part of the feed-io package.
4
 *
5
 * (c) Alexandre Debril <[email protected]>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
11
namespace FeedIo;
12
13
use FeedIo\Filter\ModifiedSince;
14
use FeedIo\Reader\Result;
15
use FeedIo\Reader\FixerSet;
16
use FeedIo\Reader\FixerAbstract;
17
use FeedIo\Rule\DateTimeBuilder;
18
use FeedIo\Adapter\ClientInterface;
19
use FeedIo\Standard\Loader;
20
use FeedIo\Async\Reader as AsyncReader;
21
use FeedIo\Async\CallbackInterface;
22
use FeedIo\FeedInterface;
23
use Psr\Log\LoggerInterface;
24
use FeedIo\Http\ResponseBuilder;
25
use Psr\Http\Message\ResponseInterface;
26
27
/**
28
 * This class acts as a facade. It provides methods to access feed-io main features
29
 *
30
 * <code>
31
 *   // $client is a \FeedIo\Adapter\ClientInterface instance, $logger a \Psr\Log\LoggerInterface
32
 *   $feedIo = new FeedIo($client, $logger);
33
 *
34
 *   // read a feed. Output is a Result instance
35
 *   $result = $feedIo->read('http://somefeed.org/feed.rss');
36
 *
37
 *   // use the feed
38
 *   $feed = $result->getFeed();
39
 *   echo $feed->getTitle();
40
 *
41
 *   // and its items
42
 *   foreach ( $feed as $item ) {
43
 *       echo $item->getTitle();
44
 *       echo $item->getDescription();
45
 *   }
46
 *
47
 * </code>
48
 *
49
 * <code>
50
 *   // build the feed to publish
51
 *   $feed = new \FeedIo\Feed;
52
 *   $feed->setTitle('title');
53
 *   // ...
54
 *
55
 *   // add items to it
56
 *   $item = new \FeedIo\Feed\Item
57
 *   $item->setTitle('my great post');
58
 *
59
 *   // want to publish a media ? no problem
60
 *   $media = new \FeedIo\Feed\Item\Media
61
 *   $media->setUrl('http://yourdomain.tld/medias/some-podcast.mp3');
62
 *   $media->setType('audio/mpeg');
63
 *
64
 *   // add it to the item
65
 *   $item->addMedia($media);
66
 *
67
 *   // add the item to the feed (almost there)
68
 *   $feed->add($item);
69
 *
70
 *   // format it in atom
71
 *   $feedIo->toAtom($feed);
72
 * </code>
73
 *
74
 */
75
class FeedIo
76
{
77
78
    /**
79
     * @var \FeedIo\Reader
80
     */
81
    protected $reader;
82
83
    /**
84
     * @var \FeedIo\Rule\DateTimeBuilder
85
     */
86
    protected $dateTimeBuilder;
87
88
    /**
89
     * @var \FeedIo\Adapter\ClientInterface;
90
     */
91
    protected $client;
92
93
    /**
94
     * @var \Psr\Log\LoggerInterface
95
     */
96
    protected $logger;
97
98
    /**
99
     * @var array
100
     */
101
    protected $standards;
102
103
    /**
104
     * @var \FeedIo\Reader\FixerSet
105
     */
106
    protected $fixerSet;
107
108
    /**
109
     * @param \FeedIo\Adapter\ClientInterface $client
110
     * @param \Psr\Log\LoggerInterface        $logger
111
     */
112 13
    public function __construct(ClientInterface $client, LoggerInterface $logger)
113
    {
114 13
        $this->client = $client;
115 13
        $this->logger = $logger;
116 13
        $this->dateTimeBuilder = new DateTimeBuilder($logger);
117 13
        $this->setReader(new Reader($client, $logger));
118 13
        $this->loadCommonStandards();
119 13
        $this->loadFixerSet();
120 13
    }
121
122
    /**
123
     * Loads main standards (RSS, RDF, Atom) in current object's attributes
124
     *
125
     * @return FeedIo
126
     */
127 13
    protected function loadCommonStandards() : FeedIo
128
    {
129 13
        $standards = $this->getCommonStandards();
130 13
        foreach ($standards as $name => $standard) {
131 13
            $this->addStandard($name, $standard);
132
        }
133
134 13
        return $this;
135
    }
136
137
    /**
138
     * adds a filter to the reader
139
     *
140
     * @param \FeedIo\FilterInterface $filter
141
     * @return FeedIo
142
     */
143 2
    public function addFilter(FilterInterface $filter) : FeedIo
144
    {
145 2
        $this->getReader()->addFilter($filter);
146
147 2
        return $this;
148
    }
149
150
    /**
151
     * Returns main standards
152
     *
153
     * @return array
154
     */
155 13
    public function getCommonStandards() : array
156
    {
157 13
        $loader = new Loader();
158
159 13
        return $loader->getCommonStandards($this->getDateTimeBuilder());
160
    }
161
162
    /**
163
     * @param  string                   $name
164
     * @param  \FeedIo\StandardAbstract $standard
165
     * @return FeedIo
166
     */
167 13
    public function addStandard(string $name, StandardAbstract $standard) : FeedIo
168
    {
169 13
        $name = strtolower($name);
170 13
        $this->standards[$name] = $standard;
171 13
        $parser = $this->newParser($standard->getSyntaxFormat(), $standard);
172 13
        $this->reader->addParser($parser);
173
174 13
        return $this;
175
    }
176
177
    /**
178
     * @param string $format
179
     * @param StandardAbstract $standard
180
     * @return ParserAbstract
181
     */
182 12
    public function newParser(string $format, StandardAbstract $standard) : ParserAbstract
183
    {
184 12
        $reflection = new \ReflectionClass("FeedIo\\Parser\\{$format}Parser");
185
186 12
        if (! $reflection->isSubclassOf('FeedIo\ParserAbstract')) {
187
            throw new \InvalidArgumentException();
188
        }
189
190 12
        return $reflection->newInstanceArgs([$standard, $this->logger]);
191
    }
192
193
    /**
194
     * @return \FeedIo\Reader\FixerSet
195
     */
196 1
    public function getFixerSet() : FixerSet
197
    {
198 1
        return $this->fixerSet;
199
    }
200
201
    /**
202
     * @return FeedIo
203
     */
204 12
    protected function loadFixerSet() : FeedIo
205
    {
206 12
        $this->fixerSet = new FixerSet();
207 12
        $fixers = $this->getBaseFixers();
208
209 12
        foreach ($fixers as $fixer) {
210 12
            $this->addFixer($fixer);
211
        }
212
213 12
        return $this;
214
    }
215
216
    /**
217
     * @param  FixerAbstract $fixer
218
     * @return FeedIo
219
     */
220 12
    public function addFixer(FixerAbstract $fixer) : FeedIo
221
    {
222 12
        $fixer->setLogger($this->logger);
223 12
        $this->fixerSet->add($fixer);
224
225 12
        return $this;
226
    }
227
228
    /**
229
     * @return array
230
     */
231 12
    public function getBaseFixers() : array
232
    {
233
        return array(
234 12
            new Reader\Fixer\LastModified(),
235 12
            new Reader\Fixer\PublicId(),
236
        );
237
    }
238
239
    /**
240
     * @param array $formats
241
     * @return FeedIo
242
     */
243 1
    public function addDateFormats(array $formats) : FeedIo
244
    {
245 1
        foreach ($formats as $format) {
246 1
            $this->getDateTimeBuilder()->addDateFormat($format);
247
        }
248
249 1
        return $this;
250
    }
251
252
    /**
253
     * @return \FeedIo\Rule\DateTimeBuilder
254
     */
255 13
    public function getDateTimeBuilder() : DateTimeBuilder
256
    {
257 13
        return $this->dateTimeBuilder;
258
    }
259
260
    /**
261
     * @return \FeedIo\Reader
262
     */
263 4
    public function getReader() : Reader
264
    {
265 4
        return $this->reader;
266
    }
267
268
    /**
269
     * @param \FeedIo\Reader $reader
270
     * @return FeedIo
271
     */
272 13
    public function setReader(Reader $reader) : FeedIo
273
    {
274 13
        $this->reader = $reader;
275
276 13
        return $this;
277
    }
278
279
    /**
280
     * Discover feeds from the webpage's headers
281
     * @param  string $url
282
     * @return array
283
     */
284 1
    public function discover(string $url) : array
285
    {
286 1
        $explorer = new Explorer($this->client, $this->logger);
287
288 1
        return $explorer->discover($url);
289
    }
290
291
    /**
292
     * @param iterable $requests
293
     * @param CallbackInterface $callback
294
     * @param string $feedClass
295
     */
296
    public function readAsync(iterable $requests, CallbackInterface $callback, string $feedClass = '\FeedIo\Feed') : void
297
    {
298
        $reader = new AsyncReader($this->reader, $this->reader->getClient(), $callback, $feedClass);
0 ignored issues
show
Compatibility introduced by
$this->reader->getClient() of type object<FeedIo\Adapter\ClientInterface> is not a sub-type of object<FeedIo\Adapter\Guzzle\Client>. It seems like you assume a concrete implementation of the interface FeedIo\Adapter\ClientInterface 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...
299
300
        $reader->process($requests);
301
    }
302
303
    /**
304
     * @param  string                $url
305
     * @param  FeedInterface         $feed
306
     * @param  \DateTime             $modifiedSince
307
     * @return \FeedIo\Reader\Result
308
     */
309 2
    public function read(string $url, FeedInterface $feed = null, \DateTime $modifiedSince = null) : Result
310
    {
311 2
        if (is_null($feed)) {
312 1
            $feed = new Feed();
313
        }
314
315 2
        if ($modifiedSince instanceof \DateTime) {
316 1
            $this->addFilter(new ModifiedSince($modifiedSince));
317
        }
318
319 2
        $this->logAction($feed, "read access : $url into a feed instance");
320 2
        $result = $this->reader->read($url, $feed, $modifiedSince);
321
322 2
        $this->fixerSet->correct($result->getFeed());
323
324 2
        return $result;
325
    }
326
327
    /**
328
     * @param  string                $url
329
     * @param  \DateTime             $modifiedSince
330
     * @return \FeedIo\Reader\Result
331
     */
332 1
    public function readSince(string $url, \DateTime $modifiedSince) : Result
333
    {
334 1
        return $this->read($url, new Feed(), $modifiedSince);
335
    }
336
337
    /**
338
     * @return FeedIo
339
     */
340 1
    public function resetFilters() : FeedIo
341
    {
342 1
        $this->getReader()->resetFilters();
343
344 1
        return $this;
345
    }
346
347
    /**
348
     * Get a PSR-7 compliant response for the given feed
349
     *
350
     * @param \FeedIo\FeedInterface $feed
351
     * @param string $standard
352
     * @param int $maxAge
353
     * @param bool $public
354
     * @return ResponseInterface
355
     */
356 1
    public function getPsrResponse(FeedInterface $feed, string $standard, int $maxAge = 600, bool $public = true) : ResponseInterface
357
    {
358 1
        $this->logAction($feed, "creating a PSR 7 Response in $standard format");
359
360 1
        $formatter = $this->getStandard($standard)->getFormatter();
361 1
        $responseBuilder = new ResponseBuilder($maxAge, $public);
362
363 1
        return $responseBuilder->createResponse($standard, $formatter, $feed);
364
    }
365
366
    /**
367
     * @param  FeedInterface $feed
368
     * @param  string        $standard Standard's name
369
     * @return string
370
     */
371 1
    public function format(FeedInterface $feed, string $standard) : string
372
    {
373 1
        $this->logAction($feed, "formatting a feed in $standard format");
374
375 1
        $formatter = $this->getStandard($standard)->getFormatter();
376
377 1
        return $formatter->toString($feed);
378
    }
379
380
    /**
381
     * @param  \FeedIo\FeedInterface $feed
382
     * @return string
383
     */
384 1
    public function toRss(FeedInterface $feed) : string
385
    {
386 1
        return $this->format($feed, 'rss');
387
    }
388
389
    /**
390
     * @param  \FeedIo\FeedInterface $feed
391
     * @return string
392
     */
393 1
    public function toAtom(FeedInterface $feed) : string
394
    {
395 1
        return $this->format($feed, 'atom');
396
    }
397
398
    /**
399
     * @param  \FeedIo\FeedInterface $feed
400
     * @return string
401
     */
402 1
    public function toJson(FeedInterface $feed) : string
403
    {
404 1
        return $this->format($feed, 'json');
405
    }
406
407
408
    /**
409
     * @param  string                   $name
410
     * @return \FeedIo\StandardAbstract
411
     * @throws \OutOfBoundsException
412
     */
413 3
    public function getStandard(string $name) : StandardAbstract
414
    {
415 3
        $name = strtolower($name);
416 3
        if (array_key_exists($name, $this->standards)) {
417 2
            return $this->standards[$name];
418
        }
419
420 1
        throw new \OutOfBoundsException("no standard found for $name");
421
    }
422
423
    /**
424
     * @param  \FeedIo\FeedInterface $feed
425
     * @param  string                $message
426
     * @return FeedIo
427
     */
428 3
    protected function logAction(FeedInterface $feed, string $message) : FeedIo
429
    {
430 3
        $class = get_class($feed);
431 3
        $this->logger->debug("$message (feed class : $class)");
432
433 3
        return $this;
434
    }
435
}
436