Completed
Pull Request — master (#13)
by Peter
02:38
created

RenderIndexFileStream   A

Complexity

Total Complexity 12

Size/Duplication

Total Lines 131
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 3

Test Coverage

Coverage 95.24%

Importance

Changes 0
Metric Value
wmc 12
lcom 1
cbo 3
dl 0
loc 131
ccs 40
cts 42
cp 0.9524
rs 10
c 0
b 0
f 0

7 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 8 1
A getFilename() 0 4 1
A open() 0 6 1
A close() 0 8 1
A push() 0 13 3
A addSubStreamFileToIndex() 0 20 4
A getIndexPartFilename() 0 10 1
1
<?php
2
declare(strict_types=1);
3
4
/**
5
 * GpsLab component.
6
 *
7
 * @author    Peter Gribanov <[email protected]>
8
 * @copyright Copyright (c) 2011, Peter Gribanov
9
 * @license   http://opensource.org/licenses/MIT
10
 */
11
12
namespace GpsLab\Component\Sitemap\Stream;
13
14
use GpsLab\Component\Sitemap\Render\SitemapIndexRender;
15
use GpsLab\Component\Sitemap\Stream\Exception\IndexStreamException;
16
use GpsLab\Component\Sitemap\Stream\Exception\OverflowException;
17
use GpsLab\Component\Sitemap\Stream\Exception\StreamStateException;
18
use GpsLab\Component\Sitemap\Stream\State\StreamState;
19
use GpsLab\Component\Sitemap\Url\Url;
20
21
class RenderIndexFileStream implements FileStream
22
{
23
    /**
24
     * @var SitemapIndexRender
25
     */
26
    private $render;
27
28
    /**
29
     * @var FileStream
30
     */
31
    private $substream;
32
33
    /**
34
     * @var StreamState
35
     */
36
    private $state;
37
38
    /**
39
     * @var string
40
     */
41
    private $host = '';
42
43
    /**
44
     * @var string
45
     */
46
    private $filename = '';
47
48
    /**
49
     * @var int
50
     */
51
    private $index = 0;
52
53
    /**
54
     * @var string
55
     */
56
    private $buffer = '';
57
58
    /**
59
     * @param SitemapIndexRender $render
60
     * @param FileStream         $substream
61
     * @param string             $host
62
     * @param string             $filename
63
     */
64 10
    public function __construct(SitemapIndexRender $render, FileStream $substream, string $host, string $filename)
65
    {
66 10
        $this->render = $render;
67 10
        $this->substream = $substream;
68 10
        $this->host = $host;
69 10
        $this->filename = $filename;
70 10
        $this->state = new StreamState();
71 10
    }
72
73
    /**
74
     * @return string
75
     */
76 1
    public function getFilename(): string
77
    {
78 1
        return $this->filename;
79
    }
80
81 7
    public function open(): void
82
    {
83 7
        $this->state->open();
84 7
        $this->substream->open();
85 7
        $this->buffer = $this->render->start();
86 7
    }
87
88 8
    public function close(): void
89
    {
90 8
        $this->state->close();
91 7
        $this->addSubStreamFileToIndex();
92
93 7
        file_put_contents($this->filename, $this->buffer.$this->render->end());
94 7
        $this->buffer = '';
95 7
    }
96
97
    /**
98
     * @param Url $url
99
     */
100 4
    public function push(Url $url): void
101
    {
102 4
        if (!$this->state->isReady()) {
103 2
            throw StreamStateException::notReady();
104
        }
105
106
        try {
107 2
            $this->substream->push($url);
108 1
        } catch (OverflowException $e) {
109 1
            $this->addSubStreamFileToIndex();
110 1
            $this->substream->open();
111
        }
112 2
    }
113
114 7
    private function addSubStreamFileToIndex(): void
115
    {
116 7
        $this->substream->close();
117
118 7
        $filename = $this->substream->getFilename();
119 7
        $indexed_filename = $this->getIndexPartFilename($filename, ++$this->index);
120
121 7
        if (!is_file($filename) || !($time = filemtime($filename))) {
122
            throw IndexStreamException::undefinedSubstreamFile($filename);
123
        }
124
125 7
        $last_mod = (new \DateTimeImmutable())->setTimestamp($time);
126
127
        // rename sitemap file to the index part file
128 7
        if (!rename($filename, dirname($filename).'/'.$indexed_filename)) {
129
            throw IndexStreamException::failedRename($filename, dirname($filename).'/'.$indexed_filename);
130
        }
131
132 7
        $this->buffer .= $this->render->sitemap($this->host.$indexed_filename, $last_mod);
0 ignored issues
show
Security Bug introduced by
It seems like $last_mod defined by (new \DateTimeImmutable())->setTimestamp($time) on line 125 can also be of type false; however, GpsLab\Component\Sitemap...pIndexRender::sitemap() does only seem to accept null|object<DateTimeInterface>, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
133 7
    }
134
135
    /**
136
     * @param string $filename
137
     * @param int    $index
138
     *
139
     * @return string
140
     */
141 7
    private function getIndexPartFilename(string $filename, int $index): string
142
    {
143
        // use explode() for correct add index
144
        // sitemap.xml -> sitemap1.xml
145
        // sitemap.xml.gz -> sitemap1.xml.gz
146
147 7
        list($filename, $extension) = explode('.', basename($filename), 2);
148
149 7
        return sprintf('%s%s.%s', $filename, $index, $extension);
150
    }
151
}
152