@@ -104,20 +104,35 @@ abstract class Entity extends Model implements
104104 'owned_by ' ,
105105 ];
106106
107- public function newFromBuilder ($ attributes = [], $ connection = null ): static
107+ // TODO - To Remove, reduce contents/relatedData to just one of them.
108+ // TODO - Update/remove existing usages of contents/relatedData
109+ // TODO - Review usages of query-time update or mass insert of entity model data since those will still need to consider the multi-table layout.
110+
111+ /**
112+ * Override the save method to also save the contents for convenience.
113+ */
114+ public function save (array $ options = []): bool
108115 {
109- $ entityFields = array_intersect_key ( $ attributes , array_flip ( static :: $ commonFields ) );
110- $ extraFields = array_diff_key ( $ attributes , $ entityFields );
116+ $ contents = $ this -> relatedData ()-> firstOrNew ( );
117+ $ contentFields = $ this -> getContentsAttributes ( );
111118
112- $ instance = parent ::newFromBuilder ($ entityFields , $ connection );
113- $ data = $ instance ->relatedData ()->newModelInstance ()->newFromBuilder ($ extraFields , $ connection );
119+ foreach ($ contentFields as $ key => $ value ) {
120+ $ contents ->setAttribute ($ key , $ value );
121+ unset($ this ->attributes [$ key ]);
122+ }
114123
115- $ instance ->setRelation ('contents ' , $ data );
124+ $ result = parent ::save ($ options );
125+ $ contentsResult = true ;
116126
117- return $ instance ;
118- }
127+ if ($ result && $ contents ->isDirty ()) {
128+ $ contentsResult = $ contents ->save ();
129+ $ this ->touch ();
130+ }
119131
120- // TODO - Move attribute usage to `->contents()->attr` calls
132+ $ this ->forceFill ($ contentFields );
133+
134+ return $ result && $ contentsResult ;
135+ }
121136
122137 /**
123138 * Check if this item is a container item.
@@ -187,7 +202,7 @@ public function matchesOrContains(self $entity): bool
187202 }
188203
189204 if ($ entity instanceof Page && $ this instanceof Chapter) {
190- return $ entity ->contents ()-> chapter_id === $ this ->id ;
205+ return $ entity ->chapter_id === $ this ->id ;
191206 }
192207
193208 return false ;
@@ -438,19 +453,36 @@ public function logDescriptor(): string
438453 abstract public function relatedData (): HasOne ;
439454
440455 /**
441- * Get the contents of this entity.
456+ * Get the attributes that are intended for the related contents model.
457+ * @return array<string, mixed>
442458 */
443- public function contents (): EntityContainerContents | EntityPageContents | null
459+ protected function getContentsAttributes (): array
444460 {
445- if ($ this ->relationLoaded ('contents ' )) {
446- return $ this ->getRelation ('contents ' );
447- }
461+ $ contentFields = [];
448462
449- $ relatedData = $ this ->relatedData ()->first ();
450- if ($ relatedData ) {
451- return $ relatedData ;
463+ foreach ($ this ->attributes as $ key => $ value ) {
464+ if (!in_array ($ key , static ::$ commonFields )) {
465+ $ contentFields [$ key ] = $ value ;
466+ }
452467 }
453468
454- return null ;
469+ return $ contentFields ;
470+ }
471+
472+ /**
473+ * Get the contents model of this entity.
474+ * Should only really be used if accessing the methods of the contents model
475+ * since the properties would already be part of the fetched entity model.
476+ */
477+ public function contents (): EntityContainerContents |EntityPageContents
478+ {
479+ $ contentsData = $ this ->getContentsAttributes ();
480+
481+ /**
482+ * @var EntityContainerContents|EntityPageContents $instance
483+ */
484+ $ instance = $ this ->relatedData ()->newModelInstance ()->newFromBuilder ($ contentsData , $ this ->getConnection ());
485+
486+ return $ instance ;
455487 }
456488}
0 commit comments