Completed
Push — master ( d75f0c...82ab0a )
by Paweł
03:12
created

OutputXMLWriter   A

Complexity

Total Complexity 35

Size/Duplication

Total Lines 237
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
eloc 86
c 0
b 0
f 0
dl 0
loc 237
ccs 107
cts 107
cp 1
rs 9.6
wmc 35

14 Methods

Rating   Name   Duplication   Size   Complexity  
A addUrl() 0 7 2
A openSitemapIndex() 0 11 1
A __construct() 0 8 2
A openSitemap() 0 16 2
A flushData() 0 3 1
A addElement() 0 14 4
A closeSitemap() 0 8 1
A addSitemap() 0 11 2
A closeSitemapIndex() 0 8 1
A getSitemapSize() 0 5 2
A endFile() 0 18 4
B addElementArrayAssoc() 0 25 9
A addElementArray() 0 6 2
A addElementArrayNonAssoc() 0 4 2
1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 * This file is part of Wszetko Sitemap.
7
 *
8
 * (c) Paweł Kłopotek-Główczewski <[email protected]>
9
 *
10
 * This source file is subject to the MIT license that is bundled
11
 * with this source code in the file LICENSE.
12
 */
13
14
namespace Wszetko\Sitemap\Drivers\Output;
15
16
use Exception;
17
use InvalidArgumentException;
18
use Wszetko\Sitemap\Sitemap;
19
use XMLWriter;
20
21
/**
22
 * Class XMLWriter.
23
 *
24
 * @package Wszetko\Sitemap\Drivers\XML
25
 */
