Passed
Push — master ( 0dde30...57f1fc )
by Jim
03:20
created

RouteManager::updateRoutes()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 15
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 3

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 8
nc 3
nop 1
dl 0
loc 15
ccs 8
cts 8
cp 1
crap 3
rs 10
c 1
b 0
f 0
1
<?php
2
3
namespace Oddvalue\DbRouter;
4
5
use Oddvalue\DbRouter\Route;
6
use Illuminate\Database\QueryException;
7
use Oddvalue\DbRouter\Contracts\Routable;
8
use Oddvalue\DbRouter\Contracts\RouteGenerator;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, Oddvalue\DbRouter\RouteGenerator. Consider defining an alias.

Let?s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let?s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
9
use Illuminate\Database\Eloquent\Relations\Relation;
10
use Oddvalue\DbRouter\Contracts\ChildRouteGenerator;
11
use Oddvalue\DbRouter\Exceptions\RouteCollisionException;
12
13
class RouteManager
14
{
15
    /**
16
     * If the slug has changed then softdelete current path for self and all
17
     * descendants and insert new path for self and all descendants
18
     * By default only the primary entity types have Routes
19
     *
20
     * @param Oddvalue\DbRouter\Contracts\Routable $instance
0 ignored issues
show
Bug introduced by
The type Oddvalue\DbRouter\Oddval...uter\Contracts\Routable was not found. Did you mean Oddvalue\DbRouter\Contracts\Routable? If so, make sure to prefix the type with \.
Loading history...
21
     */
22 36
    public function updateRoutes(Routable $instance)
23
    {
24 36
        $this->deleteRoutes($instance);
25
26 36
        $generator = $instance->getRouteGenerator();
27
28 36
        if (! $generator->isRoutable($instance)) {
29 3
            return;
30
        }
31
32 36
        $this->addRoutes($instance);
33
34 36
        if ($generator instanceof ChildRouteGenerator) {
35
            $generator->getRouteChildren($instance)->map(function ($childInstance) {
36 3
                $this->updateRoutes($childInstance);
37 36
            });
38
        }
39 36
    }
40
41
    /**
42
     * Create new Route OR restore old path if already exists
43
     */
44 36
    public function addRoutes(Routable $instance)
45
    {
46
        try {
47 36
            $routes = collect($instance->getRouteGenerator()->getRoutes($instance));
48
49 36
            $canonicalRouteString = $routes->shift();
50 36
            $canonicalId = $this->createOrRestoreRoute($canonicalRouteString, $instance)->id;
51
52
            $routes->each(function ($route) use ($instance, $canonicalId) {
53 9
                $this->createOrRestoreRoute($route, $instance, $canonicalId);
54 36
            });
55 3
        } catch (QueryException $e) {
56 3
            throw RouteCollisionException::fromQueryException($e);
57
        }
58 36
    }
59
60 36
    public function createOrRestoreRoute(string $routeString, Routable $instance, int $canonicalId = null)
61
    {
62 36
        $type = get_class($instance);
63 36
        $type = Relation::getMorphedModel($type) ?? $type;
64
        Route::onlyTrashed()->whereHasMorph('routable', $type, function ($query) use ($instance) {
65 36
            $query->where($instance->getKeyName(), $instance->id);
0 ignored issues
show
Bug introduced by
The method getKeyName() does not exist on Oddvalue\DbRouter\Contracts\Routable. Since it exists in all sub-types, consider adding an abstract or default implementation to Oddvalue\DbRouter\Contracts\Routable. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

65
            $query->where($instance->/** @scrutinizer ignore-call */ getKeyName(), $instance->id);
Loading history...
Bug introduced by
Accessing id on the interface Oddvalue\DbRouter\Contracts\Routable suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
66 36
        })->whereUrl($routeString)->forceDelete();
67
68 36
        $generator = $instance->getRouteGenerator();
0 ignored issues
show
Unused Code introduced by
The assignment to $generator is dead and can be removed.
Loading history...
69 36
        $path = $instance->routes()->withTrashed()->firstOrCreate([
70 36
            'url' => $routeString,
71 36
            'canonical_id' => $canonicalId,
72
        ]);
73 36
        $path->restore();
74
75 36
        return $path;
76
    }
77
78
    /**
79
     * Delete existing Route instances for an entity
80
     */
81 36
    public function deleteRoutes(Routable $instance)
82
    {
83 36
        $instance->routes()->delete();
84
85 36
        $generator = $instance->getRouteGenerator();
86 36
        if ($generator instanceof ChildRouteGenerator) {
87
            $generator->getRouteChildren($instance)->map(function ($childInstance) {
88 3
                $this->deleteRoutes($childInstance);
89 36
            });
90
        }
91 36
    }
92
93
    /**
94
     * Create a redirect route
95
     *
96
     * @param string $url
97
     * @param self $route
98
     * @return Route
99
     */
100 6
    public static function createRedirect(string $url, Route $route) : Route
101
    {
102 6
        $redirect = new Route(['url' => $url]);
103 6
        $redirect->redirect()->associate($route);
104 6
        $redirect->save();
105 6
        return $redirect;
106
    }
107
}
108