ControllerLinkType::getCollectionLinks()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 5
nc 2
nop 0
dl 0
loc 9
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Spatie\ResourceLinks\LinkTypes;
4
5
use Exception;
6
use Illuminate\Database\Eloquent\Model;
7
use Illuminate\Routing\Route;
8
use Illuminate\Routing\Router;
9
use Illuminate\Support\Arr;
10
use Illuminate\Support\Collection;
11
use Illuminate\Support\Str;
12
13
class ControllerLinkType extends LinkType
14
{
15
    /** @var string */
16
    private $controller;
17
18
    /** @var array */
19
    private $methods = [];
20
21
    /** @var array */
22
    private static $cachedRoutes = [];
23
24
    /** @var array */
25
    private $names = [];
26
27
    public static function make(string $controller): ControllerLinkType
28
    {
29
        return new ControllerLinkType($controller);
30
    }
31
32
    public function __construct(string $controller)
33
    {
34
        $this->controller = $controller;
35
    }
36
37
    public function methods($methods): ControllerLinkType
38
    {
39
        $this->methods = Arr::wrap($methods);
40
41
        return $this;
42
    }
43
44
    public function names(array $names): ControllerLinkType
45
    {
46
        $this->names = $names;
47
48
        return $this;
49
    }
50
51
    public function getLinks(Model $model = null): array
52
    {
53
        $this->ensureUserDefinedMethodsExist();
54
55
        $methodsToInclude = empty($this->methods)
56
            ? ['show', 'edit', 'update', 'destroy']
57
            : $this->methods;
58
59
        return $this->resolveLinks($methodsToInclude, $model);
60
    }
61
62
    public function getCollectionLinks(): array
63
    {
64
        $this->ensureUserDefinedMethodsExist();
65
66
        $methodsToInclude = empty($this->methods)
67
            ? ['index', 'store', 'create']
68
            : $this->methods;
69
70
        return $this->resolveLinks($methodsToInclude);
71
    }
72
73
    public static function clearCache(): void
74
    {
75
        self::$cachedRoutes = [];
76
    }
77
78
    private function resolveLinks(array $methodsToInclude, Model $model = null): array
79
    {
80
        $links = self::getRoutesForController($this->controller)
81
            ->filter(function (Route $route) use ($methodsToInclude) {
82
                return in_array($route->getActionMethod(), $methodsToInclude);
83
            })
84
            ->map(function (Route $route) use ($model) {
85
                $route = RouteLinkType::make($route)
86
                    ->parameters($this->parameters)
87
                    ->name($this->resolveNameForRoute($route))
88
                    ->prefix($this->prefix)
89
                    ->query($this->query)
90
                    ->serializer($this->serializer)
91
                    ->getLinks($model);
92
93
                return $route;
94
            })
95
            ->toArray();
96
97
        return ! empty($links)
98
            ? array_merge_recursive(...$links)
99
            : [];
100
    }
101
102
    private static function getRoutesForController(string $controller): Collection
103
    {
104
        if (array_key_exists($controller, self::$cachedRoutes)) {
105
            return self::$cachedRoutes[$controller];
106
        }
107
108
        $routes = collect(resolve(Router::class)->getRoutes()->getRoutes());
109
110
        self::$cachedRoutes[$controller] = $routes
111
            ->filter(function (Route $route) use ($controller) {
112
                return $controller === Str::before($route->getActionName(), '@');
113
            });
114
115
        return self::$cachedRoutes[$controller];
116
    }
117
118
    private function resolveNameForRoute(Route $route): string
119
    {
120
        $method = $route->getActionMethod();
121
122
        if (array_key_exists($method, $this->names)) {
123
            return $this->names[$method];
124
        }
125
126
        return $method;
127
    }
128
129
    private function ensureUserDefinedMethodsExist()
130
    {
131
        foreach ($this->methods as $method) {
132
            if (! method_exists($this->controller, $method)) {
133
                throw new Exception("Resource links tried to check non-existing method {$method} on controller: {$this->controller}");
134
            }
135
        }
136
    }
137
}
138