RollbarExtension::getFunctions()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 13
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 13
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 8
nc 1
nop 0
1
<?php
2
3
namespace Ftrrtf\RollbarBundle\Twig;
4
5
use Ftrrtf\RollbarBundle\Helper\UserHelper;
6
use Ftrrtf\RollbarBundle\Provider\CheckIgnoreFunctionProviderInterface;
7
use Ftrrtf\RollbarBundle\Provider\TransformPayloadFunctionProviderInterface;
8
9
/**
10
 * Rollbar twig extension.
11
 */
12
class RollbarExtension extends \Twig_Extension
13
{
14
    /**
15
     * @var array
16
     */
17
    protected $notifierOptions;
18
19
    /**
20
     * @var array
21
     */
22
    protected $environmentOptions;
23
24
    /**
25
     * @var UserHelper
26
     */
27
    private $userHelper;
28
29
    /**
30
     * @var CheckIgnoreFunctionProviderInterface
31
     */
32
    private $checkIgnoreFunctionProvider;
33
34
    /**
35
     * @var TransformPayloadFunctionProviderInterface
36
     */
37
    private $transformPayloadFunctionProvider;
38
39
    /**
40
     * @param array                                     $notifierOptions
41
     * @param array                                     $environmentOptions
42
     * @param UserHelper                                $userHelper
43
     * @param CheckIgnoreFunctionProviderInterface      $checkIgnoreFunctionProvider
44
     * @param TransformPayloadFunctionProviderInterface $transformPayloadFunctionProvider
45
     */
46
    public function __construct(
47
        array $notifierOptions,
48
        array $environmentOptions,
49
        UserHelper $userHelper,
50
        CheckIgnoreFunctionProviderInterface $checkIgnoreFunctionProvider,
51
        TransformPayloadFunctionProviderInterface $transformPayloadFunctionProvider
52
    ) {
53
        $this->notifierOptions = $notifierOptions;
54
        $this->environmentOptions = $environmentOptions;
55
        $this->userHelper = $userHelper;
56
        $this->checkIgnoreFunctionProvider = $checkIgnoreFunctionProvider;
57
        $this->transformPayloadFunctionProvider = $transformPayloadFunctionProvider;
58
    }
59
60
    /**
61
     * Returns a list of functions to add to the existing list.
62
     *
63
     * @return array An array of functions
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use \Twig_SimpleFunction[].

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
64
     */
65
    public function getFunctions()
66
    {
67
        return array(
68
            new \Twig_SimpleFunction(
69
                'rollbarjs',
70
                array($this, 'getInitRollbarCode'),
71
                array(
72
                    'needs_context' => true,
73
                    'is_safe' => array('html'),
74
                )
75
            ),
76
        );
77
    }
78
79
    /**
80
     * @param array $context
81
     *
82
     * @return string
83
     */
84
    public function getInitRollbarCode(array $context)
85
    {
86
        $accessToken = $this->notifierOptions['access_token'];
87
88
        $config = array(
89
            'accessToken' => $accessToken,
90
            'captureUncaught' => true,
91
            'payload' => array(
92
                'environment' => $this->environmentOptions['environment'],
93
            ),
94
        );
95
96
        $user = $context['app']->getUser();
97
        if (isset($user)) {
98
            $config['payload']['person'] = $this->userHelper->buildUserData($user);
99
        }
100
101
        if ($this->notifierOptions['source_map_enabled']) {
102
            $config['payload']['client'] = array(
103
                'javascript' => array(
104
                    'source_map_enabled' => $this->notifierOptions['source_map_enabled'],
105
                    'code_version' => $this->notifierOptions['code_version'],
106
                    'guess_uncaught_frames' => $this->notifierOptions['guess_uncaught_frames'],
107
                ),
108
            );
109
        }
110
111
        $rollbarJsVersion = $this->notifierOptions['rollbarjs_version'];
112
113
        $config = json_encode($config);
114
115
        $checkIgnoreConfig = $this->getCheckIgnoreConfig();
116
117
        $transform = $this->transformPayloadFunctionProvider->getTransformFunctionCode();
118
119
        return <<<END_HTML
120
<script>
121
var _rollbarConfig = {$config};
122
_rollbarConfig.transform = {$transform};
123
// Rollbar Snippet
124
!function(r){function o(e){if(t[e])return t[e].exports;var n=t[e]={exports:{},id:e,loaded:!1};return r[e].call(n.exports,n,n.exports,o),n.loaded=!0,n.exports}var t={};return o.m=r,o.c=t,o.p="",o(0)}([function(r,o,t){"use strict";var e=t(1).Rollbar,n=t(2);_rollbarConfig.rollbarJsUrl=_rollbarConfig.rollbarJsUrl||"https://d37gvrvc0wt4s1.cloudfront.net/js/{$rollbarJsVersion}/rollbar.min.js";var a=e.init(window,_rollbarConfig),i=n(a,_rollbarConfig);a.loadFull(window,document,!_rollbarConfig.async,_rollbarConfig,i)},function(r,o){"use strict";function t(r){return function(){try{return r.apply(this,arguments)}catch(o){try{console.error("[Rollbar]: Internal error",o)}catch(t){}}}}function e(r,o,t){window._rollbarWrappedError&&(t[4]||(t[4]=window._rollbarWrappedError),t[5]||(t[5]=window._rollbarWrappedError._rollbarContext),window._rollbarWrappedError=null),r.uncaughtError.apply(r,t),o&&o.apply(window,t)}function n(r){var o=function(){var o=Array.prototype.slice.call(arguments,0);e(r,r._rollbarOldOnError,o)};return o.belongsToShim=!0,o}function a(r){this.shimId=++s,this.notifier=null,this.parentShim=r,this._rollbarOldOnError=null}function i(r){var o=a;return t(function(){if(this.notifier)return this.notifier[r].apply(this.notifier,arguments);var t=this,e="scope"===r;e&&(t=new o(this));var n=Array.prototype.slice.call(arguments,0),a={shim:t,method:r,args:n,ts:new Date};return window._rollbarShimQueue.push(a),e?t:void 0})}function l(r,o){if(o.hasOwnProperty&&o.hasOwnProperty("addEventListener")){var t=o.addEventListener;o.addEventListener=function(o,e,n){t.call(this,o,r.wrap(e),n)};var e=o.removeEventListener;o.removeEventListener=function(r,o,t){e.call(this,r,o&&o._wrapped?o._wrapped:o,t)}}}var s=0;a.init=function(r,o){var e=o.globalAlias||"Rollbar";if("object"==typeof r[e])return r[e];r._rollbarShimQueue=[],r._rollbarWrappedError=null,o=o||{};var i=new a;return t(function(){if(i.configure(o),o.captureUncaught){i._rollbarOldOnError=r.onerror,r.onerror=n(i);var t,a,s="EventTarget,Window,Node,ApplicationCache,AudioTrackList,ChannelMergerNode,CryptoOperation,EventSource,FileReader,HTMLUnknownElement,IDBDatabase,IDBRequest,IDBTransaction,KeyOperation,MediaController,MessagePort,ModalWindow,Notification,SVGElementInstance,Screen,TextTrack,TextTrackCue,TextTrackList,WebSocket,WebSocketWorker,Worker,XMLHttpRequest,XMLHttpRequestEventTarget,XMLHttpRequestUpload".split(",");for(t=0;t<s.length;++t)a=s[t],r[a]&&r[a].prototype&&l(i,r[a].prototype)}return r[e]=i,i})()},a.prototype.loadFull=function(r,o,e,n,a){var i=function(){var o;if(void 0===r._rollbarPayloadQueue){var t,e,n,i;for(o=new Error("rollbar.js did not load");t=r._rollbarShimQueue.shift();)for(n=t.args,i=0;i<n.length;++i)if(e=n[i],"function"==typeof e){e(o);break}}"function"==typeof a&&a(o)},l=!1,s=o.createElement("script"),u=o.getElementsByTagName("script")[0],p=u.parentNode;s.crossOrigin="",s.src=n.rollbarJsUrl,s.async=!e,s.onload=s.onreadystatechange=t(function(){if(!(l||this.readyState&&"loaded"!==this.readyState&&"complete"!==this.readyState)){s.onload=s.onreadystatechange=null;try{p.removeChild(s)}catch(r){}l=!0,i()}}),p.insertBefore(s,u)},a.prototype.wrap=function(r,o){try{var t;if(t="function"==typeof o?o:function(){return o||{}},"function"!=typeof r)return r;if(r._isWrap)return r;if(!r._wrapped){r._wrapped=function(){try{return r.apply(this,arguments)}catch(o){throw o._rollbarContext=t()||{},o._rollbarContext._wrappedSource=r.toString(),window._rollbarWrappedError=o,o}},r._wrapped._isWrap=!0;for(var e in r)r.hasOwnProperty(e)&&(r._wrapped[e]=r[e])}return r._wrapped}catch(n){return r}};for(var u="log,debug,info,warn,warning,error,critical,global,configure,scope,uncaughtError".split(","),p=0;p<u.length;++p)a.prototype[u[p]]=i(u[p]);r.exports={Rollbar:a,_rollbarWindowOnError:e}},function(r,o){"use strict";r.exports=function(r,o){return function(t){if(!t&&!window._rollbarInitialized){var e=window.RollbarNotifier,n=o||{},a=n.globalAlias||"Rollbar",i=window.Rollbar.init(n,r);i._processShimQueue(window._rollbarShimQueue||[]),window[a]=i,window._rollbarInitialized=!0,e.processPayloads()}}}}]);
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 4109 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
125
// End Rollbar Snippet
126
{$checkIgnoreConfig}
127
</script>
128
END_HTML;
129
    }
130
131
    /**
132
     * Configure and return JS for "ignore errors" feature.
133
     *
134
     * @return string
135
     */
136
    protected function getCheckIgnoreConfig()
137
    {
138
        $allowedHosts = json_encode($this->notifierOptions['allowed_js_hosts']);
139
        $customCheckIgnoreFunction = $this->checkIgnoreFunctionProvider->getCheckIgnoreFunctionCode();
140
141
        return <<<END_HTML
142
(function(Rollbar) {
143
    var allowedHosts = {$allowedHosts};
144
    var customCheckIgnoreFunction = {$customCheckIgnoreFunction};
145
    if (allowedHosts.length === 0) {
146
        allowedHosts.push(window.location.origin);
147
    }
148
149
    function isFromAllowedHosts(filename) {
150
        for (var i = 0; i < allowedHosts.length; i++) {
151
            if (filename.match(allowedHosts[i])) {
152
                return true;
153
            }
154
        }
155
156
        return false;
157
    }
158
159
    function isLogMessage(payload) {
160
        try {
161
            if (payload.data.body.message !== undefined) {
162
                return true;
163
            }
164
        } catch (e) {
165
        }
166
167
        return false;
168
    }
169
170
    function ignoreRemoteUncaught(isUncaught, args, payload) {
171
        try {
172
            if (typeof customCheckIgnoreFunction === 'function' && customCheckIgnoreFunction(isUncaught, args, payload)) {
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 122 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
173
                return true;
174
            }
175
176
            //this prevents breaking simple string reporting
177
            if (isLogMessage(payload)) {
178
                return false;
179
            }
180
181
            var filename = payload.data.body.trace.frames[0].filename;
182
            if (isUncaught && !isFromAllowedHosts(filename)) {
183
                return true;
184
            }
185
        } catch (e) {
186
            // Most likely there was no filename or the frame doesn't exist.
187
            return true;
188
        }
189
190
        return false;
191
    }
192
193
    Rollbar.configure({checkIgnore: ignoreRemoteUncaught});
194
})(Rollbar);
195
END_HTML;
196
    }
197
198
    /**
199
     * Returns the name of the extension.
200
     *
201
     * @return string The extension name
202
     */
203
    public function getName()
204
    {
205
        return 'ftrrtf_rollbar';
206
    }
207
}
208