Completed
Branch master (5c1b13)
by Markus
184:11 queued 119:40
created

ExceptionStrategy::setExceptionTemplate()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 5
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
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\Http\ExceptionStrategy
9
 * @license    MIT License {@link /docs/LICENSE}
10
 * @copyright  Copyright (c) 2016, Bright Answer OÜ
11
 */
12
13
namespace ZendSentry\Mvc\View\Http;
14
15
use Zend\EventManager\AbstractListenerAggregate;
16
use Zend\EventManager\EventManagerInterface;
17
use Zend\Http\Response as HttpResponse;
18
use Zend\Mvc\Application;
19
use Zend\Mvc\MvcEvent;
20
use Zend\Stdlib\ResponseInterface as Response;
21
use Zend\View\Model\ViewModel;
22
23
/**
24
 * For the moment, this is just an augmented copy of the default ZF ExceptionStrategy
25
 * This is on purpose despite the duplication of code until the module stabilizes and it's clear what need exactly
26
 *
27
 * @package    ZendSentry\Mvc\View\Http\ExceptionStrategy
28
 */
29
class ExceptionStrategy extends AbstractListenerAggregate
30
{
31
    /**
32
     * Display exceptions?
33
     * @var bool
34
     */
35
    protected $displayExceptions = false;
36
37
    /**
38
     * Default Exception Message
39
     * @var string
40
     */
41
    protected $defaultExceptionMessage = 'Oh no. Something went wrong, but we have been notified. If you are testing, tell us your eventID: %s';
42
43
    /**
44
     * Name of exception template
45
     * @var string
46
     */
47
    protected $exceptionTemplate = 'error';
48
49
    /**
50
     * {@inheritDoc}
51
     */
52
    public function attach(EventManagerInterface $events, $priority = 1)
53
    {
54
        $this->listeners[] = $events->attach(MvcEvent::EVENT_DISPATCH_ERROR, [$this, 'prepareExceptionViewModel']);
55
        $this->listeners[] = $events->attach(MvcEvent::EVENT_RENDER_ERROR, [$this, 'prepareExceptionViewModel']);
56
    }
57
58
    /**
59
     * Flag: display exceptions in error pages?
60
     *
61
     * @param  bool $displayExceptions
62
     * @return ExceptionStrategy
63
     */
64
    public function setDisplayExceptions($displayExceptions): ExceptionStrategy
65
    {
66
        $this->displayExceptions = (bool) $displayExceptions;
67
        return $this;
68
    }
69
70
    /**
71
     * Should we display exceptions in error pages?
72
     *
73
     * @return bool
74
     */
75
    public function displayExceptions(): bool
76
    {
77
        return $this->displayExceptions;
78
    }
79
80
    /**
81
     * Set the default exception message
82
     * @param string $defaultExceptionMessage
83
     * @return self
84
     */
85
    public function setDefaultExceptionMessage($defaultExceptionMessage): self
86
    {
87
        $this->defaultExceptionMessage = $defaultExceptionMessage;
88
        return $this;
89
    }
90
91
    /**
92
     * Set the exception template
93
     *
94
     * @param  string $exceptionTemplate
95
     * @return ExceptionStrategy
96
     */
97
    public function setExceptionTemplate($exceptionTemplate): ExceptionStrategy
98
    {
99
        $this->exceptionTemplate = (string) $exceptionTemplate;
100
        return $this;
101
    }
102
103
    /**
104
     * Retrieve the exception template
105
     *
106
     * @return string
107
     */
108
    public function getExceptionTemplate(): string
109
    {
110
        return $this->exceptionTemplate;
111
    }
112
113
    /**
114
     * Create an exception view model, and set the HTTP status code
115
     *
116
     * @param  MvcEvent $e
117
     * @return void
118
     */
119
    public function prepareExceptionViewModel(MvcEvent $e): void
120
    {
121
        // Do nothing if no error in the event
122
        $error = $e->getError();
123
        if (empty($error)) {
124
            return;
125
        }
126
127
        // Do nothing if the result is a response object
128
        $result = $e->getResult();
129
        if ($result instanceof Response) {
130
            return;
131
        }
132
133
        // Proceed to showing an error page with or without exception
134
        switch ($error) {
135
            case Application::ERROR_CONTROLLER_NOT_FOUND:
136
            case Application::ERROR_CONTROLLER_INVALID:
137
            case Application::ERROR_ROUTER_NO_MATCH:
138
                // Specifically not handling these
139
                return;
140
141
            case Application::ERROR_EXCEPTION:
142
            default:
143
                // check if there really is an exception
144
                // ZF also throws normal errors, for example: error-route-unauthorized
145
                // if there is no exception we have nothing to log
146
                if ($e->getParam('exception') == null) {
147
                    return;
148
                }
149
150
                // Log exception to sentry by triggering an exception event
151
                $eventID = $e->getApplication()->getEventManager()->trigger('logException', $this, ['exception' => $e->getParam('exception')]);
152
153
                $model = new ViewModel(
154
                    [
155
                    'message'            => sprintf($this->defaultExceptionMessage, $eventID->last()),
156
                    'exception'          => $e->getParam('exception'),
157
                    'display_exceptions' => $this->displayExceptions(),
158
                    ]
159
                );
160
                $model->setTemplate($this->getExceptionTemplate());
161
                $e->setResult($model);
162
163
                $response = $e->getResponse();
164
                if (!$response) {
165
                    $response = new HttpResponse();
166
                    $response->setStatusCode(500);
167
                    $e->setResponse($response);
168
                } else {
169
                    $statusCode = $response->getStatusCode();
170
                    if ($statusCode === 200) {
171
                        $response->setStatusCode(500);
172
                    }
173
                }
174
175
                break;
176
        }
177
    }
178
}