Scrutinizer GitHub App not installed

We could not synchronize checks via GitHub's checks API since Scrutinizer's GitHub App is not installed for this repository.

Install GitHub App

Completed
Push — master ( 1c3701...3da348 )
by Mark
02:16
created

BackendController::page()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 13
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 8
nc 1
nop 2
dl 0
loc 13
rs 9.4285
c 0
b 0
f 0
1
<?php
2
/**
3
 * Created by PhpStorm.
4
 * User: Mark
5
 * Date: 13/03/2016
6
 * Time: 14:55.
7
 */
8
9
namespace App\Plugins\Menus;
10
11
use DB;
12
use App\Model\Menu;
13
use App\Model\Page;
14
use App\Classes\Popup;
15
use Illuminate\Http\Request;
16
use App\Plugins\PluginEngine;
17
use League\Flysystem\Exception;
18
use App\Classes\Repositories\MenuRepository;
19
use App\Classes\Repositories\PageRepository;
20
use Illuminate\Database\Eloquent\Collection;
21
22
/**
23
 * Class Controller.
24
 */
25
class BackendController extends PluginEngine
26
{
27
    /**
28
     * @var MenuRepository
29
     */
30
    private $menus;
31
32
    /**
33
     * @var PageRepository
34
     */
35
    private $pages;
36
37
    /**
38
     * AdminController constructor.
39
     * @param MenuRepository $menus
40
     * @param PageRepository $pages
41
     */
42
    public function __construct(MenuRepository $menus, PageRepository $pages)
43
    {
44
        $this->menus = $menus;
45
46
        $this->pages = $pages;
47
    }
48
49
    /**
50
     * Show all the menus in one place.
51
     */
52
    public function index()
53
    {
54
        return $this->make('index')->with('menus', $this->menus->allByPriorityOrder())->with('pages', $this->pages->allPagesWithoutMenusAndEditable())->with('submenu_group', $this->menus->allSubmenusByPriorityOrderAndGrouped());
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 228 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
55
    }
56
57
    /**
58
     * Create a menu form.
59
     */
60
    public function create()
61
    {
62
        return $this->make('create')->with('submenus', $this->menus->listAllMenusNotRequired())->with('pages', $this->pages->listAllPagesWithoutMenusAndEditable());
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 164 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
63
    }
64
65
    /**
66
     * Delete a menu with ajax.
67
     *
68
     * @param Request $request
69
     * @param $id
70
     * @return bool
0 ignored issues
show
Documentation introduced by
Should the return type not be \Illuminate\Http\JsonResponse?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
71
     */
72
    public function ajax_delete(Request $request, $id)
0 ignored issues
show
Coding Style introduced by
This method is not in camel caps format.

This check looks for method names that are not written in camelCase.

In camelCase names are written without any punctuation, the start of each new word being marked by a capital letter. Thus the name database connection seeker becomes databaseConnectionSeeker.

Loading history...
73
    {
74
        try {
75
            /** @var Menu $menu */
76
            $menu = $this->menus->whereID($id);
77
78
            if ($menu->required) {
79
                return response()->json(['success' => false, 'message' => 'You cannot remove application bound menus']);
80
            }
81
82
            $menu_id = $menu->id;
83
84
            $menu->submenus()->delete();
0 ignored issues
show
Bug introduced by
The method delete does only exist in App\Model\Menu, but not in Illuminate\Database\Eloquent\Relations\HasMany.

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...
85
86
            $menu->delete();
87
88
            if ($menu_id) {
89
                $this->reorderRowsFromCollection($this->menus->allMenus());
90
            } else {
91
                $this->reorderRowsFromCollection($this->menus->submenusWhereID($menu_id));
0 ignored issues
show
Bug introduced by
It seems like $this->menus->submenusWhereID($menu_id) targeting App\Classes\Repositories...tory::submenusWhereID() can also be of type array<integer,object<Ill...base\Eloquent\Builder>>; however, App\Plugins\Menus\Backen...derRowsFromCollection() does only seem to accept null|object<Illuminate\D...se\Eloquent\Collection>, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
92
            }
93
94
            popups()->setSession($request->session())->add((new Popup(['message' => 'Menu and its entities were removed successfully.']))->success());
0 ignored issues
show
Documentation introduced by
$request->session() is of type object<Symfony\Component...\SessionInterface>|null, but the function expects a object<Illuminate\Session\Store>.

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...
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 150 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
95
96
            return response()->json(['success' => true, 'notify' => false]);
97
        } catch (\Exception $e) {
98
            return response()->json(['success' => false, 'notify' => true]);
99
        }
100
    }
101
102
    /**
103
     * Update the menu values with ajax.
104
     *
105
     * @param Request $request
106
     * @return \Illuminate\Http\JsonResponse
0 ignored issues
show
Documentation introduced by
Should the return type not be \Illuminate\Http\JsonResponse|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
107
     */
108
    public function ajax_update(Request $request)
0 ignored issues
show
Coding Style introduced by
This method is not in camel caps format.

This check looks for method names that are not written in camelCase.

In camelCase names are written without any punctuation, the start of each new word being marked by a capital letter. Thus the name database connection seeker becomes databaseConnectionSeeker.

Loading history...
109
    {
110
        $validator = \Validator::make($request->all(),
111
            [
112
                'value' => 'required',
113
            ],
114
            [
115
                'value.required' => 'A valid value is required.',
116
            ]);
117
118 View Code Duplication
        if ($validator->fails()) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
119
            return response()->json(['error' => ['message' => $validator->errors()->first()]]);
120
        }
121
122
        // VALIDATION FOR TITLES
123
        if ($request['name'] == 'title') {
124
            $request['title'] = str_slug($request['value']);
125
126
            $validator = \Validator::make($request->all(),
127
                [
128
                    'title' => 'unique:menus,slug,NULL,id,deleted_at,NULL|required|min:3|max:255',
129
                ],
130
                [
131
                    'title.unique' => 'A menu with this name already exists!',
132
                ]);
133
134 View Code Duplication
            if ($validator->fails()) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
135
                return response()->json(['error' => ['message' => $validator->errors()->first()]]);
136
            }
137
        }
