Passed
Pull Request — master (#49)
by Evgeniy
01:57
created

MessageCollection::count()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

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