Passed
Pull Request — master (#1)
by Tom
03:27
created

HasLinksTrait::buildLinks()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 17
rs 9.7
c 0
b 0
f 0
cc 3
nc 3
nop 0
1
<?php
2
/**
3
 * Created by PhpStorm.
4
 * User: tom
5
 * Date: 28/03/19
6
 * Time: 12:47
7
 */
8
9
namespace TomHart\Restful\Traits;
10
11
use Illuminate\Database\Eloquent\Relations\Relation;
12
use Illuminate\Routing\Router;
13
use Illuminate\Support\Str;
14
use ReflectionException;
15
use ReflectionMethod;
16
use TomHart\Restful\Concerns\HasLinks;
17
use TomHart\Restful\LinkBuilder;
18
19
trait HasLinksTrait
20
{
21
22
    /**
23
     * Append attributes to query when building a query.
24
     *
25
     * @param string[]|string $attributes
26
     * @return $this
27
     */
28
    abstract public function append($attributes);
29
30
    /**
31
     * Get the value of the model's route key.
32
     *
33
     * @return mixed
34
     */
35
    abstract public function getRouteKey();
36
37
    /**
38
     * Add the links attribute to the model.
39
     */
40
    public function initializeHasLinksTrait(): void
41
    {
42
        $this->append('_links');
43
    }
44
45
    /**
46
     * Get the links for this model.
47
     * @return mixed[]
48
     * @throws ReflectionException
49
     */
50
    public function getLinksAttribute(): array
51
    {
52
        $links = $this->buildLinks();
53
        $relationships = $this->buildRelationshipLinks();
54
        if (!empty($relationships)) {
55
            $links['relationships'] = $relationships;
56
        }
57
58
        return $links;
59
    }
60
61
    /**
62
     * Returns the _links for the REST responses.
63
     *
64
     * @return mixed[]
65
     */
66
    public function buildLinks(): array
67
    {
68
        $routes = ['create', 'store', 'show', 'update', 'destroy'];
69
        $links = [];
70
71
        $router = app(Router::class);
72
73
        foreach ($routes as $routePart) {
74
            $link = LinkBuilder::buildLink($this, $routePart, $router);
75
76
            if ($link) {
77
                $links[$routePart] = $link;
78
            }
79
        }
80
81
        return $links;
82
    }
83
84
85
    /**
86
     * Builds the links to create the relationship resources.
87
     *
88
     * @return mixed[]
89
     * @throws ReflectionException
90
     */
91
    public function buildRelationshipLinks(): array
92
    {
93
        $methods = get_class_methods($this);
94
95
        $links = [];
96
        $router = app(Router::class);
97
98
        foreach ($methods as $method) {
99
            $method2 = new ReflectionMethod($this, $method);
100
            $return = (string)$method2->getReturnType();
101
102
            if (empty($return)) {
103
                continue;
104
            }
105
106
            $isRelationship = is_subclass_of($return, Relation::class);
107
108
            if (!$isRelationship) {
109
                continue;
110
            }
111
112
            /** @var Relation $relationship */
113
            $relationship = $this->$method();
114
115
            $targetClass = $relationship->getRelated();
116
117
            if (!($targetClass instanceof HasLinks)) {
118
                continue;
119
            }
120
121
            $createLink = LinkBuilder::buildLink($targetClass, 'create', $router);
122
            $storeLink = LinkBuilder::buildLink($targetClass, 'store', $router);
123
124
            if ($createLink || $storeLink) {
125
                $links[$method] = [
126
                    'create' => $createLink,
127
                    'store' => $storeLink
128
                ];
129
            }
130
        }
131
132
        return $links;
133
    }
134
135
136
    /**
137
     * Return the name for the resource route this model
138
     * @return string|null
139
     */
140
    public function getRouteName(): ?string
141
    {
142
        $name = $this->getRouteKey();
143
        if (!$name) {
144
            return null;
145
        }
146
        return Str::kebab(Str::studly($name));
147
    }
148
}
149