Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
54 / 54
100.00% covered (success)
100.00%
8 / 8
CRAP
100.00% covered (success)
100.00%
1 / 1
ExceptionHandler
100.00% covered (success)
100.00%
54 / 54
100.00% covered (success)
100.00%
8 / 8
22
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 addException
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 hasExceptions
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getExceptions
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 prepare
100.00% covered (success)
100.00%
13 / 13
100.00% covered (success)
100.00%
1 / 1
3
 prepareHeaderAsString
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 prepareAsString
100.00% covered (success)
100.00%
14 / 14
100.00% covered (success)
100.00%
1 / 1
3
 log
100.00% covered (success)
100.00%
18 / 18
100.00% covered (success)
100.00%
1 / 1
10
1<?php
2/**
3 * Pop PHP Framework (http://www.popphp.org/)
4 *
5 * @link       https://github.com/popphp/popphp-framework
6 * @author     Nick Sagona, III <dev@nolainteractive.com>
7 * @copyright  Copyright (c) 2009-2024 NOLA Interactive, LLC. (http://www.nolainteractive.com)
8 * @license    http://www.popphp.org/license     New BSD License
9 */
10
11/**
12 * @namespace
13 */
14namespace Pop\Debug\Handler;
15
16use Pop\Log\Logger;
17
18/**
19 * Debug exception handler class
20 *
21 * @category   Pop
22 * @package    Pop\Debug
23 * @author     Nick Sagona, III <dev@nolainteractive.com>
24 * @copyright  Copyright (c) 2009-2024 NOLA Interactive, LLC. (http://www.nolainteractive.com)
25 * @license    http://www.popphp.org/license     New BSD License
26 * @version    2.2.0
27 */
28class ExceptionHandler extends AbstractHandler
29{
30
31    /**
32     * Verbose flag
33     * @var bool
34     */
35    protected bool $verbose = false;
36
37    /**
38     * Exceptions
39     * @var array
40     */
41    protected array $exceptions = [];
42
43    /**
44     * Constructor
45     *
46     * Instantiate a handler object
47     *
48     * @param bool    $verbose
49     * @param ?string $name
50     * @param ?Logger $logger
51     * @param array   $loggingParams
52     */
53    public function __construct(bool $verbose = false, ?string $name = null, ?Logger $logger = null, array $loggingParams = [])
54    {
55        parent::__construct($name, $logger, $loggingParams);
56        $this->verbose = $verbose;
57    }
58
59    /**
60     * Add exception
61     *
62     * @param  \Exception $exception
63     * @return ExceptionHandler
64     */
65    public function addException(\Exception $exception): ExceptionHandler
66    {
67        $this->exceptions[] = ['exception' => $exception, 'timestamp' => (string)microtime(true)];
68        return $this;
69    }
70
71    /**
72     * Determine if the handler has exceptions
73     *
74     * @return bool
75     */
76    public function hasExceptions(): bool
77    {
78        return (count($this->exceptions) > 0);
79    }
80
81    /**
82     * Get exceptions
83     *
84     * @return array
85     */
86    public function getExceptions(): array
87    {
88        return $this->exceptions;
89    }
90
91    /**
92     * Prepare handler data for storage
93     *
94     * @param  bool $simpleData
95     * @return array
96     */
97    public function prepare(bool $simpleData = false): array
98    {
99        if ($simpleData) {
100            $exceptions = [];
101            foreach ($this->exceptions as $exception) {
102                $exceptions[] = [
103                    'class'   => get_class($exception['exception']),
104                    'code'    => $exception['exception']->getCode(),
105                    'line'    => $exception['exception']->getLine(),
106                    'file'    => $exception['exception']->getFile(),
107                    'message' => $exception['exception']->getMessage(),
108                    'trace'   => $exception['exception']->getTrace()
109                ];
110            }
111            return $exceptions;
112        } else {
113            return $this->exceptions;
114        }
115    }
116
117    /**
118     * Prepare header string
119     *
120     * @return string
121     */
122    public function prepareHeaderAsString(): string
123    {
124        $string  = ((!empty($this->name)) ? $this->name . ' ' : '') . 'Exception Handler';
125        $string .= PHP_EOL . str_repeat('=', strlen($string)) . PHP_EOL;
126
127        return $string;
128    }
129
130    /**
131     * Prepare handler data as string
132     *
133     * @return string
134     */
135    public function prepareAsString(): string
136    {
137        $string = '';
138
139        foreach ($this->exceptions as $exception) {
140            if ($this->verbose) {
141                $string .= number_format($exception['timestamp'], 5, '.', '') . PHP_EOL .
142                    "Class: " . get_class($exception['exception']) . PHP_EOL .
143                    "Code: " . $exception['exception']->getCode() . PHP_EOL .
144                    "Line: " . $exception['exception']->getLine() . PHP_EOL .
145                    "File: " . $exception['exception']->getFile() . PHP_EOL .
146                    "Message: " . $exception['exception']->getMessage() . PHP_EOL .
147                    "Trace: " . $exception['exception']->getTraceAsString() . PHP_EOL;
148            } else {
149                $string .= number_format($exception['timestamp'], 5, '.', '') . "\t" . get_class($exception['exception']) .
150                    "\t" . $exception['exception']->getMessage() . PHP_EOL;
151            }
152
153        }
154        $string .= PHP_EOL;
155
156        return $string;
157    }
158
159    /**
160     * Trigger handler logging
161     *
162     * @throws Exception
163     * @return void
164     */
165    public function log(): void
166    {
167        if (($this->hasLogger()) && ($this->hasLoggingParams())) {
168            $logLevel   = $this->loggingParams['level'] ?? null;
169            $useContext = $this->loggingParams['context'] ?? null;
170
171            if ($logLevel !== null) {
172                $context          = [];
173                $exceptionClasses = [];
174                foreach ($this->exceptions as $exception) {
175                    $exceptionClasses[] = get_class($exception['exception']);
176                }
177
178                $message = (count($exceptionClasses) > 1) ?
179                    'The following (' . count($exceptionClasses) . ') exceptions have been thrown: ' . implode(', ', $exceptionClasses) :
180                    'The following (1) exception has been thrown: ' . implode(', ', $exceptionClasses);
181
182                if (!empty($useContext)) {
183                    $context['exceptions'] = (($useContext !== null) && (strtolower($useContext) == 'text')) ?
184                        $this->prepareAsString() : $this->prepare(true);
185
186                    if (is_string($useContext)) {
187                        $context['format'] = $useContext;
188                    }
189                }
190
191                $this->logger->log($logLevel, $message, $context);
192            } else {
193                throw new Exception('Error: The log level parameter was not set.');
194            }
195        }
196    }
197
198}