Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support Laravel Folio #733

Merged
merged 15 commits into from
May 16, 2024
2 changes: 2 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ jobs:
with:
node-version: 20
cache: 'npm'
- run: composer remove laravel/folio --dev --no-update --no-interaction
if: matrix.laravel == 9
- run: composer require laravel/framework:"${{ matrix.laravel }}.*" --no-update --no-interaction
- uses: ramsey/composer-install@v2
with:
Expand Down
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
"laravel/framework": ">=9.0"
},
"require-dev": {
"laravel/folio": "^1.1",
"orchestra/testbench": "^7.0 || ^8.0 || ^9.0",
"phpunit/phpunit": "^9.5 || ^10.3"
},
Expand Down
111 changes: 98 additions & 13 deletions src/Ziggy.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,14 @@
use Illuminate\Contracts\Routing\UrlRoutable;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Arr;
use Illuminate\Support\Collection;
use Illuminate\Support\Reflector;
use Illuminate\Support\Str;
use JsonSerializable;
use Laravel\Folio\FolioManager;
use Laravel\Folio\FolioRoutes;
use Laravel\Folio\Pipeline\MatchedView;
use Laravel\Folio\Pipeline\PotentiallyBindablePathSegment;
use ReflectionClass;
use ReflectionMethod;
use ReflectionProperty;
Expand Down Expand Up @@ -137,19 +142,23 @@ private function nameKeyedRoutes()
$routes->put($name, $route);
});

return $routes->map(function ($route) use ($bindings) {
return collect($route)->only(['uri', 'methods', 'wheres'])
->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());
})->filter();
});
return tap($this->folioRoutes(), fn ($all) => $routes->each(
fn ($route, $name) => $all->put(
$name,
collect($route)->only(['uri', 'methods', 'wheres'])
->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());
})
->filter()
)
));
}

/**
Expand Down Expand Up @@ -218,4 +227,80 @@ private function resolveBindings(array $routes): array

return $routes;
}

/**
* @see https://github.com/laravel/folio/blob/master/src/Console/ListCommand.php
*/
private function folioRoutes(): Collection
{
if (! app()->has(FolioRoutes::class)) {
return collect();
}

// Use existing named Folio routes (instead of searching view files) to respect route caching
return collect(app(FolioRoutes::class)->routes())->map(function (array $route) {
$uri = rtrim($route['baseUri'], '/') . str_replace([$route['mountPath'], '.blade.php'], '', $route['path']);

$segments = explode('/', $uri);
$parameters = [];
$bindings = [];

foreach ($segments as $i => $segment) {
// Folio doesn't support sub-segment parameters
if (Str::startsWith($segment, '[')) {
$param = new PotentiallyBindablePathSegment($segment);

$parameters[] = $name = $param->variable();
$segments[$i] = "{{$name}}";

if ($field = $param->field()) {
$bindings[$name] = $field;
} elseif ($param->bindable()) {
$override = (new ReflectionClass($param->class()))->isInstantiable() && (
(new ReflectionMethod($param->class(), 'getRouteKeyName'))->class !== Model::class
|| (new ReflectionMethod($param->class(), 'getKeyName'))->class !== Model::class
|| (new ReflectionProperty($param->class(), 'primaryKey'))->class !== Model::class
);

$bindings[$name] = $override ? app($param->class())->getRouteKeyName() : 'id';
}
}
}

$uri = implode('/', $segments);
$uri = Str::replaceEnd('/index', '', $uri);

if ($route['domain'] && str_contains($route['domain'], '{')) {
preg_match_all('/{(.*?)}/', $route['domain'], $matches);
array_unshift($parameters, ...$matches[1]);
}

$middleware = [];

if ($ziggyMiddleware = config('ziggy.middleware')) {
$mountPath = Arr::first(
app(FolioManager::class)->mountPaths(),
fn ($mountPath) => $mountPath->path === realpath($route['mountPath'])
);
$matchedView = new MatchedView(realpath($route['path']), [], $route['mountPath']);

$middleware = $mountPath->middleware
->match($matchedView)
->prepend('web')
->merge($matchedView->inlineMiddleware())
->unique()
->when(is_array($ziggyMiddleware), fn ($middleware) => $middleware->intersect($ziggyMiddleware))
->values()->all();
}

return array_filter([
'uri' => $uri === '' ? '/' : trim($uri, '/'),
'methods' => ['GET'],
'domain' => $route['domain'],
'parameters' => $parameters,
'bindings' => $bindings,
'middleware' => $middleware,
]);
});
}
}
Loading
Loading