Completed
Pull Request — master (#371)
by
unknown
10:49
created

LogViewerController   A

Complexity

Total Complexity 20

Size/Duplication

Total Lines 300
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 12

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
dl 0
loc 300
ccs 87
cts 87
cp 1
rs 10
c 0
b 0
f 0
wmc 20
lcom 1
cbo 12

14 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 1
A index() 0 8 1
A listLogs() 0 8 1
A lastLog() 0 6 1
A show() 0 10 1
A showByLevel() 0 12 2
A search() 0 22 2
A download() 0 4 1
A delete() 0 10 2
A view() 0 6 1
A paginate() 0 14 1
A getLogOrFail() 0 13 2
A prepareChartData() 0 15 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 60
    public function __construct(LogViewerContract $logViewer)
52
    {
53 60
        $this->logViewer = $logViewer;
54 60
        $this->perPage = config('log-viewer.per-page', $this->perPage);
55 60
    }
56
57
    /* -----------------------------------------------------------------
58
     |  Main Methods
59
     | -----------------------------------------------------------------
60
     */
61
62
    /**
63
     * Show the dashboard.
64
     *
65
     * @return \Illuminate\View\View
66
     */
67 4
    public function index()
68
    {
69 4
        $stats     = $this->logViewer->statsTable();
70 4
        $chartData = $this->prepareChartData($stats);
71 4
        $percents  = $this->calcPercentages($stats->footer(), $stats->header());
72
73 4
        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 4
    public function listLogs(Request $request)
84
    {
85 4
        $stats   = $this->logViewer->statsTable();
86 4
        $headers = $stats->header();
87 4
        $rows    = $this->paginate($stats->rows(), $request);
88
89 4
        return $this->view('logs', compact('headers', 'rows'));
90
    }
91
92
    /**
93
     * Show the last log.
94
     *
95
     * @param  \Illuminate\Http\Request  $request
96
     *
97
     * @return \Illuminate\View\View
98
     */
99
    public function lastLog(Request $request)
100 8
    {
101
        $dates = $this->logViewer->dates();
102 8
        $lastDate = reset($dates);
103 8
        return $this->show($request, $lastDate);
104 4
    }
105 4
106 4
    /**
107
     * Show the log.
108 4
     *
109
     * @param  \Illuminate\Http\Request  $request
110
     * @param  string                    $date
111
     *
112
     * @return \Illuminate\View\View
113
     */
114
    public function show(Request $request, $date)
115
    {
116
        $level   = 'all';
117
        $log     = $this->getLogOrFail($date);
118
        $query   = $request->get('query');
119
        $levels  = $this->logViewer->levelsNames();
120 8
        $entries = $log->entries($level)->paginate($this->perPage);
121
122 8
        return $this->view('show', compact('level', 'log', 'query', 'levels', 'entries'));
123 4
    }
124
125 4
    /**
126 4
     * Filter the log entries by level.
127 4
     *
128 4
     * @param  \Illuminate\Http\Request  $request
129
     * @param  string                    $date
130 4
     * @param  string                    $level
131
     *
132
     * @return \Illuminate\View\View|\Illuminate\Http\RedirectResponse
133
     */
134
    public function showByLevel(Request $request, $date, $level)
135
    {
136
        if ($level === 'all')
137
            return redirect()->route($this->showRoute, [$date]);
138
139
        $log     = $this->getLogOrFail($date);
140
        $query   = $request->get('query');
141
        $levels  = $this->logViewer->levelsNames();
142 20
        $entries = $this->logViewer->entries($date, $level)->paginate($this->perPage);
143
144 20
        return $this->view('show', compact('level', 'log', 'query', 'levels', 'entries'));
145
    }
146 20
147 4
    /**
148
     * Show the log with the search query.
149 16
     *
150 16
     * @param  \Illuminate\Http\Request  $request
151 16
     * @param  string                    $date
152 16
     * @param  string                    $level
153 16
     *
154 16
     * @return \Illuminate\View\View|\Illuminate\Http\RedirectResponse
155 16
     */
156 16
    public function search(Request $request, $date, $level = 'all')
157 16
    {
158 16
        $query   = $request->get('query');
159 16
160 16
        if (is_null($query))
161
            return redirect()->route($this->showRoute, [$date]);
162 16
163
        $log     = $this->getLogOrFail($date);
164
        $levels  = $this->logViewer->levelsNames();
165
        $needles = array_map(function ($needle) {
166
            return Str::lower($needle);
167
        }, array_filter(explode(' ', $query)));
168
        $entries = $log->entries($level)
169
            ->unless(empty($needles), function (LogEntryCollection $entries) use ($needles) {
170
                return $entries->filter(function (LogEntry $entry) use ($needles) {
171
                    return Str::containsAll(Str::lower($entry->header), $needles);
172 4
                });
173
            })
174 4
            ->paginate($this->perPage);
175
176
        return $this->view('show', compact('level', 'log', 'query', 'levels', 'entries'));
177
    }
178
179
    /**
180
     * Download the log
181
     *
182
     * @param  string  $date
183
     *
184 12
     * @return \Symfony\Component\HttpFoundation\BinaryFileResponse
185
     */
186 12
    public function download($date)
187
    {
188 8
        return $this->logViewer->download($date);
189
    }
190 8
191 8
    /**
192
     * Delete a log.
193
     *
194
     * @param  \Illuminate\Http\Request  $request
195
     *
196
     * @return \Illuminate\Http\JsonResponse
197
     */
198
    public function delete(Request $request)
199
    {
200
        abort_unless($request->ajax(), 405, 'Method Not Allowed');
201
202
        $date = $request->input('date');
203
204
        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...
205
            'result' => $this->logViewer->delete($date) ? 'success' : 'error'
206
        ]);
207
    }
