Notifier::pushHandler()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

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