Test Failed
Push — feature-laravel-5.4 ( 475d96...446986 )
by Kirill
07:30
created

LaravelNewsDataProvider::parseContent()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 14
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 8
nc 2
nop 1
dl 0
loc 14
rs 9.4285
c 0
b 0
f 0
1
<?php
2
/**
3
 * This file is part of laravel.su package.
4
 * For the full copyright and license information, please view the LICENSE
5
 * file that was distributed with this source code.
6
 */
7
declare(strict_types=1);
8
9
namespace App\Services\DataProviders;
10
11
use Carbon\Carbon;
12
use GuzzleHttp\Client;
13
use Illuminate\Support\Collection;
14
use Symfony\Component\DomCrawler\Crawler;
15
16
/**
17
 * Class LaravelNewsDataProvider.
18
 */
19
class LaravelNewsDataProvider implements DataProviderInterface
20
{
21
    private const CONTENT_NAMESPACE = 'http://purl.org/rss/1.0/modules/content/';
22
    private const FEED_URL = 'https://feed.laravel-news.com';
23
24
    /**
25
     * @var Client
26
     */
27
    private $client;
28
29
    /**
30
     * LaravelNewsDataProvider constructor.
31
     * @param Client $client
32
     */
33
    public function __construct(Client $client)
34
    {
35
        $this->client = $client;
36
    }
37
38
    /**
39
     * @param \DateTime $latest
40
     * @return Collection|ExternalArticle[]
41
     * @throws \RuntimeException
42
     */
43
    public function getLatest(\DateTime $latest): Collection
44
    {
45
        $result = new Collection();
46
47
        foreach ($this->getArticles() as $article) {
48
            if ($article->getCreatedAt() < $latest) {
49
                break;
50
            }
51
52
            $result->push($article);
53
        }
54
55
        return $result;
56
    }
57
58
59
    /**
60
     * @return \Generator|ExternalArticle[]
61
     * @throws \RuntimeException
62
     */
63
    private function getArticles(): \Generator
64
    {
65
        $response = $this->client->get(self::FEED_URL);
66
67
        $body = $response->getBody();
68
69
        yield from $this->parseBody((string)$body);
70
    }
71
72
    /**
73
     * @param string $body
74
     * @return \Generator
75
     * @throws \RuntimeException
76
     */
77
    private function parseBody(string $body): \Generator
78
    {
79
        $parser = new Crawler($body);
80
81
        /** @var \DOMElement $node */
82
        foreach ($parser->filter('rss > channel > item') as $node) {
83
            $parsed = $this->parseContent(
84
                $node->getElementsByTagNameNS(self::CONTENT_NAMESPACE, '*')
85
                    ->item(0)
86
                    ->textContent
87
            );
88
89
            ['images' => $images, 'body' => $content] = $parsed;
0 ignored issues
show
Bug introduced by
The variable $images does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
Bug introduced by
The variable $content does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
90
91
            $article = new ExternalArticle(
92
                (string)$this->getContentOf($node, 'title'),
93
                trim($content),
94
                (string)$this->getContentOf($node, 'link')
95
            );
96
97
            foreach ($images as $image) {
98
                $article->addImageUrl($image);
99
            }
100
101
            $article->setCreatedAt(Carbon::parse(
102
                (string)$this->getContentOf($node, 'pubDate')
103
            ));
104
105
            yield $article;
106
        }
107
    }
108
109
    /**
110
     * @param string $body
111
     * @return array
112
     */
113
    private function parseContent(string $body): array
114
    {
115
        $images = [];
116
117
        $pattern = '/<img.+?src\s*=\s*"(.*?)".+?>/isu';
118
        preg_match_all($pattern, $body, $matches);
119
120
        for ($i = 0, $len = count($matches[0]); $i < $len; $i++) {
121
            $images[] = $matches[1][$i] ?? null;
122
            $body = str_replace($matches[0][$i] ?? '', '', $body);
123
        }
124
125
        return ['images' => $images, 'body' => $body];
126
    }
127
128
    /**
129
     * @param \DOMElement $root
130
     * @param string      $tagName
131
     * @return null|string
132
     */
133
    private function getContentOf(\DOMElement $root, string $tagName): ?string
134
    {
135
        $node = $root->getElementsByTagName($tagName);
136
137
        if ($node->length >= 1) {
138
            return $node->item(0)->textContent;
139
        }
140
141
        return null;
142
    }
143
}