Completed
Pull Request — master (#173)
by ARCANEDEV
03:38
created

LogViewerController::getLogOrFail()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 13
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 7
nc 2
nop 1
dl 0
loc 13
rs 9.4285
c 0
b 0
f 0
ccs 6
cts 6
cp 1
crap 2
1
<?php namespace Arcanedev\LogViewer\Http\Controllers;
2
3
use Arcanedev\LogViewer\Contracts\LogViewer as LogViewerContract;
4
use Arcanedev\LogViewer\Entities\LogEntry;
5
use Arcanedev\LogViewer\Exceptions\LogNotFoundException;
6
use Arcanedev\LogViewer\Tables\StatsTable;
7
use Illuminate\Http\Request;
8
use Illuminate\Pagination\LengthAwarePaginator;
9
use Illuminate\Routing\Controller;
10
use Illuminate\Support\Arr;
11
use Illuminate\Support\Collection;
12
use Illuminate\Support\Str;
13
14
/**
15
 * Class     LogViewerController
16
 *
17
 * @package  LogViewer\Http\Controllers
18
 * @author   ARCANEDEV <[email protected]>
19
 */
20
class LogViewerController extends Controller
21
{
22
    /* -----------------------------------------------------------------
23
     |  Properties
24
     | -----------------------------------------------------------------
25
     */
26
27
    /**
28
     * The log viewer instance
29
     *
30
     * @var \Arcanedev\LogViewer\Contracts\LogViewer
31
     */
32
    protected $logViewer;
33
34
    /** @var int */
35
    protected $perPage = 30;
36
37
    /** @var string */
38
    protected $showRoute = 'log-viewer::logs.show';
39
40
    /* -----------------------------------------------------------------
41
     |  Constructor
42
     | -----------------------------------------------------------------
43
     */
44
45
    /**
46
     * LogViewerController constructor.
47
     *
48
     * @param  \Arcanedev\LogViewer\Contracts\LogViewer  $logViewer
49
     */
50 33
    public function __construct(LogViewerContract $logViewer)
51
    {
52 33
        $this->logViewer = $logViewer;
53 33
        $this->perPage = config('log-viewer.per-page', $this->perPage);
54 33
    }
55
56
    /* -----------------------------------------------------------------
57
     |  Main Methods
58
     | -----------------------------------------------------------------
59
     */
60
61
    /**
62
     * Show the dashboard.
63
     *
64
     * @return \Illuminate\View\View
65
     */
66 3
    public function index()
67
    {
68 3
        $stats     = $this->logViewer->statsTable();
69 3
        $chartData = $this->prepareChartData($stats);
70 3
        $percents  = $this->calcPercentages($stats->footer(), $stats->header());
71
72 3
        return $this->view('dashboard', compact('chartData', 'percents'));
73
    }
74
75
    /**
76
     * List all logs.
77
     *
78
     * @param  \Illuminate\Http\Request  $request
79
     *
80
     * @return \Illuminate\View\View
81
     */
82 3
    public function listLogs(Request $request)
83
    {
84 3
        $stats   = $this->logViewer->statsTable();
85 3
        $headers = $stats->header();
86 3
        $rows    = $this->paginate($stats->rows(), $request);
87
88 3
        return $this->view('logs', compact('headers', 'rows', 'footer'));
89
    }
90
91
    /**
92
     * Show the log.
93
     *
94
     * @param  string  $date
95
     *
96
     * @return \Illuminate\View\View
97
     */
98 6
    public function show($date)
99
    {
100 6
        $log     = $this->getLogOrFail($date);
101 3
        $levels  = $this->logViewer->levelsNames();
102 3
        $entries = $log->entries($level = 'all')->paginate($this->perPage);
103
104 3
        return $this->view('show', compact('log', 'levels', 'level', 'search', 'entries'));
105
    }
106
107
    /**
108
     * Filter the log entries by level.
109
     *
110
     * @param  string  $date
111
     * @param  string  $level
112
     *
113
     * @return \Illuminate\View\View|\Illuminate\Http\RedirectResponse
114
     */
115 6
    public function showByLevel($date, $level)
116
    {
117 6
        $log = $this->getLogOrFail($date);
118
119 6
        if ($level === 'all')
120 3
            return redirect()->route($this->showRoute, [$date]);
121
122 3
        $levels  = $this->logViewer->levelsNames();
123 3
        $entries = $this->logViewer->entries($date, $level)->paginate($this->perPage);
124
125 3
        return $this->view('show', compact('log', 'levels', 'level', 'search', 'entries'));
126
    }
127
128
    /**
129
     * Show the log with the search query.
130
     *
131
     * @param  string                    $date
132
     * @param  string                    $level
133
     * @param  \Illuminate\Http\Request  $request
134
     *
135
     * @return \Illuminate\View\View
136
     */
137 3
    public function search($date, $level = 'all', Request $request) {
138 3
        $log = $this->getLogOrFail($date);
139
140 3
        if (is_null($query = $request->get('query')))
141
            return redirect()->route('log-viewer::logs.show', [$date]);
0 ignored issues
show
Bug Best Practice introduced by
The return type of return redirect()->route...s.show', array($date)); (Illuminate\Http\RedirectResponse) is incompatible with the return type documented by Arcanedev\LogViewer\Http...iewerController::search of type Illuminate\View\View.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
142
143 3
        $levels  = $this->logViewer->levelsNames();
144 3
        $entries = $log->entries($level)->filter(function (LogEntry $value) use ($query) {
145 3
            return Str::contains($value->header, $query);
146 3
        })->paginate($this->perPage);
147
148 3
        return $this->view('show', compact('log', 'levels', 'level', 'query', 'entries'));
149
    }
150
151
    /**
152
     * Download the log
153
     *
154
     * @param  string  $date
155
     *
156
     * @return \Symfony\Component\HttpFoundation\BinaryFileResponse
157
     */
158 3
    public function download($date)
159
    {
160 3
        return $this->logViewer->download($date);
161
    }
162
163
    /**
164
     * Delete a log.
165
     *
166
     * @param  \Illuminate\Http\Request  $request
167
     *
168
     * @return \Illuminate\Http\JsonResponse
169
     */
170 9
    public function delete(Request $request)
171
    {
172 9
        if ( ! $request->ajax())
173 3
            abort(405, 'Method Not Allowed');
174
175 6
        $date = $request->get('date');
176
177 6
        return response()->json([
178 6
            'result' => $this->logViewer->delete($date) ? 'success' : 'error'
179
        ]);
180
    }
181
182
    /* -----------------------------------------------------------------
183
     |  Other Methods
184
     | -----------------------------------------------------------------
185
     */
186
187
    /**
188
     * Get the evaluated view contents for the given view.
189
     *
190
     * @param  string  $view
191
     * @param  array   $data
192
     * @param  array   $mergeData
193
     *
194
     * @return \Illuminate\View\View
195
     */
196 15
    protected function view($view, $data = [], $mergeData = [])
197
    {
198 15
        $theme = config('log-viewer.theme');
199
200 15
        return view("log-viewer::{$theme}.{$view}", $data, $mergeData);
0 ignored issues
show
Bug Compatibility introduced by
The expression view("log-viewer::{$them...}", $data, $mergeData); of type Illuminate\View\View|Ill...\Contracts\View\Factory adds the type Illuminate\Contracts\View\Factory to the return on line 200 which is incompatible with the return type documented by Arcanedev\LogViewer\Http...gViewerController::view of type Illuminate\View\View.
Loading history...
201
    }
202
203
    /**
204
     * Paginate logs.
205
     *
206
     * @param  array                     $data
207
     * @param  \Illuminate\Http\Request  $request
208
     *
209
     * @return \Illuminate\Pagination\LengthAwarePaginator
210
     */
211 3
    protected function paginate(array $data, Request $request)
212
    {
213 3
        $data = new Collection($data);
214 3
        $page = $request->get('page', 1);
215 3
        $url  = $request->url();
216
217 3
        return new LengthAwarePaginator(
218 3
            $data->forPage($page, $this->perPage),
219 3
            $data->count(),
220 3
            $this->perPage,
221 3
            $page,
222 3
            compact('url')
223
        );
224
    }
225
226
    /**
227
     * Get a log or fail
228
     *
229
     * @param  string  $date
230
     *
231
     * @return \Arcanedev\LogViewer\Entities\Log|null
232
     */
233 15
    protected function getLogOrFail($date)
234
    {
235 15
        $log = null;
236
237
        try {
238 15
            $log = $this->logViewer->get($date);
239
        }
240 3
        catch (LogNotFoundException $e) {
241 3
            abort(404, $e->getMessage());
242
        }
243
244 12
        return $log;
245
    }
246
247
    /**
248
     * Prepare chart data.
249
     *
250
     * @param  \Arcanedev\LogViewer\Tables\StatsTable  $stats
251
     *
252
     * @return string
253
     */
254 3
    protected function prepareChartData(StatsTable $stats)
255
    {
256 3
        $totals = $stats->totals()->all();
257
258 3
        return json_encode([
259 3
            'labels'   => Arr::pluck($totals, 'label'),
260
            'datasets' => [
261
                [
262 3
                    'data'                 => Arr::pluck($totals, 'value'),
263 3
                    'backgroundColor'      => Arr::pluck($totals, 'color'),
264 3
                    'hoverBackgroundColor' => Arr::pluck($totals, 'highlight'),
265
                ],
266
            ],
267
        ]);
268
    }
269
270
    /**
271
     * Calculate the percentage.
272
     *
273
     * @param  array  $total
274
     * @param  array  $names
275
     *
276
     * @return array
277
     */
278 3
    protected function calcPercentages(array $total, array $names)
279
    {
280 3
        $percents = [];
281 3
        $all      = Arr::get($total, 'all');
282
283 3
        foreach ($total as $level => $count) {
284 3
            $percents[$level] = [
285 3
                'name'    => $names[$level],
286 3
                'count'   => $count,
287 3
                'percent' => $all ? round(($count / $all) * 100, 2) : 0,
288
            ];
289
        }
290
291 3
        return $percents;
292
    }
293
}
294