Completed
Pull Request — master (#89)
by Peter
02:19
created

RenderGzipFileStream::open()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 23

Duplication

Lines 23
Ratio 100 %

Code Coverage

Tests 11
CRAP Score 3.0327

Importance

Changes 0
Metric Value
dl 23
loc 23
c 0
b 0
f 0
ccs 11
cts 13
cp 0.8462
rs 9.552
cc 3
nc 3
nop 0
crap 3.0327
1
<?php
2
/**
3
 * GpsLab component.
4
 *
5
 * @author    Peter Gribanov <[email protected]>
6
 * @copyright Copyright (c) 2011, Peter Gribanov
7
 * @license   http://opensource.org/licenses/MIT
8
 */
9
10
namespace GpsLab\Component\Sitemap\Stream;
11
12
use GpsLab\Component\Sitemap\Render\SitemapRender;
13
use GpsLab\Component\Sitemap\Stream\Exception\CompressionLevelException;
14
use GpsLab\Component\Sitemap\Stream\Exception\FileAccessException;
15
use GpsLab\Component\Sitemap\Stream\Exception\LinksOverflowException;
16
use GpsLab\Component\Sitemap\Stream\Exception\SizeOverflowException;
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 RenderGzipFileStream implements FileStream
22
{
23
    /**
24
     * @var SitemapRender
25
     */
26
    private $render;
27
28
    /**
29
     * @var StreamState
30
     */
31
    private $state;
32
33
    /**
34
     * @var resource|null
35
     */
36
    private $handle;
37
38
    /**
39
     * @var string
40
     */
41
    private $filename = '';
42
43
    /**
44
     * @var string
45
     */
46
    private $tmp_filename = '';
47
48
    /**
49
     * @var int
50
     */
51
    private $compression_level = 9;
52
53
    /**
54
     * @var int
55
     */
56
    private $counter = 0;
57
58
    /**
59
     * @var string
60
     */
61
    private $end_string = '';
62
63
    /**
64
     * @var int
65
     */
66
    private $used_bytes = 0;
67
68
    /**
69
     * @param SitemapRender $render
70
     * @param string        $filename
71
     * @param int           $compression_level
72
     */
73 15
    public function __construct(SitemapRender $render, $filename, $compression_level = 9)
74
    {
75 15
        if (!is_numeric($compression_level) || $compression_level < 1 || $compression_level > 9) {
76 4
            throw CompressionLevelException::invalid($compression_level, 1, 9);
77
        }
78
79 15
        $this->render = $render;
80 15
        $this->state = new StreamState();
81 15
        $this->filename = $filename;
82 15
        $this->compression_level = $compression_level;
83 15
    }
84
85
    /**
86
     * @return string
87
     */
88 1
    public function getFilename()
89
    {
90 1
        return $this->filename;
91
    }
92
93
    /**
94
     * @return void
95
     */
96 8 View Code Duplication
    public function open()
97
    {
98 8
        $this->state->open();
99
100 8
        $tmp_filename = tempnam(sys_get_temp_dir(), 'sitemap');
101
102 8
        if ($tmp_filename === false) {
103
            throw FileAccessException::failedCreateUnique(sys_get_temp_dir(), 'sitemap');
104
        }
105
106 8
        $handle = @gzopen($tmp_filename, 'wb'.$this->compression_level);
107
108 8
        if ($handle === false) {
109
            throw FileAccessException::notWritable($tmp_filename);
110
        }
111
112 8
        $this->tmp_filename = $tmp_filename;
113 8
        $this->handle = $handle;
114
115 8
        $this->write($this->render->start());
116
        // render end string only once
117 8
        $this->end_string = $this->render->end();
118 8
    }
119
120
    /**
121
     * @return void
122
     */
123 15 View Code Duplication
    public function close()
124
    {
125 15
        $this->state->close();
126 8
        $this->write($this->end_string);
127 8
        gzclose($this->handle);
128
129 8
        if (!rename($this->tmp_filename, $this->filename)) {
130
            unlink($this->tmp_filename);
131
132
            throw FileAccessException::failedOverwrite($this->tmp_filename, $this->filename);
133
        }
134
135 8
        $this->handle = null;
136 8
        $this->tmp_filename = '';
137 8
        $this->counter = 0;
138 8
        $this->used_bytes = 0;
139 8
    }
140
141
    /**
142
     * @param Url $url
143
     *
144
     * @return void
145
     */
146 6 View Code Duplication
    public function push(Url $url)
147
    {
148 6
        if (!$this->state->isReady()) {
149 2
            throw StreamStateException::notReady();
150
        }
151
152 4
        if ($this->counter >= self::LINKS_LIMIT) {
153 1
            throw LinksOverflowException::withLimit(self::LINKS_LIMIT);
154
        }
155
156 4
        $render_url = $this->render->url($url);
157
158 4
        $expected_bytes = $this->used_bytes + strlen($render_url) + strlen($this->end_string);
159 4
        if ($expected_bytes > self::BYTE_LIMIT) {
160 1
            throw SizeOverflowException::withLimit(self::BYTE_LIMIT);
161
        }
162
163 4
        $this->write($render_url);
164 4
        ++$this->counter;
165 4
    }
166
167
    /**
168
     * @return int
169
     */
170 2
    public function count()
171
    {
172 2
        return $this->counter;
173
    }
174
175
    /**
176
     * @param string $string
177
     *
178
     * @return void
179
     */
180 8
    private function write($string)
181
    {
182 8
        gzwrite($this->handle, $string);
183 8
        $this->used_bytes += strlen($string);
184 8
    }
185
}
186