Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
1 | <?php |
||
16 | trait HasRelationships |
||
17 | { |
||
18 | /** |
||
19 | * List of available relations. |
||
20 | * |
||
21 | * @var string[] |
||
22 | */ |
||
23 | protected $relations = []; |
||
24 | |||
25 | /** |
||
26 | * A list of autoloaded default relations. |
||
27 | * |
||
28 | * @var array |
||
29 | */ |
||
30 | protected $load = []; |
||
31 | |||
32 | /** |
||
33 | * Get a list of whitelisted relations that are requested, including nested relations. |
||
34 | * |
||
35 | * @param array $requested |
||
36 | * @return array |
||
37 | */ |
||
38 | 42 | View Code Duplication | public function relations(array $requested = []): array |
46 | |||
47 | /** |
||
48 | * Get a list of default relations including nested relations. |
||
49 | * |
||
50 | * @param array $requested |
||
51 | * @return array |
||
52 | */ |
||
53 | 42 | View Code Duplication | public function defaultRelations(array $requested = []): array |
61 | |||
62 | /** |
||
63 | * Get a list of available relations from the transformer with a normalized structure. |
||
64 | * |
||
65 | * @return array |
||
66 | */ |
||
67 | 45 | protected function availableRelations(): array |
|
71 | |||
72 | /** |
||
73 | * Get nested relations from transformers resolved from the $available parameter that |
||
74 | * also occur in the $requested parameter. |
||
75 | * |
||
76 | * @param array $requested |
||
77 | * @param array $available |
||
78 | * @param string $method |
||
79 | * @return array |
||
80 | */ |
||
81 | 42 | protected function nestedRelations(array $requested, array $available, string $method): array |
|
82 | { |
||
83 | 42 | $transformers = $this->mappedTransformers($available); |
|
84 | |||
85 | return collect(array_keys($transformers))->reduce(function ($nestedRelations, $relation) use ($requested, $method, $transformers) { |
||
86 | 12 | $transformer = $transformers[$relation]; |
|
87 | 12 | $children = $this->extractChildRelations($requested, $relation); |
|
88 | 12 | $childRelations = $this->wrapChildRelations($transformer->$method($children), $relation); |
|
89 | |||
90 | 12 | return array_merge($nestedRelations, $childRelations); |
|
91 | 42 | }, []); |
|
92 | } |
||
93 | |||
94 | /** |
||
95 | * Extract available root relations from the given list of relations. |
||
96 | * |
||
97 | * @param array $relations |
||
98 | * @return array |
||
99 | */ |
||
100 | 42 | protected function extractRelations(array $relations): array |
|
101 | { |
||
102 | 42 | $available = $this->availableRelations(); |
|
103 | |||
104 | return array_filter($this->mapRelations($relations, function ($relation, $constraint) { |
||
105 | 19 | $identifier = explode('.', $relation)[0]; |
|
106 | 19 | $constraint = $identifier === $relation ? $constraint : null; |
|
107 | |||
108 | 19 | return [$identifier => $constraint ?: $this->resolveQueryConstraint($identifier)]; |
|
109 | }), function ($relation) use ($available) { |
||
110 | 19 | return Arr::has($available, explode(':', $relation)[0]); |
|
111 | 42 | }, ARRAY_FILTER_USE_KEY); |
|
112 | } |
||
113 | |||
114 | /** |
||
115 | * Extract all nested relations under a given identifier. |
||
116 | * |
||
117 | * @param array $relations |
||
118 | * @param string $identifier |
||
119 | * @return array |
||
120 | */ |
||
121 | 12 | protected function extractChildRelations(array $relations, string $identifier): array |
|
134 | |||
135 | /** |
||
136 | * Wrap the identifier of each relation of the given list of nested relations with |
||
137 | * the parent relation identifier using dot notation. |
||
138 | * |
||
139 | * @param array $nestedRelations |
||
140 | * @param string $relation |
||
141 | * @return array |
||
142 | */ |
||
143 | 12 | protected function wrapChildRelations(array $nestedRelations, string $relation): array |
|
149 | |||
150 | /** |
||
151 | * Normalize relations to force an [identifier => constraint/transformer] structure. |
||
152 | * |
||
153 | * @param array $relations |
||
154 | * @return array |
||
155 | */ |
||
156 | 47 | protected function normalizeRelations(array $relations): array |
|
166 | |||
167 | /** |
||
168 | * Map over a list of relations with the [identifier => constraint/transformer] structure. |
||
169 | * |
||
170 | * @param array $relations |
||
171 | * @param callable $callback |
||
172 | * @return array |
||
173 | */ |
||
174 | 42 | protected function mapRelations(array $relations, callable $callback): array |
|
184 | |||
185 | /** |
||
186 | * Applies any query constraints defined in the transformer to the list of relaations. |
||
187 | * |
||
188 | * @param array $relations |
||
189 | * @return array |
||
190 | */ |
||
191 | 42 | protected function applyQueryConstraints(array $relations): array |
|
197 | |||
198 | /** |
||
199 | * Resolve a query constraint for a given relation identifier. |
||
200 | * |
||
201 | * @param string $identifier |
||
202 | * @return \Closure|null |
||
203 | */ |
||
204 | 20 | protected function resolveQueryConstraint(string $identifier) |
|
218 | |||
219 | /** |
||
220 | * Resolve a relation from a model instance and an identifier. |
||
221 | * |
||
222 | * @param \Illuminate\Database\Eloquent\Model $model |
||
223 | * @param string $identifier |
||
224 | * @return mixed |
||
225 | */ |
||
226 | 19 | protected function resolveRelation(Model $model, string $identifier) |
|
240 | |||
241 | /** |
||
242 | * Resolve a list of transformers from a list of relations mapped to transformers. |
||
243 | * |
||
244 | * @param array $relations |
||
245 | * @return array |
||
246 | */ |
||
247 | 42 | protected function mappedTransformers(array $relations): array |
|
257 | |||
258 | /** |
||
259 | * Get a related transformer class mapped to a relation identifier. |
||
260 | * |
||
261 | * @param string $identifier |
||
262 | * @return string|null |
||
263 | */ |
||
264 | 23 | protected function mappedTransformerClass(string $identifier) |
|
268 | |||
269 | /** |
||
270 | * Resolve a transformer from a class name string. |
||
271 | * |
||
272 | * @param string $transformer |
||
273 | * @return mixed |
||
274 | */ |
||
275 | protected abstract function resolveTransformer(string $transformer); |
||
276 | } |
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.