1
0
mirror of https://github.com/Intervention/image.git synced 2025-08-26 15:24:37 +02:00

Merge branch 'develop' into next

This commit is contained in:
Oliver Vogel
2025-07-30 15:14:22 +02:00
5 changed files with 144 additions and 11 deletions

View File

@@ -81,13 +81,21 @@ abstract class AbstractDriver implements DriverInterface
}
// resolve classname for specializable object
$driver_namespace = (new ReflectionClass($this))->getNamespaceName();
$object_path = substr($object::class, strlen("Intervention\\Image\\"));
$specialized_classname = $driver_namespace . "\\" . $object_path;
$specialized_classname = implode("\\", [
(new ReflectionClass($this))->getNamespaceName(), // driver's namespace
match (true) {
$object instanceof ModifierInterface => 'Modifiers',
$object instanceof AnalyzerInterface => 'Analyzers',
$object instanceof EncoderInterface => 'Encoders',
$object instanceof DecoderInterface => 'Decoders',
},
$object_shortname = (new ReflectionClass($object))->getShortName(),
]);
// fail if driver specialized classname does not exists
if (!class_exists($specialized_classname)) {
throw new NotSupportedException(
"Class '" . $object_path . "' is not supported by " . $this->id() . " driver."
"Class '" . $object_shortname . "' is not supported by " . $this->id() . " driver."
);
}

View File

@@ -26,7 +26,7 @@ interface DriverInterface
public function config(): Config;
/**
* Resolve given object into a specialized version for the current driver
* Resolve given (generic) object into a specialized version for the current driver
*
* @throws NotSupportedException
* @throws DriverException

View File

@@ -64,15 +64,14 @@ trait CanBeDriverSpecialized
}
/**
* Determine if the given object belongs to the driver's namespace
* Determine if the current object belongs to the given driver's namespace
*/
protected function belongsToDriver(object $object): bool
protected function belongsToDriver(object $driver): bool
{
$driverId = function (object $object): string|bool {
$id = substr($object::class, 27);
return strstr($id, "\\", true);
$namespace = function (object $object): string {
return (new ReflectionClass($object))->getNamespaceName();
};
return $driverId($this) === $driverId($object);
return str_starts_with($namespace($this), $namespace($driver));
}
}

View File

@@ -5,15 +5,27 @@ declare(strict_types=1);
namespace Intervention\Image\Tests\Unit\Drivers\Gd;
use Generator;
use Intervention\Image\Analyzers\WidthAnalyzer as GenericWidthAnalyzer;
use Intervention\Image\Colors\Rgb\Colorspace;
use Intervention\Image\Colors\Rgb\Decoders\HexColorDecoder;
use Intervention\Image\Decoders\FilePathImageDecoder as GenericFilePathImageDecoder;
use Intervention\Image\Drivers\Gd\Analyzers\WidthAnalyzer;
use Intervention\Image\Drivers\Gd\Decoders\FilePathImageDecoder;
use Intervention\Image\Drivers\Gd\Driver;
use Intervention\Image\Drivers\Gd\Encoders\PngEncoder;
use Intervention\Image\Drivers\Gd\Modifiers\ResizeModifier;
use Intervention\Image\Encoders\PngEncoder as GenericPngEncoder;
use Intervention\Image\Exceptions\NotSupportedException;
use Intervention\Image\FileExtension;
use Intervention\Image\Format;
use Intervention\Image\Interfaces\AnalyzerInterface;
use Intervention\Image\Interfaces\ColorInterface;
use Intervention\Image\Interfaces\ColorProcessorInterface;
use Intervention\Image\Interfaces\DriverInterface;
use Intervention\Image\Interfaces\ImageInterface;
use Intervention\Image\Interfaces\SpecializableInterface;
use Intervention\Image\MediaType;
use Intervention\Image\Modifiers\ResizeModifier as GenericResizeModifier;
use Intervention\Image\Tests\BaseTestCase;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\DataProvider;
@@ -211,4 +223,55 @@ final class DriverTest extends BaseTestCase
{
$this->assertTrue(is_string($this->driver->version()));
}
#[DataProvider('spezializeDataProvider')]
public function testSpecialize(string $inputClassname, string $outputClassname): void
{
$this->assertInstanceOf($outputClassname, $this->driver->specialize(new $inputClassname()));
}
public static function spezializeDataProvider(): Generator
{
// specializing possible
yield [GenericResizeModifier::class, ResizeModifier::class];
yield [GenericWidthAnalyzer::class, WidthAnalyzer::class];
yield [GenericPngEncoder::class, PngEncoder::class];
yield [GenericFilePathImageDecoder::class, FilePathImageDecoder::class];
// already specialized
yield [ResizeModifier::class, ResizeModifier::class];
yield [WidthAnalyzer::class, WidthAnalyzer::class];
yield [PngEncoder::class, PngEncoder::class];
yield [FilePathImageDecoder::class, FilePathImageDecoder::class];
}
public function testSpecializeFailure(): void
{
$this->expectException(NotSupportedException::class);
$this->driver->specialize(new class () implements AnalyzerInterface, SpecializableInterface
{
protected DriverInterface $driver;
public function analyze(ImageInterface $image): mixed
{
return true;
}
/** @return array<string, mixed> **/
public function specializable(): array
{
return [];
}
public function setDriver(DriverInterface $driver): SpecializableInterface
{
return $this;
}
public function driver(): DriverInterface
{
return $this->driver;
}
});
}
}

