Passed
Pull Request — master (#55)
by Evgeniy
04:08 queued 43s
created

StreamTarget::createStream()   A

Complexity

Conditions 5
Paths 5

Size

Total Lines 21
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 5

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 5
eloc 11
nc 5
nop 0
dl 0
loc 21
ccs 12
cts 12
cp 1
crap 5
rs 9.6111
c 1
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Log;
6
7
use InvalidArgumentException;
8
use RuntimeException;
9
10
use function error_get_last;
11
use function fclose;
12
use function flock;
13
use function fopen;
14
use function fwrite;
15
use function gettype;
16
use function get_resource_type;
17
use function is_resource;
18
use function sprintf;
19
use function stream_get_meta_data;
20
21
use const LOCK_EX;
22
use const LOCK_UN;
23
24
/**
25
 * StreamTarget is the log target that writes to the specified output stream.
26
 */
27
final class StreamTarget extends Target
28
{
29
    /**
30
     * @var resource|string The string stream identifier or stream resource.
31
     *
32
     * @psalm-var mixed
33
     */
34
    private $stream;
35
36
    /**
37
     * @param resource|string $stream The string stream identifier or stream resource.
38
     */
39 9
    public function __construct($stream = 'php://stdout')
40
    {
41 9
        $this->stream = $stream;
42 9
        parent::__construct();
43 9
    }
44
45 9
    protected function export(): void
46
    {
47 9
        $stream = $this->createStream();
48 7
        flock($stream, LOCK_EX);
49
50 7
        if (fwrite($stream, $this->formatMessages("\n")) === false) {
51 4
            fclose($stream);
52 4
            throw new RuntimeException(sprintf(
53 4
                'Unable to export the log because of an error writing to the stream: %s',
54 4
                error_get_last()['message'] ?? '',
55
            ));
56
        }
57
58 3
        $this->stream = stream_get_meta_data($stream)['uri'];
59 3
        flock($stream, LOCK_UN);
60 3
        fclose($stream);
61 3
    }
62
63
    /**
64
     * Checks and creates the stream resource.
65
     *
66
     * @throws RuntimeException if the stream cannot be opened.
67
     * @throws InvalidArgumentException if the stream is invalid.
68
     *
69
     * @return resource The stream resource.
70
     */
71 9
    private function createStream()
72
    {
73 9
        $stream = $this->stream;
74
75 9
        if (is_string($stream)) {
76 4
            if (($stream = @fopen($stream, 'ab')) === false) {
77 1
                throw new RuntimeException(sprintf(
78 1
                    'The "%s" stream cannot be opened.',
79 1
                    $this->stream,
0 ignored issues
show
Bug introduced by
It seems like $this->stream can also be of type resource; however, parameter $args of sprintf() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

79
                    /** @scrutinizer ignore-type */ $this->stream,
Loading history...
80
                ));
81
            }
82
        }
83
84 8
        if (!is_resource($stream) || get_resource_type($stream) !== 'stream') {
85 1
            throw new InvalidArgumentException(sprintf(
86 1
                'Invalid stream provided. It must be a string stream identifier or stream resource, "%s" received.',
87 1
                gettype($stream),
88
            ));
89
        }
90
91 7
        return $stream;
92
    }
93
}
94