Completed
Branch develop (a57190)
by Michael
05:52 queued 01:37
created

Stream   B

Complexity

Total Complexity 40

Size/Duplication

Total Lines 232
Duplicated Lines 12.07 %

Coupling/Cohesion

Components 1
Dependencies 0

Test Coverage

Coverage 100%

Importance

Changes 1
Bugs 0 Features 1
Metric Value
wmc 40
c 1
b 0
f 1
lcom 1
cbo 0
dl 28
loc 232
ccs 83
cts 83
cp 1
rs 8.2608

17 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 9 2
A __destruct() 0 4 1
A __toString() 0 10 2
A close() 0 10 3
A detach() 0 11 2
A getSize() 0 14 4
A tell() 0 10 2
A eof() 0 4 2
A isSeekable() 0 4 2
A seek() 0 10 3
A rewind() 0 4 1
A isWritable() 0 4 2
A write() 0 14 3
A isReadable() 0 4 2
A read() 14 14 3
A getContents() 14 14 3
A getMetadata() 0 8 3

How to fix   Duplicated Code    Complexity   

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:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like Stream often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Stream, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/**
4
 * This file is part of the miBadger package.
5
 *
6
 * @author Michael Webbers <[email protected]>
7
 * @license http://opensource.org/licenses/Apache-2.0 Apache v2 License
8
 * @version 1.0.0
9
 */
10
11
namespace miBadger\Http;
12
13
use Psr\Http\Message\StreamInterface;
14
15
/**
16
 * The stream class
17
 *
18
 * @see http://www.php-fig.org/psr/psr-7/
19
 * @since 1.0.0
20
 */
