Completed
Push — master ( b86906...5e7e78 )
by Alex
03:01
created

src/FeedIo/FeedIo.php (1 issue)

Severity

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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