ExceptionStrategy::prepareExceptionViewModel()   C
last analyzed

Complexity

Conditions 10
Paths 11

Size

Total Lines 70

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 70
rs 6.7878
c 0
b 0
f 0
cc 10
nc 11
nop 1

How to fix   Long Method    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
/**
4
 * Bright Answer ZendSentry
5
 *
6
 * This source file is part of the Bright Answer ZendSentry package
7
 *
8
 * @package    ZendSentry\Mvc\View\Console\ExceptionStrategy
9
 * @license    MIT License {@link /docs/LICENSE}
10
 * @copyright  Copyright (c) 2016, Bright Answer OÜ
11
 */
12
13
namespace ZendSentry\Mvc\View\Console;
14
15
use Zend\EventManager\AbstractListenerAggregate;
16
use Zend\EventManager\EventManagerInterface;
17
use Zend\Mvc\Application;
18
use Zend\Mvc\MvcEvent;
19
use Zend\Stdlib\ResponseInterface;
20
use Zend\View\Model\ConsoleModel;
21
22
/**
23
 * For the moment, this is just an augmented copy of the default ZF ExceptionStrategy
24
 * This is on purpose despite the duplication of code until the module stabilizes and it's clear what need exactly
25
 *
26
 * @package    ZendSentry\Mvc\View\Console\ExceptionStrategy
27
 */
28
class ExceptionStrategy extends AbstractListenerAggregate
29
{
30
    /**
31
     * Display exceptions?
32
     *
33
     * @var bool
34
     */
35
    protected $displayExceptions = false;
36
37
    /**
38
     * Default Exception Message
39
     *
40
     * @var string
41
     */
42
    protected $defaultExceptionMessage = "Oh no. Something went wrong, but we have been notified.\n";
43
44
    /**
45
     * A template for message to show in console when an exception has occurred.
46
     *
47
     * @var string|callable
48
     */
49
    protected $message = <<<EOT
50
    ======================================================================
51
       The application has thrown an exception!
52
    ======================================================================
53
     :className
54
     :message
55
    ----------------------------------------------------------------------
56
    :file::line
57
    :stack
58
    ======================================================================
59
       Previous Exception(s):
60
    ======================================================================
61
    :previous
62
63
EOT;
64
65
    /**
66
     * {@inheritDoc}
67
     */
68
    public function attach(EventManagerInterface $events, $priority = 1)
69
    {
70
        $this->listeners[] = $events->attach(MvcEvent::EVENT_DISPATCH_ERROR, [$this, 'prepareExceptionViewModel']);
71
        $this->listeners[] = $events->attach(MvcEvent::EVENT_RENDER_ERROR, [$this, 'prepareExceptionViewModel']);
72
    }
73
74
    /**
75
     * Flag: display exceptions in error pages?
76
     *
77
     * @param  bool $displayExceptions
78
     *
79
     * @return ExceptionStrategy
80
     */
81
    public function setDisplayExceptions($displayExceptions): ExceptionStrategy
82
    {
83
        $this->displayExceptions = (bool)$displayExceptions;
84
        return $this;
85
    }
86
87
    /**
88
     * Should we display exceptions in error pages?
89
     *
90
     * @return bool
91
     */
92
    public function displayExceptions(): bool
93
    {
94
        return $this->displayExceptions;
95
    }
96
97
    /**
98
     * Get current template for message that will be shown in Console.
99
     *
100
     * @return string
101
     */
102
    public function getMessage(): string
103
    {
104
        return $this->message;
105
    }
106
107
    /**
108
     * Set template for message that will be shown in Console.
109
     * The message can be a string (template) or a callable (i.e. a closure).
110
     *
111
     * The closure is expected to return a string and will be called with 2 parameters:
112
     *        Exception $exception           - the exception being thrown
113
     *        boolean   $displayExceptions   - whether to display exceptions or not
114
     *
115
     * If the message is a string, one can use the following template params:
116
     *
117
     *   :className   - full class name of exception instance
118
     *   :message     - exception message
119
     *   :code        - exception code
120
     *   :file        - the file where the exception has been thrown
121
     *   :line        - the line where the exception has been thrown
122
     *   :stack       - full exception stack
123
     *
124
     * @param string|callable $message
125
     *
126
     * @return ExceptionStrategy
127
     */
128
    public function setMessage($message): ExceptionStrategy
129
    {
130
        $this->message = $message;
131
        return $this;
132
    }
133
134
    /**
135
     * Set the default exception message
136
     *
137
     * @param string $defaultExceptionMessage
138
     *
139
     * @return self
140
     */
141
    public function setDefaultExceptionMessage($defaultExceptionMessage): self
142
    {
143
        $this->defaultExceptionMessage = $defaultExceptionMessage;
144
        return $this;
145
    }
146
147
    /**
148
     * Create an exception view model, and set the console status code
149
     *
150
     * @param  MvcEvent $e
151
     *
152
     * @return void
153
     */
154
    public function prepareExceptionViewModel(MvcEvent $e)
155
    {
156
        // Do nothing if no error in the event
157
        $error = $e->getError();
158
        if (empty($error)) {
159
            return;
160
        }
161
162
        // Do nothing if the result is a response object
163
        $result = $e->getResult();
164
        if ($result instanceof ResponseInterface) {
165
            return;
166
        }
167
168
        // Proceed to showing an error page with or without exception
169
        switch ($error) {
170
            case Application::ERROR_CONTROLLER_NOT_FOUND:
171
            case Application::ERROR_CONTROLLER_INVALID:
172
            case Application::ERROR_ROUTER_NO_MATCH:
173
                // Specifically not handling these
174
                return;
175
176
            case Application::ERROR_EXCEPTION:
177
            default:
178
                // Prepare error message
179
                $exception = $e->getParam('exception');
180
181
                // Log exception to sentry by triggering an exception event
182
                $e->getApplication()->getEventManager()->trigger('logException', $this, ['exception' => $exception]);
183
184
                if (\is_callable($this->message)) {
185
                    $callback = $this->message;
186
                    $message  = (string)$callback($exception, $this->displayExceptions);
187
                } elseif ($this->displayExceptions && $exception instanceof \Exception) {
188
                    /* @var $exception \Exception */
189
                    $message = str_replace(
190
                        [
191
                            ':className',
192
                            ':message',
193
                            ':code',
194
                            ':file',
195
                            ':line',
196
                            ':stack',
197
                            ':previous',
198
                        ], [
199
                        \get_class($exception),
200
                        $exception->getMessage(),
201
                        $exception->getCode(),
202
                        $exception->getFile(),
203
                        $exception->getLine(),
204
                        $exception->getTraceAsString(),
205
                        $exception->getPrevious(),
206
                    ],
207
                        $this->message
208
                    );
209
                } else {
210
                    $message = $this->defaultExceptionMessage;
211
                }
212
213
                // Prepare view model
214
                $model = new ConsoleModel();
215
                $model->setResult($message);
216
                $model->setErrorLevel(1);
217
218
                // Inject it into MvcEvent
219
                $e->setResult($model);
220
221
                break;
222
        }
223
    }
224
}