Completed
Push — zend-sentry-update ( a43d56...83315a )
by Markus
36:54
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
        /** @noinspection PhpUndefinedMethodInspection */
87
        $event->getApplication()->getServiceManager()->setService('raven', $ravenClient);
88
        $this->ravenClient = $ravenClient;
89
        $this->zendSentry = new ZendSentry($ravenClient);
90
91
        // Get the eventManager and set it as a member for convenience
92
        $this->eventManager = $event->getApplication()->getEventManager();
93
94
        // If ZendSentry is configured to use the custom logger, attach the listener
95
        if ($this->config['zend-sentry']['attach-log-listener']) {
96
            $this->setupBasicLogging($event);
97
        }
98
99
        // If ZendSentry is configured to log exceptions, a few things need to be set up
100
        if ($this->config['zend-sentry']['handle-exceptions']) {
101
            $this->setupExceptionLogging($event);
102
        }
103
104
        // If ZendSentry is configured to log errors, register it as error handler
105
        if ($this->config['zend-sentry']['handle-errors']) {
106
            $errorReportingLevel = (isset($this->config['zend-sentry']['error-reporting'])) ? $this->config['zend-sentry']['error-reporting'] : -1;
107
            $this->zendSentry->registerErrorHandler($this->config['zend-sentry']['call-existing-error-handler'], $errorReportingLevel);
108
        }
109
110
        // If ZendSentry is configured to log shutdown errors, register it
111
        if ($this->config['zend-sentry']['handle-shutdown-errors']) {
112
            $this->zendSentry->registerShutdownFunction();
113
        }
114
115
        // If ZendSentry is configured to log Javascript errors, add needed scripts to the view
116
        if ($this->config['zend-sentry']['handle-javascript-errors']) {
117
            $this->setupJavascriptLogging($event);
118
        }
119
    }
120
121
    /**
122
     * @return array
123
     */
124
    public function getAutoloaderConfig()
125
    {
126
        return array('Zend\Loader\StandardAutoloader' => array('namespaces' => array(
127
            __NAMESPACE__ => __DIR__.'/src/'.__NAMESPACE__,
128
        )));
129
    }
130
131
    /**
132
     * @return mixed
133
     */
134
    public function getConfig()
135
    {
136
        return include __DIR__.'/config/module.config.php';
137
    }/** @noinspection PhpUnusedParameterInspection */
138
    /** @noinspection PhpUnusedParameterInspection */
139
140
    /**
141
     * Gives us the possibility to write logs to Sentry from anywhere in the application
142
     * Doesn't use the ZF compatible Log Writer because we want to return the Sentry event ID
143
     * ZF Logging doesn't provide the possibility to return values from writers
144
     *
145
     * @param MvcEvent $event
146
     */
147
    protected function setupBasicLogging(MvcEvent $event)
148
    {
149
        // Get the shared event manager and attach a logging listener for the log event on application level
150
        $sharedManager = $this->eventManager->getSharedManager();
151
        $raven = $this->ravenClient;
152
        $logLevels = $this->logLevels;
153
154
        $sharedManager->attach('*', 'log', function($event) use ($raven, $logLevels) {
155
            /** @var $event MvcEvent */
156
            if (is_object($event->getTarget())) {
157
                $target = get_class($event->getTarget());
158
            } else {
159
                $target = (string) $event->getTarget();
160
            }
161
            $message  = $event->getParam('message', 'No message provided');
162
            $priority = (int) $event->getParam('priority', Logger::INFO);
163
            $message  = sprintf('%s: %s', $target, $message);
164
            $tags     = $event->getParam('tags', array());
165
            $extra    = $event->getParam('extra', array());
166
            $eventID  = $raven->captureMessage(
167
                $message,
168
                array(),
169
                array('tags' => $tags, 'level' => $logLevels[$priority], 'extra' => $extra)
170
            );
171
172
            return $eventID;
173
        }, 2);
174
    }
