From efec1a8f1c8a1d228abbd797056ba3e6ef250973 Mon Sep 17 00:00:00 2001 From: Josh Salway Date: Fri, 20 Dec 2024 22:43:07 +1000 Subject: [PATCH 01/17] feat(artisan): Prompt and optionally add HasApiTokens trait to User model during API installation - When installing Sanctum or Passport via `install:api`, prompt the user to add the HasApiTokens trait automatically. - Check for `App\Models\User` before modifying the file, gracefully warning the user if it doesn't exist. - Only modify the User model if necessary, ensuring non-destructive and minimal changes. - Improve developer experience by reducing manual steps after API scaffolding installation. --- .../Foundation/Console/ApiInstallCommand.php | 87 ++++++++++++++++++- 1 file changed, 85 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Foundation/Console/ApiInstallCommand.php b/src/Illuminate/Foundation/Console/ApiInstallCommand.php index bccdacd4d529..f5697dc4616e 100644 --- a/src/Illuminate/Foundation/Console/ApiInstallCommand.php +++ b/src/Illuminate/Foundation/Console/ApiInstallCommand.php @@ -74,6 +74,15 @@ public function handle() ])); $this->components->info('API scaffolding installed. Please add the [Laravel\Passport\HasApiTokens] trait to your User model.'); + + if ($this->confirm("Would you like to add the [Laravel\\Sanctum\\HasApiTokens] trait to your User model now?", true)) { + if (class_exists('App\\Models\\User')) { + $this->addTraitToModel('Laravel\\Sanctum\\HasApiTokens', 'App\\Models\\User'); + } else { + $this->components->warn("The [App\\Models\\User] model does not exist. Please manually add the trait to your User model if you've moved or renamed it."); + } + } + } else { if (! $this->option('without-migration-prompt')) { if ($this->confirm('One new database migration has been published. Would you like to run all pending database migrations?', true)) { @@ -82,7 +91,17 @@ public function handle() } $this->components->info('API scaffolding installed. Please add the [Laravel\Sanctum\HasApiTokens] trait to your User model.'); + + if ($this->confirm("Would you like to add the [Laravel\\Sanctum\\HasApiTokens] trait to your User model now?", true)) { + if (class_exists('App\\Models\\User')) { + $this->addTraitToModel('Laravel\\Sanctum\\HasApiTokens', 'App\\Models\\User'); + } else { + $this->components->warn("The [App\\Models\\User] model does not exist. Please manually add the trait to your User model if you've moved or renamed it."); + } + } } + + return Command::SUCCESS; } /** @@ -93,7 +112,6 @@ public function handle() protected function uncommentApiRoutesFile() { $appBootstrapPath = $this->laravel->bootstrapPath('app.php'); - $content = file_get_contents($appBootstrapPath); if (str_contains($content, '// api: ')) { @@ -152,4 +170,69 @@ protected function installPassport() 'laravel/passport:^12.0', ]); } -} + + /** + * Attempt to add the given trait to the specified model. + * + * @param string $trait + * @param string $model + * @return void + */ + protected function addTraitToModel(string $trait, string $model) + { + $modelPath = $this->laravel->basePath(str_replace('\\', '/', $model).'.php'); + + if (! file_exists($modelPath)) { + $this->components->error("Model not found at {$modelPath}."); + return; + } + + $content = file_get_contents($modelPath); + $traitBasename = class_basename($trait); + + // If trait already present, do nothing + if (strpos($content, $traitBasename) !== false) { + $this->components->info("The [{$trait}] trait is already present in your [{$model}] model."); + return; + } + + $modified = false; + + // Ensure the 'use $trait;' statement is present + if (!str_contains($content, "use $trait;")) { + $content = preg_replace( + '/(namespace\s+.*;)/', + "$1\n\nuse $trait;", + $content, + 1, + $count + ); + + if ($count > 0) { + $modified = true; + } + } + + // Insert the trait into the class if not present + if (!str_contains($content, "use $traitBasename;")) { + $content = preg_replace( + '/(class\s+\w+\s+extends\s+\w+[A-Za-z\\\\]*)(\s*\{)/', + "$1 {\n use $traitBasename;\n", + $content, + 1, + $count + ); + + if ($count > 0) { + $modified = true; + } + } + + if ($modified) { + file_put_contents($modelPath, $content); + $this->components->info("The [{$trait}] trait has been added to your [{$model}] model."); + } else { + $this->components->info("No changes were made to your [{$model}] model."); + } + } +} \ No newline at end of file From 4c5866455f24a2f29abe058831fa5d4d9281448c Mon Sep 17 00:00:00 2001 From: Josh Salway Date: Sat, 21 Dec 2024 00:07:56 +1000 Subject: [PATCH 02/17] Style changes. --- .../Foundation/Console/ApiInstallCommand.php | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/Illuminate/Foundation/Console/ApiInstallCommand.php b/src/Illuminate/Foundation/Console/ApiInstallCommand.php index f5697dc4616e..f543188aa9b3 100644 --- a/src/Illuminate/Foundation/Console/ApiInstallCommand.php +++ b/src/Illuminate/Foundation/Console/ApiInstallCommand.php @@ -75,11 +75,11 @@ public function handle() $this->components->info('API scaffolding installed. Please add the [Laravel\Passport\HasApiTokens] trait to your User model.'); - if ($this->confirm("Would you like to add the [Laravel\\Sanctum\\HasApiTokens] trait to your User model now?", true)) { + if ($this->confirm('Would you like to add the [Laravel\\Sanctum\\HasApiTokens] trait to your User model now?', true)) { if (class_exists('App\\Models\\User')) { $this->addTraitToModel('Laravel\\Sanctum\\HasApiTokens', 'App\\Models\\User'); } else { - $this->components->warn("The [App\\Models\\User] model does not exist. Please manually add the trait to your User model if you've moved or renamed it."); + $this->components->warn('The [App\\Models\\User] model does not exist. Please manually add the trait to your User model if you\'ve moved or renamed it.'); } } @@ -92,11 +92,11 @@ public function handle() $this->components->info('API scaffolding installed. Please add the [Laravel\Sanctum\HasApiTokens] trait to your User model.'); - if ($this->confirm("Would you like to add the [Laravel\\Sanctum\\HasApiTokens] trait to your User model now?", true)) { + if ($this->confirm('Would you like to add the [Laravel\\Sanctum\\HasApiTokens] trait to your User model now?', true)) { if (class_exists('App\\Models\\User')) { $this->addTraitToModel('Laravel\\Sanctum\\HasApiTokens', 'App\\Models\\User'); } else { - $this->components->warn("The [App\\Models\\User] model does not exist. Please manually add the trait to your User model if you've moved or renamed it."); + $this->components->warn('The [App\\Models\\User] model does not exist. Please manually add the trait to your User model if you\'ve moved or renamed it.'); } } } @@ -184,6 +184,7 @@ protected function addTraitToModel(string $trait, string $model) if (! file_exists($modelPath)) { $this->components->error("Model not found at {$modelPath}."); + return; } @@ -193,13 +194,14 @@ protected function addTraitToModel(string $trait, string $model) // If trait already present, do nothing if (strpos($content, $traitBasename) !== false) { $this->components->info("The [{$trait}] trait is already present in your [{$model}] model."); + return; } $modified = false; // Ensure the 'use $trait;' statement is present - if (!str_contains($content, "use $trait;")) { + if (! str_contains($content, "use $trait;")) { $content = preg_replace( '/(namespace\s+.*;)/', "$1\n\nuse $trait;", @@ -214,7 +216,7 @@ protected function addTraitToModel(string $trait, string $model) } // Insert the trait into the class if not present - if (!str_contains($content, "use $traitBasename;")) { + if (! str_contains($content, "use $traitBasename;")) { $content = preg_replace( '/(class\s+\w+\s+extends\s+\w+[A-Za-z\\\\]*)(\s*\{)/', "$1 {\n use $traitBasename;\n", From c0781d5bb33254efbab4e2903aa6f9111b7a677f Mon Sep 17 00:00:00 2001 From: Josh Salway Date: Sat, 21 Dec 2024 00:36:09 +1000 Subject: [PATCH 03/17] Change how it adds the changes to User.php file. --- .../Foundation/Console/ApiInstallCommand.php | 53 ++++++++++++------- 1 file changed, 33 insertions(+), 20 deletions(-) diff --git a/src/Illuminate/Foundation/Console/ApiInstallCommand.php b/src/Illuminate/Foundation/Console/ApiInstallCommand.php index f543188aa9b3..c726fdcab34a 100644 --- a/src/Illuminate/Foundation/Console/ApiInstallCommand.php +++ b/src/Illuminate/Foundation/Console/ApiInstallCommand.php @@ -180,31 +180,29 @@ protected function installPassport() */ protected function addTraitToModel(string $trait, string $model) { - $modelPath = $this->laravel->basePath(str_replace('\\', '/', $model).'.php'); + $modelPath = $this->laravel->basePath(str_replace('\\', '/', $model) . '.php'); - if (! file_exists($modelPath)) { + if (!file_exists($modelPath)) { $this->components->error("Model not found at {$modelPath}."); - return; } $content = file_get_contents($modelPath); $traitBasename = class_basename($trait); - // If trait already present, do nothing + // Check if the trait is already used in the model if (strpos($content, $traitBasename) !== false) { $this->components->info("The [{$trait}] trait is already present in your [{$model}] model."); - return; } $modified = false; - // Ensure the 'use $trait;' statement is present - if (! str_contains($content, "use $trait;")) { + // Ensure the 'use $trait;' statement is inserted correctly below other imports + if (!str_contains($content, "use $trait;")) { $content = preg_replace( - '/(namespace\s+.*;)/', - "$1\n\nuse $trait;", + '/(use\s+[\w\\\\]+;(\s+\/\/.*\n)*\s*)+/s', + "$0use $trait;\n", $content, 1, $count @@ -215,17 +213,32 @@ protected function addTraitToModel(string $trait, string $model) } } - // Insert the trait into the class if not present - if (! str_contains($content, "use $traitBasename;")) { - $content = preg_replace( - '/(class\s+\w+\s+extends\s+\w+[A-Za-z\\\\]*)(\s*\{)/', - "$1 {\n use $traitBasename;\n", - $content, - 1, - $count - ); - - if ($count > 0) { + // Ensure the trait is added to the `use` block within the class + if (preg_match('/class\s+\w+\s+extends\s+\w+[A-Za-z\\\\]*\s*\{/', $content, $matches, PREG_OFFSET_CAPTURE)) { + $insertPosition = $matches[0][1] + strlen($matches[0][0]); + + // Add the trait to the existing 'use' block if found + if (preg_match('/use\s+(.*?);/s', $content, $useMatches, PREG_OFFSET_CAPTURE, $insertPosition)) { + $traits = $useMatches[1][0]; + $traitList = array_map('trim', explode(',', $traits)); + if (!in_array($traitBasename, $traitList)) { + $traitList[] = $traitBasename; + $content = substr_replace( + $content, + 'use ' . implode(', ', $traitList) . ';', + $useMatches[0][1], + strlen($useMatches[0][0]) + ); + $modified = true; + } + } else { + // Add a new 'use' block for traits if none exists + $content = substr_replace( + $content, + "\n use $traitBasename;", + $insertPosition, + 0 + ); $modified = true; } } From cf8152df386d23ce6082ab8d44aca299a68cd013 Mon Sep 17 00:00:00 2001 From: Josh Salway Date: Sat, 21 Dec 2024 00:38:42 +1000 Subject: [PATCH 04/17] Style changes. --- .../Foundation/Console/ApiInstallCommand.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Illuminate/Foundation/Console/ApiInstallCommand.php b/src/Illuminate/Foundation/Console/ApiInstallCommand.php index c726fdcab34a..56ad83ff1549 100644 --- a/src/Illuminate/Foundation/Console/ApiInstallCommand.php +++ b/src/Illuminate/Foundation/Console/ApiInstallCommand.php @@ -174,16 +174,15 @@ protected function installPassport() /** * Attempt to add the given trait to the specified model. * - * @param string $trait - * @param string $model * @return void */ protected function addTraitToModel(string $trait, string $model) { - $modelPath = $this->laravel->basePath(str_replace('\\', '/', $model) . '.php'); + $modelPath = $this->laravel->basePath(str_replace('\\', '/', $model).'.php'); - if (!file_exists($modelPath)) { + if (! file_exists($modelPath)) { $this->components->error("Model not found at {$modelPath}."); + return; } @@ -193,13 +192,14 @@ protected function addTraitToModel(string $trait, string $model) // Check if the trait is already used in the model if (strpos($content, $traitBasename) !== false) { $this->components->info("The [{$trait}] trait is already present in your [{$model}] model."); + return; } $modified = false; // Ensure the 'use $trait;' statement is inserted correctly below other imports - if (!str_contains($content, "use $trait;")) { + if (! str_contains($content, "use $trait;")) { $content = preg_replace( '/(use\s+[\w\\\\]+;(\s+\/\/.*\n)*\s*)+/s', "$0use $trait;\n", @@ -221,11 +221,11 @@ protected function addTraitToModel(string $trait, string $model) if (preg_match('/use\s+(.*?);/s', $content, $useMatches, PREG_OFFSET_CAPTURE, $insertPosition)) { $traits = $useMatches[1][0]; $traitList = array_map('trim', explode(',', $traits)); - if (!in_array($traitBasename, $traitList)) { + if (! in_array($traitBasename, $traitList)) { $traitList[] = $traitBasename; $content = substr_replace( $content, - 'use ' . implode(', ', $traitList) . ';', + 'use '.implode(', ', $traitList).';', $useMatches[0][1], strlen($useMatches[0][0]) ); @@ -250,4 +250,4 @@ protected function addTraitToModel(string $trait, string $model) $this->components->info("No changes were made to your [{$model}] model."); } } -} \ No newline at end of file +} From 86efb7a6205f09678da13749a54a83ae41d794b8 Mon Sep 17 00:00:00 2001 From: Josh Salway Date: Sat, 21 Dec 2024 00:51:03 +1000 Subject: [PATCH 05/17] feat: add functionality to dynamically inject traits into models - Implemented `addTraitToModel` function to add a specified trait to a model. - Handles importing the trait and ensuring its usage within the model class. - Prevents duplication if the trait already exists. - Includes file path validation and precise modifications to maintain code integrity. --- .../Foundation/Console/ApiInstallCommand.php | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/Illuminate/Foundation/Console/ApiInstallCommand.php b/src/Illuminate/Foundation/Console/ApiInstallCommand.php index 56ad83ff1549..914337e45a28 100644 --- a/src/Illuminate/Foundation/Console/ApiInstallCommand.php +++ b/src/Illuminate/Foundation/Console/ApiInstallCommand.php @@ -189,8 +189,8 @@ protected function addTraitToModel(string $trait, string $model) $content = file_get_contents($modelPath); $traitBasename = class_basename($trait); - // Check if the trait is already used in the model - if (strpos($content, $traitBasename) !== false) { + // Check if the trait is already imported or used + if (strpos($content, "use $trait;") !== false || strpos($content, $traitBasename) !== false) { $this->components->info("The [{$trait}] trait is already present in your [{$model}] model."); return; @@ -198,7 +198,7 @@ protected function addTraitToModel(string $trait, string $model) $modified = false; - // Ensure the 'use $trait;' statement is inserted correctly below other imports + // Add the trait import statement if it doesn't exist if (! str_contains($content, "use $trait;")) { $content = preg_replace( '/(use\s+[\w\\\\]+;(\s+\/\/.*\n)*\s*)+/s', @@ -213,26 +213,24 @@ protected function addTraitToModel(string $trait, string $model) } } - // Ensure the trait is added to the `use` block within the class + // Add the trait usage within the class if (preg_match('/class\s+\w+\s+extends\s+\w+[A-Za-z\\\\]*\s*\{/', $content, $matches, PREG_OFFSET_CAPTURE)) { $insertPosition = $matches[0][1] + strlen($matches[0][0]); - // Add the trait to the existing 'use' block if found if (preg_match('/use\s+(.*?);/s', $content, $useMatches, PREG_OFFSET_CAPTURE, $insertPosition)) { - $traits = $useMatches[1][0]; - $traitList = array_map('trim', explode(',', $traits)); - if (! in_array($traitBasename, $traitList)) { - $traitList[] = $traitBasename; + $traits = array_map('trim', explode(',', $useMatches[1][0])); + + if (! in_array($traitBasename, $traits)) { + $traits[] = $traitBasename; $content = substr_replace( $content, - 'use '.implode(', ', $traitList).';', + 'use '.implode(', ', $traits).';', $useMatches[0][1], strlen($useMatches[0][0]) ); $modified = true; } } else { - // Add a new 'use' block for traits if none exists $content = substr_replace( $content, "\n use $traitBasename;", From 35e10a53cf10a1bf4bc2cb5fb0e0e7549dfeb910 Mon Sep 17 00:00:00 2001 From: Josh Salway Date: Sat, 21 Dec 2024 00:58:18 +1000 Subject: [PATCH 06/17] Add correct trait to the model. --- src/Illuminate/Foundation/Console/ApiInstallCommand.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Foundation/Console/ApiInstallCommand.php b/src/Illuminate/Foundation/Console/ApiInstallCommand.php index 914337e45a28..fc684358a387 100644 --- a/src/Illuminate/Foundation/Console/ApiInstallCommand.php +++ b/src/Illuminate/Foundation/Console/ApiInstallCommand.php @@ -75,9 +75,9 @@ public function handle() $this->components->info('API scaffolding installed. Please add the [Laravel\Passport\HasApiTokens] trait to your User model.'); - if ($this->confirm('Would you like to add the [Laravel\\Sanctum\\HasApiTokens] trait to your User model now?', true)) { + if ($this->confirm('Would you like to add the [Laravel\Passport\HasApiTokens] trait to your User model now?', true)) { if (class_exists('App\\Models\\User')) { - $this->addTraitToModel('Laravel\\Sanctum\\HasApiTokens', 'App\\Models\\User'); + $this->addTraitToModel('Laravel\Passport\HasApiTokens', 'App\\Models\\User'); } else { $this->components->warn('The [App\\Models\\User] model does not exist. Please manually add the trait to your User model if you\'ve moved or renamed it.'); } From 3704b365f53ea022efab74cae8062e7e9269234c Mon Sep 17 00:00:00 2001 From: Josh Salway Date: Sat, 21 Dec 2024 01:18:33 +1000 Subject: [PATCH 07/17] Improve targeted regex patterns. --- .../Foundation/Console/ApiInstallCommand.php | 64 ++++++++----------- 1 file changed, 27 insertions(+), 37 deletions(-) diff --git a/src/Illuminate/Foundation/Console/ApiInstallCommand.php b/src/Illuminate/Foundation/Console/ApiInstallCommand.php index fc684358a387..0d4f70e70052 100644 --- a/src/Illuminate/Foundation/Console/ApiInstallCommand.php +++ b/src/Illuminate/Foundation/Console/ApiInstallCommand.php @@ -182,62 +182,52 @@ protected function addTraitToModel(string $trait, string $model) if (! file_exists($modelPath)) { $this->components->error("Model not found at {$modelPath}."); - return; } $content = file_get_contents($modelPath); $traitBasename = class_basename($trait); - // Check if the trait is already imported or used if (strpos($content, "use $trait;") !== false || strpos($content, $traitBasename) !== false) { $this->components->info("The [{$trait}] trait is already present in your [{$model}] model."); - return; } $modified = false; - // Add the trait import statement if it doesn't exist - if (! str_contains($content, "use $trait;")) { - $content = preg_replace( - '/(use\s+[\w\\\\]+;(\s+\/\/.*\n)*\s*)+/s', - "$0use $trait;\n", - $content, - 1, - $count - ); + // Insert the trait at the top-level (import) + $topLevelUsePattern = '/(namespace\s+[\w\\\\]+;\s*(?:use\s+[\w\\\\]+;\s*)*)/s'; + $topLevelUseReplacement = '$1use ' . $trait . ';' . "\n"; - if ($count > 0) { - $modified = true; - } + $newContent = preg_replace($topLevelUsePattern, $topLevelUseReplacement, $content, 1, $count); + if ($count > 0) { + $modified = true; + $content = $newContent; } - // Add the trait usage within the class - if (preg_match('/class\s+\w+\s+extends\s+\w+[A-Za-z\\\\]*\s*\{/', $content, $matches, PREG_OFFSET_CAPTURE)) { - $insertPosition = $matches[0][1] + strlen($matches[0][0]); - - if (preg_match('/use\s+(.*?);/s', $content, $useMatches, PREG_OFFSET_CAPTURE, $insertPosition)) { - $traits = array_map('trim', explode(',', $useMatches[1][0])); - - if (! in_array($traitBasename, $traits)) { - $traits[] = $traitBasename; - $content = substr_replace( - $content, - 'use '.implode(', ', $traits).';', - $useMatches[0][1], - strlen($useMatches[0][0]) - ); + // Insert or merge the trait at the class-level + $classPattern = '/(class\s+\w+(?:\s+extends\s+\w+(?:\\\\\w+)*)?(?:\s+implements\s+[^{]+)?\s*\{)/s'; + + if (preg_match('/class\s+\w+(?:\s+extends\s+\w+(?:\\\\\w+)*)?(?:\s+implements\s+[^{]+)?\s*\{\s*(use\s+[^;]+;)?/s', $content, $m, PREG_OFFSET_CAPTURE)) { + if (!empty($m[1][0])) { + // Existing class-level use line + $useLineStart = $m[1][1]; + preg_match('/use\s+([^;]+);/', $m[1][0], $traitsMatches); + $existingTraits = array_map('trim', explode(',', $traitsMatches[1])); + + if (!in_array($traitBasename, $existingTraits)) { + $existingTraits[] = $traitBasename; + $newUseLine = 'use ' . implode(', ', $existingTraits) . ';'; + $content = substr_replace($content, $newUseLine, $useLineStart, strlen($m[1][0])); $modified = true; } } else { - $content = substr_replace( - $content, - "\n use $traitBasename;", - $insertPosition, - 0 - ); - $modified = true; + // No class-level use line, insert a new one + $newContent = preg_replace($classPattern, '$1' . "\n use $traitBasename;", $content, 1, $count); + if ($count > 0) { + $modified = true; + $content = $newContent; + } } } From 3fa3806b5ac30543bd48d0a62756551fb6131cfb Mon Sep 17 00:00:00 2001 From: Josh Salway Date: Sat, 21 Dec 2024 01:40:25 +1000 Subject: [PATCH 08/17] Revert "Improve targeted regex patterns." This reverts commit 3704b365f53ea022efab74cae8062e7e9269234c. --- .../Foundation/Console/ApiInstallCommand.php | 64 +++++++++++-------- 1 file changed, 37 insertions(+), 27 deletions(-) diff --git a/src/Illuminate/Foundation/Console/ApiInstallCommand.php b/src/Illuminate/Foundation/Console/ApiInstallCommand.php index 0d4f70e70052..fc684358a387 100644 --- a/src/Illuminate/Foundation/Console/ApiInstallCommand.php +++ b/src/Illuminate/Foundation/Console/ApiInstallCommand.php @@ -182,52 +182,62 @@ protected function addTraitToModel(string $trait, string $model) if (! file_exists($modelPath)) { $this->components->error("Model not found at {$modelPath}."); + return; } $content = file_get_contents($modelPath); $traitBasename = class_basename($trait); + // Check if the trait is already imported or used if (strpos($content, "use $trait;") !== false || strpos($content, $traitBasename) !== false) { $this->components->info("The [{$trait}] trait is already present in your [{$model}] model."); + return; } $modified = false; - // Insert the trait at the top-level (import) - $topLevelUsePattern = '/(namespace\s+[\w\\\\]+;\s*(?:use\s+[\w\\\\]+;\s*)*)/s'; - $topLevelUseReplacement = '$1use ' . $trait . ';' . "\n"; + // Add the trait import statement if it doesn't exist + if (! str_contains($content, "use $trait;")) { + $content = preg_replace( + '/(use\s+[\w\\\\]+;(\s+\/\/.*\n)*\s*)+/s', + "$0use $trait;\n", + $content, + 1, + $count + ); - $newContent = preg_replace($topLevelUsePattern, $topLevelUseReplacement, $content, 1, $count); - if ($count > 0) { - $modified = true; - $content = $newContent; + if ($count > 0) { + $modified = true; + } } - // Insert or merge the trait at the class-level - $classPattern = '/(class\s+\w+(?:\s+extends\s+\w+(?:\\\\\w+)*)?(?:\s+implements\s+[^{]+)?\s*\{)/s'; - - if (preg_match('/class\s+\w+(?:\s+extends\s+\w+(?:\\\\\w+)*)?(?:\s+implements\s+[^{]+)?\s*\{\s*(use\s+[^;]+;)?/s', $content, $m, PREG_OFFSET_CAPTURE)) { - if (!empty($m[1][0])) { - // Existing class-level use line - $useLineStart = $m[1][1]; - preg_match('/use\s+([^;]+);/', $m[1][0], $traitsMatches); - $existingTraits = array_map('trim', explode(',', $traitsMatches[1])); - - if (!in_array($traitBasename, $existingTraits)) { - $existingTraits[] = $traitBasename; - $newUseLine = 'use ' . implode(', ', $existingTraits) . ';'; - $content = substr_replace($content, $newUseLine, $useLineStart, strlen($m[1][0])); + // Add the trait usage within the class + if (preg_match('/class\s+\w+\s+extends\s+\w+[A-Za-z\\\\]*\s*\{/', $content, $matches, PREG_OFFSET_CAPTURE)) { + $insertPosition = $matches[0][1] + strlen($matches[0][0]); + + if (preg_match('/use\s+(.*?);/s', $content, $useMatches, PREG_OFFSET_CAPTURE, $insertPosition)) { + $traits = array_map('trim', explode(',', $useMatches[1][0])); + + if (! in_array($traitBasename, $traits)) { + $traits[] = $traitBasename; + $content = substr_replace( + $content, + 'use '.implode(', ', $traits).';', + $useMatches[0][1], + strlen($useMatches[0][0]) + ); $modified = true; } } else { - // No class-level use line, insert a new one - $newContent = preg_replace($classPattern, '$1' . "\n use $traitBasename;", $content, 1, $count); - if ($count > 0) { - $modified = true; - $content = $newContent; - } + $content = substr_replace( + $content, + "\n use $traitBasename;", + $insertPosition, + 0 + ); + $modified = true; } } From 5be0d9520adba8623f55aac0c451e64046180c29 Mon Sep 17 00:00:00 2001 From: Josh Salway Date: Sat, 21 Dec 2024 01:52:55 +1000 Subject: [PATCH 09/17] Improve targeted regex patterns. --- .../Foundation/Console/ApiInstallCommand.php | 29 +++++++++---------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/src/Illuminate/Foundation/Console/ApiInstallCommand.php b/src/Illuminate/Foundation/Console/ApiInstallCommand.php index fc684358a387..63c7d7743851 100644 --- a/src/Illuminate/Foundation/Console/ApiInstallCommand.php +++ b/src/Illuminate/Foundation/Console/ApiInstallCommand.php @@ -182,7 +182,6 @@ protected function addTraitToModel(string $trait, string $model) if (! file_exists($modelPath)) { $this->components->error("Model not found at {$modelPath}."); - return; } @@ -192,28 +191,25 @@ protected function addTraitToModel(string $trait, string $model) // Check if the trait is already imported or used if (strpos($content, "use $trait;") !== false || strpos($content, $traitBasename) !== false) { $this->components->info("The [{$trait}] trait is already present in your [{$model}] model."); - return; } $modified = false; - // Add the trait import statement if it doesn't exist - if (! str_contains($content, "use $trait;")) { - $content = preg_replace( - '/(use\s+[\w\\\\]+;(\s+\/\/.*\n)*\s*)+/s', - "$0use $trait;\n", - $content, - 1, - $count - ); - - if ($count > 0) { - $modified = true; - } + // 1. Add the top-level `use` statement if it doesn't exist + $content = preg_replace( + '/^(namespace\s+[\w\\\\]+;\s*(?:\/\/.*\n)*)((?:use\s+[\w\\\\]+;\n)*)\s*/m', + '$1$2use ' . $trait . ";\n", + $content, + 1, + $count + ); + + if ($count > 0) { + $modified = true; } - // Add the trait usage within the class + // 2. Add the trait usage within the class if (preg_match('/class\s+\w+\s+extends\s+\w+[A-Za-z\\\\]*\s*\{/', $content, $matches, PREG_OFFSET_CAPTURE)) { $insertPosition = $matches[0][1] + strlen($matches[0][0]); @@ -241,6 +237,7 @@ protected function addTraitToModel(string $trait, string $model) } } + // Write the updated content back to the file if modified if ($modified) { file_put_contents($modelPath, $content); $this->components->info("The [{$trait}] trait has been added to your [{$model}] model."); From 1a1b89694c1cc2bac92a2381881d8b2aec7e952e Mon Sep 17 00:00:00 2001 From: Josh Salway Date: Sat, 21 Dec 2024 01:58:48 +1000 Subject: [PATCH 10/17] Improve targeted regex patterns. --- src/Illuminate/Foundation/Console/ApiInstallCommand.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Foundation/Console/ApiInstallCommand.php b/src/Illuminate/Foundation/Console/ApiInstallCommand.php index 63c7d7743851..e29df6fc92fb 100644 --- a/src/Illuminate/Foundation/Console/ApiInstallCommand.php +++ b/src/Illuminate/Foundation/Console/ApiInstallCommand.php @@ -196,7 +196,7 @@ protected function addTraitToModel(string $trait, string $model) $modified = false; - // 1. Add the top-level `use` statement if it doesn't exist + // Add the top-level `use` statement if it doesn't exist $content = preg_replace( '/^(namespace\s+[\w\\\\]+;\s*(?:\/\/.*\n)*)((?:use\s+[\w\\\\]+;\n)*)\s*/m', '$1$2use ' . $trait . ";\n", @@ -209,13 +209,14 @@ protected function addTraitToModel(string $trait, string $model) $modified = true; } - // 2. Add the trait usage within the class + // Add the trait usage within the class, avoiding duplicate additions if (preg_match('/class\s+\w+\s+extends\s+\w+[A-Za-z\\\\]*\s*\{/', $content, $matches, PREG_OFFSET_CAPTURE)) { $insertPosition = $matches[0][1] + strlen($matches[0][0]); if (preg_match('/use\s+(.*?);/s', $content, $useMatches, PREG_OFFSET_CAPTURE, $insertPosition)) { $traits = array_map('trim', explode(',', $useMatches[1][0])); + // Only add the trait if it doesn't already exist in the class-level use block if (! in_array($traitBasename, $traits)) { $traits[] = $traitBasename; $content = substr_replace( @@ -227,6 +228,7 @@ protected function addTraitToModel(string $trait, string $model) $modified = true; } } else { + // No existing use block in the class, insert a new one $content = substr_replace( $content, "\n use $traitBasename;", From 66ef6c183597978cdc448e91d203c6750d42d3bb Mon Sep 17 00:00:00 2001 From: Josh Salway Date: Sat, 21 Dec 2024 02:06:41 +1000 Subject: [PATCH 11/17] fix(model): ensure accurate detection and addition of traits in User model - Refactored `addTraitToModel` function to properly check for top-level `use` imports and class-level trait usage. - Prevented redundant additions of the trait in both top-level and class-level blocks. - Improved logic to handle cases where the trait is missing in either block and correctly adds it. - Ensured compatibility with Laravel conventions and better error handling for edge cases. --- .../Foundation/Console/ApiInstallCommand.php | 81 ++++++++++--------- 1 file changed, 44 insertions(+), 37 deletions(-) diff --git a/src/Illuminate/Foundation/Console/ApiInstallCommand.php b/src/Illuminate/Foundation/Console/ApiInstallCommand.php index e29df6fc92fb..670546cc1c97 100644 --- a/src/Illuminate/Foundation/Console/ApiInstallCommand.php +++ b/src/Illuminate/Foundation/Console/ApiInstallCommand.php @@ -178,7 +178,7 @@ protected function installPassport() */ protected function addTraitToModel(string $trait, string $model) { - $modelPath = $this->laravel->basePath(str_replace('\\', '/', $model).'.php'); + $modelPath = $this->laravel->basePath(str_replace('\\', '/', $model) . '.php'); if (! file_exists($modelPath)) { $this->components->error("Model not found at {$modelPath}."); @@ -187,59 +187,66 @@ protected function addTraitToModel(string $trait, string $model) $content = file_get_contents($modelPath); $traitBasename = class_basename($trait); + $topLevelCheck = "use $trait;"; + $classLevelCheck = $traitBasename; - // Check if the trait is already imported or used - if (strpos($content, "use $trait;") !== false || strpos($content, $traitBasename) !== false) { + // 1. Check if the trait is already imported or used + $isTopLevelImported = strpos($content, $topLevelCheck) !== false; + $isClassLevelUsed = preg_match('/use\s+([A-Za-z,\\\\\s]+);/', $content, $matches) && + strpos($matches[1], $classLevelCheck) !== false; + + if ($isTopLevelImported && $isClassLevelUsed) { $this->components->info("The [{$trait}] trait is already present in your [{$model}] model."); return; } $modified = false; - // Add the top-level `use` statement if it doesn't exist - $content = preg_replace( - '/^(namespace\s+[\w\\\\]+;\s*(?:\/\/.*\n)*)((?:use\s+[\w\\\\]+;\n)*)\s*/m', - '$1$2use ' . $trait . ";\n", - $content, - 1, - $count - ); - - if ($count > 0) { - $modified = true; + // 2. Add the top-level `use` statement if missing + if (! $isTopLevelImported) { + $content = preg_replace( + '/^(namespace\s+[\w\\\\]+;\s*(?:\/\/.*\n)*)((?:use\s+[\w\\\\]+;\n)*)/m', + '$1$2use ' . $trait . ";\n", + $content, + 1, + $count + ); + if ($count > 0) { + $modified = true; + } } - // Add the trait usage within the class, avoiding duplicate additions - if (preg_match('/class\s+\w+\s+extends\s+\w+[A-Za-z\\\\]*\s*\{/', $content, $matches, PREG_OFFSET_CAPTURE)) { - $insertPosition = $matches[0][1] + strlen($matches[0][0]); - - if (preg_match('/use\s+(.*?);/s', $content, $useMatches, PREG_OFFSET_CAPTURE, $insertPosition)) { - $traits = array_map('trim', explode(',', $useMatches[1][0])); - - // Only add the trait if it doesn't already exist in the class-level use block - if (! in_array($traitBasename, $traits)) { - $traits[] = $traitBasename; + // 3. Add the class-level trait if missing + if (! $isClassLevelUsed) { + if (preg_match('/class\s+\w+\s+extends\s+\w+[A-Za-z\\\\]*\s*\{/', $content, $matches, PREG_OFFSET_CAPTURE)) { + $insertPosition = $matches[0][1] + strlen($matches[0][0]); + + if (preg_match('/use\s+(.*?);/s', $content, $useMatches, PREG_OFFSET_CAPTURE, $insertPosition)) { + $traits = array_map('trim', explode(',', $useMatches[1][0])); + + if (! in_array($traitBasename, $traits)) { + $traits[] = $traitBasename; + $content = substr_replace( + $content, + 'use ' . implode(', ', $traits) . ';', + $useMatches[0][1], + strlen($useMatches[0][0]) + ); + $modified = true; + } + } else { $content = substr_replace( $content, - 'use '.implode(', ', $traits).';', - $useMatches[0][1], - strlen($useMatches[0][0]) + "\n use $traitBasename;", + $insertPosition, + 0 ); $modified = true; } - } else { - // No existing use block in the class, insert a new one - $content = substr_replace( - $content, - "\n use $traitBasename;", - $insertPosition, - 0 - ); - $modified = true; } } - // Write the updated content back to the file if modified + // 4. Write the changes back to the file if ($modified) { file_put_contents($modelPath, $content); $this->components->info("The [{$trait}] trait has been added to your [{$model}] model."); From 8c5ecd4b67ad74c4ab027a7a73c7149a55e1e787 Mon Sep 17 00:00:00 2001 From: Josh Salway Date: Sat, 21 Dec 2024 02:22:20 +1000 Subject: [PATCH 12/17] Deals with conflict. --- .../Foundation/Console/ApiInstallCommand.php | 33 +++++++++++-------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/src/Illuminate/Foundation/Console/ApiInstallCommand.php b/src/Illuminate/Foundation/Console/ApiInstallCommand.php index 670546cc1c97..edb0a4378a99 100644 --- a/src/Illuminate/Foundation/Console/ApiInstallCommand.php +++ b/src/Illuminate/Foundation/Console/ApiInstallCommand.php @@ -187,22 +187,24 @@ protected function addTraitToModel(string $trait, string $model) $content = file_get_contents($modelPath); $traitBasename = class_basename($trait); - $topLevelCheck = "use $trait;"; - $classLevelCheck = $traitBasename; + $sanctumTrait = 'Laravel\\Sanctum\\HasApiTokens'; + $passportTrait = 'Laravel\\Passport\\HasApiTokens'; - // 1. Check if the trait is already imported or used - $isTopLevelImported = strpos($content, $topLevelCheck) !== false; - $isClassLevelUsed = preg_match('/use\s+([A-Za-z,\\\\\s]+);/', $content, $matches) && - strpos($matches[1], $classLevelCheck) !== false; + // Detect conflicts + if (str_contains($content, "use $sanctumTrait;")) { + $this->warn("Sanctum is already installed in your [$model] model. Please manually switch to Passport if needed."); + return; + } - if ($isTopLevelImported && $isClassLevelUsed) { - $this->components->info("The [{$trait}] trait is already present in your [{$model}] model."); + if (str_contains($content, "use $passportTrait;")) { + $this->warn("Passport is already installed in your [$model] model. Please manually switch to Sanctum if needed."); return; } + // Add the top-level `use` statement if missing $modified = false; + $isTopLevelImported = str_contains($content, "use $trait;"); - // 2. Add the top-level `use` statement if missing if (! $isTopLevelImported) { $content = preg_replace( '/^(namespace\s+[\w\\\\]+;\s*(?:\/\/.*\n)*)((?:use\s+[\w\\\\]+;\n)*)/m', @@ -216,7 +218,10 @@ protected function addTraitToModel(string $trait, string $model) } } - // 3. Add the class-level trait if missing + // Add the class-level trait if missing + $isClassLevelUsed = preg_match('/use\s+([A-Za-z,\\\\\s]+);/', $content, $matches) && + str_contains($matches[1], $traitBasename); + if (! $isClassLevelUsed) { if (preg_match('/class\s+\w+\s+extends\s+\w+[A-Za-z\\\\]*\s*\{/', $content, $matches, PREG_OFFSET_CAPTURE)) { $insertPosition = $matches[0][1] + strlen($matches[0][0]); @@ -224,7 +229,7 @@ protected function addTraitToModel(string $trait, string $model) if (preg_match('/use\s+(.*?);/s', $content, $useMatches, PREG_OFFSET_CAPTURE, $insertPosition)) { $traits = array_map('trim', explode(',', $useMatches[1][0])); - if (! in_array($traitBasename, $traits)) { + if (!in_array($traitBasename, $traits, true)) { $traits[] = $traitBasename; $content = substr_replace( $content, @@ -246,12 +251,12 @@ protected function addTraitToModel(string $trait, string $model) } } - // 4. Write the changes back to the file + // Save changes if modified if ($modified) { file_put_contents($modelPath, $content); - $this->components->info("The [{$trait}] trait has been added to your [{$model}] model."); + $this->components->info("The [$trait] trait has been added to your [$model] model."); } else { - $this->components->info("No changes were made to your [{$model}] model."); + $this->components->info("No changes were made to your [$model] model."); } } } From bbbc0d68cfe9ec48ba955618b8369c4b2284f761 Mon Sep 17 00:00:00 2001 From: Josh Salway Date: Sat, 21 Dec 2024 02:32:38 +1000 Subject: [PATCH 13/17] WIP --- .../Foundation/Console/ApiInstallCommand.php | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/Illuminate/Foundation/Console/ApiInstallCommand.php b/src/Illuminate/Foundation/Console/ApiInstallCommand.php index edb0a4378a99..813c1096b0f0 100644 --- a/src/Illuminate/Foundation/Console/ApiInstallCommand.php +++ b/src/Illuminate/Foundation/Console/ApiInstallCommand.php @@ -172,10 +172,10 @@ protected function installPassport() } /** - * Attempt to add the given trait to the specified model. - * - * @return void - */ + * Attempt to add the given trait to the specified model. + * + * @return void + */ protected function addTraitToModel(string $trait, string $model) { $modelPath = $this->laravel->basePath(str_replace('\\', '/', $model) . '.php'); @@ -190,7 +190,7 @@ protected function addTraitToModel(string $trait, string $model) $sanctumTrait = 'Laravel\\Sanctum\\HasApiTokens'; $passportTrait = 'Laravel\\Passport\\HasApiTokens'; - // Detect conflicts + // Detect existing traits and warn if (str_contains($content, "use $sanctumTrait;")) { $this->warn("Sanctum is already installed in your [$model] model. Please manually switch to Passport if needed."); return; @@ -201,8 +201,18 @@ protected function addTraitToModel(string $trait, string $model) return; } - // Add the top-level `use` statement if missing + // Confirm with the user before making changes + if (! $this->components->confirm( + "Would you like to add the [$trait] trait to your [$model] model now?", + true + )) { + $this->components->info("No changes were made to your [$model] model."); + return; + } + $modified = false; + + // Add the top-level `use` statement if missing $isTopLevelImported = str_contains($content, "use $trait;"); if (! $isTopLevelImported) { From 0bb9d0e621cf2bb2f548cc5118569a988e2a8242 Mon Sep 17 00:00:00 2001 From: Josh Salway Date: Sat, 21 Dec 2024 02:52:43 +1000 Subject: [PATCH 14/17] WIP --- .../Foundation/Console/ApiInstallCommand.php | 36 ++++++++++--------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/src/Illuminate/Foundation/Console/ApiInstallCommand.php b/src/Illuminate/Foundation/Console/ApiInstallCommand.php index 813c1096b0f0..0554e5abe09e 100644 --- a/src/Illuminate/Foundation/Console/ApiInstallCommand.php +++ b/src/Illuminate/Foundation/Console/ApiInstallCommand.php @@ -172,10 +172,10 @@ protected function installPassport() } /** - * Attempt to add the given trait to the specified model. - * - * @return void - */ + * Attempt to add the given trait to the specified model. + * + * @return void + */ protected function addTraitToModel(string $trait, string $model) { $modelPath = $this->laravel->basePath(str_replace('\\', '/', $model) . '.php'); @@ -187,23 +187,27 @@ protected function addTraitToModel(string $trait, string $model) $content = file_get_contents($modelPath); $traitBasename = class_basename($trait); - $sanctumTrait = 'Laravel\\Sanctum\\HasApiTokens'; - $passportTrait = 'Laravel\\Passport\\HasApiTokens'; - // Detect existing traits and warn - if (str_contains($content, "use $sanctumTrait;")) { - $this->warn("Sanctum is already installed in your [$model] model. Please manually switch to Passport if needed."); - return; - } + // Map traits to their readable names + $traitNames = [ + 'Laravel\\Sanctum\\HasApiTokens' => 'Sanctum', + 'Laravel\\Passport\\HasApiTokens' => 'Passport', + ]; - if (str_contains($content, "use $passportTrait;")) { - $this->warn("Passport is already installed in your [$model] model. Please manually switch to Sanctum if needed."); - return; + // Determine the readable name for the requested trait + $traitName = $traitNames[$trait] ?? $traitBasename; + + // Detect existing traits and warn with improved messages + foreach ($traitNames as $existingTrait => $existingTraitName) { + if (str_contains($content, "use $existingTrait;")) { + $this->warn("$existingTraitName is already installed in your [$model] model. Please manually install [$traitName] if needed."); + return; + } } // Confirm with the user before making changes if (! $this->components->confirm( - "Would you like to add the [$trait] trait to your [$model] model now?", + "Would you like to add the [$traitName] trait to your [$model] model now?", true )) { $this->components->info("No changes were made to your [$model] model."); @@ -264,7 +268,7 @@ protected function addTraitToModel(string $trait, string $model) // Save changes if modified if ($modified) { file_put_contents($modelPath, $content); - $this->components->info("The [$trait] trait has been added to your [$model] model."); + $this->components->info("The [$traitName] trait has been added to your [$model] model."); } else { $this->components->info("No changes were made to your [$model] model."); } From c4822740b622bb853334bea9421be4d6bae18310 Mon Sep 17 00:00:00 2001 From: Josh Salway Date: Sat, 21 Dec 2024 02:55:14 +1000 Subject: [PATCH 15/17] WIP --- .../Foundation/Console/ApiInstallCommand.php | 37 +++++++++---------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/src/Illuminate/Foundation/Console/ApiInstallCommand.php b/src/Illuminate/Foundation/Console/ApiInstallCommand.php index 0554e5abe09e..9277130a94ff 100644 --- a/src/Illuminate/Foundation/Console/ApiInstallCommand.php +++ b/src/Illuminate/Foundation/Console/ApiInstallCommand.php @@ -172,10 +172,10 @@ protected function installPassport() } /** - * Attempt to add the given trait to the specified model. - * - * @return void - */ + * Attempt to add the given trait to the specified model. + * + * @return void + */ protected function addTraitToModel(string $trait, string $model) { $modelPath = $this->laravel->basePath(str_replace('\\', '/', $model) . '.php'); @@ -187,27 +187,26 @@ protected function addTraitToModel(string $trait, string $model) $content = file_get_contents($modelPath); $traitBasename = class_basename($trait); + $sanctumTrait = 'Laravel\\Sanctum\\HasApiTokens'; + $passportTrait = 'Laravel\\Passport\\HasApiTokens'; - // Map traits to their readable names - $traitNames = [ - 'Laravel\\Sanctum\\HasApiTokens' => 'Sanctum', - 'Laravel\\Passport\\HasApiTokens' => 'Passport', - ]; - - // Determine the readable name for the requested trait - $traitName = $traitNames[$trait] ?? $traitBasename; + // Determine whether the requested trait is Sanctum or Passport + $traitName = ($trait === $sanctumTrait) ? 'Sanctum' : (($trait === $passportTrait) ? 'Passport' : $traitBasename); // Detect existing traits and warn with improved messages - foreach ($traitNames as $existingTrait => $existingTraitName) { - if (str_contains($content, "use $existingTrait;")) { - $this->warn("$existingTraitName is already installed in your [$model] model. Please manually install [$traitName] if needed."); - return; - } + if (str_contains($content, "use $sanctumTrait;")) { + $this->warn("Sanctum is already installed in your [$model] model. Please manually install [$traitName] if needed."); + return; + } + + if (str_contains($content, "use $passportTrait;")) { + $this->warn("Passport is already installed in your [$model] model. Please manually install [$traitName] if needed."); + return; } // Confirm with the user before making changes if (! $this->components->confirm( - "Would you like to add the [$traitName] trait to your [$model] model now?", + "Would you like to add the [$trait] trait to your [$model] model now?", true )) { $this->components->info("No changes were made to your [$model] model."); @@ -268,7 +267,7 @@ protected function addTraitToModel(string $trait, string $model) // Save changes if modified if ($modified) { file_put_contents($modelPath, $content); - $this->components->info("The [$traitName] trait has been added to your [$model] model."); + $this->components->info("The [$trait] trait has been added to your [$model] model."); } else { $this->components->info("No changes were made to your [$model] model."); } From 031f3fdc090cbe5051e8ef2c21c7c0198f5187a6 Mon Sep 17 00:00:00 2001 From: Josh Salway Date: Sat, 21 Dec 2024 03:04:15 +1000 Subject: [PATCH 16/17] WIP --- .../Foundation/Console/ApiInstallCommand.php | 43 +++++++++++-------- 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/src/Illuminate/Foundation/Console/ApiInstallCommand.php b/src/Illuminate/Foundation/Console/ApiInstallCommand.php index 9277130a94ff..33486dd2d471 100644 --- a/src/Illuminate/Foundation/Console/ApiInstallCommand.php +++ b/src/Illuminate/Foundation/Console/ApiInstallCommand.php @@ -40,14 +40,16 @@ class ApiInstallCommand extends Command */ public function handle() { + // Install Passport or Sanctum if ($this->option('passport')) { $this->installPassport(); } else { $this->installSanctum(); } - if (file_exists($apiRoutesPath = $this->laravel->basePath('routes/api.php')) && - ! $this->option('force')) { + // Handle API Routes + $apiRoutesPath = $this->laravel->basePath('routes/api.php'); + if (file_exists($apiRoutesPath) && ! $this->option('force')) { $this->components->error('API routes file already exists.'); } else { $this->components->info('Published API routes file.'); @@ -55,16 +57,13 @@ public function handle() copy(__DIR__.'/stubs/api-routes.stub', $apiRoutesPath); if ($this->option('passport')) { - (new Filesystem)->replaceInFile( - 'auth:sanctum', - 'auth:api', - $apiRoutesPath, - ); + (new Filesystem)->replaceInFile('auth:sanctum', 'auth:api', $apiRoutesPath); } $this->uncommentApiRoutesFile(); } + // Handle Passport-Specific Commands if ($this->option('passport')) { Process::run(array_filter([ php_binary(), @@ -76,14 +75,10 @@ public function handle() $this->components->info('API scaffolding installed. Please add the [Laravel\Passport\HasApiTokens] trait to your User model.'); if ($this->confirm('Would you like to add the [Laravel\Passport\HasApiTokens] trait to your User model now?', true)) { - if (class_exists('App\\Models\\User')) { - $this->addTraitToModel('Laravel\Passport\HasApiTokens', 'App\\Models\\User'); - } else { - $this->components->warn('The [App\\Models\\User] model does not exist. Please manually add the trait to your User model if you\'ve moved or renamed it.'); - } + $this->addTraitIfExists('Laravel\Passport\HasApiTokens', 'App\\Models\\User'); } - } else { + // Handle Sanctum-Specific Migration Prompt if (! $this->option('without-migration-prompt')) { if ($this->confirm('One new database migration has been published. Would you like to run all pending database migrations?', true)) { $this->call('migrate'); @@ -93,17 +88,29 @@ public function handle() $this->components->info('API scaffolding installed. Please add the [Laravel\Sanctum\HasApiTokens] trait to your User model.'); if ($this->confirm('Would you like to add the [Laravel\\Sanctum\\HasApiTokens] trait to your User model now?', true)) { - if (class_exists('App\\Models\\User')) { - $this->addTraitToModel('Laravel\\Sanctum\\HasApiTokens', 'App\\Models\\User'); - } else { - $this->components->warn('The [App\\Models\\User] model does not exist. Please manually add the trait to your User model if you\'ve moved or renamed it.'); - } + $this->addTraitIfExists('Laravel\\Sanctum\\HasApiTokens', 'App\\Models\\User'); } } return Command::SUCCESS; } + /** + * Attempt to add the given trait to the specified model if it exists. + * + * @param string $trait + * @param string $model + * @return void + */ + protected function addTraitIfExists(string $trait, string $model) + { + if (class_exists($model)) { + $this->addTraitToModel($trait, $model); + } else { + $this->components->warn("The [$model] model does not exist. Please manually add the [$trait] trait to your model."); + } + } + /** * Uncomment the API routes file in the application bootstrap file. * From 773b761213eb5c42cd647edd89e305c04b154a27 Mon Sep 17 00:00:00 2001 From: Josh Salway Date: Sat, 21 Dec 2024 03:13:23 +1000 Subject: [PATCH 17/17] WIP --- src/Illuminate/Foundation/Console/ApiInstallCommand.php | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/Illuminate/Foundation/Console/ApiInstallCommand.php b/src/Illuminate/Foundation/Console/ApiInstallCommand.php index 33486dd2d471..9e25e73682a5 100644 --- a/src/Illuminate/Foundation/Console/ApiInstallCommand.php +++ b/src/Illuminate/Foundation/Console/ApiInstallCommand.php @@ -211,15 +211,6 @@ protected function addTraitToModel(string $trait, string $model) return; } - // Confirm with the user before making changes - if (! $this->components->confirm( - "Would you like to add the [$trait] trait to your [$model] model now?", - true - )) { - $this->components->info("No changes were made to your [$model] model."); - return; - } - $modified = false; // Add the top-level `use` statement if missing