@@ -30,8 +30,22 @@ public function output(Tree $tree): array
3030 return $ this ->output ;
3131 }
3232
33+ private function pivotColumns (array $ columns , array $ relationships ): array
34+ {
35+ // TODO: ideally restrict to only "belongsTo" columns used for pivot relationship
36+ return collect ($ columns )
37+ ->map (fn ($ column ) => $ column ->name ())
38+ ->reject (fn ($ column ) => in_array ($ column , ['created_at ' , 'updated_at ' ]) || in_array ($ column , $ relationships ['belongsTo ' ] ?? []))
39+ ->all ();
40+ }
41+
3342 protected function populateStub (string $ stub , Model $ model )
3443 {
44+ if ($ model ->isPivot ()) {
45+ $ stub = str_replace ('class {{ class }} extends Model ' , 'class {{ class }} extends Pivot ' , $ stub );
46+ $ stub = str_replace ('use Illuminate \\Database \\Eloquent \\Model; ' , 'use Illuminate \\Database \\Eloquent \\Relations \\Pivot; ' , $ stub );
47+ }
48+
3549 $ stub = str_replace ('{{ namespace }} ' , $ model ->fullyQualifiedNamespace (), $ stub );
3650 $ stub = str_replace (PHP_EOL . 'class {{ class }} ' , $ this ->buildClassPhpDoc ($ model ) . PHP_EOL . 'class {{ class }} ' , $ stub );
3751 $ stub = str_replace ('{{ class }} ' , $ model ->name (), $ stub );
@@ -103,34 +117,42 @@ protected function buildClassPhpDoc(Model $model)
103117
104118 protected function buildProperties (Model $ model )
105119 {
106- $ properties = '' ;
120+ $ properties = [];
121+
122+ if ($ model ->usesCustomTableName () || $ model ->isPivot ()) {
123+ $ properties [] = str_replace ('{{ name }} ' , $ model ->tableName (), $ this ->filesystem ->stub ('model.table.stub ' ));
124+ }
107125
108126 if (!$ model ->usesTimestamps ()) {
109- $ properties .= $ this ->filesystem ->stub ('model.timestamps.stub ' );
127+ $ properties [] = $ this ->filesystem ->stub ('model.timestamps.stub ' );
128+ }
129+
130+ if ($ model ->isPivot () && $ model ->usesPrimaryKey ()) {
131+ $ properties [] = $ this ->filesystem ->stub ('model.incrementing.stub ' );
110132 }
111133
112134 if (config ('blueprint.use_guarded ' )) {
113- $ properties . = $ this ->filesystem ->stub ('model.guarded.stub ' );
135+ $ properties[] = $ this ->filesystem ->stub ('model.guarded.stub ' );
114136 } else {
115137 $ columns = $ this ->fillableColumns ($ model ->columns ());
116138 if (!empty ($ columns )) {
117- $ properties .= PHP_EOL . str_replace ('[] ' , $ this ->pretty_print_array ($ columns , false ), $ this ->filesystem ->stub ('model.fillable.stub ' ));
139+ $ properties[] = str_replace ('[] ' , $ this ->pretty_print_array ($ columns , false ), $ this ->filesystem ->stub ('model.fillable.stub ' ));
118140 } else {
119- $ properties . = $ this ->filesystem ->stub ('model.fillable.stub ' );
141+ $ properties[] = $ this ->filesystem ->stub ('model.fillable.stub ' );
120142 }
121143 }
122144
123145 $ columns = $ this ->hiddenColumns ($ model ->columns ());
124146 if (!empty ($ columns )) {
125- $ properties .= PHP_EOL . str_replace ('[] ' , $ this ->pretty_print_array ($ columns , false ), $ this ->filesystem ->stub ('model.hidden.stub ' ));
147+ $ properties[] = str_replace ('[] ' , $ this ->pretty_print_array ($ columns , false ), $ this ->filesystem ->stub ('model.hidden.stub ' ));
126148 }
127149
128150 $ columns = $ this ->castableColumns ($ model ->columns ());
129151 if (!empty ($ columns )) {
130- $ properties .= PHP_EOL . str_replace ('[] ' , $ this ->pretty_print_array ($ columns ), $ this ->filesystem ->stub ('model.casts.stub ' ));
152+ $ properties[] = str_replace ('[] ' , $ this ->pretty_print_array ($ columns ), $ this ->filesystem ->stub ('model.casts.stub ' ));
131153 }
132154
133- return trim ($ properties );
155+ return trim (implode ( PHP_EOL , array_filter ( $ properties, fn ( $ property ) => ! empty ( trim ( $ property )))) );
134156 }
135157
136158 protected function buildRelationships (Model $ model )
@@ -146,6 +168,7 @@ protected function buildRelationships(Model $model)
146168 foreach ($ model ->relationships () as $ type => $ references ) {
147169 foreach ($ references as $ reference ) {
148170 $ is_model_fqn = Str::startsWith ($ reference , '\\' );
171+ $ is_pivot = false ;
149172
150173 $ custom_template = $ template ;
151174 $ key = null ;
@@ -157,7 +180,13 @@ protected function buildRelationships(Model $model)
157180 if (Str::contains ($ reference , ': ' )) {
158181 [$ foreign_reference , $ column_name ] = explode (': ' , $ reference );
159182
160- $ method_name = Str::beforeLast ($ column_name , '_id ' );
183+ if (Str::startsWith ($ column_name , '& ' )) {
184+ $ is_pivot = true ;
185+ $ column_name = Str::after ($ column_name , '& ' );
186+ $ method_name = $ column_name ;
187+ } else {
188+ $ method_name = Str::beforeLast ($ column_name , '_id ' );
189+ }
161190
162191 if (Str::contains ($ foreign_reference , '. ' )) {
163192 [$ class , $ key ] = explode ('. ' , $ foreign_reference );
@@ -192,7 +221,22 @@ protected function buildRelationships(Model $model)
192221 } elseif (!is_null ($ key )) {
193222 $ relationship = sprintf ('$this->%s(%s::class, \'%s \', \'%s \') ' , $ type , $ fqcn , $ column_name , $ key );
194223 } elseif (!is_null ($ class ) && $ type === 'belongsToMany ' ) {
195- $ relationship = sprintf ('$this->%s(%s::class, \'%s \') ' , $ type , $ fqcn , $ column_name );
224+ if ($ is_pivot ) {
225+ $ relationship = sprintf ('$this->%s(%s::class) ' , $ type , $ fqcn );
226+ $ relationship .= sprintf ('%s->using(%s::class) ' , PHP_EOL . str_pad (' ' , 12 ), $ column_name );
227+ $ relationship .= sprintf ('%s->as( \'%s \') ' , PHP_EOL . str_pad (' ' , 12 ), Str::snake ($ column_name ));
228+
229+ $ foreign = $ this ->tree ->modelForContext ($ column_name );
230+ $ columns = $ this ->pivotColumns ($ foreign ->columns (), $ foreign ->relationships ());
231+ if ($ columns ) {
232+ $ relationship .= sprintf ('%s->withPivot( \'%s \') ' , PHP_EOL . str_pad (' ' , 12 ), implode ("', ' " , $ columns ));
233+ }
234+ if ($ foreign ->usesTimestamps ()) {
235+ $ relationship .= sprintf ('%s->withTimestamps() ' , PHP_EOL . str_pad (' ' , 12 ));
236+ }
237+ } else {
238+ $ relationship = sprintf ('$this->%s(%s::class, \'%s \') ' , $ type , $ fqcn , $ column_name );
239+ }
196240 $ column_name = $ class ;
197241 } else {
198242 $ relationship = sprintf ('$this->%s(%s::class) ' , $ type , $ fqcn );
0 commit comments