Passed
Pull Request — master (#55)
by Alexander
02:18
created

StreamTarget   A

Complexity

Total Complexity 8

Size/Duplication

Total Lines 66
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 25
c 2
b 0
f 0
dl 0
loc 66
ccs 29
cts 29
cp 1
rs 10
wmc 8

3 Methods

Rating   Name   Duplication   Size   Complexity  
A export() 0 16 2
A __construct() 0 4 1
A createStream() 0 22 5
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 A string stream identifier or a stream resource.
31
     *
32
     * @psalm-var mixed
33
     */
34
    private $stream;
35
36
    /**
37
     * @param resource|string $stream A string stream identifier or a 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
     * Check and create a 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
            $stream = @fopen($stream, 'ab');
77 4
            if ($stream === false) {
78 1
                throw new RuntimeException(sprintf(
79 1
                    'The "%s" stream cannot be opened.',
80 1
                    (string) $this->stream,
81
                ));
82
            }
83
        }
84
85 8
        if (!is_resource($stream) || get_resource_type($stream) !== 'stream') {
86 1
            throw new InvalidArgumentException(sprintf(
87 1
                'Invalid stream provided. It must be a string stream identifier or a stream resource, "%s" received.',
88 1
                gettype($stream),
89
            ));
90
        }
91
92 7
        return $stream;
93
    }
94
}
95