175
176
    /**
177
     * 1. Registers Sentry as exception handler
178
     * 2. Replaces the default ExceptionStrategy so Exception that are caught by Zend Framework can still be logged
179
     *
180
     * @param MvcEvent $event
181
     */
182
    protected function setupExceptionLogging(MvcEvent $event)
183
    {
184
        // Register Sentry as exception handler for exception that bubble up to the top
185
        $this->zendSentry->registerExceptionHandler($this->config['zend-sentry']['call-existing-exception-handler']);
186
187
        // Replace the default ExceptionStrategy with ZendSentry's strategy
188
        if ($event->getApplication()->getServiceManager()->has('HttpExceptionStrategy')) {
189
            /** @var $exceptionStrategy ExceptionStrategy */
190
            $exceptionStrategy = $event->getApplication()->getServiceManager()->get('HttpExceptionStrategy');
191
            $exceptionStrategy->detach($this->eventManager);
192
        }
193
194
        // Check if script is running in console
195
        $exceptionStrategy = (PHP_SAPI == 'cli') ? (new SentryConsoleStrategy()) : (new SentryHttpStrategy());
196
        $exceptionStrategy->attach($this->eventManager);
197
        $exceptionStrategy->setDisplayExceptions($this->config['zend-sentry']['display-exceptions']);
198
        $exceptionStrategy->setDefaultExceptionMessage($this->config['zend-sentry'][(PHP_SAPI == 'cli') ? 'default-exception-console-message' : 'default-exception-message']);
199
        if ($exceptionStrategy instanceof SentryHttpStrategy && isset($this->config['view_manager']['exception_template'])) {
200
            $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...
201
        }
202
        $ravenClient = $this->ravenClient;
203
204
        // Attach an exception listener for the ZendSentry exception strategy, can be triggered from anywhere else too
205
        $this->eventManager->getSharedManager()->attach('*', 'logException', function($event) use ($ravenClient) {
206
            /** @var $event MvcEvent */
207
            $exception = $event->getParam('exception');
208
            $tags = $event->getParam('tags', array());
209
            $eventID = $ravenClient->captureException($exception, array('tags' => $tags));
210
            return $eventID;
211
        });
212
    }
213
214
    /**
215
     * Adds the necessary javascript, tries to prepend
216
     *
217
     * @param MvcEvent $event
218
     */
219
    protected function setupJavascriptLogging(MvcEvent $event)
220
    {
221
        $viewHelper = $event->getApplication()->getServiceManager()->get('ViewHelperManager')->get('headscript');
222
        /** @noinspection PhpUndefinedMethodInspection */
223
        $useRavenjsCDN = $this->config['zend-sentry']['use-ravenjs-cdn'];
224
        if (!isset($useRavenjsCDN) || $useRavenjsCDN) {
225
            $viewHelper->offsetSetFile(0, '//cdn.ravenjs.com/3.17.0/raven.min.js');
226
        }
227
        $publicApiKey = $this->convertKeyToPublic($this->config['zend-sentry']['sentry-api-key']);
228
        /** @noinspection PhpUndefinedMethodInspection */
229
        $ravenjsConfig = json_encode($this->config['zend-sentry']['ravenjs-config']);
230
        $viewHelper->offsetSetScript(1, sprintf("if (typeof Raven !== 'undefined') Raven.config('%s', %s).install()", $publicApiKey, $ravenjsConfig));
231
    }
232
233
    /**
234
     * @param string $key
235
     * @return string $publicKey
236
     */
237
    private function convertKeyToPublic($key)
238
    {
239
        // Find private part
240
        $start = strpos($key, ':', 6);
241
        $end = strpos($key, '@');
242
        $privatePart = substr($key, $start, $end - $start);
243
244
        // Replace it with an empty string
245
        $publicKey = str_replace($privatePart, '', $key);
246
247
        return $publicKey;
248
    }
249
}
250