FeedIo::format()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 8
ccs 3
cts 3
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 2
crap 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\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 12
    public function __construct(ClientInterface $client, LoggerInterface $logger, DateTimeBuilderInterface $dateTimeBuilder = null)
114
    {
115 12
        $this->client = $client;
116 12
        $this->logger = $logger;
117 12
        $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 12
        $this->setReader(new Reader($client, $logger));
119 12
        $this->loadCommonStandards();
120 12
        $this->loadFixerSet();
121 12
    }
122
123
    /**
124
     * Loads main standards (RSS, RDF, Atom) in current object's attributes
125
     *
126
     * @return FeedIo
127
     */
128 12
    protected function loadCommonStandards() : FeedIo
129
    {
130 12
        $standards = $this->getCommonStandards();
131 12
        foreach ($standards as $name => $standard) {
132 12
            $this->addStandard($name, $standard);
133
        }
134
135 12
        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 12
    public function getCommonStandards() : array
157
    {
158 12
        $loader = new Loader();
159
160 12
        return $loader->getCommonStandards($this->getDateTimeBuilder());
161
    }
162
163
    /**
164
     * @param  string                   $name
165
     * @param  \FeedIo\StandardAbstract $standard
166
     * @return FeedIo
167
     */
168 12
    public function addStandard(string $name, StandardAbstract $standard) : FeedIo
169
    {
170 12
        $name = strtolower($name);
171 12
        $this->standards[$name] = $standard;
172 12
        $parser = $this->newParser($standard->getSyntaxFormat(), $standard);
173 12
        $this->reader->addParser($parser);
174
175 12
        return $this;
176
    }
177
178
    /**
179
     * @param string $format
180
     * @param StandardAbstract $standard
181
     * @return ParserAbstract
182
     */
183 11
    public function newParser(string $format, StandardAbstract $standard) : ParserAbstract
184
    {
185 11
        $reflection = new \ReflectionClass("FeedIo\\Parser\\{$format}Parser");
186
187 11
        if (! $reflection->isSubclassOf('FeedIo\ParserAbstract')) {
188
            throw new \InvalidArgumentException();
189
        }
190
191 11
        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 11
    protected function loadFixerSet() : FeedIo
206
    {
207 11
        $this->fixerSet = new FixerSet();
208 11
        $fixers = $this->getBaseFixers();
209
210 11
        foreach ($fixers as $fixer) {
211 11
            $this->addFixer($fixer);
212
        }
213
214 11
        return $this;
215
    }
216
217
    /**
218
     * @param  FixerAbstract $fixer
219
     * @return FeedIo
220
     */
221 11
    public function addFixer(FixerAbstract $fixer) : FeedIo
222
    {
223 11
        $fixer->setLogger($this->logger);
224 11
        $this->fixerSet->add($fixer);
225
226 11
        return $this;
227
    }
228
229
    /**
230
     * @return array
231
     */
232 11
    public function getBaseFixers() : array
233
    {
234
        return array(
235 11
            new Reader\Fixer\HttpLastModified(),
236 11
            new Reader\Fixer\PublicId(),
237 11
        );
238 11
    }
239
240
    /**
241
     * @param array $formats
242
     * @return FeedIo
243
     */
244
    public function addDateFormats(array $formats) : FeedIo
245
    {
246
        foreach ($formats as $format) {
247
            $this->getDateTimeBuilder()->addDateFormat($format);
248
        }
249
250
        return $this;
251
    }
252
253
    /**
254
     * @return \FeedIo\Rule\DateTimeBuilder
255
     */
256
    public function getDateTimeBuilder() : DateTimeBuilder
257
    {
258 12
        return $this->dateTimeBuilder;
259
    }
260 12
261
    /**
262
     * @return \FeedIo\Reader
263
     */
264
    public function getReader() : Reader
265
    {
266 4
        return $this->reader;
267
    }
268 4
269
    /**
270
     * @param \FeedIo\Reader $reader
271
     * @return FeedIo
272
     */
273
    public function setReader(Reader $reader) : FeedIo
274
    {
275 12
        $this->reader = $reader;
276
277 12
        return $this;
278
    }
279 12
280
    /**
281
     * Discover feeds from the webpage's headers
282
     * @param  string $url
283
     * @return array
284
     */
285
    public function discover(string $url) : array
286
    {
287 1
        $explorer = new Explorer($this->client, $this->logger);
288
289 1
        return $explorer->discover($url);
290
    }
291 1
292
    /**
293
     * @param iterable $requests
294
     * @param CallbackInterface $callback
295
     * @param string $feedClass
296
     */
297
    public function readAsync(iterable $requests, CallbackInterface $callback, string $feedClass = '\FeedIo\Feed') : void
298
    {
299
        $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...
300
301
        $reader->process($requests);
302
    }
303
304
    /**
305
     * @param  string                $url
306
     * @param  FeedInterface         $feed
307
     * @param  \DateTime             $modifiedSince
308
     * @return \FeedIo\Reader\Result
309
     */
310
    public function read(string $url, FeedInterface $feed = null, \DateTime $modifiedSince = null) : Result
311
    {
312 2
        if (is_null($feed)) {
313
            $feed = new Feed();
314 2
        }
315 1
316
        if ($modifiedSince instanceof \DateTime) {
317
            $this->addFilter(new ModifiedSince($modifiedSince));
318 2
        }
319 1
320
        $this->logAction($feed, "read access : $url into a feed instance");
321
        $result = $this->reader->read($url, $feed, $modifiedSince);
322 2
323 2
        $this->fixerSet->correct($result);
324
        $this->resetFilters();
325 2
326 2
        return $result;
327
    }
328 2
329
    /**
330
     * @param  string                $url
331
     * @param  \DateTime             $modifiedSince
332
     * @return \FeedIo\Reader\Result
333
     */
334
    public function readSince(string $url, \DateTime $modifiedSince) : Result
335
    {
336 1
        return $this->read($url, new Feed(), $modifiedSince);
337
    }
338 1
339
    /**
340
     * @return FeedIo
341
     */
342
    public function resetFilters() : FeedIo
343
    {
344 2
        $this->getReader()->resetFilters();
345
346 2
        return $this;
347
    }
348 2
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
    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
        $responseBuilder = new ResponseBuilder($maxAge, $public);
364 1
365 1
        return $responseBuilder->createResponse($standard, $formatter, $feed);
366
    }
367 1
368
    /**
369
     * @param  FeedInterface $feed
370
     * @param  string        $standard Standard's name
371
     * @return string
372
     */
373
    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 1
382
    /**
383
     * @param  \FeedIo\FeedInterface $feed
384
     * @return string
385
     */
386
    public function toRss(FeedInterface $feed) : string
387
    {
388 1
        return $this->format($feed, 'rss');
389
    }
390 1
391
    /**
392
     * @param  \FeedIo\FeedInterface $feed
393
     * @return string
394
     */
395
    public function toAtom(FeedInterface $feed) : string
396
    {
397 1
        return $this->format($feed, 'atom');
398
    }
399 1
400
    /**
401
     * @param  \FeedIo\FeedInterface $feed
402
     * @return string
403
     */
404
    public function toJson(FeedInterface $feed) : string
405
    {
406 1
        return $this->format($feed, 'json');
407
    }
408 1
409
410
    /**
411
     * @param  string                   $name
412
     * @return \FeedIo\StandardAbstract
413
     * @throws \OutOfBoundsException
414
     */
415
    public function getStandard(string $name) : StandardAbstract
416
    {
417 3
        $name = strtolower($name);
418
        if (array_key_exists($name, $this->standards)) {
419 3
            return $this->standards[$name];
420 3
        }
421 2
422
        throw new \OutOfBoundsException("no standard found for $name");
423
    }
424 1
425
    /**
426
     * @param  \FeedIo\FeedInterface $feed
427
     * @param  string                $message
428
     * @return FeedIo
429
     */
430
    protected function logAction(FeedInterface $feed, string $message) : FeedIo
431
    {
432 3
        $class = get_class($feed);
433
        $this->logger->debug("$message (feed class : $class)");
434 3
435 3
        return $this;
436
    }
437
}
438