From a192e142838d3ac194428f630c56696a86b6f667 Mon Sep 17 00:00:00 2001 From: Jacob Baker-Kretzmar Date: Fri, 17 May 2024 15:09:20 -0400 Subject: [PATCH 1/3] Modernize some syntax and remove single-use methods --- src/BladeRouteGenerator.php | 11 ++- src/CommandRouteGenerator.php | 28 ++------ src/Output/File.php | 21 +++--- src/Output/MergeScript.php | 16 ++--- src/Output/Script.php | 19 ++--- src/Output/Types.php | 21 +++--- src/Ziggy.php | 90 +++++++----------------- src/ZiggyServiceProvider.php | 4 +- tests/Unit/CommandRouteGeneratorTest.php | 6 +- 9 files changed, 72 insertions(+), 144 deletions(-) diff --git a/src/BladeRouteGenerator.php b/src/BladeRouteGenerator.php index f1b1cea9..1775a6e0 100644 --- a/src/BladeRouteGenerator.php +++ b/src/BladeRouteGenerator.php @@ -23,18 +23,15 @@ public function generate($group = null, string $nonce = null): string $output = config('ziggy.output.script', Script::class); - return (string) new $output($ziggy, $this->getRouteFunction(), $nonce); + $routeFunction = config('ziggy.skip-route-function') ? '' : file_get_contents(__DIR__ . '/../dist/route.umd.js'); + + return (string) new $output($ziggy, $routeFunction, $nonce); } - private function generateMergeJavascript(Ziggy $ziggy, $nonce) + private function generateMergeJavascript(Ziggy $ziggy, string $nonce) { $output = config('ziggy.output.merge_script', MergeScript::class); return new $output($ziggy, $nonce); } - - private function getRouteFunction() - { - return config('ziggy.skip-route-function') ? '' : file_get_contents(__DIR__ . '/../dist/route.umd.js'); - } } diff --git a/src/CommandRouteGenerator.php b/src/CommandRouteGenerator.php index eb5e5b08..cfa359ad 100644 --- a/src/CommandRouteGenerator.php +++ b/src/CommandRouteGenerator.php @@ -19,25 +19,16 @@ class CommandRouteGenerator extends Command protected $description = 'Generate a JavaScript file containing Ziggy’s routes and configuration.'; - protected $files; - - public function __construct(Filesystem $files) - { - parent::__construct(); - - $this->files = $files; - } - - public function handle() + public function handle(Filesystem $filesystem) { $ziggy = new Ziggy($this->option('group'), $this->option('url') ? url($this->option('url')) : null); $path = $this->argument('path') ?? config('ziggy.output.path', 'resources/js/ziggy.js'); - if ($this->files->isDirectory(base_path($path))) { + if ($filesystem->isDirectory(base_path($path))) { $path .= '/ziggy'; } else { - $this->makeDirectory($path); + $filesystem->ensureDirectoryExists(dirname(base_path($path)), recursive: true); } $name = preg_replace('/(\.d)?\.ts$|\.js$/', '', $path); @@ -45,24 +36,15 @@ public function handle() if (! $this->option('types-only')) { $output = config('ziggy.output.file', File::class); - $this->files->put(base_path("{$name}.js"), new $output($ziggy)); + $filesystem->put(base_path("{$name}.js"), new $output($ziggy)); } if ($this->option('types') || $this->option('types-only')) { $types = config('ziggy.output.types', Types::class); - $this->files->put(base_path("{$name}.d.ts"), new $types($ziggy)); + $filesystem->put(base_path("{$name}.d.ts"), new $types($ziggy)); } $this->info('Files generated!'); } - - private function makeDirectory($path) - { - if (! $this->files->isDirectory(dirname(base_path($path)))) { - $this->files->makeDirectory(dirname(base_path($path)), 0755, true, true); - } - - return $path; - } } diff --git a/src/Output/File.php b/src/Output/File.php index a039d312..127e17ec 100644 --- a/src/Output/File.php +++ b/src/Output/File.php @@ -7,22 +7,19 @@ class File implements Stringable { - protected $ziggy; - - public function __construct(Ziggy $ziggy) - { - $this->ziggy = $ziggy; - } + public function __construct( + protected Ziggy $ziggy, + ) {} public function __toString(): string { return <<ziggy->toJson()}; -if (typeof window !== 'undefined' && typeof window.Ziggy !== 'undefined') { - Object.assign(Ziggy.routes, window.Ziggy.routes); -} -export { Ziggy }; + const Ziggy = {$this->ziggy->toJson()}; + if (typeof window !== 'undefined' && typeof window.Ziggy !== 'undefined') { + Object.assign(Ziggy.routes, window.Ziggy.routes); + } + export { Ziggy }; -JAVASCRIPT; + JAVASCRIPT; } } diff --git a/src/Output/MergeScript.php b/src/Output/MergeScript.php index bc74a26b..48492c8e 100644 --- a/src/Output/MergeScript.php +++ b/src/Output/MergeScript.php @@ -7,21 +7,17 @@ class MergeScript implements Stringable { - protected $ziggy; - protected $nonce; - - public function __construct(Ziggy $ziggy, string $nonce = '') - { - $this->ziggy = $ziggy; - $this->nonce = $nonce; - } + public function __construct( + protected Ziggy $ziggy, + protected string $nonce = '', + ) {} public function __toString(): string { $routes = json_encode($this->ziggy->toArray()['routes']); return <<nonce}>Object.assign(Ziggy.routes,{$routes}); -HTML; + + HTML; } } diff --git a/src/Output/Script.php b/src/Output/Script.php index 4aea0100..56e2ce75 100644 --- a/src/Output/Script.php +++ b/src/Output/Script.php @@ -7,21 +7,16 @@ class Script implements Stringable { - protected $ziggy; - protected $function; - protected $nonce; - - public function __construct(Ziggy $ziggy, string $function, string $nonce = '') - { - $this->ziggy = $ziggy; - $this->function = $function; - $this->nonce = $nonce; - } + public function __construct( + protected Ziggy $ziggy, + protected string $function, + protected string $nonce = '', + ) {} public function __toString(): string { return <<nonce}>const Ziggy={$this->ziggy->toJson()};{$this->function} -HTML; + + HTML; } } diff --git a/src/Output/Types.php b/src/Output/Types.php index 6269c587..9827e812 100644 --- a/src/Output/Types.php +++ b/src/Output/Types.php @@ -9,12 +9,9 @@ class Types implements Stringable { - protected $ziggy; - - public function __construct(Ziggy $ziggy) - { - $this->ziggy = $ziggy; - } + public function __construct( + protected Ziggy $ziggy, + ) {} public function __toString(): string { @@ -27,12 +24,12 @@ public function __toString(): string }); return <<toJson(JSON_PRETTY_PRINT)} -} -export {}; + /* This file is generated by Ziggy. */ + declare module 'ziggy-js' { + interface RouteList {$routes->toJson(JSON_PRETTY_PRINT)} + } + export {}; -JAVASCRIPT; + JAVASCRIPT; } } diff --git a/src/Ziggy.php b/src/Ziggy.php index 247029e4..dd784ec0 100644 --- a/src/Ziggy.php +++ b/src/Ziggy.php @@ -21,21 +21,14 @@ class Ziggy implements JsonSerializable { protected static $cache; - protected $url; - protected $group; - protected $routes; - - public function __construct($group = null, string $url = null) - { - $this->group = $group; + protected Collection $routes; + public function __construct( + protected $group = null, + protected ?string $url = null, + ) { $this->url = rtrim($url ?? url('/'), '/'); - - if (! static::$cache) { - static::$cache = $this->nameKeyedRoutes(); - } - - $this->routes = static::$cache; + $this->routes = static::$cache ??= $this->nameKeyedRoutes(); } public static function clearRoutes() @@ -49,16 +42,11 @@ private function applyFilters($group) return $this->group($group); } - // return unfiltered routes if user set both config options. - if (config()->has('ziggy.except') && config()->has('ziggy.only')) { - return $this->routes; - } - - if (config()->has('ziggy.except')) { + if (config()->has('ziggy.except') && ! config()->has('ziggy.only')) { return $this->filter(config('ziggy.except'), false)->routes; } - if (config()->has('ziggy.only')) { + if (config()->has('ziggy.only') && ! config()->has('ziggy.except')) { return $this->filter(config('ziggy.only'))->routes; } @@ -94,9 +82,7 @@ public function filter($filters = [], $include = true): self { $filters = Arr::wrap($filters); - $reject = collect($filters)->every(function (string $pattern) { - return Str::startsWith($pattern, '!'); - }); + $reject = collect($filters)->every(fn (string $pattern) => str_starts_with($pattern, '!')); $this->routes = $reject ? $this->routes->reject(function ($route, $name) use ($filters) { @@ -112,7 +98,7 @@ public function filter($filters = [], $include = true): self } foreach ($filters as $pattern) { - if (Str::startsWith($pattern, '!') && Str::is(substr($pattern, 1), $name)) { + if (str_starts_with($pattern, '!') && Str::is(substr($pattern, 1), $name)) { return false; } } @@ -126,21 +112,15 @@ public function filter($filters = [], $include = true): self /** * Get a list of the application's named routes, keyed by their names. */ - private function nameKeyedRoutes() + private function nameKeyedRoutes(): Collection { [$fallbacks, $routes] = collect(app('router')->getRoutes()->getRoutesByName()) - ->reject(function ($route) { - return Str::startsWith($route->getName(), 'generated::'); - }) - ->partition(function ($route) { - return $route->isFallback; - }); + ->reject(fn ($route) => str_starts_with($route->getName(), 'generated::')) + ->partition('isFallback'); $bindings = $this->resolveBindings($routes->toArray()); - $fallbacks->map(function ($route, $name) use ($routes) { - $routes->put($name, $route); - }); + $fallbacks->each(fn ($route, $name) => $routes->put($name, $route)); return tap($this->folioRoutes(), fn ($all) => $routes->each( fn ($route, $name) => $all->put( @@ -149,46 +129,33 @@ private function nameKeyedRoutes() ->put('domain', $route->domain()) ->put('parameters', $route->parameterNames()) ->put('bindings', $bindings[$route->getName()] ?? []) - ->when($middleware = config('ziggy.middleware'), function ($collection) use ($middleware, $route) { - if (is_array($middleware)) { - return $collection->put('middleware', collect($route->middleware())->intersect($middleware)->values()->all()); - } - - return $collection->put('middleware', $route->middleware()); - }) + ->when(config('ziggy.middleware'), fn ($collection, $middleware) => is_array($middleware) + ? $collection->put('middleware', collect($route->middleware())->intersect($middleware)->values()->all()) + : $collection->put('middleware', $route->middleware()), + ) ->filter() ) )); } - /** - * Convert this Ziggy instance to an array. - */ public function toArray(): array { return [ 'url' => $this->url, - 'port' => parse_url($this->url)['port'] ?? null, - 'defaults' => method_exists(app('url'), 'getDefaultParameters') - ? app('url')->getDefaultParameters() - : [], + 'port' => parse_url($this->url, PHP_URL_PORT) ?? null, + 'defaults' => app('url')->getDefaultParameters(), 'routes' => $this->applyFilters($this->group)->toArray(), ]; } - /** - * Convert this Ziggy instance into something JSON serializable. - */ public function jsonSerialize(): array { - return array_merge($routes = $this->toArray(), [ + return [ + ...($routes = $this->toArray()), 'defaults' => (object) $routes['defaults'], - ]); + ]; } - /** - * Convert this Ziggy instance to JSON. - */ public function toJson(int $options = 0): string { return json_encode($this->jsonSerialize(), $options); @@ -199,8 +166,6 @@ public function toJson(int $options = 0): string */ private function resolveBindings(array $routes): array { - $scopedBindings = method_exists(head($routes) ?: '', 'bindingFields'); - foreach ($routes as $name => $route) { $bindings = []; @@ -209,9 +174,8 @@ private function resolveBindings(array $routes): array break; } - $model = class_exists(Reflector::class) - ? Reflector::getParameterClassName($parameter) - : $parameter->getType()->getName(); + $model = Reflector::getParameterClassName($parameter); + $override = (new ReflectionClass($model))->isInstantiable() && ( (new ReflectionMethod($model, 'getRouteKeyName'))->class !== Model::class || (new ReflectionMethod($model, 'getKeyName'))->class !== Model::class @@ -222,7 +186,7 @@ private function resolveBindings(array $routes): array $bindings[$parameter->getName()] = $override ? app($model)->getRouteKeyName() : 'id'; } - $routes[$name] = $scopedBindings ? array_merge($bindings, $route->bindingFields()) : $bindings; + $routes[$name] = [...$bindings, ...$route->bindingFields()]; } return $routes; @@ -247,7 +211,7 @@ private function folioRoutes(): Collection foreach ($segments as $i => $segment) { // Folio doesn't support sub-segment parameters - if (Str::startsWith($segment, '[')) { + if (str_starts_with($segment, '[')) { $param = new PotentiallyBindablePathSegment($segment); $parameters[] = $name = $param->variable(); diff --git a/src/ZiggyServiceProvider.php b/src/ZiggyServiceProvider.php index 996196c2..9ea40d2c 100644 --- a/src/ZiggyServiceProvider.php +++ b/src/ZiggyServiceProvider.php @@ -9,12 +9,12 @@ class ZiggyServiceProvider extends ServiceProvider { - public function boot() + public function boot(): void { if ($this->app->resolved('blade.compiler')) { $this->registerDirective($this->app['blade.compiler']); } else { - $this->app->afterResolving('blade.compiler', fn (BladeCompiler $blade) => $this->registerDirective($blade)); + $this->app->afterResolving('blade.compiler', $this->registerDirective(...)); } Event::listen(RequestReceived::class, function () { diff --git a/tests/Unit/CommandRouteGeneratorTest.php b/tests/Unit/CommandRouteGeneratorTest.php index c0863983..12956a9d 100644 --- a/tests/Unit/CommandRouteGeneratorTest.php +++ b/tests/Unit/CommandRouteGeneratorTest.php @@ -8,7 +8,7 @@ beforeEach(function () { if (is_dir(base_path('resources/js'))) { - array_map(fn ($file) => unlink($file), glob(base_path('resources/js/*'))); + array_map(unlink(...), glob(base_path('resources/js/*'))); } }); @@ -145,13 +145,13 @@ test('generate correct routes and dts files based on provided arguments', function (string $args, array $files) { if (is_dir(base_path('resources/scripts'))) { - array_map(fn ($file) => unlink($file), glob(base_path('resources/scripts/*'))); + array_map(unlink(...), glob(base_path('resources/scripts/*'))); rmdir(base_path('resources/scripts')); } artisan("ziggy:generate {$args}"); - expect(array_map(fn ($f) => base_path($f), $files))->each->toBeFile(); + expect(array_map(base_path(...), $files))->each->toBeFile(); })->with([ ['resources/js/x.js --types', ['resources/js/x.js', 'resources/js/x.d.ts']], ['resources/js/y.ts --types', ['resources/js/y.js', 'resources/js/y.d.ts']], From e0c00befec8bff516f3e4935b0426e080e731dee Mon Sep 17 00:00:00 2001 From: Jacob Baker-Kretzmar Date: Fri, 17 May 2024 16:20:20 -0400 Subject: [PATCH 2/3] Wip --- src/Output/File.php | 2 +- src/Output/Types.php | 2 +- src/ZiggyServiceProvider.php | 2 +- tests/fixtures/admin.js | 2 +- tests/fixtures/custom-pathname.js | 2 +- tests/fixtures/custom-url.js | 2 +- tests/fixtures/ziggy.js | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Output/File.php b/src/Output/File.php index 127e17ec..df7146aa 100644 --- a/src/Output/File.php +++ b/src/Output/File.php @@ -16,7 +16,7 @@ public function __toString(): string return <<ziggy->toJson()}; if (typeof window !== 'undefined' && typeof window.Ziggy !== 'undefined') { - Object.assign(Ziggy.routes, window.Ziggy.routes); + Object.assign(Ziggy.routes, window.Ziggy.routes); } export { Ziggy }; diff --git a/src/Output/Types.php b/src/Output/Types.php index 9827e812..171b8846 100644 --- a/src/Output/Types.php +++ b/src/Output/Types.php @@ -26,7 +26,7 @@ public function __toString(): string return <<toJson(JSON_PRETTY_PRINT)} + interface RouteList {$routes->toJson(JSON_PRETTY_PRINT)} } export {}; diff --git a/src/ZiggyServiceProvider.php b/src/ZiggyServiceProvider.php index 9ea40d2c..46c688bc 100644 --- a/src/ZiggyServiceProvider.php +++ b/src/ZiggyServiceProvider.php @@ -26,7 +26,7 @@ public function boot(): void } } - protected function registerDirective(BladeCompiler $blade) + protected function registerDirective(BladeCompiler $blade): void { $blade->directive('routes', fn ($group) => "generate({$group}); ?>"); } diff --git a/tests/fixtures/admin.js b/tests/fixtures/admin.js index b78a8475..e7a855bc 100644 --- a/tests/fixtures/admin.js +++ b/tests/fixtures/admin.js @@ -1,5 +1,5 @@ const Ziggy = {"url":"http:\/\/ziggy.dev","port":null,"defaults":{},"routes":{"admin.dashboard":{"uri":"admin","methods":["GET","HEAD"]}}}; if (typeof window !== 'undefined' && typeof window.Ziggy !== 'undefined') { - Object.assign(Ziggy.routes, window.Ziggy.routes); + Object.assign(Ziggy.routes, window.Ziggy.routes); } export { Ziggy }; diff --git a/tests/fixtures/custom-pathname.js b/tests/fixtures/custom-pathname.js index f9932bae..a6527192 100644 --- a/tests/fixtures/custom-pathname.js +++ b/tests/fixtures/custom-pathname.js @@ -1,5 +1,5 @@ const Ziggy = {"url":"http:\/\/ziggy.dev\/foo\/bar","port":null,"defaults":{},"routes":{"postComments.index":{"uri":"posts\/{post}\/comments","methods":["GET","HEAD"],"parameters":["post"]}}}; if (typeof window !== 'undefined' && typeof window.Ziggy !== 'undefined') { - Object.assign(Ziggy.routes, window.Ziggy.routes); + Object.assign(Ziggy.routes, window.Ziggy.routes); } export { Ziggy }; diff --git a/tests/fixtures/custom-url.js b/tests/fixtures/custom-url.js index 081dfc49..243c8652 100644 --- a/tests/fixtures/custom-url.js +++ b/tests/fixtures/custom-url.js @@ -1,5 +1,5 @@ const Ziggy = {"url":"http:\/\/example.org","port":null,"defaults":{"locale":"en"},"routes":{"postComments.index":{"uri":"posts\/{post}\/comments","methods":["GET","HEAD"],"parameters":["post"]}}}; if (typeof window !== 'undefined' && typeof window.Ziggy !== 'undefined') { - Object.assign(Ziggy.routes, window.Ziggy.routes); + Object.assign(Ziggy.routes, window.Ziggy.routes); } export { Ziggy }; diff --git a/tests/fixtures/ziggy.js b/tests/fixtures/ziggy.js index 3d12dedd..62aeed04 100644 --- a/tests/fixtures/ziggy.js +++ b/tests/fixtures/ziggy.js @@ -1,5 +1,5 @@ const Ziggy = {"url":"http:\/\/ziggy.dev","port":null,"defaults":{},"routes":{"postComments.index":{"uri":"posts\/{post}\/comments","methods":["GET","HEAD"],"parameters":["post"]},"slashes":{"uri":"slashes\/{slug}","methods":["GET","HEAD"],"wheres":{"slug":".*"},"parameters":["slug"]}}}; if (typeof window !== 'undefined' && typeof window.Ziggy !== 'undefined') { - Object.assign(Ziggy.routes, window.Ziggy.routes); + Object.assign(Ziggy.routes, window.Ziggy.routes); } export { Ziggy }; From e710650016498bb594636f21128cd8f86c2c89b8 Mon Sep 17 00:00:00 2001 From: Jacob Baker-Kretzmar Date: Sun, 21 Jul 2024 12:09:42 -0400 Subject: [PATCH 3/3] Wip --- src/Ziggy.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Ziggy.php b/src/Ziggy.php index dd784ec0..fd121752 100644 --- a/src/Ziggy.php +++ b/src/Ziggy.php @@ -28,6 +28,7 @@ public function __construct( protected ?string $url = null, ) { $this->url = rtrim($url ?? url('/'), '/'); + $this->routes = static::$cache ??= $this->nameKeyedRoutes(); }