Test Failed
Push — ft/sitemap ( 8c914b...fc5f2e )
by Ben
06:39
created

SitemapXml::prepareOnlineUrls()   A

Complexity

Conditions 2
Paths 1

Size

Total Lines 15
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 8
c 1
b 0
f 0
dl 0
loc 15
rs 10
cc 2
nc 1
nop 2
1
<?php
2
declare(strict_types=1);
3
4
namespace Thinktomorrow\Chief\System\Sitemap;
5
6
use GuzzleHttp\Pool;
7
use GuzzleHttp\Client;
8
use Spatie\Sitemap\Sitemap;
9
use GuzzleHttp\Psr7\Request;
10
use Spatie\Sitemap\Tags\Url;
11
use GuzzleHttp\Psr7\Response;
12
use Illuminate\Support\Collection;
13
use Thinktomorrow\Chief\Urls\UrlRecord;
14
use GuzzleHttp\Exception\RequestException;
15
use Thinktomorrow\Chief\Urls\ProvidesUrl\ProvidesUrl;
16
17
class SitemapXml
18
{
19
    /** @var Sitemap */
20
    private $sitemap;
21
22
    /** @var Client */
23
    private $httpClient;
24
25
    /** @var Collection */
26
    private $urls;
27
28
    /** @var array */
29
    private $alternateUrls;
30
31
    public function __construct(Client $httpClient)
32
    {
33
        $this->httpClient = $httpClient;
34
35
        $this->reset();
36
    }
37
38
    private function reset(): void
39
    {
40
        $this->sitemap = new Sitemap();
41
        $this->urls = collect();
0 ignored issues
show
Documentation Bug introduced by
It seems like collect() of type Tightenco\Collect\Support\Collection is incompatible with the declared type Illuminate\Support\Collection of property $urls.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
42
        $this->alternateUrls = [];
43
    }
44
45
    public function generate(string $locale, array $alternateLocales = []): string
46
    {
47
        $this->reset();
48
49
        $this->prepareOnlineUrls($locale, $alternateLocales);
50
51
        $this->rejectNonVisitableUrls($locale);
0 ignored issues
show
Unused Code introduced by
The call to Thinktomorrow\Chief\Syst...ejectNonVisitableUrls() has too many arguments starting with $locale. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

51
        $this->/** @scrutinizer ignore-call */ 
52
               rejectNonVisitableUrls($locale);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
52
53
        return $this->generateXml();
54
    }
55
56
    private function generateXml(): string
57
    {
58
        foreach($this->urls as $url) {
59
            $urlTag = Url::create($url);
60
61
            if(isset($this->alternateUrls[$url])) {
62
                foreach($this->alternateUrls[$url] as $locale => $alternateUrl) {
63
                    $urlTag->addAlternate($alternateUrl, $locale);
64
                }
65
            }
66
67
            $this->sitemap->add($urlTag);
68
        }
69
70
        return $this->sitemap->render();
71
    }
72
73
    private function prepareOnlineUrls(string $locale, array $alternateLocales = []): void
74
    {
75
        $models = UrlRecord::allOnlineModels($locale);
76
77
        $this->urls = $models->map(function(ProvidesUrl $model) use($locale, $alternateLocales){
78
            $url = $model->url($locale);
79
            $alternateUrls = [];
80
81
            foreach($alternateLocales as $alternateLocale) {
82
                $alternateUrls[$alternateLocale] = $model->url($alternateLocale);
83
            }
84
85
            $this->alternateUrls[$url] = $alternateUrls;
86
87
            return $url;
88
        });
89
    }
90
91
    private function rejectNonVisitableUrls()
92
    {
93
        $pool = new Pool($this->httpClient, $this->crawlableUrlGenerator(), [
94
            'concurrency' => 5,
95
            'fulfilled' => function (Response $response, $index) {
96
                if($response->getStatusCode() !== \Symfony\Component\HttpFoundation\Response::HTTP_OK){
97
                    unset($this->urls[$index]);
98
                }
99
            },
100
            'rejected' => function (RequestException $reason, $index) {
101
                unset($this->urls[$index]);
102
            },
103
        ]);
104
105
        // Initiate the transfers and create a promise
106
        $promise = $pool->promise();
107
108
        // Force the pool of requests to complete.
109
        $promise->wait();
110
    }
111
112
    private function crawlableUrlGenerator(): \Generator
113
    {
114
        foreach($this->urls as $index => $url){
115
            yield $index => new Request('GET', $url);
116
        }
117
    }
118
}
119