Completed
Push — fix/56 ( 07c17d...0aa823 )
by Tyler
02:08
created

Recorder::record()   B

Complexity

Conditions 10
Paths 109

Size

Total Lines 42

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 21
CRAP Score 10.4096

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 42
ccs 21
cts 25
cp 0.84
rs 7.5916
cc 10
nc 109
nop 1
crap 10.4096

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace Tylercd100\LERN\Components;
4
5
use Exception;
6
use Illuminate\Support\Facades\Auth;
7
use Illuminate\Support\Facades\Input;
8
use Illuminate\Support\Facades\Request;
9
use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
10
use Tylercd100\LERN\Exceptions\RecorderFailedException;
11
use Tylercd100\LERN\Models\ExceptionModel;
12
13
class Recorder extends Component {
14
15
    /**
16
     * @var mixed
17
     */
18
    protected $config = [];
19
20
    /**
21
     * @var array
22
     */
23
    protected $absolutelyDontHandle = [
24
        \Tylercd100\LERN\Exceptions\RecorderFailedException::class,
25
    ];
26
27
    /**
28
     * The constructor
29
     */
30 33
    public function __construct() {
31 33
        $this->config = config('lern.record');
32 33
    }
33
34
    /**
35
     * Records an Exception to the database
36
     * @param  Exception $e The exception you want to record
37
     * @return false|ExceptionModel
38
     * @throws RecorderFailedException
39
     */
40 3
    public function record(Exception $e)
41
    {
42 3
        if ($this->shouldntHandle($e)) {
43
            return false;
44
        }
45
46
        $opts = [
47 3
            'class'       => get_class($e),
48 3
            'file'        => $e->getFile(),
49 3
            'line'        => $e->getLine(),
50 3
            'code'        => (is_int($e->getCode()) ? $e->getCode() : 0),
51 3
            'message'     => $e->getMessage(),
52 3
            'trace'       => $e->getTraceAsString(),
53
        ];
54
55 3
        $configDependant = array_keys($this->config['collect']);
56
57
        try {
58 3
            foreach ($configDependant as $key) {
59 3
                if ($this->canCollect($key)) {
60 3
                    $value = $this->collect($key, $e);
61 3
                    if ($value !== null) {
62 3
                        $opts[$key] = $value;
63
                    }
64
                }
65
            }
66
67 3
            $class = config('lern.recorder.model');
68 3
            $class = !empty($class) ? $class : ExceptionModel::class;
69
70 3
            $model = new $class();
71 3
            foreach($opts as $key => $value) {
72 3
                $model->{$key} = $value;
73
            }
74
75 3
            $model->save();
76 3
            return $model;
77
        } catch (Exception $e) {
78
            $code = (is_int($e->getCode()) ? $e->getCode() : 0);
79
            throw new RecorderFailedException($e->getMessage(), $code, $e);
80
        }
81
    }
82
83
    /**
84
     * Checks the config to see if you can collect certain information
85
     * @param  string $type the config value you want to check
86
     * @return boolean      
87
     */
88 3
    private function canCollect($type) {
89 3
        if (!empty($this->config) && !empty($this->config['collect']) && !empty($this->config['collect'][$type])) {
90 3
            return $this->config['collect'][$type] === true;
91
        }
92
        return false;
93
    }
94
95
    /**
96
     * @param string $key
97
     * @param Exception $e
98
     * @return array|int|null|string
99
     * @throws Exception
100
     */
101 3
    protected function collect($key, Exception $e = null) {
102
        switch ($key) {
103 3
            case 'user_id':
104 3
                return $this->getUserId();
105 3
            case 'method':
106 3
                return $this->getMethod();
107 3
            case 'url':
108 3
                return $this->getUrl();
109 3
            case 'data':
110 3
                return $this->getData();
111 3
            case 'ip':
112
                return $this->getIp();
113 3
            case 'status_code':
114 3
                if ($e === null) {
115
                    return 0;
116
                }
117 3
                return $this->getStatusCode($e);
118
            default:
119
                throw new Exception("{$key} is not supported! Therefore it cannot be collected!");
120
        }
121
    }
122
123
    /**
124
     * Gets the ID of the User that is logged in
125
     * @return integer|null The ID of the User or Null if not logged in
126
     */
127 3
    protected function getUserId() {
128 3
        $user = Auth::user();
129 3
        if (is_object($user) && !empty($user->id)) {
0 ignored issues
show
Bug introduced by
Accessing id on the interface Illuminate\Contracts\Auth\Authenticatable suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
130
            return $user->id;
0 ignored issues
show
Bug introduced by
Accessing id on the interface Illuminate\Contracts\Auth\Authenticatable suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
131
        } else {
132 3
            return null;
133
        }
134
    }
135
136
    /**
137
     * Gets the Method of the Request
138
     * @return string|null Possible values are null or GET, POST, DELETE, PUT, etc...
139
     */
140 3
    protected function getMethod() {
141 3
        $method = Request::method();
142 3
        if (!empty($method)) {
143 3
            return $method;
144
        } else {
145
            return null;
146
        }
147
    }
148
149
    /**
150
     * Gets the input data of the Request
151
     * @return array|null The Input data or null
152
     */
153 3
    protected function getData() {
154 3
        $data = Input::all();
155 3
        if (is_array($data)) {
156 3
            return $this->excludeKeys($data);
157
        } else {
158
            return null;
159
        }
160
    }
161
162
    /**
163
     * Gets the URL of the Request
164
     * @return string|null Returns a URL string or null
165
     */
166 3
    protected function getUrl() {
167 3
        $url = Request::url();
168 3
        if (is_string($url)) {
169 3
            return $url;
170
        } else {
171
            return null;
172
        }
173
    }
174
175
    /**
176
     * Returns the IP from the request
177
     *
178
     * @return string
179
     */
180
    protected function getIp() {
181
        return Request::ip();
182
    }
183
184
    /**
185
     * Gets the status code of the Exception
186
     * @param  Exception $e The Exception to check
187
     * @return string|integer The status code value
188
     */
189 3
    protected function getStatusCode(Exception $e) {
190 3
        if ($e instanceof HttpExceptionInterface) {
191
            return $e->getStatusCode();
192
        } else {
193 3
            return 0;
194
        }
195
    }
196
197
    /**
198
     * This function will remove all keys from an array recursively as defined in the config file
199
     * @param  array $data The array to remove keys from
200
     * @return void
201
     */
202 3
    protected function excludeKeys(array $data) {
203 3
        $keys = isset($this->config['excludeKeys']) ? $this->config['excludeKeys'] : [];
204 3
        foreach ($data as $key => &$value) {
205
            if (in_array($key, $keys)) {
206
                unset($data[$key]);
207
            } else if (is_array($value)) {
208
                $value = $this->excludeKeys($value);
209
            }
210
        }
211
212 3
        return $data;
213
    }
214
}
215