From 66a808eae752160eef2e04ca9e9d2cf7b59e6d8e Mon Sep 17 00:00:00 2001 From: Tony Messias Date: Thu, 4 Jan 2024 00:00:06 -0300 Subject: [PATCH 1/4] Allow using a partials subfolder --- src/Facades/Turbo.php | 11 ++++++++ src/NamesResolver.php | 10 +++++--- tests/Models/NamesResolverTest.php | 40 ++++++++++++++++++++++++++++++ 3 files changed, 58 insertions(+), 3 deletions(-) create mode 100644 tests/Models/NamesResolverTest.php diff --git a/src/Facades/Turbo.php b/src/Facades/Turbo.php index 155ea5d2..06581aef 100644 --- a/src/Facades/Turbo.php +++ b/src/Facades/Turbo.php @@ -2,6 +2,7 @@ namespace HotwiredLaravel\TurboLaravel\Facades; +use Closure; use HotwiredLaravel\TurboLaravel\Broadcasters\Broadcaster; use HotwiredLaravel\TurboLaravel\Turbo as BaseTurbo; use Illuminate\Database\Eloquent\Model; @@ -23,6 +24,16 @@ */ class Turbo extends Facade { + public static function usePartialsSubfolderPattern() + { + static::resolvePartialsPathUsing('{plural}.partials.{singular}'); + } + + public static function resolvePartialsPathUsing(string|Closure $pattern) + { + config()->set('turbo-laravel.partials_path', $pattern); + } + protected static function getFacadeAccessor() { return BaseTurbo::class; diff --git a/src/NamesResolver.php b/src/NamesResolver.php index 2437e87d..f4c8461e 100644 --- a/src/NamesResolver.php +++ b/src/NamesResolver.php @@ -17,9 +17,13 @@ public static function partialNameFor(Model $model): string { $name = Name::forModel($model); - $resource = $name->plural; - $partial = $name->element; + $replacements = [ + '{plural}' => $name->plural, + '{singular}' => $name->element, + ]; - return "{$resource}._{$partial}"; + $pattern = config('turbo-laravel.partials_path', '{plural}._{singular}'); + + return str_replace(array_keys($replacements), array_values($replacements), value($pattern, $model)); } } diff --git a/tests/Models/NamesResolverTest.php b/tests/Models/NamesResolverTest.php new file mode 100644 index 00000000..af93c7ed --- /dev/null +++ b/tests/Models/NamesResolverTest.php @@ -0,0 +1,40 @@ +make(); + + $this->assertEquals('articles._article', NamesResolver::partialNameFor($article)); + } + + /** @test */ + public function resolves_partial_naming_using_subfolder() + { + $article = ArticleFactory::new()->make(); + + Turbo::usePartialsSubfolderPattern(); + + $this->assertEquals('articles.partials.article', NamesResolver::partialNameFor($article)); + } + + /** @test */ + public function resolves_using_custom_closure() + { + $article = ArticleFactory::new()->make(); + + Turbo::resolvePartialsPathUsing(fn (Model $model) => 'partials.article'); + + $this->assertEquals('partials.article', NamesResolver::partialNameFor($article)); + } +} From 284994f7a2c9aba5b3ce0e0ae85e35d64df66c15 Mon Sep 17 00:00:00 2001 From: Tony Messias Date: Thu, 4 Jan 2024 00:15:59 -0300 Subject: [PATCH 2/4] docs --- docs/conventions.md | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/docs/conventions.md b/docs/conventions.md index 82d3a903..4f9599c6 100644 --- a/docs/conventions.md +++ b/docs/conventions.md @@ -31,6 +31,50 @@ When using this config, the redirection behavior will still happen, but the pack You may want to split up your views in smaller chunks (aka. "partials"), such as a `comments/_comment.blade.php` to display a comment resource, or `comments/_form.blade.php` to display the form for both creating and updating comments. This allows you to reuse these _partials_ in [Turbo Streams](/docs/{{version}}/turbo-streams). +Alternatively, you may override opt-in to a `{plural}.partials.{singular}` convention for your partials location by calling the `Turbo::usePartialsSubfolderPattern()` method of the Turbo Facade from your `AppServiceProvider::boot()` method: + +```php + 'partials.{singular}'); + } +} +``` + +You may also want to define your own pattern, which you can do by either specifying a string where you have the `{plural}` and `{singular}` placeholders available, but you can also specify a Closure, which will receive the model instance. On that Closure, you must return a string with the view location using the dot convention of Laravel. For instance, the subfolder pattern sets the config value to `{plural}.partials.{singular}` instead of the default, which is `{plural}._{singular}`. These will resolve to `comments.partials.comment` and `comments._comment` views, respectively. + The models' partials (such as a `comments/_comment.blade.php` for a `Comment` model) may only rely on having a single `$comment` variable passed to them. That's because Turbo Stream Model Broadcasts - which is an _optional_ feature, by the way - relies on these conventions to figure out the partial for a given model when broadcasting and will also pass the model to such partial, using the class basename as the variable instance in _camelCase_. Again, this is optional, you can customize most of these things or create your own model broadcasting convention. Read the [Broadcasting](/docs/{{version}}/broadcasting) section to know more. ## Turbo Stream Channel Names From 591c466bf1cf8daf44fb3cc67358a0869c750440 Mon Sep 17 00:00:00 2001 From: Tony Messias Date: Thu, 4 Jan 2024 00:41:01 -0300 Subject: [PATCH 3/4] Use static property instead of config because configs must be serializable (and closures are not) --- src/Facades/Turbo.php | 3 ++- src/NamesResolver.php | 10 +++++++++- tests/TestCase.php | 2 ++ 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/Facades/Turbo.php b/src/Facades/Turbo.php index 06581aef..9453812f 100644 --- a/src/Facades/Turbo.php +++ b/src/Facades/Turbo.php @@ -4,6 +4,7 @@ use Closure; use HotwiredLaravel\TurboLaravel\Broadcasters\Broadcaster; +use HotwiredLaravel\TurboLaravel\NamesResolver; use HotwiredLaravel\TurboLaravel\Turbo as BaseTurbo; use Illuminate\Database\Eloquent\Model; use Illuminate\Support\Facades\Facade; @@ -31,7 +32,7 @@ public static function usePartialsSubfolderPattern() public static function resolvePartialsPathUsing(string|Closure $pattern) { - config()->set('turbo-laravel.partials_path', $pattern); + NamesResolver::resolvePartialsPathUsing($pattern); } protected static function getFacadeAccessor() diff --git a/src/NamesResolver.php b/src/NamesResolver.php index f4c8461e..cfb7dba5 100644 --- a/src/NamesResolver.php +++ b/src/NamesResolver.php @@ -2,12 +2,20 @@ namespace HotwiredLaravel\TurboLaravel; +use Closure; use HotwiredLaravel\TurboLaravel\Models\Naming\Name; use Illuminate\Database\Eloquent\Model; use Illuminate\Support\Str; class NamesResolver { + protected static $partialsPathResolver = '{plural}._{singular}'; + + public static function resolvePartialsPathUsing(string|Closure $resolver) + { + static::$partialsPathResolver = $resolver; + } + public static function resourceVariableName(Model $model): string { return Str::camel(Name::forModel($model)->singular); @@ -22,7 +30,7 @@ public static function partialNameFor(Model $model): string '{singular}' => $name->element, ]; - $pattern = config('turbo-laravel.partials_path', '{plural}._{singular}'); + $pattern = value(static::$partialsPathResolver, $model); return str_replace(array_keys($replacements), array_values($replacements), value($pattern, $model)); } diff --git a/tests/TestCase.php b/tests/TestCase.php index 07e81fca..8a53a0c1 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -2,6 +2,7 @@ namespace HotwiredLaravel\TurboLaravel\Tests; +use HotwiredLaravel\TurboLaravel\Facades\Turbo; use HotwiredLaravel\TurboLaravel\Facades\TurboStream; use Illuminate\Foundation\Testing\RefreshDatabase; use Orchestra\Testbench\Concerns\WithWorkbench; @@ -17,6 +18,7 @@ protected function setUp(): void parent::setUp(); TurboStream::fake(); + Turbo::resolvePartialsPathUsing('{plural}._{singular}'); } protected function defineEnvironment($app) From 968ab51c6cd1f28157a8f5a9d8f66e016bd7f9d4 Mon Sep 17 00:00:00 2001 From: Tony Messias Date: Thu, 4 Jan 2024 00:52:42 -0300 Subject: [PATCH 4/4] wip --- docs/conventions.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/conventions.md b/docs/conventions.md index 4f9599c6..5f571a02 100644 --- a/docs/conventions.md +++ b/docs/conventions.md @@ -31,7 +31,7 @@ When using this config, the redirection behavior will still happen, but the pack You may want to split up your views in smaller chunks (aka. "partials"), such as a `comments/_comment.blade.php` to display a comment resource, or `comments/_form.blade.php` to display the form for both creating and updating comments. This allows you to reuse these _partials_ in [Turbo Streams](/docs/{{version}}/turbo-streams). -Alternatively, you may override opt-in to a `{plural}.partials.{singular}` convention for your partials location by calling the `Turbo::usePartialsSubfolderPattern()` method of the Turbo Facade from your `AppServiceProvider::boot()` method: +Alternatively, you may override the pattern to a `{plural}.partials.{singular}` convention for your partials location by calling the `Turbo::usePartialsSubfolderPattern()` method of the Turbo Facade from your `AppServiceProvider::boot()` method: ```php 'partials.{singular}'); }