Completed
Push — master ( c67e2b...ab6b60 )
by Tyler
02:09
created

Notifier::send()   B

Complexity

Conditions 6
Paths 31

Size

Total Lines 27

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 16
CRAP Score 6

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 27
ccs 16
cts 16
cp 1
rs 8.8657
cc 6
nc 31
nop 2
crap 6
1
<?php
2
3
namespace Tylercd100\LERN\Components;
4
5
use Auth;
6
use Exception;
7
use Illuminate\Support\Facades\Input;
8
use Illuminate\Support\Facades\Cache;
9
use Monolog\Handler\HandlerInterface;
10
use Monolog\Logger;
11
use Request;
12
use Tylercd100\LERN\Exceptions\NotifierFailedException;
13
use Tylercd100\Notify\Drivers\FromConfig as Notify;
14
use View;
15
use Carbon\Carbon;
16
17
class Notifier extends Component
18
{
19
    protected $config;
20
    protected $log;
21
    protected $messageCb;
22
    protected $subjectCb;
23
    protected $contextCb;
24
25
    /**
26
     * @var array
27
     */
28
    protected $absolutelyDontHandle = [
29
        \Tylercd100\LERN\Exceptions\NotifierFailedException::class,
30
    ];
31
32
    /**
33
     * You can provide a Monolog Logger instance to use in the constructor
34
     * @param Logger|null $log Logger instance to use
35
     */
36 84
    public function __construct(Logger $log = null)
37
    {
38 84
        if ($log === null) {
39 84
            $log = new Logger(config('lern.notify.channel'));
40
        }
41
42 84
        $this->config = config('lern.notify');
43 84
        $this->log = $log;
44 84
    }
45
46
    /**
47
     * Transforms a value into a closure that returns itself when called
48
     * @param  callable|string $cb The value that you want to wrap in a closure
49
     * @return callable
50
     */
51 15
    private function wrapValueInClosure($cb)
52
    {
53 15
        if (is_callable($cb)) {
54 9
            return $cb;
55
        } else {
56
            return function () use ($cb) { return $cb; };
57
        }
58
    }
59
60
    /**
61
     * Set a string or a closure to be called that will generate the message body for the notification
62
     * @param callable|string $cb A closure or string that will be set for the message
63
     * @return $this
64
     */
65 6
    public function setMessage($cb)
66
    {
67 6
        $this->messageCb = $this->wrapValueInClosure($cb);
68 6
        return $this;
69
    }
70
71
    /**
72
     * Returns the result of the message closure
73
     * @param  Exception $e The Exception instance that you want to build the message around
74
     * @return string       The message string
75
     */
76 36
    public function getMessage(Exception $e)
77
    {
78 36
        $msg = $this->getMessageViaView($e);
79
80 36
        if ($msg === false) {
81 9
            $msg = $this->getMessageViaCallback($e);
82
        }
83
84 36
        if ($msg === false) {
85 3
            $msg = $this->getMessageViaDefault($e);
86
        }
87
        
88 36
        return $msg;
89
    }
90
91
    /**
92
     * Gets a basic Exception message
93
     * @param  Exception $e The Exception instance that you want to build the message around
94
     * @return String       Returns the message string
95
     */
96 3
    public function getMessageViaDefault(Exception $e)
97
    {
98 3
        $msg = get_class($e)." was thrown! \n".$e->getMessage();
99 3
        if ($this->config['includeExceptionStackTrace'] === true) {
100 3
            $msg .= "\n\n".$e->getTraceAsString();
101
        }
102 3
        return $msg;
103
    }
104
105
    /**
106
     * Gets the Exception message using a callback if it is set
107
     * @param  Exception    $e The Exception instance that you want to build the message around
108
     * @return String|false    Returns the message string or false
109
     */
110 9
    public function getMessageViaCallback(Exception $e)
111
    {
112 9
        if (is_callable($this->messageCb)) {
113 6
            return $this->messageCb->__invoke($e);
114
        }
115 3
        return false;
116
    }
117
118
    /**
119
     * Gets the Exception message using a Laravel view file
120
     * @param  Exception    $e The Exception instance that you want to build the message around
121
     * @return String|false    Returns the message string or false
122
     */
123 36
    public function getMessageViaView(Exception $e)
124
    {
125 36
        $path = @$this->config["view"];
126 36
        if (!empty($path) && View::exists($path)) {
127 27
            return View::make($path, [
128 27
                "exception" => $e,
129 27
                "url" => Request::url(),
130 27
                "method" => Request::method(),
131 27
                "input" => Input::all(),
132 27
                "user" => Auth::user(),
133 27
            ])->render();
134
        }
135 9
        return false;
136
    }
137
138
    /**
139
     * Set a string or a closure to be called that will generate the subject line for the notification
140
     * @param callable|string $cb A closure or string that will be set for the subject line
141
     * @return $this
142
     */
143 6
    public function setSubject($cb)
144
    {
145 6
        $this->subjectCb = $this->wrapValueInClosure($cb);
146 6
        return $this;
147
    }
148
149
    /**
150
     * Returns the result of the subject closure
151
     * @param  Exception $e The Exception instance that you want to build the subject around
152
     * @return string       The subject string
153
     */
154 27
    public function getSubject(Exception $e)
155
    {
156 27
        if (is_callable($this->subjectCb)) {
157 6
            return $this->subjectCb->__invoke($e);
158
        } else {
159 21
            return get_class($e);
160
        }
161
    }
162
163
    /**
164
     * Set an array or a closure to be called that will generate the context array for the notification
165
     * @param callable|array $cb A closure or array that will be set for the context
166
     * @return $this
167
     */
168 3
    public function setContext($cb)
169
    {
170 3
        $this->contextCb = $this->wrapValueInClosure($cb);
171 3
        return $this;
172
    }
173
174
    /**
175
     * Returns the result of the context closure
176
     * @param  Exception $e The Exception instance that you want to build the context around
177
     * @return array        The context array
178
     */
179 24
    public function getContext(Exception $e, $context = [])
180
    {
181
        //This needs a better solution. How do I set specific context needs for different drivers?
182 24
        if (in_array('pushover', $this->config['drivers'])) {
183 21
            $context['sound'] = $this->config['pushover']['sound'];
184
        }
185
186
        // Call the callback or return the default
187 24
        if (is_callable($this->contextCb)) {
188 3
            return $this->contextCb->__invoke($e, $context);
189
        } else {
190 21
            return $context;
191
        }
192
    }
193
194
    /**
195
     * Get the log level
196
     * @return string 
197
     */
198 3
    public function getLogLevel()
199
    {
200 3
        return $this->config['log_level'];
201
    }
202
203
    /**
204
     * Set the log level
205
     * @param string $level The log level
206
     * @return \Tylercd100\LERN\LERN
207
     */
208 3
    public function setLogLevel($level)
209
    {
210 3
        $this->config['log_level'] = $level;
211 3
        return $this;
212
    }
213
214
    /**
215
     * Pushes on another Monolog Handler
216
     * @param  HandlerInterface $handler The handler instance to add on
217
     * @return Notifier                  Returns this
218
     */
219 6
    public function pushHandler(HandlerInterface $handler)
220
    {
221 6
        $this->log->pushHandler($handler);
222 6
        return $this;
223
    }
224
225
    /**
226
     * Triggers the Monolog Logger instance to log an error to all handlers
227
     * @param  Exception $e The exception to use
228
     * @param  array $context Additional information that you would like to pass to Monolog
229
     * @return bool
230
     * @throws NotifierFailedException
231
     */
232 24
    public function send(Exception $e, array $context = [])
233
    {
234 24
        if ($this->shouldntHandle($e)) {
235 6
            return false;
236
        }
237
238 21
        $message = $this->getMessage($e);
239 21
        $subject = $this->getSubject($e);
240 21
        $context = $this->getContext($e, $context);
241
        
242
        try {
243 21
            $notify = new Notify($this->config, $this->log, $subject);
244
            
245 21
            $level = (array_key_exists('log_level', $this->config) && !empty($this->config['log_level']))
246 21
            ? $this->config['log_level']
247 21
            : 'critical';
248
            
249 21
            $notify->{$level}($message, $context);
250
251 18
            Cache::forever($this->getCacheKey($e), Carbon::now());
252
            
253 18
            return true;
254 3
        } catch (Exception $e) {
255 3
            $code = (is_int($e->getCode()) ? $e->getCode() : 0);
256 3
            throw new NotifierFailedException($e->getMessage(), $code, $e);
257
        }
258
    }
259
}
260