Completed
Push — master ( 30142f...c651b6 )
by Alex
16s queued 11s
created

FeedIo::readAsync()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 6
ccs 0
cts 4
cp 0
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 3
crap 2
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\Rule\DateTimeBuilderInterface;
19
use FeedIo\Adapter\ClientInterface;
20
use FeedIo\Standard\Loader;
21
use FeedIo\Async\Reader as AsyncReader;
22
use FeedIo\Async\CallbackInterface;
23
use FeedIo\FeedInterface;
24
use Psr\Log\LoggerInterface;
25
use FeedIo\Http\ResponseBuilder;
26
use Psr\Http\Message\ResponseInterface;
27
28
/**
29
 * This class acts as a facade. It provides methods to access feed-io main features
30
 *
31
 * <code>
32
 *   // $client is a \FeedIo\Adapter\ClientInterface instance, $logger a \Psr\Log\LoggerInterface
33
 *   $feedIo = new FeedIo($client, $logger);
34
 *
35
 *   // read a feed. Output is a Result instance
36
 *   $result = $feedIo->read('http://somefeed.org/feed.rss');
37
 *
38
 *   // use the feed
39
 *   $feed = $result->getFeed();
40
 *   echo $feed->getTitle();
41
 *
42
 *   // and its items
43
 *   foreach ( $feed as $item ) {
44
 *       echo $item->getTitle();
45
 *       echo $item->getDescription();
46
 *   }
47
 *
48
 * </code>
49
 *
50
 * <code>
51
 *   // build the feed to publish
52
 *   $feed = new \FeedIo\Feed;
53
 *   $feed->setTitle('title');
54
 *   // ...
55
 *
56
 *   // add items to it
57
 *   $item = new \FeedIo\Feed\Item
58
 *   $item->setTitle('my great post');
59
 *
60
 *   // want to publish a media ? no problem
61
 *   $media = new \FeedIo\Feed\Item\Media
62
 *   $media->setUrl('http://yourdomain.tld/medias/some-podcast.mp3');
63
 *   $media->setType('audio/mpeg');
64
 *
65
 *   // add it to the item
66
 *   $item->addMedia($media);
67
 *
68
 *   // add the item to the feed (almost there)
69
 *   $feed->add($item);
70
 *
71
 *   // format it in atom
72
 *   $feedIo->toAtom($feed);
73
 * </code>
74
 *
75
 */
