RSS::key()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 3
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
eloc 1
nc 1
nop 0
crap 1
1
<?php
2
declare(strict_types = 1);
3
4
namespace PersonalGalaxy\RSS\Parser;
5
6
use PersonalGalaxy\RSS\{
7
    Entity\Article,
8
    Entity\Article\Author,
9
    Entity\Article\Description,
10
    Entity\Article\Title,
11
    UrlFactory,
12
};
13
use Innmind\Url\Url;
14
use Innmind\Crawler\{
15
    Parser,
16
    HttpResource\Attribute\Attribute,
17
};
18
use Innmind\Http\Message\{
19
    Request,
20
    Response,
21
};
22
use Innmind\Xml\{
23
    ReaderInterface,
24
    NodeInterface,
25
    ElementInterface,
26
};
27
use Innmind\TimeContinuum\TimeContinuumInterface;
28
use Innmind\Immutable\{
29
    MapInterface,
30
    SetInterface,
31
    Set,
32
    StreamInterface,
33
    Stream,
34
};
35
36
final class RSS implements Parser
37
{
38
    private $reader;
39
    private $clock;
40
    private $make;
41
42 4
    public function __construct(
43
        ReaderInterface $reader,
44
        TimeContinuumInterface $clock,
45
        UrlFactory $make
46
    ) {
47 4
        $this->reader = $reader;
48 4
        $this->clock = $clock;
49 4
        $this->make = $make;
50 4
    }
51
52 3
    public function parse(
53
        Request $request,
54
        Response $response,
55
        MapInterface $attributes
56
    ): MapInterface {
57
        if (
58 3
            !$response->headers()->has('content-type') ||
59 3
            (string) $response->headers()->get('content-type')->values()->current() !== 'application/rss'
60
        ) {
61 2
            return $attributes;
62
        }
63
64 1
        $xml = $this->reader->read($response->body());
65
        $articles = $xml
66 1
            ->children()
67 1
            ->values()
68 1
            ->first() // rss node
69 1
            ->children()
70 1
            ->values()
71 1
            ->filter(static function(NodeInterface $node): bool {
72 1
                return $node instanceof ElementInterface && $node->name() === 'channel';
73 1
            })
74 1
            ->reduce(
75 1
                Stream::of(NodeInterface::class),
76 1
                static function(StreamInterface $channels, ElementInterface $channel): StreamInterface {
77 1
                    return $channels->append($channel->children()->values());
78 1
                }
79
            )
80 1
            ->filter(static function(NodeInterface $node): bool {
81 1
                return $node instanceof ElementInterface && $node->name() === 'item';
82 1
            })
83 1
            ->reduce(
84 1
                Set::of(Article::class),
85 1
                function(SetInterface $articles, ElementInterface $item): SetInterface {
86
                    $elements = $item
87 1
                        ->children()
88 1
                        ->values()
89 1
                        ->filter(static function(NodeInterface $node): bool {
90 1
                            return $node instanceof ElementInterface;
91 1
                        });
92
                    $link = $elements
93 1
                        ->filter(static function(ElementInterface $element): bool {
94 1
                            return $element->name() === 'link';
95 1
                        })
96 1
                        ->first()
97 1
                        ->content();
98
                    $author = $elements
99 1
                        ->filter(static function(ElementInterface $element): bool {
100 1
                            return $element->name() === 'author' || $element->name() === 'dc:creator';
101 1
                        })
102 1
                        ->first()
103 1
                        ->content();
104
                    $description = $elements
105 1
                        ->filter(static function(ElementInterface $element): bool {
106 1
                            return $element->name() === 'description';
107 1
                        })
108 1
                        ->first()
109 1
                        ->content();
110
                    $title = $elements
111 1
                        ->filter(static function(ElementInterface $element): bool {
112 1
                            return $element->name() === 'title';
113 1
                        })
114 1
                        ->first()
115 1
                        ->content();
116
                    $publicationDate = $elements
117 1
                        ->filter(static function(ElementInterface $element): bool {
118 1
                            return $element->name() === 'pubDate';
119 1
                        })
120 1
                        ->first()
121 1
                        ->content();
122
123 1
                    return $articles->add(Article::fetch(
124 1
                        ($this->make)(trim($link)),
125 1
                        new Author(trim($author)),
126 1
                        new Description(trim($description)),
127 1
                        new Title(trim($title)),
128 1
                        $this->clock->at(trim($publicationDate))
129
                    ));
130 1
                }
131
            );
132
133 1
        return $attributes->put(
134 1
            self::key(),
135 1
            new Attribute(
136 1
                self::key(),
137 1
                $articles
138
            )
139
        );
140
    }
141
142 2
    public static function key(): string
143
    {
144 2
        return 'articles';
145
    }
146
}
147