138
139
        // VALIDATION FOR LINKS
140
        if ($request['name'] == 'link') {
141
            $request['link'] = $request['value'];
142
            {
143
                $hashed = str_contains($request['value'], '#');
144
145
                if ($hashed == false) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
146
                    $validator = \Validator::make($request->all(),
147
                    [
148
                        'link' => 'active_url',
149
                    ]);
150
151 View Code Duplication
                    if ($validator->fails()) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
152
                        return response()->json(['error' => ['message' => $validator->errors()->first()]]);
153
                    }
154
                }
155
            }
156
        }
157
158
        try {
159
            $method = 'set'.ucwords($request['name']);
160
161
            /** @var Menu $menu */
162
            $menu = $this->menus->whereID($request['pk']);
163
164
            /*
165
             * DO NOT CHANGE THE SLUG OF REQUIRED ITEMS, SINCE
166
             * THE APPLICATION USES THE SLUG TO RETRIEVE THE ITEM.
167
             */
168
            if (!$menu->required && $request['name'] == 'title') {
169
                $menu->slug = ($request['title']);
170
            }
171
            $menu->$method($request['value'])->save();
172
        } catch (Exception $e) {
173
            return response()->json(['error' => ['message' => 'Some strange error has occurred.']]);
174
        }
175
    }
176
177
    /**
178
     * Run this to re-order all columns of their counterpart menus
179
     * if a row is deleted or it becaomes somewhat unsynced.
180
     *
181
     * @param Collection $collection
0 ignored issues
show
Documentation introduced by
Should the type for parameter $collection not be null|Collection?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
182
     * @return bool
183
     */
184
    public function reorderRowsFromCollection(Collection $collection = null)
