root = sys_get_temp_dir() . '/thinkadmin-helper-test-' . bin2hex(random_bytes(6)); mkdir($this->root . '/vendor/composer', 0777, true); $this->createPluginPackage('demo', 'vendor/demo-plugin', 'plugin\demo\Service'); } protected function tearDown(): void { $this->removeTree($this->root); } public function testDiscoverWorkspacePackagesFindsLocalPluginComposer(): void { $command = new PublishCommand(); function_exists('test_reset_model_makers') && test_reset_model_makers(); $app = new App($this->root); RuntimeService::init($app); $command->setApp($app); $method = new \ReflectionMethod($command, 'discoverWorkspacePackages'); $method->setAccessible(true); $items = $method->invoke($command); $this->assertCount(1, $items); $this->assertSame('vendor/demo-plugin', $items[0]['name']); $this->assertSame(str_replace('\\', '/', $this->root . '/plugin/demo'), $items[0]['__path']); } public function testRunPublishesWorkspaceServicesAndMigrations(): void { $this->createPluginPackage( 'system', 'vendor/system-plugin', 'plugin\system\Service', [ '20241010000001_install_system20241010.php', '20241010000002_install_storage20241010.php', ] ); $this->createPluginPackage( 'worker', 'vendor/worker-plugin', 'plugin\worker\Service', '20241010000008_install_worker20241010.php' ); $command = $this->newCommand(); $code = $command->run(new Input([]), new Output('buffer')); $services = require $this->root . '/vendor/services.php'; $versions = require $this->root . '/vendor/versions.php'; $manifest = json_decode((string)file_get_contents($this->root . '/database/migrations/.published.json'), true); $resourceManifest = json_decode((string)file_get_contents($this->root . '/vendor/' . self::RESOURCE_MANIFEST), true); $this->assertSame(0, $code); $this->assertContains('plugin\demo\Service', $services); $this->assertContains('plugin\system\Service', $services); $this->assertContains('plugin\worker\Service', $services); $this->assertSame('System', $versions['vendor/system-plugin']['name']); $this->assertSame('plugin', $versions['vendor/system-plugin']['type']); $this->assertSame('plugin', $versions['vendor/worker-plugin']['type']); $this->assertArrayNotHasKey('vendor/storage-plugin', $versions); $this->assertFileExists($this->root . '/database/migrations/20241010000001_install_system20241010.php'); $this->assertFileExists($this->root . '/database/migrations/20241010000002_install_storage20241010.php'); $this->assertFileExists($this->root . '/database/migrations/20241010000008_install_worker20241010.php'); $this->assertSame( 'plugin/system/stc/database/20241010000001_install_system20241010.php', $manifest['20241010000001_install_system20241010.php']['source'] ); $this->assertSame( 'plugin/system/stc/database/20241010000002_install_storage20241010.php', $manifest['20241010000002_install_storage20241010.php']['source'] ); $this->assertSame([], $resourceManifest); } public function testWorkspaceComposerPublishRulesOverrideInstalledMetadata(): void { $manifestFile = $this->root . '/plugin/demo/composer.json'; $manifest = json_decode((string)file_get_contents($manifestFile), true, 512, JSON_THROW_ON_ERROR); $manifest['extra']['xadmin']['publish'] = [ 'copy' => [ 'stc/runtime/demo.txt' => 'runtime-publish/demo.txt', ], ]; file_put_contents($manifestFile, json_encode($manifest, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)); mkdir($this->root . '/plugin/demo/stc/runtime', 0777, true); file_put_contents($this->root . '/plugin/demo/stc/runtime/demo.txt', "workspace\n"); file_put_contents($this->root . '/vendor/composer/installed.json', json_encode([ 'packages' => [[ 'name' => 'vendor/demo-plugin', 'type' => 'think-admin-plugin', 'version' => '0.9.0', 'extra' => [ 'think' => ['services' => ['plugin\demo\Service']], 'xadmin' => [ 'app' => ['code' => 'demo', 'name' => 'Legacy Demo'], 'publish' => ['copy' => ['stc/legacy.txt' => 'legacy.txt']], ], ], ]], ], JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)); $command = $this->newCommand(); $code = $command->run(new Input([]), new Output('buffer')); $versions = require $this->root . '/vendor/versions.php'; $this->assertSame(0, $code); $this->assertFileExists($this->root . '/runtime-publish/demo.txt'); $this->assertSame("workspace\n", file_get_contents($this->root . '/runtime-publish/demo.txt')); $this->assertSame('Demo', $versions['vendor/demo-plugin']['name']); } public function testExplicitCopyRulesTakePrecedenceOverDefaultDirectories(): void { $manifestFile = $this->root . '/plugin/demo/composer.json'; $manifest = json_decode((string)file_get_contents($manifestFile), true, 512, JSON_THROW_ON_ERROR); $manifest['extra']['xadmin']['publish'] = [ 'copy' => [ 'stc/runtime/demo.txt' => 'runtime-publish/demo.txt', ], ]; file_put_contents($manifestFile, json_encode($manifest, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)); mkdir($this->root . '/plugin/demo/stc/runtime', 0777, true); file_put_contents($this->root . '/plugin/demo/stc/runtime/demo.txt', "runtime\n"); mkdir($this->root . '/plugin/demo/stc/config', 0777, true); file_put_contents($this->root . '/plugin/demo/stc/config/demo.php', " false];\n"); $command = $this->newCommand(); $code = $command->run(new Input([]), new Output('buffer')); $this->assertSame(0, $code); $this->assertFileExists($this->root . '/runtime-publish/demo.txt'); $this->assertFileDoesNotExist($this->root . '/config/demo.php'); } public function testPluginWithoutCopyRulesDoesNotPublishDefaultDirectories(): void { mkdir($this->root . '/plugin/demo/stc/config', 0777, true); file_put_contents($this->root . '/plugin/demo/stc/config/demo.php', " false];\n"); $command = $this->newCommand(); $code = $command->run(new Input([]), new Output('buffer')); $this->assertSame(0, $code); $this->assertFileDoesNotExist($this->root . '/config/demo.php'); } public function testStructuredExcludeRulesSkipMatchingDirectoryFiles(): void { $manifestFile = $this->root . '/plugin/demo/composer.json'; $manifest = json_decode((string)file_get_contents($manifestFile), true, 512, JSON_THROW_ON_ERROR); $manifest['extra']['xadmin']['publish'] = [ 'copy' => [[ 'from' => 'stc/public/static/theme', 'to' => 'public/static/theme', 'exclude' => ['*.less', '*.css.map', 'package.json'], ]], ]; file_put_contents($manifestFile, json_encode($manifest, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)); mkdir($this->root . '/plugin/demo/stc/public/static/theme/css', 0777, true); mkdir($this->root . '/plugin/demo/stc/public/static/theme/img', 0777, true); file_put_contents($this->root . '/plugin/demo/stc/public/static/theme/css/login.css', "body{}\n"); file_put_contents($this->root . '/plugin/demo/stc/public/static/theme/css/login.less', "@c:#fff;\n"); file_put_contents($this->root . '/plugin/demo/stc/public/static/theme/css/login.css.map', "{}\n"); file_put_contents($this->root . '/plugin/demo/stc/public/static/theme/css/package.json', "{\"name\":\"demo\"}\n"); file_put_contents($this->root . '/plugin/demo/stc/public/static/theme/img/demo.txt', "ok\n"); $command = $this->newCommand(); $code = $command->run(new Input([]), new Output('buffer')); $this->assertSame(0, $code); $this->assertFileExists($this->root . '/public/static/theme/css/login.css'); $this->assertFileDoesNotExist($this->root . '/public/static/theme/css/login.less'); $this->assertFileDoesNotExist($this->root . '/public/static/theme/css/login.css.map'); $this->assertFileDoesNotExist($this->root . '/public/static/theme/css/package.json'); $this->assertFileExists($this->root . '/public/static/theme/img/demo.txt'); } public function testKeyValueObjectRuleSupportsExcludeWithoutExplicitFrom(): void { $manifestFile = $this->root . '/plugin/demo/composer.json'; $manifest = json_decode((string)file_get_contents($manifestFile), true, 512, JSON_THROW_ON_ERROR); $manifest['extra']['xadmin']['publish'] = [ 'copy' => [ 'stc/public/static/theme' => [ 'to' => 'public/static/theme', 'exclude' => ['*.less', '*.css.map', 'package.json'], ], ], ]; file_put_contents($manifestFile, json_encode($manifest, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)); mkdir($this->root . '/plugin/demo/stc/public/static/theme/css', 0777, true); file_put_contents($this->root . '/plugin/demo/stc/public/static/theme/css/login.css', "body{}\n"); file_put_contents($this->root . '/plugin/demo/stc/public/static/theme/css/login.less', "@c:#fff;\n"); file_put_contents($this->root . '/plugin/demo/stc/public/static/theme/css/login.css.map', "{}\n"); file_put_contents($this->root . '/plugin/demo/stc/public/static/theme/css/package.json', "{\"name\":\"demo\"}\n"); $command = $this->newCommand(); $code = $command->run(new Input([]), new Output('buffer')); $this->assertSame(0, $code); $this->assertFileExists($this->root . '/public/static/theme/css/login.css'); $this->assertFileDoesNotExist($this->root . '/public/static/theme/css/login.less'); $this->assertFileDoesNotExist($this->root . '/public/static/theme/css/login.css.map'); $this->assertFileDoesNotExist($this->root . '/public/static/theme/css/package.json'); } public function testBangTargetForcesOverwriteWithoutGlobalForce(): void { $manifestFile = $this->root . '/plugin/demo/composer.json'; $manifest = json_decode((string)file_get_contents($manifestFile), true, 512, JSON_THROW_ON_ERROR); $manifest['extra']['xadmin']['publish'] = [ 'copy' => [ 'stc/runtime/demo.txt' => '!runtime-publish/demo.txt', ], ]; file_put_contents($manifestFile, json_encode($manifest, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)); mkdir($this->root . '/plugin/demo/stc/runtime', 0777, true); file_put_contents($this->root . '/plugin/demo/stc/runtime/demo.txt', "new\n"); is_dir($this->root . '/runtime-publish') || mkdir($this->root . '/runtime-publish', 0777, true); file_put_contents($this->root . '/runtime-publish/demo.txt', "old\n"); $command = $this->newCommand(); $code = $command->run(new Input([]), new Output('buffer')); $this->assertSame(0, $code); $this->assertSame("new\n", file_get_contents($this->root . '/runtime-publish/demo.txt')); } public function testStructuredForceFlagForcesOverwriteWithoutGlobalForce(): void { $manifestFile = $this->root . '/plugin/demo/composer.json'; $manifest = json_decode((string)file_get_contents($manifestFile), true, 512, JSON_THROW_ON_ERROR); $manifest['extra']['xadmin']['publish'] = [ 'copy' => [[ 'from' => 'stc/runtime/demo.txt', 'to' => 'runtime-publish/demo.txt', 'force' => true, ]], ]; file_put_contents($manifestFile, json_encode($manifest, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)); mkdir($this->root . '/plugin/demo/stc/runtime', 0777, true); file_put_contents($this->root . '/plugin/demo/stc/runtime/demo.txt', "new\n"); is_dir($this->root . '/runtime-publish') || mkdir($this->root . '/runtime-publish', 0777, true); file_put_contents($this->root . '/runtime-publish/demo.txt', "old\n"); $command = $this->newCommand(); $code = $command->run(new Input([]), new Output('buffer')); $this->assertSame(0, $code); $this->assertSame("new\n", file_get_contents($this->root . '/runtime-publish/demo.txt')); } public function testPublishedResourcesAreTrackedAndUpdatedOnSourceChange(): void { $manifestFile = $this->root . '/plugin/demo/composer.json'; $manifest = json_decode((string)file_get_contents($manifestFile), true, 512, JSON_THROW_ON_ERROR); $manifest['extra']['xadmin']['publish'] = [ 'copy' => [ 'stc/runtime/demo.txt' => 'runtime-publish/demo.txt', ], ]; file_put_contents($manifestFile, json_encode($manifest, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)); mkdir($this->root . '/plugin/demo/stc/runtime', 0777, true); file_put_contents($this->root . '/plugin/demo/stc/runtime/demo.txt', "first\n"); $command = $this->newCommand(); $this->assertSame(0, $command->run(new Input([]), new Output('buffer'))); $this->assertSame("first\n", file_get_contents($this->root . '/runtime-publish/demo.txt')); file_put_contents($this->root . '/plugin/demo/stc/runtime/demo.txt', "second\n"); $command = $this->newCommand(); $this->assertSame(0, $command->run(new Input([]), new Output('buffer'))); $this->assertSame("second\n", file_get_contents($this->root . '/runtime-publish/demo.txt')); $resourceManifest = json_decode((string)file_get_contents($this->root . '/vendor/' . self::RESOURCE_MANIFEST), true, 512, JSON_THROW_ON_ERROR); $this->assertSame('vendor/demo-plugin', $resourceManifest['runtime-publish/demo.txt']['package']); $this->assertSame( 'plugin/demo/stc/runtime/demo.txt', $resourceManifest['runtime-publish/demo.txt']['source'] ); $this->assertSame( sha1_file($this->root . '/runtime-publish/demo.txt'), $resourceManifest['runtime-publish/demo.txt']['sha1'] ); } public function testIgnoreFilePreventsPublishedResourceOverwrite(): void { $manifestFile = $this->root . '/plugin/demo/composer.json'; $manifest = json_decode((string)file_get_contents($manifestFile), true, 512, JSON_THROW_ON_ERROR); $manifest['extra']['xadmin']['publish'] = [ 'copy' => [ 'stc/runtime/demo.txt' => 'runtime-publish/demo.txt', ], ]; file_put_contents($manifestFile, json_encode($manifest, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)); mkdir($this->root . '/plugin/demo/stc/runtime', 0777, true); file_put_contents($this->root . '/plugin/demo/stc/runtime/demo.txt', "first\n"); $command = $this->newCommand(); $this->assertSame(0, $command->run(new Input([]), new Output('buffer'))); is_dir($this->root . '/runtime-publish') || mkdir($this->root . '/runtime-publish', 0777, true); file_put_contents($this->root . '/runtime-publish/ignore', ''); file_put_contents($this->root . '/plugin/demo/stc/runtime/demo.txt', "second\n"); $command = $this->newCommand(); $this->assertSame(0, $command->run(new Input([]), new Output('buffer'))); $this->assertSame("first\n", file_get_contents($this->root . '/runtime-publish/demo.txt')); $resourceManifest = json_decode((string)file_get_contents($this->root . '/vendor/' . self::RESOURCE_MANIFEST), true, 512, JSON_THROW_ON_ERROR); $this->assertSame( sha1("first\n"), $resourceManifest['runtime-publish/demo.txt']['sha1'] ); } public function testRemovedPluginDeletesUnchangedPublishedResources(): void { $this->createPluginPackage('publish-demo', 'vendor/publish-demo', 'plugin\publishdemo\Service', null, [ 'stc/runtime/demo.txt' => 'runtime-publish/demo.txt', ]); mkdir($this->root . '/plugin/publish-demo/stc/runtime', 0777, true); file_put_contents($this->root . '/plugin/publish-demo/stc/runtime/demo.txt', "demo\n"); $command = $this->newCommand(); $this->assertSame(0, $command->run(new Input([]), new Output('buffer'))); $this->assertFileExists($this->root . '/runtime-publish/demo.txt'); $this->removeTree($this->root . '/plugin/publish-demo'); $command = $this->newCommand(); $this->assertSame(0, $command->run(new Input([]), new Output('buffer'))); $this->assertFileDoesNotExist($this->root . '/runtime-publish/demo.txt'); $resourceManifest = json_decode((string)file_get_contents($this->root . '/vendor/' . self::RESOURCE_MANIFEST), true, 512, JSON_THROW_ON_ERROR); $this->assertArrayNotHasKey('runtime-publish/demo.txt', $resourceManifest); } public function testRemovedPluginPreservesChangedPublishedResources(): void { $this->createPluginPackage('publish-demo', 'vendor/publish-demo', 'plugin\publishdemo\Service', null, [ 'stc/runtime/demo.txt' => 'runtime-publish/demo.txt', ]); mkdir($this->root . '/plugin/publish-demo/stc/runtime', 0777, true); file_put_contents($this->root . '/plugin/publish-demo/stc/runtime/demo.txt', "demo\n"); $command = $this->newCommand(); $this->assertSame(0, $command->run(new Input([]), new Output('buffer'))); file_put_contents($this->root . '/runtime-publish/demo.txt', "local-change\n"); $this->removeTree($this->root . '/plugin/publish-demo'); $command = $this->newCommand(); $this->assertSame(0, $command->run(new Input([]), new Output('buffer'))); $this->assertSame("local-change\n", file_get_contents($this->root . '/runtime-publish/demo.txt')); $resourceManifest = json_decode((string)file_get_contents($this->root . '/vendor/' . self::RESOURCE_MANIFEST), true, 512, JSON_THROW_ON_ERROR); $this->assertArrayHasKey('runtime-publish/demo.txt', $resourceManifest); } public function testRuleShrinkRemovesPreviouslyPublishedExcludedFile(): void { $manifestFile = $this->root . '/plugin/demo/composer.json'; $manifest = json_decode((string)file_get_contents($manifestFile), true, 512, JSON_THROW_ON_ERROR); $manifest['extra']['xadmin']['publish'] = [ 'copy' => [ 'stc/public/static/theme' => 'public/static/theme', ], ]; file_put_contents($manifestFile, json_encode($manifest, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)); mkdir($this->root . '/plugin/demo/stc/public/static/theme/css', 0777, true); file_put_contents($this->root . '/plugin/demo/stc/public/static/theme/css/login.css', "body{}\n"); file_put_contents($this->root . '/plugin/demo/stc/public/static/theme/css/login.less', "@c:#fff;\n"); $command = $this->newCommand(); $this->assertSame(0, $command->run(new Input([]), new Output('buffer'))); $this->assertFileExists($this->root . '/public/static/theme/css/login.less'); $manifest = json_decode((string)file_get_contents($manifestFile), true, 512, JSON_THROW_ON_ERROR); $manifest['extra']['xadmin']['publish'] = [ 'copy' => [ 'stc/public/static/theme' => [ 'to' => 'public/static/theme', 'exclude' => ['*.less'], ], ], ]; file_put_contents($manifestFile, json_encode($manifest, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)); $command = $this->newCommand(); $this->assertSame(0, $command->run(new Input([]), new Output('buffer'))); $this->assertFileDoesNotExist($this->root . '/public/static/theme/css/login.less'); $this->assertFileExists($this->root . '/public/static/theme/css/login.css'); $resourceManifest = json_decode((string)file_get_contents($this->root . '/vendor/' . self::RESOURCE_MANIFEST), true, 512, JSON_THROW_ON_ERROR); $this->assertArrayNotHasKey('public/static/theme/css/login.less', $resourceManifest); $this->assertArrayHasKey('public/static/theme/css/login.css', $resourceManifest); } public function testSyncMigrationsRemovesStalePublishedFiles(): void { $this->createPluginPackage( 'system', 'vendor/system-plugin', 'plugin\system\Service', '20241010000001_install_system20241010.php' ); $targetDir = $this->root . '/database/migrations'; mkdir($targetDir, 0777, true); file_put_contents($targetDir . '/20241010000002_install_storage20241010.php', " [ 'source' => 'plugin/system/stc/database/20241010000002_install_storage20241010.php', 'mtime' => 1, ], '20241010000001_install_system20241010.php' => [ 'source' => 'plugin/system/stc/database/20241010000001_install_system20241010.php', 'mtime' => 1, ], ], JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)); $command = $this->newCommand(); $this->invokeSyncMigrations($command, [ '20241010000001_install_system20241010.php' => $this->root . '/plugin/system/stc/database/20241010000001_install_system20241010.php', ]); $manifest = json_decode((string)file_get_contents($targetDir . '/' . self::MIGRATION_MANIFEST), true); $this->assertFileDoesNotExist($targetDir . '/20241010000002_install_storage20241010.php'); $this->assertFileExists($targetDir . '/20241010000001_install_system20241010.php'); $this->assertArrayNotHasKey('20241010000002_install_storage20241010.php', $manifest); $this->assertArrayHasKey('20241010000001_install_system20241010.php', $manifest); } public function testSyncMigrationsRejectsDuplicateVersions(): void { $this->createPluginPackage('system-a', 'vendor/system-a', 'plugin\systema\Service', '20241010000011_install_system_a.php'); $this->createPluginPackage('system-b', 'vendor/system-b', 'plugin\systemb\Service', '20241010000011_install_system_b.php'); $command = $this->newCommand(); $this->expectException(\RuntimeException::class); $this->expectExceptionMessage( 'Duplicate migration version [20241010000011] between [20241010000011_install_system_a.php] and [20241010000011_install_system_b.php]' ); $this->invokeSyncMigrations($command, [ '20241010000011_install_system_a.php' => $this->root . '/plugin/system-a/stc/database/20241010000011_install_system_a.php', '20241010000011_install_system_b.php' => $this->root . '/plugin/system-b/stc/database/20241010000011_install_system_b.php', ]); } public function testSyncMigrationsRemovesConflictingLegacyVersionFile(): void { $this->createPluginPackage( 'system', 'vendor/system-plugin', 'plugin\system\Service', '20241010000001_install_system20241010.php' ); $targetDir = $this->root . '/database/migrations'; mkdir($targetDir, 0777, true); file_put_contents($targetDir . '/20241010000001_install_legacy_system.php', "newCommand(); $this->invokeSyncMigrations($command, [ '20241010000001_install_system20241010.php' => $this->root . '/plugin/system/stc/database/20241010000001_install_system20241010.php', ]); $manifest = json_decode((string)file_get_contents($targetDir . '/' . self::MIGRATION_MANIFEST), true); $this->assertFileDoesNotExist($targetDir . '/20241010000001_install_legacy_system.php'); $this->assertFileExists($targetDir . '/20241010000001_install_system20241010.php'); $this->assertSame( 'plugin/system/stc/database/20241010000001_install_system20241010.php', $manifest['20241010000001_install_system20241010.php']['source'] ); } public function testSyncMigrationsPreservesUnmanagedRootMigrationFile(): void { $this->createPluginPackage( 'system', 'vendor/system-plugin', 'plugin\system\Service', '20241010000001_install_system20241010.php' ); $targetDir = $this->root . '/database/migrations'; mkdir($targetDir, 0777, true); file_put_contents($targetDir . '/20241010000099_project_custom.php', "newCommand(); $this->invokeSyncMigrations($command, [ '20241010000001_install_system20241010.php' => $this->root . '/plugin/system/stc/database/20241010000001_install_system20241010.php', ]); $manifest = json_decode((string)file_get_contents($targetDir . '/' . self::MIGRATION_MANIFEST), true); $this->assertFileExists($targetDir . '/20241010000099_project_custom.php'); $this->assertFileExists($targetDir . '/20241010000001_install_system20241010.php'); $this->assertArrayHasKey('20241010000001_install_system20241010.php', $manifest); $this->assertArrayNotHasKey('20241010000099_project_custom.php', $manifest); } /** * @param null|string|list $migration */ private function createPluginPackage(string $code, string $name, string $service, null|string|array $migration = null, array $publish = []): void { $path = "{$this->root}/plugin/{$code}"; mkdir($path, 0777, true); $extra = [ 'think' => ['services' => [$service]], 'xadmin' => ['app' => ['code' => $code, 'name' => ucfirst($code)]], ]; if ($publish !== []) { $extra['xadmin']['publish'] = ['copy' => $publish]; } file_put_contents($path . '/composer.json', json_encode([ 'name' => $name, 'type' => 'think-admin-plugin', 'version' => '1.0.0', 'description' => ucfirst($code), 'extra' => $extra, ], JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)); if ($migration) { mkdir($path . '/stc/database', 0777, true); foreach ((array)$migration as $filename) { file_put_contents($path . '/stc/database/' . $filename, "root); RuntimeService::init($app); $app->config->set([ 'default' => 'file', 'stores' => [ 'file' => ['type' => 'File', 'path' => $this->root . '/runtime/cache'], ], ], 'cache'); $command->setApp($app); return $command; } /** * @param array $sources */ private function invokeSyncMigrations(PublishCommand $command, array $sources, bool $force = false): void { $property = new \ReflectionProperty(Command::class, 'output'); $property->setAccessible(true); $property->setValue($command, new Output('buffer')); $method = new \ReflectionMethod($command, 'syncMigrations'); $method->setAccessible(true); $method->invoke($command, $sources, $force); } private function removeTree(string $path): void { if (!is_dir($path)) { return; } $items = new \RecursiveIteratorIterator( new \RecursiveDirectoryIterator($path, \FilesystemIterator::SKIP_DOTS), \RecursiveIteratorIterator::CHILD_FIRST ); foreach ($items as $item) { $item->isDir() ? rmdir($item->getPathname()) : unlink($item->getPathname()); } rmdir($path); } }