Completed
Pull Request — zf3-compat (#49)
by
unknown
02:02
created

Module.php (1 issue)

Labels
Severity

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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\Module
9
 * @license    New BSD License {@link /docs/LICENSE}
10
 * @copyright  Copyright (c) 2013, cloud solutions OÜ
11
 */
12
13
namespace ZendSentry;
14
15
use Zend\EventManager\EventManager;
16
use Zend\Mvc\MvcEvent;
17
use ZendSentry\Mvc\View\Http\ExceptionStrategy as SentryHttpStrategy;
18
use ZendSentry\Mvc\View\Console\ExceptionStrategy as SentryConsoleStrategy;
19
use Zend\Mvc\View\Http\ExceptionStrategy;
20
use Raven_Client as Raven;
21
use Zend\Log\Logger;
22
23
/**
24
 * Class Module
25
 *
26
 * @package ZendSentry
27
 */
28
class Module
29
{
30
    /**
31
     * Translates Zend Framework log levels to Raven log levels.
32
     */
33
    private $logLevels = array(
34
        7 => Raven::DEBUG,
35
        6 => Raven::INFO,
36
        5 => Raven::INFO,
37
        4 => Raven::WARNING,
38
        3 => Raven::ERROR,
39
        2 => Raven::FATAL,
40
        1 => Raven::FATAL,
41
        0 => Raven::FATAL,
42
    );
43
44
    /**
45
     * @var Raven $ravenClient
46
     */
47
    protected $ravenClient;
48
49
    /**
50
     * @var ZendSentry $zendSentry
51
     */
52
    protected $zendSentry;
53
54
    /**
55
     * @var $config
56
     */
57
    protected $config;
58
59
    /**
60
     * @var EventManager $eventManager
61
     */
62
    protected $eventManager;
63
64
    /**
65
     * @param MvcEvent $event
66
     */
67
    public function onBootstrap(MvcEvent $event)
68
    {
69
        // Setup RavenClient (provided by Sentry) and Sentry (provided by this module)
70
        $this->config = $event->getApplication()->getServiceManager()->get('Config');
71
72
        if (!$this->config['zend-sentry']['use-module']) {
73
            return;
74
        }
75
76
        if (isset($this->config['zend-sentry']['raven-config']) && is_array($this->config['zend-sentry']['raven-config'])) {
77
            $ravenConfig = $this->config['zend-sentry']['raven-config'];
78
        } else {
79
            $ravenConfig = array();
80
        }
81
82
        $sentryApiKey = $this->config['zend-sentry']['sentry-api-key'];
83
        $ravenClient = new Raven($sentryApiKey, $ravenConfig);
84
85
        // Register the RavenClient as a application wide service
86
        $event->getApplication()->getServiceManager()->setService('raven', $ravenClient);
87
        $this->ravenClient = $ravenClient;
88
        $this->zendSentry = new ZendSentry($ravenClient);
89
90
        // Get the eventManager and set it as a member for convenience
91
        $this->eventManager = $event->getApplication()->getEventManager();
92
93
        // If ZendSentry is configured to use the custom logger, attach the listener
94
        if ($this->config['zend-sentry']['attach-log-listener']) {
95
            $this->setupBasicLogging($event);
96
        }
97
98
        // If ZendSentry is configured to log exceptions, a few things need to be set up
99
        if ($this->config['zend-sentry']['handle-exceptions']) {
100
            $this->setupExceptionLogging($event);
101
        }
102
103
        // If ZendSentry is configured to log errors, register it as error handler
104
        if ($this->config['zend-sentry']['handle-errors']) {
105
            $errorReportingLevel = (isset($this->config['zend-sentry']['error-reporting'])) ? $this->config['zend-sentry']['error-reporting'] : -1;
106
            $this->zendSentry->registerErrorHandler($this->config['zend-sentry']['call-existing-error-handler'], $errorReportingLevel);
107
        }
108
109
        // If ZendSentry is configured to log shutdown errors, register it
110
        if ($this->config['zend-sentry']['handle-shutdown-errors']) {
111
            $this->zendSentry->registerShutdownFunction();
112
        }
113
114
        // If ZendSentry is configured to log Javascript errors, add needed scripts to the view
115
        if ($this->config['zend-sentry']['handle-javascript-errors']) {
116
            $this->setupJavascriptLogging($event);
117
        }
118
    }
119
120
    /**
121
     * @return array
122
     */
123
    public function getAutoloaderConfig()
124
    {
125
        return array('Zend\Loader\StandardAutoloader' => array('namespaces' => array(
126
            __NAMESPACE__ => __DIR__.'/src/'.__NAMESPACE__,
127
        )));
128
    }
129
130
    /**
131
     * @return mixed
132
     */
133
    public function getConfig()
134
    {
135
        return include __DIR__.'/config/module.config.php';
136
    }
137
138
    /**
139
     * Gives us the possibility to write logs to Sentry from anywhere in the application
140
     * Doesn't use the ZF compatible Log Writer because we want to return the Sentry event ID
141
     * ZF Logging doesn't provide the possibility to return values from writers
142
     *
143
     * @param MvcEvent $event
144
     */
145
    protected function setupBasicLogging(MvcEvent $event)
146
    {
147
        // Get the shared event manager and attach a logging listener for the log event on application level
148
        $sharedManager = $this->eventManager->getSharedManager();
149
        $raven = $this->ravenClient;
150
        $logLevels = $this->logLevels;
151
152
        $sharedManager->attach('*', 'log', function($event) use ($raven, $logLevels) {
153
            /** @var $event MvcEvent */
154
            if (is_object($event->getTarget())) {
155
                $target = get_class($event->getTarget());
156
            } else {
157
                $target = (string) $event->getTarget();
158
            }
159
            $message  = $event->getParam('message', 'No message provided');
160
            $priority = (int) $event->getParam('priority', Logger::INFO);
161
            $message  = sprintf('%s: %s', $target, $message);
162
            $tags     = $event->getParam('tags', array());
163
            $eventID = $raven->captureMessage($message, array(), array('tags' => $tags, 'level' => $logLevels[$priority]));
164
165
            return $eventID;
166
        }, 2);
167
    }
168
169
    /**
170
     * 1. Registers Sentry as exception handler
171
     * 2. Replaces the default ExceptionStrategy so Exception that are caught by Zend Framework can still be logged
172
     *
173
     * @param MvcEvent $event
174
     */
175
    protected function setupExceptionLogging(MvcEvent $event)
176
    {
177
        // Register Sentry as exception handler for exception that bubble up to the top
178
        $this->zendSentry->registerExceptionHandler($this->config['zend-sentry']['call-existing-exception-handler']);
179
180
        // Replace the default ExceptionStrategy with ZendSentry's strategy
181
        if ($event->getApplication()->getServiceManager()->has('HttpExceptionStrategy')) {
182
            /** @var $exceptionStrategy ExceptionStrategy */
183
            $exceptionStrategy = $event->getApplication()->getServiceManager()->get('HttpExceptionStrategy');
184
            $exceptionStrategy->detach($this->eventManager);
185
        }
186
187
        // Check if script is running in console
188
        $exceptionStrategy = (PHP_SAPI == 'cli') ? (new SentryConsoleStrategy()) : (new SentryHttpStrategy());
189
        $exceptionStrategy->attach($this->eventManager);
190
        $exceptionStrategy->setDisplayExceptions($this->config['zend-sentry']['display-exceptions']);
191
        $exceptionStrategy->setDefaultExceptionMessage($this->config['zend-sentry'][(PHP_SAPI == 'cli') ? 'default-exception-console-message' : 'default-exception-message']);
192
        if ($exceptionStrategy instanceof SentryHttpStrategy && isset($this->config['view_manager']['exception_template'])) {
193
            $exceptionStrategy->setExceptionTemplate($this->config['view_manager']['exception_template']);
1 ignored issue
show
The method setExceptionTemplate does only exist in ZendSentry\Mvc\View\Http\ExceptionStrategy, but not in ZendSentry\Mvc\View\Console\ExceptionStrategy.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
194
        }
195
        $ravenClient = $this->ravenClient;
196
197
        // Attach an exception listener for the ZendSentry exception strategy, can be triggered from anywhere else too
198
        $this->eventManager->getSharedManager()->attach('*', 'logException', function($event) use ($ravenClient) {
199
            /** @var $event MvcEvent */
200
            $exception = $event->getParam('exception');
201
            $tags = $event->getParam('tags', array());
202
            $eventID = $ravenClient->captureException($exception, array('tags' => $tags));
203
            return $eventID;
204
        });
205
    }
206
207
    /**
208
     * Adds the necessary javascript, tries to prepend
209
     *
210
     * @param MvcEvent $event
211
     */
212
    protected function setupJavascriptLogging(MvcEvent $event)
213
    {
214
        $viewHelper = $event->getApplication()->getServiceManager()->get('ViewHelperManager')->get('headscript');
215
        $viewHelper->offsetSetFile(0, '//cdn.ravenjs.com/3.8.0/raven.min.js');
216
        $publicApiKey = $this->convertKeyToPublic($this->config['zend-sentry']['sentry-api-key']);
217
        $viewHelper->offsetSetScript(1, sprintf("Raven.config('%s').install()", $publicApiKey));
218
    }
219
220
    /**
221
     * @param string $key
222
     * @return string $publicKey
223
     */
224
    private function convertKeyToPublic($key)
225
    {
226
        // Find private part
227
        $start = strpos($key, ':', 6);
228
        $end = strpos($key, '@');
229
        $privatePart = substr($key, $start, $end - $start);
230
231
        // Replace it with an empty string
232
        $publicKey = str_replace($privatePart, '', $key);
233
234
        return $publicKey;
235
    }
236
}
237