Completed
Push — master ( 53db6d...9722fa )
by Paweł
02:50
created

XMLWriter::openSitemapIndex()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 1

Importance

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