Completed
Push — master ( 0d3592...0bb29a )
by Peter
06:28
created

RenderGzipFileStream::__construct()   A

Complexity

Conditions 4
Paths 2

Size

Total Lines 11
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
dl 0
loc 11
rs 9.2
c 1
b 0
f 0
cc 4
eloc 7
nc 2
nop 3
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\StreamStateException;
17
use GpsLab\Component\Sitemap\Stream\State\StreamState;
18
use GpsLab\Component\Sitemap\Url\Url;
19
20
class RenderGzipFileStream implements FileStream
21
{
22
    const LINKS_LIMIT = 50000;
23
24
    const BYTE_LIMIT = 52428800; // 50 Mb
25
26
    /**
27
     * @var SitemapRender
28
     */
29
    private $render;
30
31
    /**
32
     * @var StreamState
33
     */
34
    private $state;
35
36
    /**
37
     * @var resource|null
38
     */
39
    private $handle;
40
41
    /**
42
     * @var string
43
     */
44
    private $filename = '';
45
46
    /**
47
     * @var int
48
     */
49
    private $compression_level = 9;
50
51
    /**
52
     * @var int
53
     */
54
    private $counter = 0;
55
56
    /**
57
     * @var string
58
     */
59
    private $end_string = '';
60
61
    /**
62
     * @var int
63
     */
64
//    private $used_bytes = 0;
65
66
    /**
67
     * @param SitemapRender $render
68
     * @param string        $filename
69
     * @param int           $compression_level
70
     */
71
    public function __construct(SitemapRender $render, $filename, $compression_level = 9)
72
    {
73
        if (!is_numeric($compression_level) || $compression_level < 1 || $compression_level > 9) {
74
            throw CompressionLevelException::invalid($compression_level, 1, 9);
75
        }
76
77
        $this->render = $render;
78
        $this->state = new StreamState();
79
        $this->filename = $filename;
80
        $this->compression_level = $compression_level;
1 ignored issue
show
Documentation Bug introduced by
It seems like $compression_level can also be of type double or string. However, the property $compression_level is declared as type integer. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
81
    }
82
83
    /**
84
     * @return string
85
     */
86
    public function getFilename()
87
    {
88
        return $this->filename;
89
    }
90
91 View Code Duplication
    public function open()
1 ignored issue
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
92
    {
93
        $this->state->open();
94
95
        $mode = 'wb'.$this->compression_level;
96
        if ((file_exists($this->filename) && !is_writable($this->filename)) ||
97
            ($this->handle = @gzopen($this->filename, $mode)) === false
98
        ) {
99
            throw FileAccessException::notWritable($this->filename);
100
        }
101
102
        $this->write($this->render->start());
103
        // render end string only once
104
        $this->end_string = $this->render->end();
105
    }
106
107
    public function close()
108
    {
109
        $this->state->close();
110
        $this->write($this->end_string);
111
        gzclose($this->handle);
112
    }
113
114
    /**
115
     * @param Url $url
116
     */
117 View Code Duplication
    public function push(Url $url)
1 ignored issue
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
118
    {
119
        if (!$this->state->isReady()) {
120
            throw StreamStateException::notReady();
121
        }
122
123
        if ($this->counter >= self::LINKS_LIMIT) {
124
            throw LinksOverflowException::withLimit(self::LINKS_LIMIT);
125
        }
126
127
        $render_url = $this->render->url($url);
128
129
        // impossible calculate expected size
130
//        $expected_bytes = $this->used_bytes + strlen($render_url) + strlen($this->end_string);
131
//        if ($expected_bytes > self::BYTE_LIMIT) {
132
//            throw SizeOverflowException::withLimit(self::BYTE_LIMIT);
133
//        }
134
135
        $this->write($render_url);
136
        ++$this->counter;
137
    }
138
139
    /**
140
     * @return int
141
     */
142
    public function count()
143
    {
144
        return $this->counter;
145
    }
146
147
    /**
148
     * @param string $string
149
     */
150
    private function write($string)
151
    {
152
        gzwrite($this->handle, $string);
153
//        $this->used_bytes += strlen($string);
154
    }
155
}
156