Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 17 additions & 3 deletions src/Illuminate/Foundation/Console/RouteCacheCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use Illuminate\Console\Command;
use Illuminate\Contracts\Console\Kernel as ConsoleKernelContract;
use Illuminate\Filesystem\Filesystem;
use Illuminate\Routing\Route;
use Illuminate\Routing\RouteCollection;
use Symfony\Component\Console\Attribute\AsCommand;

Expand Down Expand Up @@ -59,9 +60,7 @@ public function handle()
return $this->components->error("Your application doesn't have any routes.");
}

foreach ($routes as $route) {
$route->prepareForSerialization();
}
$routes = $this->prepareRoutes($routes);

$this->files->put(
$this->laravel->getCachedRoutesPath(), $this->buildRouteCacheFile($routes)
Expand All @@ -70,6 +69,21 @@ public function handle()
$this->components->info('Routes cached successfully.');
}

protected function prepareRoutes(RouteCollection $routes)
{
$collection = new RouteCollection;

foreach ($routes as $route) {
$collection->add(transform(clone $route, static function (Route $route) {
$route->prepareForSerialization();

return $route;
}));
}

return $collection;
}

/**
* Boot a fresh copy of the application and get the routes.
*
Expand Down
18 changes: 18 additions & 0 deletions tests/Integration/Foundation/Console/Fixtures/app.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php

namespace Illuminate\Tests\Integration\Foundation\Console\Fixtures;

use Illuminate\Foundation\Application;

if (! class_exists(AppCache::class)) {
class AppCache
{
public static $app;
}
}

if (isset($refresh)) {
return AppCache::$app = Application::configure(basePath: __DIR__)->create();
}

return AppCache::$app ??= Application::configure(basePath: __DIR__)->create();
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
*
!.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
*
!.gitignore
121 changes: 121 additions & 0 deletions tests/Integration/Foundation/Console/RouteCacheCommandTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
<?php

namespace Illuminate\Tests\Integration\Foundation\Console;

use Illuminate\Console\Command;
use Illuminate\Routing\Controller;
use Illuminate\Support\ServiceProvider;
use Illuminate\Tests\Integration\Foundation\Console\Fixtures\AppCache;
use Illuminate\Tests\Integration\Generators\TestCase;
use LogicException;
use Orchestra\Testbench\Concerns\InteractsWithPublishedFiles;

class RouteCacheCommandTest extends TestCase
{
use InteractsWithPublishedFiles;

protected $files = [
'cache/routes-v7.php',
];

protected function tearDown(): void
{
@unlink(__DIR__.'/Fixtures/cache/routes-v7.php');

parent::tearDown();
}

public function testRoutesRemainAnalyzableAfterCaching(): void
{
$this->app->useBootstrapPath(__DIR__.'/Fixtures');

$app = (static function () {
$refresh = true;

return require __DIR__.'/Fixtures/app.php';
})();

$app['router']->get('/posts', [RouteCacheCommandTestController::class, 'index'])->name('posts.index');

$this->artisan('route:cache')
->assertSuccessful()
->expectsOutputToContain('Routes cached successfully.');

$this->assertFileExists(__DIR__.'/Fixtures/cache/routes-v7.php');

foreach ($app['router']->getRoutes() as $route) {
try {
$route->getController();
$route->gatherMiddleware();
} catch (LogicException $exception) {
$this->fail(sprintf(
'Route [%s] is no longer analyzable after route:cache: %s',
$route->uri(),
$exception->getMessage(),
));
}
}
}

public function testOptimizeCanRunTasksThatAnalyzeRoutesAfterRouteCache(): void
{
$this->withoutDeprecationHandling();

$this->app->useBootstrapPath(__DIR__.'/Fixtures');

$app = (static function () {
$refresh = true;

return require __DIR__.'/Fixtures/app.php';
})();

$app['router']->get('/posts', [RouteCacheCommandTestController::class, 'index'])->name('posts.index');

$this->app->register(RouteAnalysisOptimizeServiceProvider::class);

$this->artisan('optimize', ['--except' => 'config,events,views'])
->assertSuccessful()
->expectsOutputToContain('route analysis succeeded');
}
}

class RouteCacheCommandTestController extends Controller
{
public function index(): string
{
return 'posts';
}
}

class RouteAnalysisOptimizeServiceProvider extends ServiceProvider
{
public function boot(): void
{
$this->commands([
RouteAnalysisOptimizeCommand::class,
]);

$this->optimizes(
optimize: 'test:route-analysis',
key: 'route-analysis',
);
}
}

class RouteAnalysisOptimizeCommand extends Command
{
protected $signature = 'test:route-analysis';

protected $description = 'Analyze routes after route:cache';

public function handle(): int
{
foreach (AppCache::$app['router']->getRoutes() as $route) {
$route->gatherMiddleware();
}

$this->components->info('route analysis succeeded');

return self::SUCCESS;
}
}
Loading