Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(model): ensure accurate detection and addition of traits in User …
Browse files Browse the repository at this point in the history
…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.
JoshSalway committed Dec 20, 2024
1 parent 1a1b896 commit 66ef6c1
Showing 1 changed file with 44 additions and 37 deletions.
81 changes: 44 additions & 37 deletions src/Illuminate/Foundation/Console/ApiInstallCommand.php
Original file line number Diff line number Diff line change
@@ -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.");

0 comments on commit 66ef6c1

Please sign in to comment.