21
class Stream implements StreamInterface
22
{
23
	/** @var resource The resource. */
24
	private $resource;
25
26
	/** @var array The metadata. */
27
	private $metadata;
28
29
	/** @var string[] The read modes. */
30
	private static $readModes = ['r', 'w+', 'r+', 'x+', 'c+', 'rb', 'w+b', 'r+b', 'x+b', 'c+b', 'rt', 'w+t', 'r+t', 'x+t', 'c+t', 'a+'];
31
32
	/** @var string[] The write modes. */
33
	private static $writeModes = ['w', 'w+', 'rw', 'r+', 'x+', 'c+', 'wb', 'w+b', 'r+b', 'x+b', 'c+b', 'w+t', 'r+t', 'x+t', 'c+t', 'a', 'a+'];
34
35
	/**
36
	 * Construct a Stream object with the given resource.
37
	 *
38
	 * @param resource $resource
39
	 */
40 71
	public function __construct($resource)
41
	{
42 71
		if (!is_resource($resource)) {
43 1
			throw new \InvalidArgumentException('Invalid resource');
44
		}
45
46 71
		$this->resource = $resource;
47 71
		$this->metadata = stream_get_meta_data($resource);
48 71
	}
49
50
	/**
51
	 * Destruct the Stream object.
52
	 */
53 6
	public function __destruct()
54
	{
55 6
		$this->close();
56 6
	}
57
58
	/**
59
	 * {@inheritdoc}
60
	 */
61 4
	public function __toString()
62
	{
63
		try {
64 4
			$this->seek(0);
65
66 2
			return $this->getContents();
67 2
		} catch (\Exception $e) {
68 2
			return '';
69
		}
70
	}
71
72
	/**
73
	 * {@inheritdoc}
74
	 */
75 7
	public function close()
76
	{
77 7
		if (isset($this->resource)) {
78 7
			if (is_resource($this->resource)) {
79 7
				fclose($this->resource);
80 7
			}
81
82 7
			$this->detach();
83 7
		}
84 7
	}
85
86
	/**
87
	 * {@inheritdoc}
88
	 */
89 14
	public function detach()
90
	{
91 14
		if (!isset($this->resource)) {
92 1
			return null;
93
		}
94
95 14
		$result = $this->resource;
96 14
		unset($this->resource);
97
98 14
		return $result;
99
	}
100
101
	/**
102
	 * {@inheritdoc}
103
	 */
104 2
	public function getSize()
105
	{
106 2
		if (!isset($this->resource)) {
107 1
			return null;
108
		}
109
110 1
		if ($this->getMetadata('uri')) {
111 1
			clearstatcache(true, $this->getMetadata('uri'));
112 1
		}
113
114 1
		$stats = fstat($this->resource);
115
116 1
		return isset($stats['size']) ? $stats['size'] : null;
117
	}
118
119
	/**
120
	 * {@inheritdoc}
121
	 */
122 2
	public function tell()
123
	{
124 2
		$result = ftell($this->resource);
125
126 2
		if ($result === false) {
127 1
			throw new \RuntimeException('Error while getting the position of the pointer');
128
		}
129
130 1
		return $result;
131
	}
132
133
	/**
134
	 * {@inheritdoc}
135
	 */
136 1
	public function eof()
137
	{
138 1
		return isset($this->resource) && feof($this->resource);
139
	}
140
141
	/**
142
	 * {@inheritdoc}
143
	 */
144 9
	public function isSeekable()
145
	{
146 9
		return isset($this->resource) && $this->getMetadata('seekable');
147
	}
148
149
	/**
150
	 * {@inheritdoc}
151
	 */
152 8
	public function seek($offset, $whence = SEEK_SET)
153
	{
154 8
		if (!$this->isSeekable()) {
155 3
			throw new \RuntimeException('Stream is not seekable');
156
		}
157
158 5
		if (fseek($this->resource, $offset, $whence) === false) {
159 1
			throw new \RuntimeException('Error while seeking the stream');
160
		}
161 4
	}
162
163
	/**
164
	 * {@inheritdoc}
165
	 */
166 1
	public function rewind()
167
	{
168 1
		$this->seek(0);
169 1
	}
170
171
	/**
172
	 * {@inheritdoc}
173
	 */
174 6
	public function isWritable()
175
	{
176 6
		return isset($this->resource) && in_array($this->getMetadata('mode'), self::$writeModes);
177
	}
178
179
	/**
180
	 * {@inheritdoc}
181
	 */
182 5
	public function write($string)
183
	{
184 5
		if (!$this->isWritable()) {
185 1
			throw new \RuntimeException('Stream is not writable');
186
		}
187
188 4
		$result = fwrite($this->resource, $string);
189
190 4
		if ($result === false) {
191 1
			throw new \RuntimeException('Error while writing the stream');
192
		}
193
194 3
		return $result;
195
	}
196
197
	/**
198
	 * {@inheritdoc}
199
	 */
200 10
	public function isReadable()
201
	{
202 10
		return isset($this->resource) && in_array($this->getMetadata('mode'), self::$readModes);
203
	}
204
205
	/**
206
	 * {@inheritdoc}
207
	 */
208 3 View Code Duplication
	public function read($length)
0 ignored issues
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...
209
	{
210 3
		if (!$this->isReadable()) {
211 1
			throw new \RuntimeException('Stream is not readable');
212
		}
213
214 2
		$result = fread($this->resource, $length);
215
216 2
		if ($result === false) {
217 1
			throw new \RuntimeException('Error while reading the stream');
218
		}
219
220 1
		return $result;
221
	}
222
223
	/**
224
	 * {@inheritdoc}
225
	 */
226 6 View Code Duplication
	public function getContents()
0 ignored issues
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...
227
	{
228 6
		if (!$this->isReadable()) {
229 1
			throw new \RuntimeException('Stream is not readable');
230
		}
231
232 5
		$result = stream_get_contents($this->resource);
233
234 5
		if ($result === false) {
235 1
			throw new \RuntimeException('Error while reading the stream');
236
		}
237
238 4
		return $result;
239
	}
240
241
	/**
242
	 * {@inheritdoc}
243
	 */
244 18
	public function getMetadata($key = null)
245
	{
246 18
		if ($key === null) {
247 1
			return $this->metadata;
248
		}
249
250 17
		return isset($this->metadata[$key]) ? $this->metadata[$key] : null;
251
	}
252
}
253