View File

@@ -5,14 +5,26 @@ declare(strict_types=1);
namespace Intervention\Image\Tests\Unit\Drivers\Imagick;
use Generator;
use Intervention\Image\Analyzers\WidthAnalyzer as GenericWidthAnalyzer;
use Intervention\Image\Decoders\FilePathImageDecoder as GenericFilePathImageDecoder;
use Intervention\Image\Encoders\PngEncoder as GenericPngEncoder;
use Intervention\Image\Modifiers\ResizeModifier as GenericResizeModifier;
use Intervention\Image\Colors\Rgb\Colorspace;
use Intervention\Image\Colors\Rgb\Decoders\HexColorDecoder;
use Intervention\Image\Drivers\Imagick\Analyzers\WidthAnalyzer;
use Intervention\Image\Drivers\Imagick\Decoders\FilePathImageDecoder;
use Intervention\Image\Drivers\Imagick\Driver;
use Intervention\Image\Drivers\Imagick\Encoders\PngEncoder;
use Intervention\Image\Drivers\Imagick\Modifiers\ResizeModifier;
use Intervention\Image\Exceptions\NotSupportedException;
use Intervention\Image\FileExtension;
use Intervention\Image\Format;
use Intervention\Image\Interfaces\AnalyzerInterface;
use Intervention\Image\Interfaces\ColorInterface;
use Intervention\Image\Interfaces\ColorProcessorInterface;
use Intervention\Image\Interfaces\DriverInterface;
use Intervention\Image\Interfaces\ImageInterface;
use Intervention\Image\Interfaces\SpecializableInterface;
use Intervention\Image\MediaType;
use Intervention\Image\Tests\BaseTestCase;
use PHPUnit\Framework\Attributes\CoversClass;
@@ -211,4 +223,55 @@ final class DriverTest extends BaseTestCase
{
$this->assertTrue(is_string($this->driver->version()));
}
#[DataProvider('spezializeDataProvider')]
public function testSpecialize(string $inputClassname, string $outputClassname): void
{
$this->assertInstanceOf($outputClassname, $this->driver->specialize(new $inputClassname()));
}
public static function spezializeDataProvider(): Generator
{
// specializing possible
yield [GenericResizeModifier::class, ResizeModifier::class];
yield [GenericWidthAnalyzer::class, WidthAnalyzer::class];
yield [GenericPngEncoder::class, PngEncoder::class];
yield [GenericFilePathImageDecoder::class, FilePathImageDecoder::class];
// already specialized
yield [ResizeModifier::class, ResizeModifier::class];
yield [WidthAnalyzer::class, WidthAnalyzer::class];
yield [PngEncoder::class, PngEncoder::class];
yield [FilePathImageDecoder::class, FilePathImageDecoder::class];
}
public function testSpecializeFailure(): void
{
$this->expectException(NotSupportedException::class);
$this->driver->specialize(new class () implements AnalyzerInterface, SpecializableInterface
{
protected DriverInterface $driver;
public function analyze(ImageInterface $image): mixed
{
return true;
}
/** @return array<string, mixed> **/
public function specializable(): array
{
return [];
}
public function setDriver(DriverInterface $driver): SpecializableInterface
{
return $this;
}
public function driver(): DriverInterface
{
return $this->driver;
}
});
}
}