Completed
Push — master ( 0a92dc...4f5269 )
by ARCANEDEV
02:09
created

LogViewerController   A

Complexity

Total Complexity 19

Size/Duplication

Total Lines 286
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 12

Test Coverage

Coverage 98.85%

Importance

Changes 0
Metric Value
dl 0
loc 286
ccs 86
cts 87
cp 0.9885
c 0
b 0
f 0
rs 10
wmc 19
lcom 1
cbo 12

13 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 1
A index() 0 8 1
A listLogs() 0 8 1
A show() 0 10 1
A showByLevel() 0 12 2
A download() 0 4 1
A delete() 0 10 2
A view() 0 6 1
A getLogOrFail() 0 13 2
A prepareChartData() 0 15 1
A search() 0 22 2
A paginate() 0 14 1
A calcPercentages() 0 15 3
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Arcanedev\LogViewer\Http\Controllers;
6
7
use Arcanedev\LogViewer\Contracts\LogViewer as LogViewerContract;
8
use Arcanedev\LogViewer\Entities\{LogEntry, LogEntryCollection};
9
use Arcanedev\LogViewer\Exceptions\LogNotFoundException;
10
use Arcanedev\LogViewer\Tables\StatsTable;
11
use Illuminate\Http\Request;
12
use Illuminate\Pagination\LengthAwarePaginator;
13
use Illuminate\Routing\Controller;
14
use Illuminate\Support\{Arr, Collection, Str};
15
16
/**
17
 * Class     LogViewerController
18
 *
19
 * @author   ARCANEDEV <[email protected]>
20
 */
