Passed
Pull Request — main (#14)
by Stefano
01:27
created

ImportSitemapCommand   A

Complexity

Total Complexity 12

Size/Duplication

Total Lines 134
Duplicated Lines 0 %

Importance

Changes 3
Bugs 1 Features 0
Metric Value
eloc 69
c 3
b 1
f 0
dl 0
loc 134
rs 10
wmc 12

4 Methods

Rating   Name   Duplication   Size   Complexity  
A buildOptionParser() 0 16 1
A initialize() 0 3 1
A linkOptions() 0 14 2
B execute() 0 61 8
1
<?php
2
declare(strict_types=1);
3
4
/**
5
 * BEdita Brevia plugin
6
 *
7
 * Copyright 2024 Atlas Srl
8
 */
9
namespace Brevia\BEdita\Command;
10
11
use BEdita\Core\Utility\LoggedUser;
12
use Brevia\BEdita\Client\BreviaClient;
13
use Brevia\BEdita\Utility\ReadCSVTrait;
14
use Cake\Command\Command;
15
use Cake\Console\Arguments;
16
use Cake\Console\ConsoleIo;
17
use Cake\Console\ConsoleOptionParser;
18
use Cake\Log\LogTrait;
19
use Cake\Utility\Hash;
20
21
/**
22
 * Import links from sitemap and create links
23
 *
24
 * @property \BEdita\Core\Model\Table\ObjectsTable $Collections
25
 */
26
class ImportSitemapCommand extends Command
27
{
28
    use LogTrait;
29
    use ReadCSVTrait;
30
31
    /**
32
     * Brevia API client
33
     *
34
     * @var \Brevia\BEdita\Client\BreviaClient
35
     */
36
    protected BreviaClient $client;
37
38
    /**
39
     * @inheritDoc
40
     */
41
    public $defaultTable = 'Collections';
42
43
    /**
44
     * @inheritDoc
45
     */
46
    protected function buildOptionParser(ConsoleOptionParser $parser): ConsoleOptionParser
47
    {
48
        return $parser->addOption('sitemap', [
49
                'help' => 'File path or URL of sitemap to import',
50
                'short' => 's',
51
                'required' => true,
52
            ])
53
            ->addOption('prefix', [
54
                'help' => 'Optional path prefix of URLs to import',
55
                'short' => 'p',
56
                'required' => false,
57
            ])
58
            ->addOption('collection', [
59
                'help' => 'Collection used to index (use the unique collection name)',
60
                'short' => 'c',
61
                'required' => true,
62
            ]);
63
    }
64
65
    /**
66
     * @inheritDoc
67
     */
68
    public function initialize(): void
69
    {
70
        $this->client = new BreviaClient();
71
    }
72
73
    /**
74
     * @inheritDoc
75
     */
76
    public function execute(Arguments $args, ConsoleIo $io)
77
    {
78
        $sitemap = $args->getOption('sitemap');
79
        $content = file_get_contents($sitemap);
80
        if (!$content) {
81
            $io->abort(sprintf('Sitemap content not found: %s', $sitemap));
82
        }
83
84
        $name = $args->getOption('collection');
85
        $response = $this->client->get('/collections', compact('name'));
86
        $collectionId = Hash::get($response->getJson(), '0.cmetadata.id');
87
        if (empty($collectionId)) {
88
            $io->abort(sprintf('Collection not found: %s', $name));
89
        }
90
        $collection = $this->Collections->get($collectionId, ['contain' => ['HasDocuments']]);
91
        $currentUrls = array_filter(array_map(function ($link) {
92
                $link = $link->getTable()->get($link->id);
93
94
                return $link->get('url');
95
        },
96
            $collection->has_documents));
97
        $prefix = $args->getOption('prefix');
98
99
        $xml = simplexml_load_string($content);
100
        $json = json_encode($xml);
101
        $data = (array)json_decode($json, true);
102
        $urls = Hash::extract($data, 'url.{n}.loc');
103
        if (empty($urls)) {
104
            $io->abort('No URLs found in sitemap');
105
        }
106
        $entities = [];
107
        LoggedUser::setUserAdmin();
108
        $this->Links = $this->fetchTable('Links');
109
        foreach ($urls as $url) {
110
            if (in_array($url, $currentUrls) || ($prefix && strpos($url, $prefix) !== 0)) {
111
                continue;
112
            }
113
            $io->info('Adding link: ' . $url);
114
            $data = [
115
                'status' => 'on',
116
                'title' => $url,
117
                'url' => $url,
118
                'extra' => [
119
                    'brevia' => [
120
                        'metadata' => [
121
                            'type' => 'links',
122
                            'url' => $url,
123
                        ],
124
                        'options' => $this->linkOptions($url, (array)$collection->get('link_load_options')),
125
                    ],
126
                ],
127
            ];
128
            $entity = $this->Links->newEntity($data);
129
            $entities[] = $this->Links->saveOrFail($entity);
130
        }
131
        /** @phpstan-ignore-next-line */
132
        $this->Collections->addRelated($collection, 'has_documents', $entities);
133
134
        $io->out('Done. Link added successfully: ' . count($entities));
135
136
        return null;
137
    }
138
139
    /**
140
     * Get link options
141
     *
142
     * @param string $url URL
143
     * @param array $linkLoadOptions Link load options
144
     * @return array
145
     */
146
    protected function linkOptions(string $url, array $linkLoadOptions): array
147
    {
148
        $options = array_filter($linkLoadOptions, function ($o) use ($url) {
149
            return $o['url'] === $url;
150
        });
151
        $selector = Hash::get($options, '0.selector');
152
        if (!empty($selector)) {
153
            return compact('selector');
154
        }
155
        $options = array_filter($linkLoadOptions, function ($o) use ($url) {
156
            return strpos($url, $o['url']) === 0;
157
        });
158
159
        return ['selector' => Hash::get($options, '0.selector')];
160
    }
161
}
162