diff --git a/src/Commands/Themes/DownloadStyleCommand.php b/src/Commands/Themes/DownloadStyleCommand.php index 50a51f6..f26b84f 100644 --- a/src/Commands/Themes/DownloadStyleCommand.php +++ b/src/Commands/Themes/DownloadStyleCommand.php @@ -28,7 +28,7 @@ public function handle(): void { $this->theme = \Juzaweb\Modules\Core\Facades\Theme::find($this->argument('theme')); if ($this->theme === null) { - $this->error('Theme not found!'); + $this->error("Theme {$this->argument('theme')} not found!"); return; } @@ -47,7 +47,7 @@ public function handle(): void protected function generateMixFile(array $css, array $js): void { - $mixOutput = 'themes/' . $this->theme->studlyName() . '/assets'; + $mixOutput = 'themes/' . $this->theme->name() . '/assets'; $cssList = array_map( fn($item) => "basePath + '/css/" . basename(trim($item, "'")) . "'", @@ -119,15 +119,16 @@ protected function downloadCss(HtmlDom $domp): array $path = "{$output}/css/{$name}"; try { - $this->downloadFile($href, base_path($path)); - File::put(base_path($path), $this->replaceContentCss(File::get(base_path($path)))); + $content = $this->getFileContent($href); + $content = $this->replaceContentCss($content); + File::put(base_path($path), $content); $result[] = "'{$path}'"; - $this->downloadAssetsFromCss([$path], $href); + $this->downloadAssetsFromCssWithContent($content, $href); $this->info("-- Downloaded file {$path}"); - } catch (\Exception $e) { + } catch (\Throwable $e) { $this->warn("Failed to download file: {$href}"); } } @@ -159,10 +160,11 @@ protected function downloadJs(HtmlDom $domp): array $path = "{$output}/js/{$name}"; try { - $this->downloadFile($href, base_path($path)); + $content = $this->getFileContent($href); + File::put(base_path($path), $content); $result[] = "'{$path}'"; $this->info("-- Downloaded file {$path}"); - } catch (\Exception $e) { + } catch (\Throwable $e) { $this->warn("Download error: {$href}"); } } @@ -170,9 +172,45 @@ protected function downloadJs(HtmlDom $domp): array return $result; } - protected function downloadAssetsFromCss(array $cssFiles, string $cssUrl): void + protected function downloadAssetsFromCssWithContent(string $content, string $cssUrl): void { $output = "themes/{$this->theme->name()}/assets"; + preg_match_all('/url\([\'"]?(.*?)[\'"]?\)/i', $content, $matches); + + foreach ($matches[1] as $assetUrl) { + $assetUrl = trim($assetUrl, "\"'"); + if (is_url($assetUrl) && $this->isExcludeDomain($assetUrl)) { + $this->warn("Skip {$assetUrl}"); + continue; + } + + if (str_starts_with($assetUrl, 'data:')) { + continue; + } + + $parsedUrl = get_full_url($assetUrl, $cssUrl); + if ($this->isExcludeDomain($parsedUrl)) { + continue; + } + + $urlPath = parse_url($assetUrl, PHP_URL_PATH); + if (! $urlPath) { + continue; + } + + $savePath = $output . abs_path($urlPath); + + try { + $this->downloadFile($parsedUrl, base_path($savePath)); + $this->info("-- Downloaded asset {$savePath}"); + } catch (\Throwable $e) { + $this->warn("Failed to download asset: {$parsedUrl}"); + } + } + } + + protected function downloadAssetsFromCss(array $cssFiles, string $cssUrl): void + { foreach ($cssFiles as $cssPath) { $fullPath = base_path(trim($cssPath, "'")); @@ -182,38 +220,7 @@ protected function downloadAssetsFromCss(array $cssFiles, string $cssUrl): void } $content = File::get($fullPath); - preg_match_all('/url\(["\']?(.*?)["\']?\)/i', $content, $matches); - - foreach ($matches[1] as $assetUrl) { - if (is_url($assetUrl) && $this->isExcludeDomain($assetUrl)) { - $this->warn("Skip {$assetUrl}"); - continue; - } - - if (Str::start($assetUrl, 'data:')) { - continue; - } - - $parsedUrl = get_full_url($assetUrl, $cssUrl); - if ($this->isExcludeDomain($parsedUrl)) { - continue; - } - - $urlPath = parse_url($assetUrl, PHP_URL_PATH); - if (! $urlPath) { - continue; - } - - $relativePath = ltrim($urlPath, '/'); - $savePath = $output . abs_path($relativePath); - - try { - $this->downloadFile($parsedUrl, base_path($savePath)); - $this->info("-- Downloaded asset {$savePath}"); - } catch (\Exception $e) { - $this->warn("Failed to download asset: {$parsedUrl}"); - } - } + $this->downloadAssetsFromCssWithContent($content, $cssUrl); } } diff --git a/tests/Unit/DownloadStyleCommandTest.php b/tests/Unit/DownloadStyleCommandTest.php new file mode 100644 index 0000000..6f22211 --- /dev/null +++ b/tests/Unit/DownloadStyleCommandTest.php @@ -0,0 +1,76 @@ +app['config']->set('themes.path', base_path('themes')); + $stubsPath = dirname(__DIR__, 2) . '/stubs/themes'; + $this->app['config']->set('dev-tool.themes.stubs.path', $stubsPath); + + if (File::isDirectory(base_path('themes'))) { + File::deleteDirectory(base_path('themes')); + } + + $this->artisan('theme:make', ['name' => 'test-theme', '--force' => true]); + + $this->app->forgetInstance(\Juzaweb\Modules\Core\Contracts\Theme::class); + Theme::clearResolvedInstance(\Juzaweb\Modules\Core\Contracts\Theme::class); + } + + protected function tearDown(): void + { + if (File::isDirectory(base_path('themes'))) { + File::deleteDirectory(base_path('themes')); + } + parent::tearDown(); + } + + public function test_download_style() + { + $mock = new MockHandler([ + new Response(200, [], '
'), + new Response(200, [], 'body { background: url("logo.png"); }'), + new Response(200, [], 'binary-data-of-logo'), + ]); + + $handlerStack = HandlerStack::create($mock); + $client = new Client(['handler' => $handlerStack]); + + $command = $this->getMockBuilder(\Juzaweb\DevTool\Commands\Themes\DownloadStyleCommand::class) + ->setConstructorArgs([$client]) + ->onlyMethods(['ask']) + ->getMock(); + + $command->method('ask')->willReturn('http://example.com'); + $command->setLaravel($this->app); + + $input = new \Symfony\Component\Console\Input\ArrayInput([ + 'theme' => 'test-theme', + ]); + $output = new \Symfony\Component\Console\Output\BufferedOutput(); + + // Create necessary directory for generateMixFile + $mixDir = base_path('themes/test-theme/assets'); + if (!File::isDirectory($mixDir)) { + File::makeDirectory($mixDir, 0755, true); + } + + $command->run($input, $output); + + $this->assertFileExists(base_path('themes/test-theme/assets/css/style.css')); + $this->assertFileExists(base_path('themes/test-theme/assets/logo.png')); + } +}