Completed
Pull Request — master (#48)
by Markus
03:54 queued 02:21
created

ExceptionStrategy::detach()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 8
rs 9.4285
cc 3
eloc 4
nc 3
nop 1
1
<?php
2
3
/**
4
 * cloud solutions ZendSentry
5
 *
6
 * This source file is part of the cloud solutions ZendSentry package
7
 *
8
 * @package    ZendSentry\Mvc\View\Console\ExceptionStrategy
9
 * @license    New BSD License {@link /docs/LICENSE}
10
 * @copyright  Copyright (c) 2013, cloud solutions OÜ
11
 */
12
13
namespace ZendSentry\Mvc\View\Console;
14
15
use Zend\EventManager\EventManagerInterface;
16
use Zend\EventManager\ListenerAggregateInterface;
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 implements ListenerAggregateInterface
29
{
30
    /**
31
     * Display exceptions?
32
     * @var bool
33
     */
34
    protected $displayExceptions = false;
35
36
    /**
37
     * Default Exception Message
38
     * @var string
39
     */
40
    protected $defaultExceptionMessage = "Oh no. Something went wrong, but we have been notified.\n";
41
42
    /**
43
     * A template for message to show in console when an exception has occurred.
44
     * @var string|callable
45
     */
46
    protected $message = <<<EOT
47
    ======================================================================
48
       The application has thrown an exception!
49
    ======================================================================
50
     :className
51
     :message
52
    ----------------------------------------------------------------------
53
    :file::line
54
    :stack
55
    ======================================================================
56
       Previous Exception(s):
57
    ======================================================================
58
    :previous
59
60
EOT;
61
62
    /**
63
     * @var \Zend\Stdlib\CallbackHandler[]
64
     */
65
    protected $listeners = array();
66
67
    /**
68
     * Attach the aggregate to the specified event manager
69
     *
70
     * @param  EventManagerInterface $events
71
     * @return void
72
     */
73
    public function attach(EventManagerInterface $events)
74
    {
75
        $this->listeners[] = $events->attach(MvcEvent::EVENT_DISPATCH_ERROR, array($this, 'prepareExceptionViewModel'));
76
        $this->listeners[] = $events->attach(MvcEvent::EVENT_RENDER_ERROR, array($this, 'prepareExceptionViewModel'));
77
    }
78
79
    /**
80
     * Detach aggregate listeners from the specified event manager
81
     *
82
     * @param  EventManagerInterface $events
83
     * @return void
84
     */
85
    public function detach(EventManagerInterface $events)
86
    {
87
        foreach ($this->listeners as $index => $listener) {
88
            if ($events->detach($listener)) {
89
                unset($this->listeners[$index]);
90
            }
91
        }
92
    }
93
94
    /**
95
     * Flag: display exceptions in error pages?
96
     *
97
     * @param  bool $displayExceptions
98
     * @return ExceptionStrategy
99
     */
100
    public function setDisplayExceptions($displayExceptions)
101
    {
102
        $this->displayExceptions = (bool) $displayExceptions;
103
        return $this;
104
    }
105
106
    /**
107
     * Should we display exceptions in error pages?
108
     *
109
     * @return bool
110
     */
111
    public function displayExceptions()
112
    {
113
        return $this->displayExceptions;
114
    }
115
    
116
    /**
117
     * Get current template for message that will be shown in Console.
118
     *
119
     * @return string
1 ignored issue
show
Documentation introduced by
Should the return type not be callable?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
120
     */
121
    public function getMessage()
122
    {
123
        return $this->message;
124
    }
125
    
126
    /**
127
     * Set the default exception message
128
     * @param string $defaultExceptionMessage
129
     */
130
    public function setDefaultExceptionMessage($defaultExceptionMessage)
131
    {
132
        $this->defaultExceptionMessage = $defaultExceptionMessage;
133
        return $this;
134
    }
135
136
    /**
137
     * Set template for message that will be shown in Console.
138
     * The message can be a string (template) or a callable (i.e. a closure).
139
     *
140
     * The closure is expected to return a string and will be called with 2 parameters:
141
     *        Exception $exception           - the exception being thrown
142
     *        boolean   $displayExceptions   - whether to display exceptions or not
143
     *
144
     * If the message is a string, one can use the following template params:
145
     *
146
     *   :className   - full class name of exception instance
147
     *   :message     - exception message
148
     *   :code        - exception code
149
     *   :file        - the file where the exception has been thrown
150
     *   :line        - the line where the exception has been thrown
151
     *   :stack       - full exception stack
152
     *
153
     * @param string|callable  $message
154
     * @return ExceptionStrategy
155
     */
156
    public function setMessage($message)
157
    {
158
        $this->message = $message;
159
        return $this;
160
    }
161
162
    /**
163
     * Create an exception view model, and set the console status code
164
     *
165
     * @param  MvcEvent $e
166
     * @return void
167
     */
168
    public function prepareExceptionViewModel(MvcEvent $e)
169
    {
170
        // Do nothing if no error in the event
171
        $error = $e->getError();
172
        if (empty($error)) {
173
            return;
174
        }
175
176
        // Do nothing if the result is a response object
177
        $result = $e->getResult();
178
        if ($result instanceof ResponseInterface) {
1 ignored issue
show
Bug introduced by
The class Zend\Stdlib\ResponseInterface does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
179
            return;
180
        }
181
182
        // Proceed to showing an error page with or without exception
183
        switch ($error) {
184
            case Application::ERROR_CONTROLLER_NOT_FOUND:
185
            case Application::ERROR_CONTROLLER_INVALID:
186
            case Application::ERROR_ROUTER_NO_MATCH:
187
                // Specifically not handling these
188
                return;
189
190
            case Application::ERROR_EXCEPTION:
191
            default:
192
                // Prepare error message
193
                $exception = $e->getParam('exception');
194
                
195
                // Log exception to sentry by triggering an exception event
196
                $e->getApplication()->getEventManager()->trigger('logException', $this, array('exception' => $exception));
197
198
                if (is_callable($this->message)) {
199
                    $callback = $this->message;
200
                    $message = (string) $callback($exception, $this->displayExceptions);
201
                } elseif ($this->displayExceptions && $exception instanceof \Exception) {
202
                    /* @var $exception \Exception */
203
                    $message = str_replace(
204
                        array(
205
                            ':className',
206
                            ':message',
207
                            ':code',
208
                            ':file',
209
                            ':line',
210
                            ':stack',
211
                            ':previous',
212
                        ), array(
213
                            get_class($exception),
214
                            $exception->getMessage(),
215
                            $exception->getCode(),
216
                            $exception->getFile(),
217
                            $exception->getLine(),
218
                            $exception->getTraceAsString(),
219
                            $exception->getPrevious(),
220
                        ),
221
                        $this->message
222
                    );
223
                } else {
224
                    $message = $this->defaultExceptionMessage;
225
                }
226
227
                // Prepare view model
228
                $model = new ConsoleModel();
229
                $model->setResult($message);
230
                $model->setErrorLevel(1);
231
232
                // Inject it into MvcEvent
233
                $e->setResult($model);
234
235
                break;
236
        }
237
    }
238
}
1 ignored issue
show
Coding Style introduced by
As per coding style, files should not end with a newline character.

This check marks files that end in a newline character, i.e. an empy line.

Loading history...
239