Completed
Push — master ( 4b16c6...b82f61 )
by Paweł
01:55
created

XMLWriter::addElementArray()   C

Complexity

Conditions 13
Paths 11

Size

Total Lines 36

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 182

Importance

Changes 0
Metric Value
cc 13
nc 11
nop 3
dl 0
loc 36
ccs 0
cts 35
cp 0
crap 182
rs 6.6166
c 0
b 0
f 0

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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