Completed
Push — master ( 6b3932...7d97b7 )
by Paweł
02:24
created

XMLWriter::setCurrentSitemap()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 1
dl 0
loc 4
ccs 3
cts 3
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
declare(strict_types=1);
3
4
namespace Wszetko\Sitemap\Drivers\XML;
5
6
use Exception;
7
use Wszetko\Sitemap\Interfaces\XML;
8
use Wszetko\Sitemap\Sitemap;
9
use Wszetko\Sitemap\Traits\Domain;
10
use Wszetko\Sitemap\Traits\IsAssoc;
11
12
/**
13
 * Class XMLWriter
14
 *
15
 * @package Wszetko\Sitemap\Drivers\XML
16
 */
17
class XMLWriter implements XML
18
{
19
    use IsAssoc;
20
    use Domain;
21
22
    /**
23
     * @var \XMLWriter
24
     */
25
    private $XMLWriter;
26
27
    /**
28
     * @var string
29
     */
30
    private $currentSitemap;
31
32
    /**
33
     * @var string|null
34
     */
35
    private $workDir;
36
37
    /**
38
     * XMLWriter constructor.
39
     *
40
     * @param array $config
41
     *
42
     * @throws \InvalidArgumentException
43
     */
44 8
    public function __construct(array $config)
45
    {
46 8
        if (!isset($config['domain'])) {
47 1
            throw new \InvalidArgumentException('Domain is not set.');
48
        }
49
50 8
        $this->XMLWriter = new \XMLWriter();
51 8
        $this->setDomain($config['domain']);
52 8
    }
53
54
    /**
55
     * @return string
56
     */
57 1
    public function getCurrentSitemap(): string
58
    {
59 1
        return $this->currentSitemap;
60
    }
61
62
    /**
63
     * @param string $currentSitemap
64
     */
65 4
    public function setCurrentSitemap(string $currentSitemap): void
66
    {
67 4
        $this->currentSitemap = $currentSitemap;
68 4
    }
69
70
    /**
71
     * @param string $sitemap
72
     * @param array  $extensions
73
     */
74 2
    public function openSitemap(string $sitemap, array $extensions = []): void
75
    {
76 2
        $this->setCurrentSitemap($sitemap);
77 2
        $this->getXMLWriter()->openMemory();
78 2
        $this->getXMLWriter()->startDocument('1.0', 'UTF-8');
79 2
        $this->getXMLWriter()->setIndent(true);
80 2
        $this->getXMLWriter()->startElement('urlset');
81 2
        $this->getXMLWriter()->writeAttribute('xmlns', Sitemap::SCHEMA);
82
83 2
        foreach ($extensions as $extension => $urlset) {
84 1
            $this->getXMLWriter()->writeAttribute('xmlns:' . $extension, $urlset);
85
        }
86
87 2
        $this->flushData();
88 2
    }
89
90
    /**
91
     * @throws \Exception
92
     */
93 2
    public function closeSitemap(): void
94
    {
95 2
        $this->getXMLWriter()->endElement();
96 2
        $this->getXMLWriter()->endDocument();
97 2
        $this->flushData();
98 2
        $this->endFile();
99 2
    }
100
101
    /**
102
     * @return \XMLWriter
103
     */
104 3
    private function getXMLWriter(): \XMLWriter
105
    {
106 3
        return $this->XMLWriter;
107
    }
108
109
    /**
110
     * Save from buffer to file
111
     *
112
     * @return void
113
     */
114 3
    private function flushData(): void
115
    {
116 3
        file_put_contents($this->getSitemapFileFullPath(), $this->getXMLWriter()->flush(true), FILE_APPEND);
117 3
    }
118
119
    /**
120
     * @return string
121
     */
122 3
    private function getSitemapFileFullPath(): string
123
    {
124 3
        return $this->getWorkDir() . DIRECTORY_SEPARATOR . $this->currentSitemap;
125
    }
126
127
    /**
128
     * @return string
129
     */
130 4
    public function getWorkDir(): string
131
    {
132 4
        return $this->workDir;
133
    }
134
135
    /**
136
     * @param string $dir
137
     */
138 4
    public function setWorkDir(string $dir): void
139
    {
140 4
        $this->workDir = $dir;
141 4
    }
142
143
    /**
144
     * Remove whitespace chars from end of file (Google don't like them)
145
     *
146
     * @return void
147
     * @throws Exception
148
     */
149 3
    private function endFile(): void
150
    {
151 3
        $sitemapFile = fopen($this->getSitemapFileFullPath(), 'r+');
152
153 3
        fseek($sitemapFile, -1, SEEK_END);
154 3
        $truncate = 0;
155 3
        $length = $this->getSitemapSize();
156 3
        $end = false;
157
158
        do {
159 3
            $s = fread($sitemapFile, 1);
160 3
            if (ctype_space($s)) {
161 3
                $truncate++;
162 3
                fseek($sitemapFile, -2, SEEK_CUR);
163
            } else {
164 3
                $end = true;
165
            }
166 3
        } while (!$end);
167
168 3
        ftruncate($sitemapFile, $length - $truncate);
169 3
        fclose($sitemapFile);
170 3
    }
171
172
    /**
173
     * @return int
174
     */
175 3
    public function getSitemapSize(): int
176
    {
177 3
        clearstatcache(true, $this->getSitemapFileFullPath());
178
179 3
        return file_exists($this->getSitemapFileFullPath()) ? filesize($this->getSitemapFileFullPath()) : 0;
180
    }
181
182
    /**
183
     * @param array $element
184
     */
185 1
    public function addUrl(array $element): void
186
    {
187 1
        foreach ($element as $el => $val) {
188 1
            $this->addElement($el, $val);
189
        }
190
191 1
        $this->flushData();
192 1
    }
193
194
    /**
195
     * @param string      $element
196
     * @param             $value
197
     * @param string|null $namespace
198
     */
199 1
    private function addElement(string $element, $value, ?string $namespace = null): void
200
    {
201 1
        if (!is_array($value)) {
202 1
            $this->getXMLWriter()->writeElement(($namespace ? $namespace . ':' : '') . $element, (string) $value);
203
        } else {
204 1
            if (isset($value['_namespace'])) {
205 1
                $this->addElement($value['_element'], $value[$value['_element']], $value['_namespace']);
206
            } else {
207 1
                $this->addElementArray($element, $value, $namespace);
208
            }
209
        }
210 1
    }
211
212
    /**
213
     * @param string      $element
214
     * @param             $value
215
     * @param string|null $namespace
216
     */
217 1
    private function addElementArray(string $element, $value, ?string $namespace = null): void
218
    {
219 1
        if (!$this->isAssoc($value)) {
220 1
            if (!empty($value)) {
221 1
                $this->addElementArrayNonAssoc($element, $value, $namespace);
222
            } else {
223 1
                $this->getXMLWriter()->writeElement(($namespace ? $namespace . ':' : '') . $element);
224
            }
225
        } else {
226 1
            $this->addElementArrayAssoc($element, $value, $namespace);
227
        }
228 1
    }
229
230 1
    private function addElementArrayAssoc(string $element, $value, ?string $namespace = null): void
231
    {
232 1
        $this->getXMLWriter()->startElement(($namespace ? $namespace . ':' : '') . $element);
233 1
        if (isset($value['_attributes'])) {
234 1
            foreach ($value['_attributes'] as $attribute => $val) {
235 1
                $this->getXMLWriter()->writeAttribute($attribute, $val);
236
            }
237
238 1
            if (isset($value['_value'])) {
239 1
                if (is_array($value['_value'])) {
240
                    foreach ($value['_value'] as $el => $val) {
241
                        $this->addElement($el, $val);
242
                    }
243
                } else {
244 1
                    $this->getXMLWriter()->text((string) $value['_value']);
245
                }
246
            }
247
        } else {
248 1
            foreach ($value as $el => $val) {
249 1
                if (is_array($val)) {
250 1
                    $this->addElement($el, $val, $namespace);
251
                } else {
252 1
                    $this->getXMLWriter()->writeElement(($namespace ? $namespace . ':' : '') . $el, (string) $val);
253
                }
254
            }
255
        }
256 1
        $this->getXMLWriter()->endElement();
257 1
    }
258
259
    /**
260
     * @param string      $element
261
     * @param             $value
262
     * @param string|null $namespace
263
     */
264 1
    private function addElementArrayNonAssoc(string $element, $value, ?string $namespace = null): void
265
    {
266 1
        foreach ($value as $val) {
267 1
            $this->addElement($element, $val, $namespace);
268
        }
269 1
    }
270
271
    /**
272
     * @param string $sitemap
273
     */
274 1
    public function openSitemapIndex(string $sitemap): void
275
    {
276 1
        $this->setCurrentSitemap($sitemap);
277 1
        $this->getXMLWriter()->openMemory();
278 1
        $this->getXMLWriter()->startDocument('1.0', 'UTF-8');
279 1
        $this->getXMLWriter()->setIndent(true);
280 1
        $this->getXMLWriter()->startElement('sitemapindex');
281 1
        $this->getXMLWriter()->writeAttribute('xmlns', Sitemap::SCHEMA);
282 1
        $this->flushData();
283 1
    }
284
285
    /**
286
     * @throws \Exception
287
     */
288 1
    public function closeSitemapIndex(): void
289
    {
290 1
        $this->getXMLWriter()->endElement();
291 1
        $this->getXMLWriter()->endDocument();
292 1
        $this->flushData();
293 1
        $this->endFile();
294 1
    }
295
296
    /**
297
     * @param string $sitemap
298
     * @param string|null $lastmod
299
     */
300 1
    public function addSitemap(string $sitemap, string $lastmod = null): void
301
    {
302 1
        $this->getXMLWriter()->startElement('sitemap');
303 1
        $this->getXMLWriter()->writeElement('loc', $sitemap);
304 1
        if (isset($lastmod)) {
305 1
            $this->getXMLWriter()->writeElement('lastmod', $lastmod);
306
        }
307 1
        $this->getXMLWriter()->endElement();
308 1
        $this->flushData();
309 1
    }
310
}
311