Skip to content

Commit 986abec

Browse files
authored
Merge pull request #4164 from Laravel-Backpack/refactor-model-property-check
Add support for single-method Laravel Accessors and Mutators
2 parents cc7be57 + cb70804 commit 986abec

File tree

4 files changed

+74
-48
lines changed

4 files changed

+74
-48
lines changed

src/app/Library/CrudPanel/CrudPanel.php

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -489,22 +489,4 @@ private function getRelatedEntries($model, $relationString)
489489

490490
return $results;
491491
}
492-
493-
/**
494-
* Check if the method in the given model has any parameters.
495-
*
496-
* @param object $model
497-
* @param string $method
498-
* @return bool
499-
*/
500-
private function modelMethodHasParameters($model, $method)
501-
{
502-
$reflectClassMethod = new \ReflectionMethod(get_class($model), $method);
503-
504-
if ($reflectClassMethod->getNumberOfParameters() > 0) {
505-
return true;
506-
}
507-
508-
return false;
509-
}
510492
}

src/app/Library/CrudPanel/Traits/ColumnsProtectedMethods.php

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -190,32 +190,33 @@ protected function makeSureColumnHasEntity($column)
190190
if (strpos($column['name'], '.') !== false) {
191191
$possibleMethodName = Str::before($column['name'], '.');
192192

193-
// if the first part of the string exists as method,
194-
// it is a relationship
193+
// if the first part of the string exists as method in the model
195194
if (method_exists($this->model, $possibleMethodName)) {
196195

197-
// if it has parameters it's not a relation method.
198-
$column['entity'] = $this->modelMethodHasParameters($this->model, $possibleMethodName) ? false : $column['name'];
196+
// check model method for possibility of being a relationship
197+
$column['entity'] = $this->modelMethodIsRelationship($this->model, $possibleMethodName) ? $column['name'] : false;
199198

200-
$parts = explode('.', $column['entity']);
199+
if ($column['entity']) {
200+
$parts = explode('.', $column['entity']);
201201

202-
$attribute_in_relation = false;
202+
$attribute_in_relation = false;
203203

204-
$model = $this->model;
204+
$model = $this->model;
205205

206-
// here we are going to iterate through all relation parts to check
207-
// if the attribute is present in the relation string.
208-
foreach ($parts as $i => $part) {
209-
try {
210-
$model = $model->$part()->getRelated();
211-
} catch (\Exception $e) {
212-
$attribute_in_relation = true;
206+
// here we are going to iterate through all relation parts to check
207+
// if the attribute is present in the relation string.
208+
foreach ($parts as $i => $part) {
209+
try {
210+
$model = $model->$part()->getRelated();
211+
} catch (\Exception $e) {
212+
$attribute_in_relation = true;
213+
}
214+
}
215+
// if the user setup the attribute in relation string, we are not going to infer that attribute from model
216+
// instead we get the defined attribute by the user.
217+
if ($attribute_in_relation) {
218+
$column['attribute'] = $column['attribute'] ?? end($parts);
213219
}
214-
}
215-
// if the user setup the attribute in relation string, we are not going to infer that attribute from model
216-
// instead we get the defined attribute by the user.
217-
if ($attribute_in_relation) {
218-
$column['attribute'] = $column['attribute'] ?? end($parts);
219220
}
220221

221222
return $column;
@@ -225,8 +226,8 @@ protected function makeSureColumnHasEntity($column)
225226
// if there's a method on the model with this name
226227
if (method_exists($this->model, $column['name'])) {
227228

228-
// if it has parameters it's not a relation method.
229-
$column['entity'] = $this->modelMethodHasParameters($this->model, $column['name']) ? false : $column['name'];
229+
// check model method for possibility of being a relationship
230+
$column['entity'] = $this->modelMethodIsRelationship($this->model, $column['name']);
230231

231232
return $column;
232233
}
@@ -237,9 +238,8 @@ protected function makeSureColumnHasEntity($column)
237238
$possibleMethodName = Str::replaceLast('_id', '', $column['name']);
238239

239240
if (method_exists($this->model, $possibleMethodName)) {
240-
241-
// if it has parameters it's not a relation method.
242-
$column['entity'] = $this->modelMethodHasParameters($this->model, $possibleMethodName) ? false : $possibleMethodName;
241+
// check model method for possibility of being a relationship
242+
$column['entity'] = $this->modelMethodIsRelationship($this->model, $possibleMethodName);
243243

244244
return $column;
245245
}

src/app/Library/CrudPanel/Traits/FieldsProtectedMethods.php

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -142,16 +142,16 @@ protected function makeSureFieldHasEntity($field)
142142
//if the name is dot notation we are sure it's a relationship
143143
if (strpos($field['name'], '.') !== false) {
144144
$possibleMethodName = Str::of($field['name'])->before('.');
145-
// if it has parameters it's not a relation method.
146-
$field['entity'] = $this->modelMethodHasParameters($model, $possibleMethodName) ? false : $field['name'];
145+
// check model method for possibility of being a relationship
146+
$field['entity'] = $this->modelMethodIsRelationship($model, $possibleMethodName) ? $field['name'] : false;
147147

148148
return $field;
149149
}
150150

151151
// if there's a method on the model with this name
152152
if (method_exists($model, $field['name'])) {
153-
// if it has parameters it's not a relation method.
154-
$field['entity'] = $this->modelMethodHasParameters($model, $field['name']) ? false : $field['name'];
153+
// check model method for possibility of being a relationship
154+
$field['entity'] = $this->modelMethodIsRelationship($model, $field['name']);
155155

156156
return $field;
157157
}
@@ -162,8 +162,8 @@ protected function makeSureFieldHasEntity($field)
162162
$possibleMethodName = Str::replaceLast('_id', '', $field['name']);
163163

164164
if (method_exists($model, $possibleMethodName)) {
165-
// if it has parameters it's not a relation method.
166-
$field['entity'] = $this->modelMethodHasParameters($model, $possibleMethodName) ? false : $possibleMethodName;
165+
// check model method for possibility of being a relationship
166+
$field['entity'] = $this->modelMethodIsRelationship($model, $possibleMethodName);
167167

168168
return $field;
169169
}

src/app/Library/CrudPanel/Traits/Relationships.php

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,4 +309,48 @@ private static function getPivotFieldStructure($field)
309309

310310
return $pivotSelectorField;
311311
}
312+
313+
/**
314+
* Checks the properties of the provided method to better verify if it could be a relation.
315+
* Case the method is not public, is not a relation.
316+
* Case the return type is Attribute, or extends Attribute is not a relation method.
317+
* If the return type extends the Relation class is for sure a relation
318+
* Otherwise we just assume it's a relation.
319+
*
320+
* DEV NOTE: In future versions we will return `false` when no return type is set and make the return type mandatory for relationships.
321+
* This function should be refactored to only check if $returnType is a subclass of Illuminate\Database\Eloquent\Relations\Relation.
322+
*
323+
* @param $model
324+
* @param $method
325+
* @return bool|string
326+
*/
327+
private function modelMethodIsRelationship($model, $method)
328+
{
329+
$methodReflection = new \ReflectionMethod($model, $method);
330+
331+
// relationship methods function does not have parameters
332+
if ($methodReflection->getNumberOfParameters() > 0) {
333+
return false;
334+
}
335+
336+
// relationships are always public methods.
337+
if (! $methodReflection->isPublic()) {
338+
return false;
339+
}
340+
341+
$returnType = $methodReflection->getReturnType();
342+
343+
if ($returnType) {
344+
$returnType = $returnType->getName();
345+
if (is_a((new $returnType), 'Illuminate\Database\Eloquent\Casts\Attribute')) {
346+
return false;
347+
}
348+
349+
if (is_a((new $returnType), 'Illuminate\Database\Eloquent\Relations\Relation')) {
350+
return $method;
351+
}
352+
}
353+
354+
return $method;
355+
}
312356
}

0 commit comments

Comments
 (0)