Completed
Push — master ( 9ef25d...153ee0 )
by Paweł
03:23
created

XMLWriter   A

Complexity

Total Complexity 39

Size/Duplication

Total Lines 244
Duplicated Lines 0 %

Test Coverage

Coverage 97.35%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 97
c 1
b 0
f 0
dl 0
loc 244
ccs 110
cts 113
cp 0.9735
rs 9.28
wmc 39

14 Methods

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