21
class LogViewerController extends Controller
22
{
23
    /* -----------------------------------------------------------------
24
     |  Properties
25
     | -----------------------------------------------------------------
26
     */
27
28
    /**
29
     * The log viewer instance
30
     *
31
     * @var \Arcanedev\LogViewer\Contracts\LogViewer
32
     */
33
    protected $logViewer;
34
35
    /** @var int */
36
    protected $perPage = 30;
37
38
    /** @var string */
39
    protected $showRoute = 'log-viewer::logs.show';
40
41
    /* -----------------------------------------------------------------
42
     |  Constructor
43
     | -----------------------------------------------------------------
44
     */
45
46
    /**
47
     * LogViewerController constructor.
48
     *
49
     * @param  \Arcanedev\LogViewer\Contracts\LogViewer  $logViewer
50
     */
51 90
    public function __construct(LogViewerContract $logViewer)
52
    {
53 90
        $this->logViewer = $logViewer;
54 90
        $this->perPage = config('log-viewer.per-page', $this->perPage);
55 90
    }
56
57
    /* -----------------------------------------------------------------
58
     |  Main Methods
59
     | -----------------------------------------------------------------
60
     */
61
62
    /**
63
     * Show the dashboard.
64
     *
65
     * @return \Illuminate\View\View
66
     */
67 6
    public function index()
68
    {
69 6
        $stats     = $this->logViewer->statsTable();
70 6
        $chartData = $this->prepareChartData($stats);
71 6
        $percents  = $this->calcPercentages($stats->footer(), $stats->header());
72
73 6
        return $this->view('dashboard', compact('chartData', 'percents'));
74
    }
75
76
    /**
77
     * List all logs.
78
     *
79
     * @param  \Illuminate\Http\Request  $request
80
     *
81
     * @return \Illuminate\View\View
82
     */
83 6
    public function listLogs(Request $request)
84
    {
85 6
        $stats   = $this->logViewer->statsTable();
86 6
        $headers = $stats->header();
87 6
        $rows    = $this->paginate($stats->rows(), $request);
88
89 6
        return $this->view('logs', compact('headers', 'rows'));
90
    }
91
92
    /**
93
     * Show the log.
94
     *
95
     * @param  \Illuminate\Http\Request  $request
96
     * @param  string                    $date
97
     *
98
     * @return \Illuminate\View\View
99
     */
100 12
    public function show(Request $request, $date)
101
    {
102 12
        $level   = 'all';
103 12
        $log     = $this->getLogOrFail($date);
104 6
        $query   = $request->get('query');
105 6
        $levels  = $this->logViewer->levelsNames();
106 6
        $entries = $log->entries($level)->paginate($this->perPage);
107
108 6
        return $this->view('show', compact('level', 'log', 'query', 'levels', 'entries'));
109
    }
110
111
    /**
112
     * Filter the log entries by level.
113
     *
114
     * @param  \Illuminate\Http\Request  $request
115
     * @param  string                    $date
116
     * @param  string                    $level
117
     *
118
     * @return \Illuminate\View\View|\Illuminate\Http\RedirectResponse
119
     */
120 12
    public function showByLevel(Request $request, $date, $level)
121
    {
122 12
        if ($level === 'all')
123 6
            return redirect()->route($this->showRoute, [$date]);
124
125 6
        $log     = $this->getLogOrFail($date);
126 6
        $query   = $request->get('query');
127 6
        $levels  = $this->logViewer->levelsNames();
128 6
        $entries = $this->logViewer->entries($date, $level)->paginate($this->perPage);
129
130 6
        return $this->view('show', compact('level', 'log', 'query', 'levels', 'entries'));
131
    }
132
133
    /**
134
     * Show the log with the search query.
135
     *
136
     * @param  \Illuminate\Http\Request  $request
137
     * @param  string                    $date
138
     * @param  string                    $level
139
     *
140
     * @return \Illuminate\View\View|\Illuminate\Http\RedirectResponse
141
     */
142 30
    public function search(Request $request, $date, $level = 'all')
143
    {
144 30
        $query   = $request->get('query');
145
146 30
        if (is_null($query))
147 6
            return redirect()->route($this->showRoute, [$date]);
148
149 24
        $log     = $this->getLogOrFail($date);
150 24
        $levels  = $this->logViewer->levelsNames();
151 24
        $needles = array_map(function ($needle) {
152 24
            return Str::lower($needle);
153 24
        }, array_filter(explode(' ', $query)));
154 24
        $entries = $log->entries($level)
155 24
            ->unless(empty($needles), function (LogEntryCollection $entries) use ($needles) {
156 24
                return $entries->filter(function (LogEntry $entry) use ($needles) {
157 24
                    return Str::containsAll(Str::lower($entry->header), $needles);
158 24
                });
159 24
            })
160 24
            ->paginate($this->perPage);
161
162 24
        return $this->view('show', compact('level', 'log', 'query', 'levels', 'entries'));
163
    }
164
165
    /**
166
     * Download the log
167
     *
168
     * @param  string  $date
169
     *
170
     * @return \Symfony\Component\HttpFoundation\BinaryFileResponse
171
     */
172 6
    public function download($date)
173
    {
174 6
        return $this->logViewer->download($date);
175
    }
176
177
    /**
178
     * Delete a log.
179
     *
180
     * @param  \Illuminate\Http\Request  $request
181
     *
182
     * @return \Illuminate\Http\JsonResponse
183
     */
184 18
    public function delete(Request $request)
185
    {
186 18
        abort_unless($request->ajax(), 405, 'Method Not Allowed');
187
188 12
        $date = $request->input('date');
189
190 12
        return response()->json([
0 ignored issues
show
Bug introduced by
The method json does only exist in Illuminate\Contracts\Routing\ResponseFactory, but not in Illuminate\Http\Response.

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...
191 12
            'result' => $this->logViewer->delete($date) ? 'success' : 'error'
192
        ]);
193
    }
194
195
    /* -----------------------------------------------------------------
196
     |  Other Methods
197
     | -----------------------------------------------------------------
198
     */
199
200
    /**
201
     * Get the evaluated view contents for the given view.
202
     *
203
     * @param  string  $view
204
     * @param  array   $data
205
     * @param  array   $mergeData
206
     *
207
     * @return \Illuminate\View\View
208
     */
209 48
    protected function view($view, $data = [], $mergeData = [])
210
    {
211 48
        $theme = config('log-viewer.theme');
212
213 48
        return view()->make("log-viewer::{$theme}.{$view}", $data, $mergeData);
0 ignored issues
show
Bug introduced by
The method make does only exist in Illuminate\Contracts\View\Factory, but not in Illuminate\Contracts\View\View.

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...
214
    }
215
216
    /**
217
     * Paginate logs.
218
     *
219
     * @param  array                     $data
220
     * @param  \Illuminate\Http\Request  $request
221
     *
222
     * @return \Illuminate\Pagination\LengthAwarePaginator
223
     */
224 6
    protected function paginate(array $data, Request $request)
225
    {
226 6
        $data = new Collection($data);
227 6
        $page = $request->get('page', 1);
228 6
        $path = $request->url();
229
230 6
        return new LengthAwarePaginator(
231 6
            $data->forPage($page, $this->perPage),
232 6
            $data->count(),
233 6
            $this->perPage,
234
            $page,
235 6
            compact('path')
236
        );
237
    }
238
239
    /**
240
     * Get a log or fail
241
     *
242
     * @param  string  $date
243
     *
244
     * @return \Arcanedev\LogViewer\Entities\Log|null
245
     */
246 42
    protected function getLogOrFail($date)
247
    {
248 42
        $log = null;
249
250
        try {
251 42
            $log = $this->logViewer->get($date);
252
        }
253 6
        catch (LogNotFoundException $e) {
254 6
            abort(404, $e->getMessage());
255
        }
256
257 36
        return $log;
258
    }
259
260
    /**
261
     * Prepare chart data.
262
     *
263
     * @param  \Arcanedev\LogViewer\Tables\StatsTable  $stats
264
     *
265
     * @return string
266
     */
267 6
    protected function prepareChartData(StatsTable $stats)
268
    {
269 6
        $totals = $stats->totals()->all();
270
271 6
        return json_encode([
272 6
            'labels'   => Arr::pluck($totals, 'label'),
0 ignored issues
show
Documentation introduced by
$totals is of type array, but the function expects a object<Illuminate\Support\iterable>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
273
            'datasets' => [
274
                [
275 6
                    'data'                 => Arr::pluck($totals, 'value'),
0 ignored issues
show
Documentation introduced by
$totals is of type array, but the function expects a object<Illuminate\Support\iterable>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
276 6
                    'backgroundColor'      => Arr::pluck($totals, 'color'),
0 ignored issues
show
Documentation introduced by
$totals is of type array, but the function expects a object<Illuminate\Support\iterable>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
277 6
                    'hoverBackgroundColor' => Arr::pluck($totals, 'highlight'),
0 ignored issues
show
Documentation introduced by
$totals is of type array, but the function expects a object<Illuminate\Support\iterable>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
278
                ],
279
            ],
280
        ]);
281
    }
282
283
    /**
284
     * Calculate the percentage.
285
     *
286
     * @param  array  $total
287
     * @param  array  $names
288
     *
289
     * @return array
290
     */
291 6
    protected function calcPercentages(array $total, array $names)
292
    {
293 6
        $percents = [];
294 6
        $all      = Arr::get($total, 'all');
295
296 6
        foreach ($total as $level => $count) {
297
            $percents[$level] = [
298 6
                'name'    => $names[$level],
299 6
                'count'   => $count,
300 6
                'percent' => $all ? round(($count / $all) * 100, 2) : 0,
301
            ];
302
        }
303
304 6
        return $percents;
305
    }
306
}
307