Passed
Push — main ( 915a08...2be97f )
by Sammy
01:45
created

LogLaddy::changes()   C

Complexity

Conditions 16
Paths 96

Size

Total Lines 50
Code Lines 33

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 16
eloc 33
c 2
b 0
f 0
nc 96
nop 1
dl 0
loc 50
rs 5.5666

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/*
3
 * LogLaddy
4
 *
5
 * I carry a log – yes. Is it funny to you? It is not to me.
6
 * Behind all things are reasons. Reasons can even explain the absurd.
7
 *
8
 * LogLaddy manages error reporting and crud tracking
9
 * PSR-3 Compliant, where NOTICE is to be read as SUCCESS
10
 */
11
12
namespace HexMakina\kadro\Logger;
13
14
class LogLaddy implements LoggerInterface
15
{
16
  use \Psr\Log\LoggerTrait; // PSR implementation
17
  use \HexMakina\Debugger\Debugger;
18
19
  const REPORTING_USER = 'user_messages';
20
  const INTERNAL_ERROR = 'error';
21
  const USER_EXCEPTION = 'exception';
22
  const LOG_LEVEL_SUCCESS = 'ok';
23
24
  private $has_halting_messages = false;
25
26
  /**
27
   * Everything went fine, which is always nice.
28
   * LogLaddy, being born yesterday, is a bit more optimistic than PSRLog
29
   * @param string $message
30
   * @param array  $context
31
   *
32
   * @return void
33
   */
34
  public function nice($message, array $context = array())
35
  {
36
      $this->log(LogLevel::NICE, $message, $context);
37
  }
38
39
  // ----------------------------------------------------------- Static handlers for error, use set_error_handler('\HexMakina\kadro\Logger\LogLaddy::error_handler')
40
  public static function error_handler($level, $message, $file = '', $line = 0)
41
  {
42
    $loglevel = self::map_error_level_to_log_level($level);
43
44
    (new LogLaddy())->$loglevel($message, ['file' => $file, 'line' => $line, 'trace' => debug_backtrace()]);
45
  }
46
47
  // ----------------------------------------------------------- Static handlers for throwables, use set_exception_handler('\HexMakina\kadro\Logger\LogLaddy::exception_handler');
48
  public static function exception_handler($throwable)
49
  {
50
    $context['text'] = $throwable->getMessage();
0 ignored issues
show
Comprehensibility Best Practice introduced by
$context was never initialized. Although not strictly required by PHP, it is generally a good practice to add $context = array(); before regardless.
Loading history...
51
    $context['file'] = $throwable->getFile();
52
    $context['line'] = $throwable->getLine();
53
    $context['code'] = $throwable->getCode();
54
    $context['class'] = get_class($throwable);
55
    $context['trace'] = $throwable->getTrace();
56
57
    if(is_subclass_of($throwable, 'Error') || get_class($throwable) === 'Error')
58
      (new LogLaddy())->alert(self::INTERNAL_ERROR, $context);
59
    elseif(is_subclass_of($throwable, 'Exception') || get_class($throwable) === 'Exception')
60
      (new LogLaddy())->notice(self::USER_EXCEPTION, $context);
61
    else
62
    {
63
      die('This Throwable is not an Error or an Exception. This is unfortunate.');
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
64
    }
65
66
  }
67
68
  public function system_halted($level)
69
  {
70
    switch($level)
71
    {
72
      case LogLevel::ERROR:
73
      case LogLevel::CRITICAL:
74
      case LogLevel::ALERT:
75
      case LogLevel::EMERGENCY:
76
        return true;
77
    }
78
    return false;
79
  }
80
81
  // ----------------------------------------------------------- Implementation of LoggerInterface::log(), all other methods are in LoggerTrait
82
83
  public function log($level, $message, array $context = [])
84
  {
85
86
    $display_error = null;
87
88
    // --- Handles Throwables (exception_handler())
89
    if($message==self::INTERNAL_ERROR || $message== self::USER_EXCEPTION)
90
    {
91
      $this->has_halting_messages = true;
92
      $display_error = \HexMakina\Debugger\Debugger::format_throwable_message($context['class'], $context['code'], $context['file'], $context['line'], $context['text']);
93
      error_log($display_error);
94
      $display_error.= \HexMakina\Debugger\Debugger::format_trace($context['trace'], false);
95
      self::HTTP_500($display_error);
96
    }
97
    elseif($this->system_halted($level)) // analyses error level
98
    {
99
      $display_error = sprintf(PHP_EOL.'%s in file %s:%d'.PHP_EOL.'%s', $level, \HexMakina\Debugger\Debugger::format_file($context['file']), $context['line'], $message);
100
      error_log($display_error);
101
      $display_error.= \HexMakina\Debugger\Debugger::format_trace($context['trace'], false);
102
      self::HTTP_500($display_error);
103
    }
104
    else
105
    {// --- Handles user messages, through SESSION storage
106
      $this->report_to_user($level, $message, $context);
107
    }
108
109
    // --- may of may not show errors, depends on environment
110
111
  }
112
113
  public static function HTTP_500($display_error)
114
  {
115
    \HexMakina\Debugger\Debugger::display_errors($display_error);
116
    http_response_code(500);
117
    die;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
118
  }
119
  // ----------------------------------------------------------- Allows to know if script must be halted after fatal error
120
  // TODO NEH.. not good
121
  public function has_halting_messages()
122
  {
123
    return $this->has_halting_messages === true;
124
  }
125
126
  // ----------------------------------------------------------- User messages
127
128
  // ----------------------------------------------------------- User messages:add one
129
  /* Before decoupling with Lezer
130
  public function report_to_user($level, $message, $context = [])
131
  {
132
    {
133
    if(defined("L::$message")) // message isa translatable code
134
      foreach($context as $i => $param) // message need translated params
135
        if(defined("L::$param"))
136
          $context[$i] = L($param);
137
138
      $message = L($message, $context);
139
    }
140
141
    // $_SESSION[self::REPORTING_USER][$level][] = date('Y-m-d H:i:s.u').' '.$message;
142
    // ddt($message);
143
    $_SESSION[self::REPORTING_USER] = $_SESSION[self::REPORTING_USER] ?? [];
144
    $_SESSION[self::REPORTING_USER][$level] = $_SESSION[self::REPORTING_USER][$level] ?? [];
145
146
    // $_SESSION[self::REPORTING_USER][$level][] = $message; // this
147
    $_SESSION[self::REPORTING_USER][$level][] = [$message, $context];
148
  }
149
*/
150
  // ----------------------------------------------------------- User messages:add one
151
  public function report_to_user($level, $message, $context = [])
152
  {
153
    if(!isset($_SESSION[self::REPORTING_USER]))
154
      $_SESSION[self::REPORTING_USER] = [];
155
156
    if(!isset($_SESSION[self::REPORTING_USER][$level]))
157
      $_SESSION[self::REPORTING_USER][$level] = [];
158
159
    $_SESSION[self::REPORTING_USER][$level][] = [$message, $context];
160
  }
161
162
  // ----------------------------------------------------------- User messages:get all
163
  public function get_user_report()
164
  {
165
    return $_SESSION[self::REPORTING_USER] ?? [];
166
  }
167
168
  // ----------------------------------------------------------- User messages:reset all
169
  public function clean_user_report()
170
  {
171
    unset($_SESSION[self::REPORTING_USER]);
172
  }
173
174
  // ----------------------------------------------------------- Error level mapping from \Psr\Log\LogLevel.php & http://php.net/manual/en/errorfunc.constants.php
175
  /** Error level meaning , from \Psr\Log\LogLevel.php
176
   * const EMERGENCY = 'emergency'; // System is unusable.
177
   * const ALERT     = 'alert'; // Action must be taken immediately, Example: Entire website down, database unavailable, etc.
178
   * const CRITICAL  = 'critical';  // Application component unavailable, unexpected exception.
179
   * const ERROR     = 'error'; // Run time errors that do not require immediate action
180
   * const WARNING   = 'warning'; // Exceptional occurrences that are not errors, undesirable things that are not necessarily wrong
181
   * const NOTICE    = 'notice'; // Normal but significant events.
182
   * const INFO      = 'info'; // Interesting events. User logs in, SQL logs.
183
   * const DEBUG     = 'debug'; // Detailed debug information.
184
  */
185
  private static function map_error_level_to_log_level($level) : string
186
  {
187
    // http://php.net/manual/en/errorfunc.constants.php
188
    $m=[];
189
190
    $m[E_ERROR]=$m[E_PARSE]=$m[E_CORE_ERROR]=$m[E_COMPILE_ERROR]=$m[E_USER_ERROR]=$m[E_RECOVERABLE_ERROR]=LogLevel::ALERT;
191
    $m[1]=$m[4]=$m[16]=$m[64]=$m[256]=$m[4096]=LogLevel::ALERT;
192
193
    $m[E_WARNING]=$m[E_CORE_WARNING]=$m[E_COMPILE_WARNING]=$m[E_USER_WARNING]=LogLevel::CRITICAL;
194
    $m[2]=$m[32]=$m[128]=$m[512]=LogLevel::CRITICAL;
195
196
    $m[E_NOTICE]=$m[E_USER_NOTICE]=LogLevel::ERROR;
197
    $m[8]=$m[1024]=LogLevel::ERROR;
198
199
    $m[E_STRICT]=$m[E_DEPRECATED]=$m[E_USER_DEPRECATED]=$m[E_ALL]=LogLevel::DEBUG;
200
    $m[2048]=$m[8192]=$m[16384]=$m[32767]=LogLevel::DEBUG;
201
202
    if(isset($m[$level]))
203
      return $m[$level];
204
205
    throw new \Exception(__FUNCTION__."($level): $level is unknown");
206
  }
207
}
208