208
209 32
    /* -----------------------------------------------------------------
210
     |  Other Methods
211 32
     | -----------------------------------------------------------------
212
     */
213 32
214
    /**
215
     * Get the evaluated view contents for the given view.
216
     *
217
     * @param  string  $view
218
     * @param  array   $data
219
     * @param  array   $mergeData
220
     *
221
     * @return \Illuminate\View\View
222
     */
223
    protected function view($view, $data = [], $mergeData = [])
224 4
    {
225
        $theme = config('log-viewer.theme');
226 4
227 4
        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\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...
228 4
    }
229
230 4
    /**
231 4
     * Paginate logs.
232 4
     *
233 4
     * @param  array                     $data
234
     * @param  \Illuminate\Http\Request  $request
235 4
     *
236
     * @return \Illuminate\Pagination\LengthAwarePaginator
237
     */
238
    protected function paginate(array $data, Request $request)
239
    {
240
        $data = new Collection($data);
241
        $page = $request->get('page', 1);
242
        $path = $request->url();
243
244
        return new LengthAwarePaginator(
245
            $data->forPage($page, $this->perPage),
246 28
            $data->count(),
247
            $this->perPage,
248 28
            $page,
249
            compact('path')
250
        );
251 28
    }
252
253 4
    /**
254 4
     * Get a log or fail
255
     *
256
     * @param  string  $date
257 24
     *
258
     * @return \Arcanedev\LogViewer\Entities\Log|null
259
     */
260
    protected function getLogOrFail($date)
261
    {
262
        $log = null;
263
264
        try {
265
            $log = $this->logViewer->get($date);
266
        }
267 4
        catch (LogNotFoundException $e) {
268
            abort(404, $e->getMessage());
269 4
        }
270
271 4
        return $log;
272 4
    }
273
274
    /**
275 4
     * Prepare chart data.
276 4
     *
277 4
     * @param  \Arcanedev\LogViewer\Tables\StatsTable  $stats
278
     *
279
     * @return string
280
     */
281
    protected function prepareChartData(StatsTable $stats)
282
    {
283
        $totals = $stats->totals()->all();
284
285
        return json_encode([
286
            '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...
287
            'datasets' => [
288
                [
289
                    '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...
290
                    '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...
291 4
                    '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...
292
                ],
293 4
            ],
294 4
        ]);
295
    }
296 4
297 4
    /**
298 4
     * Calculate the percentage.
299 4
     *
300 4
     * @param  array  $total
301
     * @param  array  $names
302
     *
303
     * @return array
304 4
     */
305
    protected function calcPercentages(array $total, array $names)
306
    {
307
        $percents = [];
308
        $all      = Arr::get($total, 'all');
309
310
        foreach ($total as $level => $count) {
311
            $percents[$level] = [
312
                'name'    => $names[$level],
313
                'count'   => $count,
314
                'percent' => $all ? round(($count / $all) * 100, 2) : 0,
315
            ];
316
        }
317
318
        return $percents;
319
    }
320
}
321