Completed
Push — master ( dd842b...72a857 )
by Alexander
03:27
created

HasRelationships::getNestedRelations()   A

Complexity

Conditions 2
Paths 1

Size

Total Lines 14
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 11
nc 1
nop 2
dl 0
loc 14
ccs 9
cts 9
cp 1
crap 2
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
namespace Flugg\Responder\Transformers\Concerns;
4
5
use Illuminate\Database\Eloquent\Model;
6
7
/**
8
 * A trait to be used by a transformer to handle relations
9
 *
10
 * @package flugger/laravel-responder
11
 * @author  Alexander Tømmerås <[email protected]>
12
 * @license The MIT License
13
 */
14
trait HasRelationships
15
{
16
    /**
17
     * List of available relations.
18
     *
19
     * @var string[]
20
     */
21
    protected $relations = [];
22
23
    /**
24
     * A list of autoloaded default relations.
25
     *
26
     * @var array
27
     */
28
    protected $load = [];
29
30
    /**
31
     * Get a list of whitelisted relations, including nested relations.
32
     *
33
     * @return array
34
     */
35
    public function whitelistedRelations(): array
36
    {
37 13
        $nestedRelations = $this->getNestedRelations($this->relations, function ($transformer) {
38 5
            return $transformer->whitelistedRelations();
39 13
        });
40
41 13
        return array_merge($this->normalizeRelations($this->relations), $nestedRelations);
42
    }
43
44
    /**
45
     * Get a list of default relations, including nested relations.
46
     *
47
     * @return array
48
     */
49
    public function defaultRelations(): array
50
    {
51 13
        $nestedRelations = $this->getNestedRelations($this->load, function ($transformer) {
52
            return $transformer->defaultRelations();
53 13
        });
54
55 13
        return array_merge($this->normalizeRelations($this->load), $nestedRelations);
56
    }
57
58
    /**
59
     * Extract a list of nested relations from the transformers provided in the
60
     * list of relations.
61
     *
62
     * @param  array    $relations
63
     * @param  callable $nestedCallback
64
     * @return array
65
     */
66
    protected function getNestedRelations(array $relations, callable $nestedCallback): array
67
    {
68 8
        return collect($relations)->filter(function ($transformer, $relation) {
69 8
            return ! is_numeric($relation) && ! is_null($transformer);
70
        })->map(function ($transformer) {
71 5
            return $this->resolveTransformer($transformer);
72
        })->flatMap(function ($transformer, $relation) use ($nestedCallback) {
73 5
            return collect($nestedRelations = $nestedCallback($transformer))
74 5
                ->keys()
75 5
                ->reduce(function ($value, $nestedRelation) use ($relation, $nestedRelations) {
76 5
                    return array_merge($value, ["$relation.$nestedRelation" => $nestedRelations[$nestedRelation]]);
77 5
                }, []);
78 13
        })->all();
79
    }
80
81
    /**
82
     * Normalize relations to force a key value structure.
83
     *
84
     * @param  array $relations
85
     * @return array
86
     */
87
    protected function normalizeRelations(array $relations): array
88
    {
89 19
        return collect(array_keys($relations))->reduce(function ($normalized, $relation) use ($relations) {
90 14
            if (is_numeric($relation)) {
91 11
                $relation = $relations[$relation];
92
            }
93
94 14
            return array_merge($normalized, [$relation => $this->getQueryConstraint($relation)]);
95 19
        }, []);
96
    }
97
98
    /**
99
     * Normalize relations to force a key value structure.
100
     *
101
     * @param  string $relation
102
     * @return \Closure|null
103
     */
104 14
    protected function getQueryConstraint(string $relation)
105
    {
106 14
        if (! method_exists($this, $method = 'load' . ucfirst($relation))) {
107 14
            return null;
108
        }
109
110
        return function ($query) use ($method) {
111
            return $this->$method($query);
112
        };
113
    }
114
115
    /**
116
     * Resolve a relationship from a model instance.
117
     *
118
     * @param  \Illuminate\Database\Eloquent\Model $model
119
     * @param  string                              $identifier
120
     * @return mixed
121
     */
122 7
    protected function resolveRelation(Model $model, string $identifier)
123
    {
124 7
        $relation = $model->$identifier;
125
126 7
        if (method_exists($this, $method = 'filter' . ucfirst($identifier))) {
127
            return $this->$method($relation);
128
        }
129
130 7
        return $relation;
131
    }
132
133
    /**
134
     * Get a related transformer class mapped to a relation identifier.
135
     *
136
     * @param  string $identifier
137
     * @return string|null
138
     */
139 10
    protected function getRelatedTransformerName(string $identifier)
140
    {
141 10
        $relations = array_merge($this->relations, $this->load);
142
143 10
        return array_has($relations, $identifier) ? $relations[$identifier] : null;
144
    }
145
146
    /**
147
     * Resolve a transformer from a class name string.
148
     *
149
     * @param  string $transformer
150
     * @return mixed
151
     */
152
    protected abstract function resolveTransformer(string $transformer);
153
}