Completed
Pull Request — master (#90)
by Peter
02:23
created

RenderGzipFileStream   A

Complexity

Total Complexity 15

Size/Duplication

Total Lines 146
Duplicated Lines 34.93 %

Coupling/Cohesion

Components 1
Dependencies 7

Test Coverage

Coverage 91.84%

Importance

Changes 0
Metric Value
wmc 15
lcom 1
cbo 7
dl 51
loc 146
ccs 45
cts 49
cp 0.9184
rs 10
c 0
b 0
f 0

7 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 11 4
A getFilename() 0 4 1
A open() 14 14 2
A close() 17 17 2
A count() 0 4 1
A write() 0 5 1
A push() 20 20 4

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

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 8 View Code Duplication
    public function open()
94
    {
95 8
        $this->state->open();
96
97 8
        $mode = 'wb'.$this->compression_level;
98 8
        $this->tmp_filename = tempnam(sys_get_temp_dir(), 'sitemap');
99 8
        if (($this->handle = @gzopen($this->tmp_filename, $mode)) === false) {
100
            throw FileAccessException::notWritable($this->tmp_filename);
101
        }
102
103 8
        $this->write($this->render->start());
104
        // render end string only once
105 8
        $this->end_string = $this->render->end();
106 8
    }
107
108 15 View Code Duplication
    public function close()
109
    {
110 15
        $this->state->close();
111 8
        $this->write($this->end_string);
112 8
        gzclose($this->handle);
113
114 8
        if (!rename($this->tmp_filename, $this->filename)) {
115
            unlink($this->tmp_filename);
116
117
            throw FileAccessException::failedOverwrite($this->tmp_filename, $this->filename);
118
        }
119
120 8
        $this->handle = null;
121 8
        $this->tmp_filename = '';
122 8
        $this->counter = 0;
123 8
        $this->used_bytes = 0;
124 8
    }
125
126
    /**
127
     * @param Url $url
128
     */
129 5 View Code Duplication
    public function push(Url $url)
130
    {
131 5
        if (!$this->state->isReady()) {
132 2
            throw StreamStateException::notReady();
133
        }
134
135 3
        if ($this->counter >= self::LINKS_LIMIT) {
136 1
            throw LinksOverflowException::withLimit(self::LINKS_LIMIT);
137
        }
138
139 3
        $render_url = $this->render->url($url);
140
141 3
        $expected_bytes = $this->used_bytes + strlen($render_url) + strlen($this->end_string);
142 3
        if ($expected_bytes > self::BYTE_LIMIT) {
143
            throw SizeOverflowException::withLimit(self::BYTE_LIMIT);
144
        }
145
146 3
        $this->write($render_url);
147 3
        ++$this->counter;
148 3
    }
149
150
    /**
151
     * @return int
152
     */
153 2
    public function count()
154
    {
155 2
        return $this->counter;
156
    }
157
158
    /**
159
     * @param string $string
160
     */
161 8
    private function write($string)
162
    {
163 8
        gzwrite($this->handle, $string);
164 8
        $this->used_bytes += strlen($string);
165 8
    }
166
}
167