26
class OutputXMLWriter extends AbstractOutput
27
{
28
    /**
29
     * XMLWriter constructor.
30
     *
31
     * @param array $config
32
     *
33
     * @throws \InvalidArgumentException
34
     */
35 18
    public function __construct(array $config)
36
    {
37 18
        if (!isset($config['domain'])) {
38 2
            throw new InvalidArgumentException('Domain is not set.');
39
        }
40
41 18
        $this->XMLWriter = new XMLWriter();
42 18
        $this->setDomain($config['domain']);
43 18
    }
44
45
    /**
46
     * @param string $sitemap
47
     * @param array  $extensions
48
     */
49 4
    public function openSitemap(string $sitemap, array $extensions = []): void
50
    {
51 4
        $this->setCurrentSitemap($sitemap);
52
        /** @var \XMLWriter $xmlWriter */
53 4
        $xmlWriter = $this->getXMLWriter();
54 4
        $xmlWriter->openMemory();
55 4
        $xmlWriter->startDocument('1.0', 'UTF-8');
56 4
        $xmlWriter->setIndent(true);
57 4
        $xmlWriter->startElement('urlset');
58 4
        $xmlWriter->writeAttribute('xmlns', Sitemap::SCHEMA);
59
60 4
        foreach ($extensions as $extension => $urlset) {
61 2
            $this->getXMLWriter()->writeAttribute('xmlns:' . $extension, $urlset);
62
        }
63
64 4
        $this->flushData();
65 4
    }
66
67
    /**
68
     * @throws \Exception
69
     */
70 4
    public function closeSitemap(): void
71
    {
72
        /** @var \XMLWriter $xmlWriter */
73 4
        $xmlWriter = $this->getXMLWriter();
74 4
        $xmlWriter->endElement();
75 4
        $xmlWriter->endDocument();
76 4
        $this->flushData();
77 4
        $this->endFile();
78 4
    }
79
80
    /**
81
     * @return int
82
     */
83 6
    public function getSitemapSize(): int
84
    {
85 6
        clearstatcache(true, $this->getSitemapFileFullPath());
86
87 6
        return file_exists($this->getSitemapFileFullPath()) ? (int) filesize($this->getSitemapFileFullPath()) : 0;
88
    }
89
90
    /**
91
     * @param array $element
92
     */
93 2
    public function addUrl(array $element): void
94
    {
95 2
        foreach ($element as $el => $val) {
96 2
            $this->addElement($el, $val);
97
        }
98
99 2
        $this->flushData();
100 2
    }
101
102
    /**
103
     * @param string $sitemap
104
     */
105 2
    public function openSitemapIndex(string $sitemap): void
106
    {
107 2
        $this->setCurrentSitemap($sitemap);
108
        /** @var \XMLWriter $xmlWriter */
109 2
        $xmlWriter = $this->getXMLWriter();
110 2
        $xmlWriter->openMemory();
111 2
        $xmlWriter->startDocument('1.0', 'UTF-8');
112 2
        $xmlWriter->setIndent(true);
113 2
        $xmlWriter->startElement('sitemapindex');
114 2
        $xmlWriter->writeAttribute('xmlns', Sitemap::SCHEMA);
115 2
        $this->flushData();
116 2
    }
117
118
    /**
119
     * @throws \Exception
120
     */
121 2
    public function closeSitemapIndex(): void
122
    {
123
        /** @var \XMLWriter $xmlWriter */
124 2
        $xmlWriter = $this->getXMLWriter();
125 2
        $xmlWriter->endElement();
126 2
        $xmlWriter->endDocument();
127 2
        $this->flushData();
128 2
        $this->endFile();
129 2
    }
130
131
    /**
132
     * @param string      $sitemap
133
     * @param null|string $lastmod
134
     */
135 2
    public function addSitemap(string $sitemap, string $lastmod = null): void
136
    {
137
        /** @var \XMLWriter $xmlWriter */
138 2
        $xmlWriter = $this->getXMLWriter();
139 2
        $xmlWriter->startElement('sitemap');
140 2
        $xmlWriter->writeElement('loc', $sitemap);
141 2
        if (isset($lastmod)) {
142 2
            $xmlWriter->writeElement('lastmod', $lastmod);
143
        }
144 2
        $xmlWriter->endElement();
145 2
        $this->flushData();
146 2
    }
147
148
    /**
149
     * Save from buffer to file.
150
     *
151
     * @return void
152
     */
153 6
    private function flushData(): void
154
    {
155 6
        file_put_contents($this->getSitemapFileFullPath(), $this->getXMLWriter()->flush(true), FILE_APPEND);
156 6
    }
157
158
    /**
159
     * Remove whitespace chars from end of file (Google don't like them).
160
     *
161
     * @throws Exception
162
     *
163
     * @return void
164
     */
165 6
    private function endFile(): void
166
    {
167 6
        $sitemapFile = fopen($this->getSitemapFileFullPath(), 'r+');
168
169 6
        if (false !== $sitemapFile) {
170 6
            fseek($sitemapFile, -1, SEEK_END);
171 6
            $truncate = 0;
172 6
            $length = $this->getSitemapSize();
173 6
            $char = fread($sitemapFile, 1);
174
175 6
            while (is_string($char) && ctype_space($char)) {
176 6
                ++$truncate;
177 6
                fseek($sitemapFile, -2, SEEK_CUR);
178 6
                $char = fread($sitemapFile, 1);
179
            }
180
181 6
            ftruncate($sitemapFile, $length - $truncate);
182 6
            fclose($sitemapFile);
183
        }
184 6
    }
185
186
    /**
187
     * @param string      $element
188
     * @param mixed       $value
189
     * @param null|string $namespace
190
     */
191 2
    private function addElement(string $element, $value, ?string $namespace = null): void
192
    {
193 2
        if (!is_array($value)) {
194
            /** @var \XMLWriter $xmlWriter */
195 2
            $xmlWriter = $this->getXMLWriter();
196 2
            $xmlWriter->writeElement(($namespace !== null ? $namespace . ':' : '') . $element, (string) $value);
197
198 2
            return;
199
        }
200
201 2
        if (isset($value['_namespace'])) {
202 2
            $this->addElement($value['_element'], $value[$value['_element']], $value['_namespace']);
203
        } else {
204 2
            $this->addElementArray($element, $value, $namespace);
205
        }
206 2
    }
207
208
    /**
209
     * @param string      $element
210
     * @param array       $value
211
     * @param null|string $namespace
212
     */
213 2
    private function addElementArray(string $element, array $value, ?string $namespace = null): void
214
    {
215 2
        if (!$this->isAssoc($value)) {
216 2
            $this->addElementArrayNonAssoc($element, $value, $namespace);
217
        } else {
218 2
            $this->addElementArrayAssoc($element, $value, $namespace);
219
        }
220 2
    }
221
222
    /**
223
     * @param string      $element
224
     * @param mixed       $value
225
     * @param string|null $namespace
226
     */
227 2
    private function addElementArrayAssoc(string $element, $value, ?string $namespace = null): void
228
    {
229
        /** @var \XMLWriter $xmlWriter */
230 2
        $xmlWriter = $this->getXMLWriter();
231 2
        $xmlWriter->startElement(($namespace !== null ? $namespace . ':' : '') . $element);
232
233 2
        if (isset($value['_attributes'])) {
234 2
            foreach ($value['_attributes'] as $attribute => $val) {
235 2
                $xmlWriter->writeAttribute($attribute, $val);
236
            }
237
238 2
            if (isset($value['_value']) && is_string($value['_value'])) {
239 2
                $xmlWriter->text((string) $value['_value']);
240
            }
241
        } else {
242 2
            foreach ($value as $el => $val) {
243 2
                if (is_array($val)) {
244 2
                    $this->addElement($el, $val, $namespace);
245
                } else {
246 2
                    $xmlWriter->writeElement(($namespace !== null ? $namespace . ':' : '') . $el, (string) $val);
247
                }
248
            }
249
        }
250
251 2
        $xmlWriter->endElement();
252 2
    }
253
254
    /**
255
     * @param string      $element
256
     * @param mixed       $value
257
     * @param null|string $namespace
258
     */
259 2
    private function addElementArrayNonAssoc(string $element, $value, ?string $namespace = null): void
260
    {
261 2
        foreach ($value as $val) {
262 2
            $this->addElement($element, $val, $namespace);
263
        }
264 2
    }
265
}
266