diff --git a/.gitignore b/.gitignore index 42359c5..768f5ae 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ /vendor/ /.idea/ /node_modules +webroot/modified diff --git a/composer.json b/composer.json index 27e915c..5668234 100644 --- a/composer.json +++ b/composer.json @@ -39,6 +39,7 @@ "@phpstan", "@psalm" ], + "test": "phpunit", "stan-setup": "cp composer.json composer.backup && composer require --dev phpstan/phpstan:~1.9.0 psalm/phar:~5.4.0 && mv composer.backup composer.json", "lowest-setup": "composer update --prefer-lowest --prefer-stable --prefer-dist --no-interaction && cp composer.json composer.backup && composer require --dev dereuromark/composer-prefer-lowest && mv composer.backup composer.json" }, diff --git a/phpunit.xml.dist b/phpunit.xml.dist new file mode 100644 index 0000000..3ba0949 --- /dev/null +++ b/phpunit.xml.dist @@ -0,0 +1,26 @@ + + + + + + + + + + tests/ + + + + + + + + + + + + + src/ + + + diff --git a/src/Model/Entity/Asset.php b/src/Model/Entity/Asset.php index 2d35c60..6f6517a 100644 --- a/src/Model/Entity/Asset.php +++ b/src/Model/Entity/Asset.php @@ -73,7 +73,15 @@ public function exists(): bool */ protected function _getAbsolutePath(): string { - return ROOT . DS . $this->directory . DS . $this->filename; + $relativeOrAbsolute = DS . ltrim($this->directory . DS . $this->filename, DS); + if (is_readable($relativeOrAbsolute)) { + return $relativeOrAbsolute; + } + $path = ROOT . $relativeOrAbsolute; + if (is_readable($path)) { + return $path; + } + throw new \Exception('Could not find image file.'); } /** diff --git a/src/Utilities/ImageAsset.php b/src/Utilities/ImageAsset.php index ed406aa..7865c25 100644 --- a/src/Utilities/ImageAsset.php +++ b/src/Utilities/ImageAsset.php @@ -3,7 +3,6 @@ namespace Assets\Utilities; -use App\View\AppView; use Assets\Error\FileNotFoundException; use Assets\Error\FilterNotFoundException; use Assets\Error\UnkownErrorException; @@ -11,11 +10,14 @@ use Cake\Core\Configure; use Cake\I18n\FrozenTime; use Cake\View\Helper\HtmlHelper; +use Cake\View\View; use Intervention\Image\Image; use Intervention\Image\ImageManager; +use InvalidArgumentException; use Nette\Utils\FileSystem; use Nette\Utils\Json; use Nette\Utils\Strings; +use SplFileInfo; /** * To be called through Assets::getImage() with MimeType image/* @@ -79,34 +81,38 @@ public function __construct(Asset $asset, int $quality = 90) * @param array $options - optional: * - title (string): for alt-parameter in html-output * - quality (int): for jpg compression - * @throws \Exception + * @throws \InvalidArgumentException when no file was found * @return \Assets\Utilities\ImageAsset */ public static function createFromPath(string $path, array $options = []) { - $absolute_path = null; - $img_dir = WWW_ROOT . Configure::read('App.imageBaseUrl'); + $absolute_path = false; if (file_exists($path)) { $absolute_path = $path; - } elseif (file_exists($img_dir . $path)) { - $absolute_path = $img_dir . $path; + } else { + $img_dir = WWW_ROOT . ltrim((string)Configure::read('App.imageBaseUrl'), DS); + if (file_exists($img_dir . $path)) { + $absolute_path = $img_dir . $path; + } } - if (!$absolute_path) { - throw new \Exception("Could not find image with path {$path}."); + if ($absolute_path === false || !is_readable($absolute_path)) { + throw new InvalidArgumentException("Could not find image with path {$path}."); } - $splFileInfo = new \SplFileInfo($absolute_path); - - $asset = new Asset(); - $asset->id = md5($path); - $asset->filename = $splFileInfo->getFilename(); - $asset->directory = ltrim(str_replace(ROOT, '', $splFileInfo->getPath()), DS); - $asset->mimetype = mime_content_type($absolute_path) ?: 'unknown'; - $asset->title = $options['title'] ?? null; - $asset->description = null; - $asset->modified = FrozenTime::createFromTimestamp($splFileInfo->getMTime()); - $asset->created = $asset->modified; + $splFileInfo = new SplFileInfo($absolute_path); + $fileMTime = FrozenTime::createFromTimestamp($splFileInfo->getMTime()); + + $asset = new Asset([ + 'id' => md5($path), + 'filename' => $splFileInfo->getFilename(), + 'directory' => ltrim(str_replace(ROOT, '', $splFileInfo->getPath()), DS), + 'mimetype' => mime_content_type($absolute_path) ?: 'unknown', + 'title' => $options['title'] ?? null, + 'description' => null, + 'modified' => $fileMTime, + 'created' => $fileMTime, + ]); $quality = $options['quality'] ?? 90; @@ -251,7 +257,7 @@ public function getPath(): string public function getHTML(array $params = []): string { $path = $this->getPath(); - $html = new HtmlHelper(new AppView()); + $html = new HtmlHelper(new View()); if (!$this->image) { $manager = $this->getImageManager(); @@ -313,7 +319,7 @@ private function getFilename(): string * @throws \Nette\Utils\JsonException * @throws \Assets\Error\FileNotFoundException */ - private function getRelativePath(?\SplFileInfo $file = null): string + private function getRelativePath(?SplFileInfo $file = null): string { if ($file) { return $this->outputDirectory . $file->getFilename(); @@ -377,12 +383,12 @@ private function getAssetIdentifier(): string * @return \SplFileInfo|null * @throws \Nette\Utils\JsonException */ - private function getFile(): ?\SplFileInfo + private function getFile(): ?SplFileInfo { $path = WWW_ROOT . ltrim($this->outputDirectory, DS) . $this->getFilename() . '.' . $this->format; if (file_exists($path)) { - return new \SplFileInfo($path); + return new SplFileInfo($path); } return null; diff --git a/tests/Utilities/ImageAssetTest.php b/tests/Utilities/ImageAssetTest.php new file mode 100644 index 0000000..7965d34 --- /dev/null +++ b/tests/Utilities/ImageAssetTest.php @@ -0,0 +1,66 @@ +toWebp()->scaleWidth(120)->getPath(); + static::assertFileExists($renderedPath); + $splFileInfo = new \SplFileInfo($renderedPath); + static::assertEquals('image/webp', mime_content_type($renderedPath)); + static::assertEquals(6178, $splFileInfo->getSize()); + + $renderedPathOfLargeJpg = WWW_ROOT . $image->toJpg()->scaleWidth(240)->getPath(); + static::assertFileExists($renderedPathOfLargeJpg); + $splFileInfoJpg = new \SplFileInfo($renderedPathOfLargeJpg); + static::assertEquals('image/jpeg', mime_content_type($renderedPathOfLargeJpg)); + static::assertEquals(22336, $splFileInfoJpg->getSize()); + } + + public function testHtmlCreation(): void + { + $path = static::DATA_IMAGES . 'cake.jpg'; + $image = ImageAsset::createFromPath($path); + static::assertInstanceOf(ImageAsset::class, $image); + + $html = $image + ->scaleWidth(230) + ->setCSS('some-css') + ->setLazyLoading(false) + ->getHTML([ + 'data-test' => 123, + ]); + + static::assertNotEmpty($html); + static::assertStringContainsString('width="230"', $html); + static::assertStringContainsString('class="some-css"', $html); + static::assertStringContainsString('data-test="123"', $html); + static::assertStringContainsString('loading="eager"', $html); + } +} diff --git a/tests/Utilities/cake.jpg b/tests/Utilities/cake.jpg new file mode 100644 index 0000000..a3800ce Binary files /dev/null and b/tests/Utilities/cake.jpg differ