diff --git a/src/Illuminate/Console/GeneratorCommand.php b/src/Illuminate/Console/GeneratorCommand.php index 798a9dc5e137..26ec40b3faaa 100644 --- a/src/Illuminate/Console/GeneratorCommand.php +++ b/src/Illuminate/Console/GeneratorCommand.php @@ -417,7 +417,7 @@ protected function sortImports($stub) */ protected function getNameInput() { - return (string) Str::of($this->argument('name'))->trim()->beforeLast('.php'); + return (string) Str::of($this->argument('name'))->trim()->chopEnd('.php'); } /** diff --git a/src/Illuminate/Support/Str.php b/src/Illuminate/Support/Str.php index c9082a8de161..8f3105ed0788 100644 --- a/src/Illuminate/Support/Str.php +++ b/src/Illuminate/Support/Str.php @@ -242,6 +242,42 @@ public static function charAt($subject, $index) return mb_substr($subject, $index, 1); } + /** + * Remove the given string(s) if it exists at the end of the haystack. + * + * @param string $subject + * @param string|array $needle + * @return string + */ + public static function chopEnd($subject, $needles) + { + foreach ((array) $needles as $needle) { + if (str_ends_with($subject, $needle)) { + return substr($subject, 0, -strlen($needle)); + } + } + + return $subject; + } + + /** + * Remove the given string(s) if it exists at the start of the haystack. + * + * @param string $subject + * @param string|array $needle + * @return string + */ + public static function chopStart($subject, $needle) + { + foreach ((array) $needles as $needle) { + if (str_starts_with($subject, $needle)) { + return substr($subject, strlen($needle)); + } + } + + return $subject; + } + /** * Determine if a given string contains a given substring. * diff --git a/src/Illuminate/Support/Stringable.php b/src/Illuminate/Support/Stringable.php index f9b31839c1b5..2f8a83efd320 100644 --- a/src/Illuminate/Support/Stringable.php +++ b/src/Illuminate/Support/Stringable.php @@ -111,6 +111,28 @@ public function charAt($index) return Str::charAt($this->value, $index); } + /** + * Remove the given string(s) if it exists at the end of the haystack. + * + * @param string|array $needle + * @return static + */ + public function chopEnd($needles) + { + return new static(Str::chopEnd($this->value, $needles)); + } + + /** + * Remove the given string(s) if it exists at the start of the haystack. + * + * @param string|array $needle + * @return static + */ + public function chopStart($subject, $needle) + { + return new static(Str::chopStart($this->value, $needles)); + } + /** * Get the basename of the class path. * diff --git a/tests/Integration/Console/GeneratorCommandTest.php b/tests/Integration/Console/GeneratorCommandTest.php index e840dfc982cc..d2ef17ed19b4 100644 --- a/tests/Integration/Console/GeneratorCommandTest.php +++ b/tests/Integration/Console/GeneratorCommandTest.php @@ -27,6 +27,30 @@ public function testItChopsPhpExtension() ], 'app/Console/Commands/FooCommand.php'); } + public function testItDoesNotTrimIndividualCharacters() + { + $this->artisan('make:command', ['name' => 'Photograph']) + ->assertExitCode(0); + + $this->assertFilenameExists('app/Console/Commands/Photograph.php'); + + $this->assertFileContains([ + 'class Photograph extends Command', + ], 'app/Console/Commands/Photograph.php'); + } + + public function testItDoesNotChopCharactersWithinString() + { + $this->artisan('make:command', ['name' => 'Bar.php/Photograph']) + ->assertExitCode(0); + + $this->assertFilenameExists('app/Console/Commands/Bar.php/Photograph.php'); + + $this->assertFileContains([ + 'class Photograph extends Command', + ], 'app/Console/Commands/Bar.php/Photograph.php'); + } + public function testItChopsPhpExtensionFromMakeViewCommands() { $this->artisan('make:view', ['name' => 'foo.php'])