Passed
Push — master ( 2e496e...4c080f )
by Alexander
03:20 queued 01:17
created

MessageCollection::addMultiple()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 3
nc 2
nop 1
dl 0
loc 5
ccs 4
cts 4
cp 1
crap 2
rs 10
c 1
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Log;
6
7
use Psr\Log\InvalidArgumentException;
8
use Psr\Log\LogLevel;
9
use Yiisoft\VarDumper\VarDumper;
10
11
use function count;
12
use function is_array;
13
use function is_scalar;
14
use function method_exists;
15
use function preg_replace_callback;
16
17
/**
18
 * MessageCollection stores log messages.
19
 * @internal
20
 */
21
final class MessageCollection
22
{
23
    /**
24
     * @var string[] The log message levels that this collection is interested in.
25
     * @see LogLevel See constants for valid level names.
26
     *
27
     * The value should be an array of level names.
28
     *
29
     * For example:
30
     *
31
     * ```php
32
     * ['error', 'warning'],
33
     * // or
34
     * [LogLevel::ERROR, LogLevel::WARNING]
35
     * ```
36
     *
37
     * Defaults is empty array, meaning all available levels.
38
     */
39
    private array $levels = [];
40
41
    /**
42
     * @var array[] The log messages.
43
     *
44
     ** Each log message is of the following structure:
45
     *
46
     * ```
47
     * [
48
     *   [0] => level (string)
49
     *   [1] => message (mixed, can be a string or some complex data, such as an exception object)
50
     *   [2] => context (array)
51
     * ]
52
     * ```
53
     *
54
     * Message context has a following keys:
55
     *
56
     * - category: string, message category.
57
     * - time: float, message timestamp obtained by microtime(true).
58
     * - trace: array, debug backtrace, contains the application code call stacks.
59
     * - memory: int, memory usage in bytes, obtained by `memory_get_usage()`.
60
     */
61
    private array $messages = [];
62
63
    /**
64
     * Adds a log message to the collection.
65
     *
66
     * @param mixed $level Log message level.
67
     * @param mixed $message Log message.
68
     * @param array $context Log message context.
69
     * @throws InvalidArgumentException for invalid log message level.
70
     * @see MessageCollection::$messages
71
     * @see LoggerTrait::log()
72
     */
73 68
    public function add($level, $message, array $context = []): void
74
    {
75 68
        $this->messages[] = [Logger::getLevelName($level), $this->parse($this->prepare($message), $context), $context];
76 62
    }
77
78
    /**
79
     * Adds multiple log messages to the collection.
80
     *
81
     * @param array $messages The list of log messages.
82
     * @throws InvalidArgumentException for invalid message structure.
83
     * @see MessageCollection::$messages
84
     */
85 59
    public function addMultiple(array $messages): void
86
    {
87 59
        foreach ($messages as $message) {
88 58
            $this->checkStructure($message);
89 40
            $this->add($message[0], $message[1], $message[2]);
90
        }
91 41
    }
92
93
    /**
94
     * Returns all log messages.
95
     *
96
     * @return array All log messages.
97
     * @see MessageCollection::$messages
98
     */
99 62
    public function all(): array
100
    {
101 62
        return $this->messages;
102
    }
103
104
    /**
105
     * Removes all log messages.
106
     */
107 24
    public function clear(): void
108
    {
109 24
        $this->messages = [];
110 24
    }
111
112
    /**
113
     * Returns the number of log messages in the collection.
114
     *
115
     * @return int The number of log messages in the collection.
116
     */
117 38
    public function count(): int
118
    {
119 38
        return count($this->messages);
120
    }
121
122
    /**
123
     * Checks log message structure.
124
     *
125
     * @param mixed $message The log message to be checked.
126
     * @throws InvalidArgumentException for invalid message structure.
127
     * @see MessageCollection::$messages
128
     */
129 90
    public function checkStructure($message): void
130
    {
131 90
        if (!is_array($message) || !isset($message[0], $message[1], $message[2]) || !is_array($message[2])) {
132 40
            throw new InvalidArgumentException('The message structure is not valid.');
133
        }
134 50
    }
135
136
    /**
137
     * Sets the log message levels that current collection is interested in.
138
     *
139
     * @param string[] $levels The log message levels.
140
     * @throws InvalidArgumentException for invalid log message level.
141
     * @see MessageCollection::$levels
142
     */
143 23
    public function setLevels(array $levels): void
144
    {
145 23
        foreach ($levels as $key => $level) {
146 22
            $levels[$key] = Logger::getLevelName($level);
147
        }
148
149 11
        $this->levels = $levels;
150 11
    }
151
152
    /**
153
     * Gets the log message levels of the current group.
154
     *
155
     * @return string[] The log message levels.
156
     * @see MessageCollection::$levels
157
     */
158 29
    public function getLevels(): array
159
    {
160 29
        return $this->levels;
161
    }
162
163
    /**
164
     * Prepares log message for logging.
165
     *
166
     * @param mixed $message Raw log message.
167
     * @return string Prepared log message.
168
     */
169 62
    private function prepare($message): string
170
    {
171 62
        if (is_scalar($message) || method_exists($message, '__toString')) {
172 56
            return (string) $message;
173
        }
174
175 6
        return VarDumper::create($message)->export();
176
    }
177
178
    /**
179
     * Parses log message resolving placeholders in the form: "{foo}",
180
     * where foo will be replaced by the context data in key "foo".
181
     *
182
     * @param string $message Log message.
183
     * @param array $context Message context.
184
     * @return string Parsed message.
185
     */
186 62
    private function parse(string $message, array $context): string
187
    {
188 62
        return preg_replace_callback('/{([\w.]+)}/', static function (array $matches) use ($context) {
189 3
            $placeholderName = $matches[1];
190
191 3
            if (isset($context[$placeholderName])) {
192 1
                return (string) $context[$placeholderName];
193
            }
194
195 2
            return $matches[0];
196 62
        }, $message);
197
    }
198
}
199