76
class FeedIo
77
{
78
79
    /**
80
     * @var \FeedIo\Reader
81
     */
82
    protected $reader;
83
84
    /**
85
     * @var \FeedIo\Rule\DateTimeBuilder
86
     */
87
    protected $dateTimeBuilder;
88
89
    /**
90
     * @var \FeedIo\Adapter\ClientInterface;
91
     */
92
    protected $client;
93
94
    /**
95
     * @var \Psr\Log\LoggerInterface
96
     */
97
    protected $logger;
98
99
    /**
100
     * @var array
101
     */
102
    protected $standards;
103
104
    /**
105
     * @var \FeedIo\Reader\FixerSet
106
     */
107
    protected $fixerSet;
108
109
    /**
110
     * @param \FeedIo\Adapter\ClientInterface $client
111
     * @param \Psr\Log\LoggerInterface        $logger
112
     */
113 13
    public function __construct(ClientInterface $client, LoggerInterface $logger, DateTimeBuilderInterface $dateTimeBuilder = null)
114
    {
115 13
        $this->client = $client;
116 13
        $this->logger = $logger;
117 13
        $this->dateTimeBuilder = $dateTimeBuilder ?? new DateTimeBuilder($logger);
0 ignored issues
show
Documentation Bug introduced by
$dateTimeBuilder ?? new ...ateTimeBuilder($logger) is of type object<FeedIo\Rule\DateTimeBuilderInterface>, but the property $dateTimeBuilder was declared to be of type object<FeedIo\Rule\DateTimeBuilder>. Are you sure that you always receive this specific sub-class here, or does it make sense to add an instanceof check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a given class or a super-class is assigned to a property that is type hinted more strictly.

Either this assignment is in error or an instanceof check should be added for that assignment.

class Alien {}

class Dalek extends Alien {}

class Plot
{
    /** @var  Dalek */
    public $villain;
}

$alien = new Alien();
$plot = new Plot();
if ($alien instanceof Dalek) {
    $plot->villain = $alien;
}
Loading history...
118 13
        $this->setReader(new Reader($client, $logger));
119 13
        $this->loadCommonStandards();
120 13
        $this->loadFixerSet();
121 13
    }
122
123
    /**
124
     * Loads main standards (RSS, RDF, Atom) in current object's attributes
125
     *
126
     * @return FeedIo
127
     */
128 13
    protected function loadCommonStandards() : FeedIo
129
    {
130 13
        $standards = $this->getCommonStandards();
131 13
        foreach ($standards as $name => $standard) {
132 13
            $this->addStandard($name, $standard);
133
        }
134
135 13
        return $this;
136
    }
137
138
    /**
139
     * adds a filter to the reader
140
     *
141
     * @param \FeedIo\FilterInterface $filter
142
     * @return FeedIo
143
     */
144 2
    public function addFilter(FilterInterface $filter) : FeedIo
145
    {
146 2
        $this->getReader()->addFilter($filter);
147
148 2
        return $this;
149
    }
150
151
    /**
152
     * Returns main standards
153
     *
154
     * @return array
155
     */
156 13
    public function getCommonStandards() : array
157
    {
158 13
        $loader = new Loader();
159
160 13
        return $loader->getCommonStandards($this->getDateTimeBuilder());
161
    }
162
163
    /**
164
     * @param  string                   $name
165
     * @param  \FeedIo\StandardAbstract $standard
166
     * @return FeedIo
167
     */
168 13
    public function addStandard(string $name, StandardAbstract $standard) : FeedIo
169
    {
170 13
        $name = strtolower($name);
171 13
        $this->standards[$name] = $standard;
172 13
        $parser = $this->newParser($standard->getSyntaxFormat(), $standard);
173 13
        $this->reader->addParser($parser);
174
175 13
        return $this;
176
    }
177
178
    /**
179
     * @param string $format
180
     * @param StandardAbstract $standard
181
     * @return ParserAbstract
182
     */
183 12
    public function newParser(string $format, StandardAbstract $standard) : ParserAbstract
184
    {
185 12
        $reflection = new \ReflectionClass("FeedIo\\Parser\\{$format}Parser");
186
187 12
        if (! $reflection->isSubclassOf('FeedIo\ParserAbstract')) {
188
            throw new \InvalidArgumentException();
189
        }
190
191 12
        return $reflection->newInstanceArgs([$standard, $this->logger]);
192
    }
193
194
    /**
195
     * @return \FeedIo\Reader\FixerSet
196
     */
197 1
    public function getFixerSet() : FixerSet
198
    {
199 1
        return $this->fixerSet;
200
    }
201
202
    /**
203
     * @return FeedIo
204
     */
205 12
    protected function loadFixerSet() : FeedIo
206
    {
207 12
        $this->fixerSet = new FixerSet();
208 12
        $fixers = $this->getBaseFixers();
209
210 12
        foreach ($fixers as $fixer) {
211 12
            $this->addFixer($fixer);
212
        }
213
214 12
        return $this;
215
    }
216
217
    /**
218
     * @param  FixerAbstract $fixer
219
     * @return FeedIo
220
     */
221 12
    public function addFixer(FixerAbstract $fixer) : FeedIo
222
    {
223 12
        $fixer->setLogger($this->logger);
224 12
        $this->fixerSet->add($fixer);
225
226 12
        return $this;
227
    }
228
229
    /**
230
     * @return array
231
     */
232 12
    public function getBaseFixers() : array
233
    {
234
        return array(
235 12
            new Reader\Fixer\HttpLastModified(),
236 12
            new Reader\Fixer\LastModified(),
237 12
            new Reader\Fixer\PublicId(),
238
        );
239
    }
240
241
    /**
242
     * @param array $formats
243
     * @return FeedIo
244
     */
245 1
    public function addDateFormats(array $formats) : FeedIo
246
    {
247 1
        foreach ($formats as $format) {
248 1
            $this->getDateTimeBuilder()->addDateFormat($format);
249
        }
250
251 1
        return $this;
252
    }
253
254
    /**
255
     * @return \FeedIo\Rule\DateTimeBuilder
256
     */
257 13
    public function getDateTimeBuilder() : DateTimeBuilder
258
    {
259 13
        return $this->dateTimeBuilder;
260
    }
261
262
    /**
263
     * @return \FeedIo\Reader
264
     */
265 4
    public function getReader() : Reader
266
    {
267 4
        return $this->reader;
268
    }
269
270
    /**
271
     * @param \FeedIo\Reader $reader
272
     * @return FeedIo
273
     */
274 13
    public function setReader(Reader $reader) : FeedIo
275
    {
276 13
        $this->reader = $reader;
277
278 13
        return $this;
279
    }
280
281
    /**
282
     * Discover feeds from the webpage's headers
283
     * @param  string $url
284
     * @return array
285
     */
286 1
    public function discover(string $url) : array
287
    {
288 1
        $explorer = new Explorer($this->client, $this->logger);
289
290 1
        return $explorer->discover($url);
291
    }
292
293
    /**
294
     * @param iterable $requests
295
     * @param CallbackInterface $callback
296
     * @param string $feedClass
297
     */
298
    public function readAsync(iterable $requests, CallbackInterface $callback, string $feedClass = '\FeedIo\Feed') : void
299
    {
300
        $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...
301
302
        $reader->process($requests);
303
    }
304
305
    /**
306
     * @param  string                $url
307
     * @param  FeedInterface         $feed
308
     * @param  \DateTime             $modifiedSince
309
     * @return \FeedIo\Reader\Result
310
     */
311 2
    public function read(string $url, FeedInterface $feed = null, \DateTime $modifiedSince = null) : Result
312
    {
313 2
        if (is_null($feed)) {
314 1
            $feed = new Feed();
315
        }
316
317 2
        if ($modifiedSince instanceof \DateTime) {
318 1
            $this->addFilter(new ModifiedSince($modifiedSince));
319
        }
320
321 2
        $this->logAction($feed, "read access : $url into a feed instance");
322 2
        $result = $this->reader->read($url, $feed, $modifiedSince);
323
324 2
        $this->fixerSet->correct($result);
325
326 2
        return $result;
327
    }
328
329
    /**
330
     * @param  string                $url
331
     * @param  \DateTime             $modifiedSince
332
     * @return \FeedIo\Reader\Result
333
     */
334 1
    public function readSince(string $url, \DateTime $modifiedSince) : Result
335
    {
336 1
        return $this->read($url, new Feed(), $modifiedSince);
337
    }
338
339
    /**
340
     * @return FeedIo
341
     */
342 1
    public function resetFilters() : FeedIo
343
    {
344 1
        $this->getReader()->resetFilters();
345
346 1
        return $this;
347
    }
348
349
    /**
350
     * Get a PSR-7 compliant response for the given feed
351
     *
352
     * @param \FeedIo\FeedInterface $feed
353
     * @param string $standard
354
     * @param int $maxAge
355
     * @param bool $public
356
     * @return ResponseInterface
357
     */
358 1
    public function getPsrResponse(FeedInterface $feed, string $standard, int $maxAge = 600, bool $public = true) : ResponseInterface
359
    {
360 1
        $this->logAction($feed, "creating a PSR 7 Response in $standard format");
361
362 1
        $formatter = $this->getStandard($standard)->getFormatter();
363 1
        $responseBuilder = new ResponseBuilder($maxAge, $public);
364
365 1
        return $responseBuilder->createResponse($standard, $formatter, $feed);
366
    }
367
368
    /**
369
     * @param  FeedInterface $feed
370
     * @param  string        $standard Standard's name
371
     * @return string
372
     */
373 1
    public function format(FeedInterface $feed, string $standard) : string
374
    {
375 1
        $this->logAction($feed, "formatting a feed in $standard format");
376
377 1
        $formatter = $this->getStandard($standard)->getFormatter();
378
379 1
        return $formatter->toString($feed);
380
    }
381
382
    /**
383
     * @param  \FeedIo\FeedInterface $feed
384
     * @return string
385
     */
386 1
    public function toRss(FeedInterface $feed) : string
387
    {
388 1
        return $this->format($feed, 'rss');
389
    }
390
391
    /**
392
     * @param  \FeedIo\FeedInterface $feed
393
     * @return string
394
     */
395 1
    public function toAtom(FeedInterface $feed) : string
396
    {
397 1
        return $this->format($feed, 'atom');
398
    }
399
400
    /**
401
     * @param  \FeedIo\FeedInterface $feed
402
     * @return string
403
     */
404 1
    public function toJson(FeedInterface $feed) : string
405
    {
406 1
        return $this->format($feed, 'json');
407
    }
408
409
410
    /**
411
     * @param  string                   $name
412
     * @return \FeedIo\StandardAbstract
413
     * @throws \OutOfBoundsException
414
     */
415 3
    public function getStandard(string $name) : StandardAbstract
416
    {
417 3
        $name = strtolower($name);
418 3
        if (array_key_exists($name, $this->standards)) {
419 2
            return $this->standards[$name];
420
        }
421
422 1
        throw new \OutOfBoundsException("no standard found for $name");
423
    }
424
425
    /**
426
     * @param  \FeedIo\FeedInterface $feed
427
     * @param  string                $message
428
     * @return FeedIo
429
     */
430 3
    protected function logAction(FeedInterface $feed, string $message) : FeedIo
431
    {
432 3
        $class = get_class($feed);
433 3
        $this->logger->debug("$message (feed class : $class)");
434
435 3
        return $this;
436
    }
437
}
438