185
    {
186
        $menus = $collection->sortBy('order_id');
0 ignored issues
show
Bug introduced by
It seems like $collection is not always an object, but can also be of type null. Maybe add an additional type check?

If a variable is not always an object, we recommend to add an additional type check to ensure your method call is safe:

function someFunction(A $objectMaybe = null)
{
    if ($objectMaybe instanceof A) {
        $objectMaybe->doSomething();
    }
}
Loading history...
187
188
        $order = 1;
189
190
        /** @var Menu $menu */
191
        foreach ($menus as $menu) {
192
            $menu->order_id = $order;
193
            $menu->save();
194
            $order += 1;
0 ignored issues
show
Coding Style introduced by
Increment operators should be used where possible; found "$order += 1;" but expected "$order++"
Loading history...
195
        }
196
197
        return true;
198
    }
199
200
    /**
201
     * Reorder the menus location to the table using datatables API.
202
     * This uses a transaction protocol so that no interactions can be made to it
203
     * while this is in progress, which in turn makes it more consistent with what it does.
204
     *
205
     * @param Request $request
206
     * @return \Illuminate\Http\JsonResponse
207
     */
208
    public function ajax_order(Request $request)
0 ignored issues
show
Coding Style introduced by
This method is not in camel caps format.

This check looks for method names that are not written in camelCase.

In camelCase names are written without any punctuation, the start of each new word being marked by a capital letter. Thus the name database connection seeker becomes databaseConnectionSeeker.

Loading history...
209
    {
210
        $json = $request->json()->all();
211
212
        DB::beginTransaction();
213
214
        try {
215
            foreach ($json as $array) {
216
                $slug = $array['slug'];
217
                $new_value = $array['n'];
218
219
                $menu = $this->menus->whereName($slug);
220
                $menu->order_id = $new_value;
221
                $menu->save();
0 ignored issues
show
Bug introduced by
The method save does only exist in Illuminate\Database\Eloquent\Model, but not in Illuminate\Database\Concerns\BuildsQueries.

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...
222
            }
223
224
            DB::commit();
225
        } catch (\Exception $e) {
226
            DB::rollBack();
227
228
            return response()->json(['success'=>false, 'message'=>'Changes could not be saved.']);
229
        }
230
231
        return response()->json(['success'=>true, 'message'=>'Your changes to the row orders have been saved.']);
232
    }
233
234
    /**
235
     *  Process a form into a mode.
236
     *
237
     * @param Request $request
238
     * @return \Illuminate\Http\RedirectResponse
239
     */
240
    public function store(Request $request, Menu $menu)
241
    {
242
        $request['slug'] = str_slug($request['title']);
243
244
        // we must validate that a title exists.
245
        $this->validate($request, ['slug' => 'required|unique:menus,slug,NULL,id,deleted_at,NULL|min:3|max:255']);
246
247
        /*
248
         * Generic page creation with only a single attached internal page.
249
         * This does not contain, submenus, or external links.
250
         */
251
        if ($this->isInternalPageCreation($request)) {
252
            /** @var Page $page */
253
            $page = $this->pages->whereID($request['page_id']);
254
255
            $menu->title = ($request['title']);
256
            $menu->slug = (str_slug($request['title']));
257
            $menu->target = ($request['target']);
258
            $menu->enabled = $request['enabled'] ? true : false;
259
            $menu->creator_id = (account()->id);
260
            $this->attachSubmenuIfExists($request, $menu);
261
            $page->menus()->save($menu);
0 ignored issues
show
Bug introduced by
The method save does only exist in Illuminate\Database\Eloquent\Relations\HasMany, but not in Illuminate\Database\Eloquent\Collection.

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...
262 View Code Duplication
            if ($request['submenu_id']) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
263
                $this->reorderRowsFromCollection($this->menus->submenusWhereID($request['submenu_id']));
0 ignored issues
show
Bug introduced by
It seems like $this->menus->submenusWh...$request['submenu_id']) targeting App\Classes\Repositories...tory::submenusWhereID() can also be of type array<integer,object<Ill...base\Eloquent\Builder>>; however, App\Plugins\Menus\Backen...derRowsFromCollection() does only seem to accept null|object<Illuminate\D...se\Eloquent\Collection>, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
264
            } else {
265
                $this->reorderRowsFromCollection($this->menus->all());
266
            }
267
268
            return redirect()->route('menus');
