Passed
Branch master (8a6725)
by Michał
02:20
created

Log   A

Complexity

Total Complexity 24

Size/Duplication

Total Lines 210
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
dl 0
loc 210
rs 10
c 0
b 0
f 0
ccs 72
cts 72
cp 1
wmc 24

11 Methods

Rating   Name   Duplication   Size   Complexity  
A processMessage() 0 17 3
A makeLog() 0 3 1
A wrapMessage() 0 9 1
A getLastMessage() 0 3 1
A reloadStorage() 0 4 1
A getOption() 0 7 2
A __construct() 0 8 1
B buildContext() 0 13 5
A setOption() 0 4 1
B buildMessage() 0 22 6
A log() 0 14 2
1
<?php
2
3
namespace SimpleLog;
4
5
use Psr\Log\LoggerInterface;
6
use Psr\Log\LoggerTrait;
7
use Psr\Log\LogLevel;
8
use Psr\Log\InvalidArgumentException;
9
10
class Log implements LogInterface, LoggerInterface
11
{
12
    use LoggerTrait;
13
14
    /**
15
     * @var array
16
     */
17
    protected $defaultParams = [
18
        'log_path' => './log',
19
        'level' => 'notice',
20
        'storage' => '\SimpleLog\Storage\File'
21
    ];
22
23
    /**
24
     * @var \SimpleLog\Storage\StorageInterface
25
     */
26
    protected $storage;
27
28
    /**
29
     * @var array
30
     */
31
    protected $levels = [];
32
33
    /**
34
     * @var string
35
     */
36
    protected $message = '';
37
38
    /**
39
     * @param array $params
40
     * @throws \ReflectionException
41
     */
42 9
    public function __construct(array $params = [])
43
    {
44 9
        $this->defaultParams = array_merge($this->defaultParams, $params);
45
46 9
        $levels = new \ReflectionClass(new LogLevel);
47 9
        $this->levels = $levels->getConstants();
48
49 9
        $this->reloadStorage();
50 9
    }
51
52
    /**
53
     * log event information into file
54
     *
55
     * @param array|string|object $message
56
     * @param array $context
57
     * @return $this
58
     */
59 8
    public function makeLog($message, array $context = [])
60
    {
61 8
        return $this->log($this->defaultParams['level'], $message, $context);
62
    }
63
64
    /**
65
     * @param string $level
66
     * @param string|array|object $message
67
     * @param array $context
68
     * @return $this
69
     * @throws \Psr\Log\InvalidArgumentException
70
     */
71 10
    public function log($level, $message, array $context = [])
72
    {
73 10
        $this->message = '';
74
75 10
        if (!in_array($level, $this->levels, true)) {
76 1
            throw new InvalidArgumentException('Level not defined: ' . $level);
77
        }
78
79 9
        $this->buildMessage($message)
0 ignored issues
show
Bug introduced by
It seems like $message can also be of type object; however, parameter $message of SimpleLog\Log::buildMessage() does only seem to accept string|array, 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
        $this->buildMessage(/** @scrutinizer ignore-type */ $message)
Loading history...
80 8
            ->wrapMessage()
81 8
            ->buildContext($context)
82 8
            ->storage->store($this->message, $level);
83
84 8
        return $this;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this returns the type SimpleLog\Log which is incompatible with the return type mandated by Psr\Log\LoggerInterface::log() of void.

In the issue above, the returned value is violating the contract defined by the mentioned interface.

Let's take a look at an example:

interface HasName {
    /** @return string */
    public function getName();
}

class Name {
    public $name;
}

class User implements HasName {
    /** @return string|Name */
    public function getName() {
        return new Name('foo'); // This is a violation of the ``HasName`` interface
                                // which only allows a string value to be returned.
    }
}
Loading history...
85
    }
86
87
    /**
88
     * @return $this
89
     */
90 10
    protected function reloadStorage()
91
    {
92 10
        $this->storage = new $this->defaultParams['storage']($this->defaultParams);
93 10
        return $this;
94
    }
95
96
    /**
97
     * @return $this
98
     */
99 8
    protected function wrapMessage()
100
    {
101 8
        $this->message = strftime('%d-%m-%Y - %H:%M:%S')
0 ignored issues
show
Bug introduced by
The call to strftime() has too few arguments starting with timestamp. ( Ignorable by Annotation )

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

101
        $this->message = /** @scrutinizer ignore-call */ strftime('%d-%m-%Y - %H:%M:%S')

This check compares calls to functions or methods with their respective definitions. If the call has less arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
102
            . PHP_EOL
103 8
            . $this->message
104 8
            . '-----------------------------------------------------------'
105 8
            . PHP_EOL;
106
107 8
        return $this;
108
    }
109
110
    /**
111
     * @param array $context
112
     * @return $this
113
     */
114 8
    protected function buildContext(array $context)
115
    {
116 8
        $replace = [];
117
118 8
        foreach ($context as $key => $val) {
119 1
            if (!is_array($val) && (!is_object($val) || method_exists($val, '__toString'))) {
120 1
                $replace['{' . $key . '}'] = $val;
121 1
            }
122 8
        }
123
124 8
        $this->message = strtr($this->message, $replace);
125
126 8
        return $this;
127
    }
128
129
    /**
130
     * set log option for all future executions of makeLog
131
     *
132
     * @param string $key
133
     * @param mixed $val
134
     * @return $this
135
     */
136 3
    public function setOption($key, $val)
137
    {
138 3
        $this->defaultParams[$key] = $val;
139 3
        return $this->reloadStorage();
140
    }
141
142
    /**
143
     * return all configuration or only given key value
144
     *
145
     * @param null|string $key
146
     * @return array|mixed
147
     */
148 3
    public function getOption($key = null)
149
    {
150 3
        if (is_null($key)) {
151 1
            return $this->defaultParams;
152
        }
153
154 3
        return $this->defaultParams[$key];
155
    }
156
157
    /**
158
     * @return string
159
     */
160 1
    public function getLastMessage()
161
    {
162 1
        return $this->message;
163
    }
164
165
    /**
166
     * recurrent function to convert array into message
167
     *
168
     * @param string|array $message
169
     * @param string $indent
170
     * @return $this
171
     * @throws \Psr\Log\InvalidArgumentException
172
     */
173 9
    protected function buildMessage($message, $indent = '')
174
    {
175 9
        switch (true) {
176 9
            case is_object($message) && method_exists($message, '__toString'):
177 9
            case is_string($message):
178 6
                $this->message = $message . PHP_EOL;
0 ignored issues
show
Bug introduced by
Are you sure $message of type object|string|array can be used in concatenation? ( Ignorable by Annotation )

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

178
                $this->message = /** @scrutinizer ignore-type */ $message . PHP_EOL;
Loading history...
179 6
                break;
180
181 3
            case is_array($message):
182 2
                foreach ($message as $key => $value) {
183 2
                    $this->processMessage($key, $value, $indent);
184 2
                }
185 2
                break;
186
187 1
            default:
188 1
                throw new InvalidArgumentException(
189
                    'Incorrect message type. Must be string, array or object with __toString method.'
190 1
                );
191
                break;
192 1
        }
193
194 8
        return $this;
195
    }
196
197
    /**
198
     * @param string $key
199
     * @param mixed $value
200
     * @param string $indent
201
     * @return $this
202
     */
203 2
    protected function processMessage($key, $value, $indent)
204
    {
205 2
        if (is_int($key)) {
206 1
            $key = '- ';
207 1
        } else {
208 2
            $key = '- ' . $key . ': ';
209
        }
210
211 2
        if (is_array($value)) {
212 1
            $indent .= '    ';
213 1
            $this->message .= $key . PHP_EOL;
214 1
            $this->buildMessage($value, $indent);
215 1
        } else {
216 2
            $this->message .= $indent . $key . $value . PHP_EOL;
217
        }
218
219 2
        return $this;
220
    }
221
}
222