33namespace Backpack \CRUD \app \Library \CrudPanel \Traits ;
44
55use Illuminate \Support \Arr ;
6+ use Illuminate \Support \Str ;
67
78trait Relationships
89{
@@ -15,33 +16,20 @@ trait Relationships
1516 public function getRelationInstance ($ field )
1617 {
1718 $ entity = $ this ->getOnlyRelationEntity ($ field );
18- $ entity_array = explode ('. ' , $ entity );
19- $ relation_model = $ this ->getRelationModel ($ entity );
20-
21- $ related_method = Arr::last ($ entity_array );
22- if (count (explode ('. ' , $ entity )) == count (explode ('. ' , $ field ['entity ' ]))) {
23- $ relation_model = $ this ->getRelationModel ($ entity , -1 );
24- }
25- $ relation_model = new $ relation_model ();
26-
27- //if counts are diferent means that last element of entity is the field in relation.
28- if (count (explode ('. ' , $ entity )) != count (explode ('. ' , $ field ['entity ' ]))) {
29- if (in_array ($ related_method , $ relation_model ->getFillable ())) {
30- if (count ($ entity_array ) > 1 ) {
31- $ related_method = $ entity_array [(count ($ entity_array ) - 2 )];
32- $ relation_model = $ this ->getRelationModel ($ entity , -2 );
33- } else {
34- $ relation_model = $ this ->model ;
35- }
19+ $ possible_method = Str::before ($ entity , '. ' );
20+ $ model = $ this ->model ;
21+
22+ if (method_exists ($ model , $ possible_method )) {
23+ $ parts = explode ('. ' , $ entity );
24+ // here we are going to iterate through all relation parts to check
25+ // if the attribute is present in the relation string.
26+ foreach ($ parts as $ i => $ part ) {
27+ $ relation = $ model ->$ part ();
28+ $ model = $ relation ->getRelated ();
3629 }
37- }
38- if (count ($ entity_array ) == 1 ) {
39- if (method_exists ($ this ->model , $ related_method )) {
40- return $ this ->model ->{$ related_method }();
41- }
42- }
4330
44- return $ relation_model ->{$ related_method }();
31+ return $ relation ;
32+ }
4533 }
4634
4735 /**
@@ -70,6 +58,41 @@ public function inferRelationTypeFromRelationship($field)
7058 return Arr::last (explode ('\\' , get_class ($ relation )));
7159 }
7260
61+ public function getOnlyRelationEntity ($ relation_field )
62+ {
63+ $ relation_model = $ this ->getRelationModel ($ relation_field ['entity ' ], -1 );
64+ $ related_method = Str::afterLast ($ relation_field ['entity ' ], '. ' );
65+
66+ if (! method_exists ($ relation_model , $ related_method )) {
67+ return Str::beforeLast ($ relation_field ['entity ' ], '. ' );
68+ }
69+
70+ return $ relation_field ['entity ' ];
71+ }
72+
73+ /**
74+ * Get the fields for relationships, according to the relation type. It looks only for direct
75+ * relations - it will NOT look through relationships of relationships.
76+ *
77+ * @param string|array $relation_types Eloquent relation class or array of Eloquent relation classes. Eg: BelongsTo
78+ *
79+ * @return array The fields with corresponding relation types.
80+ */
81+ public function getFieldsWithRelationType ($ relation_types ): array
82+ {
83+ $ relation_types = (array ) $ relation_types ;
84+
85+ return collect ($ this ->fields ())
86+ ->where ('model ' )
87+ ->whereIn ('relation_type ' , $ relation_types )
88+ ->filter (function ($ item ) {
89+ $ related_model = get_class ($ this ->model ->{Str::before ($ item ['entity ' ], '. ' )}()->getRelated ());
90+
91+ return Str::contains ($ item ['entity ' ], '. ' ) && $ item ['model ' ] !== $ related_model ? false : true ;
92+ })
93+ ->toArray ();
94+ }
95+
7396 /**
7497 * Parse the field name back to the related entity after the form is submited.
7598 * Its called in getAllFieldNames().
@@ -96,6 +119,19 @@ public function parseRelationFieldNamesFromHtml($fields)
96119 return $ fields ;
97120 }
98121
122+ protected function changeBelongsToNamesFromRelationshipToForeignKey ($ data ) {
123+ $ belongs_to_fields = $ this ->getFieldsWithRelationType ('BelongsTo ' );
124+
125+ foreach ($ belongs_to_fields as $ relation_field ) {
126+ $ relation = $ this ->getRelationInstance ($ relation_field );
127+ if (Arr::has ($ data , $ relation ->getRelationName ())) {
128+ $ data [$ relation ->getForeignKeyName ()] = Arr::get ($ data , $ relation ->getRelationName ());
129+ unset($ data [$ relation ->getRelationName ()]);
130+ }
131+ }
132+ return $ data ;
133+ }
134+
99135 /**
100136 * Based on relation type returns the default field type.
101137 *
0 commit comments