269
        } elseif ($this->isExternalPageCreation($request)) {
270
            $this->validate($request, ['external_link'=>'url']);
271
            $menu->title = ($request['title']);
272
            $menu->slug = (str_slug($request['title']));
273
            $menu->target = ($request['target']);
274
            $menu->enabled = $request['enabled'] ? true : false;
275
            $menu->creator_id =(account()->id);
276
            $menu->link = ($request['external_link']);
277
            $this->attachSubmenuIfExists($request, $menu);
278
            $menu->save();
279 View Code Duplication
            if ($request['submenu_id']) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
280
                $this->reorderRowsFromCollection($this->menus->submenusWhereID($request['submenu_id']));
0 ignored issues
show
Bug introduced by
It seems like $this->menus->submenusWh...$request['submenu_id']) targeting App\Classes\Repositories...tory::submenusWhereID() can also be of type array<integer,object<Ill...base\Eloquent\Builder>>; however, App\Plugins\Menus\Backen...derRowsFromCollection() does only seem to accept null|object<Illuminate\D...se\Eloquent\Collection>, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
281
            } else {
282
                $this->reorderRowsFromCollection($this->menus->all());
283
            }
284
285
            return redirect()->route('menus');
286
        }
287
288
        $this->validate($request, ['page_id' => 'required', 'external_link' => 'required'], ['required'=>'Please attach either a page or external link to this menu']);
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 167 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
289
290
        return redirect()->route('menus');
291
    }
292
293
    /**
294
     * Check if a submenu id exists for the new menu.
295
     * If true, save it to the menus creation.
296
     *
297
     * @param Request $request
298
     * @param Menu $menu
299
     * @return Menu
300
     */
301
    private function attachSubmenuIfExists(Request $request, Menu $menu)
302
    {
303
        if ($request['submenu_id']) {
304
            /** @var Menu $submenu */
305
            $submenu = $this->menus->whereID($request['submenu_id']);
306
307
            $menu->menu_id = ($submenu->id);
308
        }
309
310
        return $menu;
311
    }
312
313
    /**
314
     * Check that the form being process is a internal page creation only.
315
     *
316
     * @param Request $request
317
     * @return bool
318
     */
319
    private function isExternalPageCreation(Request $request)
320
    {
321
        return $request['external_link'] && ! $request['page_id'];
322
    }
323
324
    /**
325
     * Check that the form being process is a internal page creation only.
326
     *
327
     * @param Request $request
328
     * @return bool
329
     */
330
    private function isInternalPageCreation(Request $request)
331
    {
332
        return $request['page_id'] && ! $request['external_link'];
333
    }
334
335
    /**
336
     * Attach a page to the menu as a sub.
337
     *
338
     * Messey on one line but saves some space.
339
     * @param Request $request
340
     * @return \Illuminate\Http\RedirectResponse
341
     */
342
    public function attach(Request $request)
343
    {
344
        /** @var Page $page */
345
        $page = $this->pages->whereID($request['page_id']);
346
347
        /** @var Menu $menu */
348
        $menu = $this->menus->whereID($request['menu_id']);
349
350
        $model = new Menu;
351
        $model->title = ucfirst($page->seo_title);
352
        $model->link = url(str_slug(ucfirst($page->seo_title)));
353
        $model->enabled = true;
354
        $menu->submenus()->save($model);
355
356
        return redirect()->route('menus');
357
    }
358
359
    /**
360
     * Create a menu using a page as a base information.
361
     *
362
     * @param Request $request
363
     * @param Menu $menu
364
     * @return mixed
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use \Illuminate\Http\RedirectResponse.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
365
     */
366
    public function page(Request $request, Menu $menu)
0 ignored issues
show
Unused Code introduced by
The parameter $menu is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
367
    {
368
        /** @var Page $page */
369
        $page = $this->pages->whereID($request['page_id']);
370
371
        $menu = new Menu;
372
        $menu->link = (url($page->slug));
373
        $menu->title = ($page->seo_title);
374
        $menu->enabled = true;
375
        $menu->save();
376
377
        return redirect()->route('menus');
378
    }
379
}
380