diff --git a/src/cli/controllers/AssetsController.php b/src/cli/controllers/assets/AssetRepairTrait.php similarity index 89% rename from src/cli/controllers/AssetsController.php rename to src/cli/controllers/assets/AssetRepairTrait.php index 1b3f5b1..0adae2d 100644 --- a/src/cli/controllers/AssetsController.php +++ b/src/cli/controllers/assets/AssetRepairTrait.php @@ -1,10 +1,9 @@ '4.18.4', - '5' => '5.10.9', - ]; - /** * @var array|null */ @@ -33,8 +27,7 @@ class AssetsController extends Controller public function options($actionID): array { return array_merge(parent::options($actionID), match ($actionID) { - 'replace-metadata', - 'repair-metadata', + 'index', 'missing', 'metadata' => ['volume', 'assetId'], default => [] @@ -110,7 +103,7 @@ protected function repairMissingAssetData(): int return ExitCode::OK; } - public function actionRepairMetadata(): int + protected function repairAssetObjectMetadataForAssets(): int { $assets = Asset::find() ->volume($this->volume) @@ -127,16 +120,6 @@ public function actionRepairMetadata(): int return ExitCode::OK; } - public function actionReplaceMetadata(): int - { - $this->stdout( - 'Deprecated: use `cloud/assets/repair/metadata` to repair object metadata instead.' . PHP_EOL, - Console::FG_YELLOW, - ); - - return $this->actionRepairMetadata(); - } - /** * @return array{int,int}|null */ @@ -199,7 +182,7 @@ protected function repairAssetSize(Asset $asset): ?int protected function warnIfCraftStreamDimensionFixMissing(): void { $craftVersion = Craft::$app->getVersion(); - $fixedVersion = self::CRAFT_STREAM_DIMENSION_FIX_VERSION[explode('.', $craftVersion)[0] ?? ''] ?? null; + $fixedVersion = $this->fixedCraftStreamDimensionVersion($craftVersion); if ($fixedVersion === null || version_compare($craftVersion, $fixedVersion, '>=')) { return; @@ -228,4 +211,12 @@ protected function repairAssetObjectMetadata(Asset $asset): void $fs->replaceMetadata($path, $config); } + + private function fixedCraftStreamDimensionVersion(string $craftVersion): ?string + { + return [ + '4' => '4.18.4', + '5' => '5.10.9', + ][explode('.', $craftVersion)[0] ?? ''] ?? null; + } } diff --git a/src/cli/controllers/assets/RepairController.php b/src/cli/controllers/assets/RepairController.php index f6033c3..eafdf24 100644 --- a/src/cli/controllers/assets/RepairController.php +++ b/src/cli/controllers/assets/RepairController.php @@ -2,20 +2,13 @@ namespace craft\cloud\cli\controllers\assets; -use craft\cloud\cli\controllers\AssetsController; +use craft\console\Controller; -class RepairController extends AssetsController +class RepairController extends Controller { - public $defaultAction = 'missing'; - - public function createAction($id) - { - if (!in_array($id, ['missing', 'metadata'], true)) { - return null; - } + use AssetRepairTrait; - return parent::createAction($id); - } + public $defaultAction = 'missing'; public function actionMissing(): int { @@ -24,6 +17,6 @@ public function actionMissing(): int public function actionMetadata(): int { - return $this->actionRepairMetadata(); + return $this->repairAssetObjectMetadataForAssets(); } } diff --git a/src/cli/controllers/assets/ReplaceMetadataController.php b/src/cli/controllers/assets/ReplaceMetadataController.php new file mode 100644 index 0000000..8e793ea --- /dev/null +++ b/src/cli/controllers/assets/ReplaceMetadataController.php @@ -0,0 +1,21 @@ +stdout( + 'Deprecated: use `cloud/assets/repair/metadata` to repair object metadata instead.' . PHP_EOL, + Console::FG_YELLOW, + ); + + return $this->repairAssetObjectMetadataForAssets(); + } +} diff --git a/tests/unit/AssetsControllerTest.php b/tests/unit/AssetsControllerTest.php index d237770..775078f 100644 --- a/tests/unit/AssetsControllerTest.php +++ b/tests/unit/AssetsControllerTest.php @@ -4,11 +4,15 @@ use Codeception\Test\Unit; use Craft; +use craft\cloud\cli\controllers\assets\RepairController; +use craft\cloud\cli\controllers\assets\ReplaceMetadataController; use craft\cloud\controllers\AssetsController; use craft\cloud\fs\Fs; +use craft\console\Controller as ConsoleController; use craft\elements\Asset; use craft\models\Volume; use ReflectionMethod; +use yii\base\Module as BaseModule; use yii\web\BadRequestHttpException; class AssetsControllerTest extends Unit @@ -125,6 +129,36 @@ public function testUploadedImageDimensionsStopAfterBoundedRanges(): void $this->assertSame(0, $fs->streamReadCount); } + public function testCliAssetsRepairRoutesResolveThroughYiiModule(): void + { + $module = new BaseModule('cloud'); + $module->controllerNamespace = 'craft\\cloud\\cli\\controllers'; + + $this->assertCliRoute($module, 'assets/repair', RepairController::class, '', 'missing'); + $this->assertCliRoute($module, 'assets/repair/missing', RepairController::class, 'missing'); + $this->assertCliRoute($module, 'assets/repair/metadata', RepairController::class, 'metadata'); + $this->assertCliRoute($module, 'assets/replace-metadata', ReplaceMetadataController::class, '', 'index'); + } + + public function testCliAssetsCommandsDoNotExposeTopLevelOrUnreleasedRoutes(): void + { + $module = new BaseModule('cloud'); + $module->controllerNamespace = 'craft\\cloud\\cli\\controllers'; + + $this->assertFalse($module->createController('assets')); + $this->assertFalse($module->createController('assets/repair-metadata')); + } + + public function testCliAssetsCommandsExposeAssetFilters(): void + { + $repairController = new RepairController('assets/repair', Craft::$app); + $replaceMetadataController = new ReplaceMetadataController('assets/replace-metadata', Craft::$app); + + $this->assertCliAssetFilterOptions($repairController, 'missing'); + $this->assertCliAssetFilterOptions($repairController, 'metadata'); + $this->assertCliAssetFilterOptions($replaceMetadataController, 'index'); + } + private function invokeVolumeSubpath(Volume $volume): string { $controller = new AssetsController('cloud-assets', Craft::$app); @@ -133,6 +167,38 @@ private function invokeVolumeSubpath(Volume $volume): string return $method->invoke($controller, $volume); } + + /** + * @param class-string $controllerClass + */ + private function assertCliRoute( + BaseModule $module, + string $route, + string $controllerClass, + string $actionId, + ?string $effectiveActionId = null, + ): void { + $result = $module->createController($route); + + $this->assertIsArray($result); + + [$controller, $resolvedActionId] = $result; + $this->assertInstanceOf($controllerClass, $controller); + $this->assertSame($actionId, $resolvedActionId); + + $action = $controller->createAction($resolvedActionId); + + $this->assertNotNull($action); + $this->assertSame($effectiveActionId ?? $actionId, $action->id); + } + + private function assertCliAssetFilterOptions(ConsoleController $controller, string $actionId): void + { + $options = $controller->options($actionId); + + $this->assertContains('volume', $options); + $this->assertContains('assetId', $options); + } } class SizeTestAssetsController extends AssetsController