@@ -224,7 +224,12 @@ private function mapDatabaseTypeToTypeScriptType(Stringable $columnType): string
224224 private function getForeignKeyConstraintForAttribute (string $ attribute ): ?ForeignKeyConstraint {
225225 return $ this
226226 ->modelForeignKeyConstraints
227- ->first (fn ($ foreignKeyConstraint ) => in_array ($ attribute , $ foreignKeyConstraint ->getLocalColumns ()));
227+ ->first (function ($ foreignKeyConstraint ) use ($ attribute ) {
228+ // Doctrine combines foreign key constraints that point to the same table.
229+ // That means we have to check if the target column exists in the current
230+ // foreign key constraint's 'local columns' array.
231+ return in_array ($ attribute , $ foreignKeyConstraint ->getLocalColumns ());
232+ });
228233 }
229234
230235 /**
@@ -266,14 +271,18 @@ private function getTypeScriptType(stdClass $columnSchema): string {
266271 if ($ this ->isAttributeRelation ($ columnSchema ->Field )) {
267272 $ fullyQualifiedRelatedModelName = $ this ->convertForeignKeyToFullyQualifiedModelName ($ columnSchema ->Field );
268273
274+ // We generate new interfaces for any relational attributes.
275+ // That means we can recursively instantiate the current class to generate
276+ // as many interface definitions for relational attributes as we need.
269277 return (new self ($ fullyQualifiedRelatedModelName ))->generate ();
270278 }
271279
272- if ($ this ->isAttributeNativelyCasted ($ columnSchema ->Field )) {
273- $ mappedType = $ this ->mapNativeCastToTypeScriptType ($ columnSchema ->Field );
274- } else {
275- $ mappedType = $ this ->mapDatabaseTypeToTypeScriptType ($ columnType );
276- }
280+ // If the attribute is natively casted, we'll want to perform native cast checking
281+ // to generate the correct TypeScript type. If it's not natively casted, we can
282+ // simply map the database type to a TypeScript type.
283+ $ mappedType = $ this ->isAttributeNativelyCasted ($ columnSchema ->Field )
284+ ? $ this ->mapNativeCastToTypeScriptType ($ columnSchema ->Field )
285+ : $ this ->mapDatabaseTypeToTypeScriptType ($ columnType );
277286
278287 // We can't do much with an unknown type.
279288 if ($ mappedType === 'unknown ' ) return $ mappedType ;
@@ -302,21 +311,23 @@ private function convertForeignKeyToPredictedRelationName(string $attribute): st
302311 private function generateInterface (): string {
303312 $ tableColumns = collect (DB ::select (DB ::raw ('SHOW COLUMNS FROM ' . $ this ->model ->getTable ())));
304313
305- $ outputBuffer = collect ();
306-
307- $ outputBuffer ->push ('interface ' . (Str::of ($ this ->fullyQualifiedModelName )->afterLast ('\\' )) . " { " );
314+ $ outputBuffer = collect ([
315+ // The output buffer always needs to start with the first `interface X {` line.
316+ 'interface ' . (Str::of ($ this ->fullyQualifiedModelName )->afterLast ('\\' )) . " { "
317+ ]);
308318
309319 $ tableColumns ->each (function ($ column ) use ($ outputBuffer ) {
320+ // If this attribute is hidden and we're not including hidden, we'll skip it.
310321 if (!$ this ->includeHidden && $ this ->isAttributeHidden ($ column ->Field )) return ;
311322
312323 if ($ this ->isAttributeRelation ($ column ->Field )) {
313- // The foreign model name will be the name of the interface we'll be generating .
324+ // The foreign model name will be the name of the interface we'll generate for this relation .
314325 $ foreignModelName = Str::of ($ this ->convertForeignKeyToFullyQualifiedModelName ($ column ->Field ))->afterLast ('\\' );
315326 $ relationName = $ this ->convertForeignKeyToPredictedRelationName ($ column ->Field );
316327
317- $ outputBuffer ->push (' ' . $ relationName . ' : ' . $ foreignModelName . " ; " );
328+ $ outputBuffer ->push (sprintf ( ' %s: %s; ' , $ relationName, $ foreignModelName) );
318329
319- // Add a space so related interfaces aren't directly after each other.
330+ // Add an empty line so related interfaces aren't directly after each other.
320331 $ outputBuffer ->prepend ('' );
321332
322333 // Get the TypeScript type of this column. We know it's a relation,
@@ -329,7 +340,7 @@ private function generateInterface(): string {
329340 ->reverse ()
330341 ->each (fn ($ str ) => $ outputBuffer ->prepend ($ str ));
331342 } else {
332- $ outputBuffer ->push (' ' . $ column ->Field . ' : ' . $ this ->getTypeScriptType ($ column ) . " ; " );
343+ $ outputBuffer ->push (sprintf ( ' %s: %s; ' , $ column ->Field , $ this ->getTypeScriptType ($ column )) );
333344 }
334345 });
335346
0 commit comments