diff --git a/apps/files_sharing/tests/Controller/ShareControllerTest.php b/apps/files_sharing/tests/Controller/ShareControllerTest.php index 32fd0f09637b9..28d2622667304 100644 --- a/apps/files_sharing/tests/Controller/ShareControllerTest.php +++ b/apps/files_sharing/tests/Controller/ShareControllerTest.php @@ -384,6 +384,7 @@ public function testShowFileDropShare(): void { $file->method('isReadable')->willReturn(true); $file->method('isShareable')->willReturn(true); $file->method('getId')->willReturn(1234); + $file->method('getMimetype')->willReturn('text/plain'); $file->method('getName')->willReturn($filename); $accountName = $this->createMock(IAccountProperty::class); diff --git a/build/psalm-baseline.xml b/build/psalm-baseline.xml index 422d886658ad4..7d0d0c4eabe0e 100644 --- a/build/psalm-baseline.xml +++ b/build/psalm-baseline.xml @@ -4119,14 +4119,6 @@ - - - - - - - - diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php index add490d2b0681..d1cb05b1b3f12 100644 --- a/lib/composer/composer/autoload_classmap.php +++ b/lib/composer/composer/autoload_classmap.php @@ -720,7 +720,6 @@ 'OCP\\PreConditionNotMetException' => $baseDir . '/lib/public/PreConditionNotMetException.php', 'OCP\\Preview\\BeforePreviewFetchedEvent' => $baseDir . '/lib/public/Preview/BeforePreviewFetchedEvent.php', 'OCP\\Preview\\IMimeIconProvider' => $baseDir . '/lib/public/Preview/IMimeIconProvider.php', - 'OCP\\Preview\\IProvider' => $baseDir . '/lib/public/Preview/IProvider.php', 'OCP\\Preview\\IProviderV2' => $baseDir . '/lib/public/Preview/IProviderV2.php', 'OCP\\Preview\\IVersionedPreviewFile' => $baseDir . '/lib/public/Preview/IVersionedPreviewFile.php', 'OCP\\Profile\\BeforeTemplateRenderedEvent' => $baseDir . '/lib/public/Profile/BeforeTemplateRenderedEvent.php', @@ -1907,8 +1906,6 @@ 'OC\\Preview\\Photoshop' => $baseDir . '/lib/private/Preview/Photoshop.php', 'OC\\Preview\\Postscript' => $baseDir . '/lib/private/Preview/Postscript.php', 'OC\\Preview\\PreviewService' => $baseDir . '/lib/private/Preview/PreviewService.php', - 'OC\\Preview\\Provider' => $baseDir . '/lib/private/Preview/Provider.php', - 'OC\\Preview\\ProviderV1Adapter' => $baseDir . '/lib/private/Preview/ProviderV1Adapter.php', 'OC\\Preview\\ProviderV2' => $baseDir . '/lib/private/Preview/ProviderV2.php', 'OC\\Preview\\SGI' => $baseDir . '/lib/private/Preview/SGI.php', 'OC\\Preview\\SVG' => $baseDir . '/lib/private/Preview/SVG.php', diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php index 6c6507f8b22a0..d1a85530aca2a 100644 --- a/lib/composer/composer/autoload_static.php +++ b/lib/composer/composer/autoload_static.php @@ -11,32 +11,32 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 ); public static $prefixLengthsPsr4 = array ( - 'O' => + 'O' => array ( 'OC\\Core\\' => 8, 'OC\\' => 3, 'OCP\\' => 4, ), - 'N' => + 'N' => array ( 'NCU\\' => 4, ), ); public static $prefixDirsPsr4 = array ( - 'OC\\Core\\' => + 'OC\\Core\\' => array ( 0 => __DIR__ . '/../../..' . '/core', ), - 'OC\\' => + 'OC\\' => array ( 0 => __DIR__ . '/../../..' . '/lib/private', ), - 'OCP\\' => + 'OCP\\' => array ( 0 => __DIR__ . '/../../..' . '/lib/public', ), - 'NCU\\' => + 'NCU\\' => array ( 0 => __DIR__ . '/../../..' . '/lib/unstable', ), @@ -761,7 +761,6 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OCP\\PreConditionNotMetException' => __DIR__ . '/../../..' . '/lib/public/PreConditionNotMetException.php', 'OCP\\Preview\\BeforePreviewFetchedEvent' => __DIR__ . '/../../..' . '/lib/public/Preview/BeforePreviewFetchedEvent.php', 'OCP\\Preview\\IMimeIconProvider' => __DIR__ . '/../../..' . '/lib/public/Preview/IMimeIconProvider.php', - 'OCP\\Preview\\IProvider' => __DIR__ . '/../../..' . '/lib/public/Preview/IProvider.php', 'OCP\\Preview\\IProviderV2' => __DIR__ . '/../../..' . '/lib/public/Preview/IProviderV2.php', 'OCP\\Preview\\IVersionedPreviewFile' => __DIR__ . '/../../..' . '/lib/public/Preview/IVersionedPreviewFile.php', 'OCP\\Profile\\BeforeTemplateRenderedEvent' => __DIR__ . '/../../..' . '/lib/public/Profile/BeforeTemplateRenderedEvent.php', @@ -1948,8 +1947,6 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OC\\Preview\\Photoshop' => __DIR__ . '/../../..' . '/lib/private/Preview/Photoshop.php', 'OC\\Preview\\Postscript' => __DIR__ . '/../../..' . '/lib/private/Preview/Postscript.php', 'OC\\Preview\\PreviewService' => __DIR__ . '/../../..' . '/lib/private/Preview/PreviewService.php', - 'OC\\Preview\\Provider' => __DIR__ . '/../../..' . '/lib/private/Preview/Provider.php', - 'OC\\Preview\\ProviderV1Adapter' => __DIR__ . '/../../..' . '/lib/private/Preview/ProviderV1Adapter.php', 'OC\\Preview\\ProviderV2' => __DIR__ . '/../../..' . '/lib/private/Preview/ProviderV2.php', 'OC\\Preview\\SGI' => __DIR__ . '/../../..' . '/lib/private/Preview/SGI.php', 'OC\\Preview\\SVG' => __DIR__ . '/../../..' . '/lib/private/Preview/SVG.php', diff --git a/lib/private/Preview/Generator.php b/lib/private/Preview/Generator.php index 82c4ec88363f2..8707c257e7b8a 100644 --- a/lib/private/Preview/Generator.php +++ b/lib/private/Preview/Generator.php @@ -22,7 +22,6 @@ use OCP\IPreview; use OCP\IStreamImage; use OCP\Preview\BeforePreviewFetchedEvent; -use OCP\Preview\IProviderV2; use OCP\Preview\IVersionedPreviewFile; use Psr\Log\LoggerInterface; @@ -322,7 +321,7 @@ private function generateProviderPreview(File $file, int $width, int $height, bo foreach ($providers as $providerClosure) { $provider = $this->helper->getProvider($providerClosure); - if (!($provider instanceof IProviderV2)) { + if (!$provider) { continue; } diff --git a/lib/private/Preview/GeneratorHelper.php b/lib/private/Preview/GeneratorHelper.php index 7114a412e36ea..7849cb3ba38c7 100644 --- a/lib/private/Preview/GeneratorHelper.php +++ b/lib/private/Preview/GeneratorHelper.php @@ -7,38 +7,18 @@ namespace OC\Preview; use OCP\Files\File; -use OCP\Files\IRootFolder; use OCP\Files\SimpleFS\ISimpleFile; -use OCP\IConfig; use OCP\IImage; use OCP\Image as OCPImage; -use OCP\Preview\IProvider; +use OCP\IPreview; use OCP\Preview\IProviderV2; /** * Very small wrapper class to make the generator fully unit testable + * @psalm-import-type ProviderClosure from IPreview */ class GeneratorHelper { - /** @var IRootFolder */ - private $rootFolder; - - /** @var IConfig */ - private $config; - - public function __construct(IRootFolder $rootFolder, IConfig $config) { - $this->rootFolder = $rootFolder; - $this->config = $config; - } - - /** - * @param IProviderV2 $provider - * @param File $file - * @param int $maxWidth - * @param int $maxHeight - * - * @return bool|IImage - */ - public function getThumbnail(IProviderV2 $provider, File $file, $maxWidth, $maxHeight, bool $crop = false) { + public function getThumbnail(IProviderV2 $provider, File $file, int $maxWidth, int $maxHeight, bool $crop = false): IImage|false { if ($provider instanceof Imaginary) { return $provider->getCroppedThumbnail($file, $maxWidth, $maxHeight, $crop) ?? false; } @@ -52,14 +32,9 @@ public function getImage(ISimpleFile $maxPreview): IImage { } /** - * @param callable $providerClosure - * @return IProviderV2 + * @param \Closure|string $providerClosure (string is only authorized in unit tests) */ - public function getProvider($providerClosure) { - $provider = $providerClosure(); - if ($provider instanceof IProvider) { - $provider = new ProviderV1Adapter($provider); - } - return $provider; + public function getProvider(\Closure|string $providerClosure): IProviderV2|false { + return $providerClosure(); } } diff --git a/lib/private/Preview/Provider.php b/lib/private/Preview/Provider.php deleted file mode 100644 index 26f0ac09f084b..0000000000000 --- a/lib/private/Preview/Provider.php +++ /dev/null @@ -1,50 +0,0 @@ -options = $options; - } - - /** - * @return string Regex with the mimetypes that are supported by this provider - */ - abstract public function getMimeType(); - - /** - * Check if a preview can be generated for $path - * - * @param \OCP\Files\FileInfo $file - * @return bool - */ - public function isAvailable(\OCP\Files\FileInfo $file) { - return true; - } - - /** - * Generates thumbnail which fits in $maxX and $maxY and keeps the aspect ratio, for file at path $path - * - * @param string $path Path of file - * @param int $maxX The maximum X size of the thumbnail. It can be smaller depending on the shape of the image - * @param int $maxY The maximum Y size of the thumbnail. It can be smaller depending on the shape of the image - * @param bool $scalingup Disable/Enable upscaling of previews - * @param \OC\Files\View $fileview fileview object of user folder - * @return bool|\OCP\IImage false if no preview was generated - */ - abstract public function getThumbnail($path, $maxX, $maxY, $scalingup, $fileview); -} diff --git a/lib/private/Preview/ProviderV1Adapter.php b/lib/private/Preview/ProviderV1Adapter.php deleted file mode 100644 index ba8826ef765c3..0000000000000 --- a/lib/private/Preview/ProviderV1Adapter.php +++ /dev/null @@ -1,45 +0,0 @@ -providerV1 = $providerV1; - } - - public function getMimeType(): string { - return (string)$this->providerV1->getMimeType(); - } - - public function isAvailable(FileInfo $file): bool { - return (bool)$this->providerV1->isAvailable($file); - } - - public function getThumbnail(File $file, int $maxX, int $maxY): ?IImage { - [$view, $path] = $this->getViewAndPath($file); - $thumbnail = $this->providerV1->getThumbnail($path, $maxX, $maxY, false, $view); - return $thumbnail === false ? null: $thumbnail; - } - - private function getViewAndPath(File $file) { - $view = new View(dirname($file->getPath())); - $path = $file->getName(); - - return [$view, $path]; - } -} diff --git a/lib/private/PreviewManager.php b/lib/private/PreviewManager.php index fb88409287260..2e99dee19b1db 100644 --- a/lib/private/PreviewManager.php +++ b/lib/private/PreviewManager.php @@ -7,13 +7,13 @@ */ namespace OC; +use Closure; use OC\AppFramework\Bootstrap\Coordinator; use OC\Preview\Db\PreviewMapper; use OC\Preview\Generator; use OC\Preview\GeneratorHelper; use OC\Preview\IMagickSupport; use OC\Preview\Storage\StorageFactory; -use OCP\AppFramework\QueryException; use OCP\EventDispatcher\IEventDispatcher; use OCP\Files\File; use OCP\Files\IRootFolder; @@ -24,10 +24,14 @@ use OCP\IPreview; use OCP\Preview\IProviderV2; use Psr\Container\ContainerInterface; +use Psr\Container\NotFoundExceptionInterface; use Psr\Log\LoggerInterface; use function array_key_exists; +/** + * @psalm-import-type ProviderClosure from IPreview + */ class PreviewManager implements IPreview { protected IConfig $config; protected IRootFolder $rootFolder; @@ -36,10 +40,14 @@ class PreviewManager implements IPreview { private GeneratorHelper $helper; protected bool $providerListDirty = false; protected bool $registeredCoreProviders = false; + /** + * @var array> $providers + */ protected array $providers = []; /** @var array mime type => support status */ protected array $mimeTypeSupportMap = []; + /** @var ?list> $defaultProviders */ protected ?array $defaultProviders = null; protected ?string $userId; private Coordinator $bootstrapCoordinator; @@ -81,13 +89,10 @@ public function __construct( * In order to improve lazy loading a closure can be registered which will be * called in case preview providers are actually requested * - * $callable has to return an instance of \OCP\Preview\IProvider or \OCP\Preview\IProviderV2 - * * @param string $mimeTypeRegex Regex with the mime types that are supported by this provider - * @param \Closure $callable - * @return void + * @param ProviderClosure $callable */ - public function registerProvider($mimeTypeRegex, \Closure $callable): void { + public function registerProvider(string $mimeTypeRegex, Closure $callable): void { if (!$this->enablePreviews) { return; } @@ -131,10 +136,7 @@ private function getGenerator(): Generator { $this->generator = new Generator( $this->config, $this, - new GeneratorHelper( - $this->rootFolder, - $this->config - ), + new GeneratorHelper(), $this->eventDispatcher, $this->container->get(LoggerInterface::class), $this->container->get(PreviewMapper::class), @@ -146,11 +148,11 @@ private function getGenerator(): Generator { public function getPreview( File $file, - $width = -1, - $height = -1, - $crop = false, - $mode = IPreview::MODE_FILL, - $mimeType = null, + int $width = -1, + int $height = -1, + bool $crop = false, + string $mode = IPreview::MODE_FILL, + ?string $mimeType = null, bool $cacheResult = true, ): ISimpleFile { $this->throwIfPreviewsDisabled($file, $mimeType); @@ -168,26 +170,18 @@ public function getPreview( /** * Generates previews of a file * - * @param File $file * @param array $specifications - * @param string $mimeType * @return ISimpleFile the last preview that was generated * @throws NotFoundException * @throws \InvalidArgumentException if the preview would be invalid (in case the original image is invalid) * @since 19.0.0 */ - public function generatePreviews(File $file, array $specifications, $mimeType = null) { + public function generatePreviews(File $file, array $specifications, ?string $mimeType = null): ISimpleFile { $this->throwIfPreviewsDisabled($file, $mimeType); return $this->getGenerator()->generatePreviews($file, $specifications, $mimeType); } - /** - * returns true if the passed mime type is supported - * - * @param string $mimeType - * @return boolean - */ - public function isMimeSupported($mimeType = '*') { + public function isMimeSupported(string $mimeType = '*'): bool { if (!$this->enablePreviews) { return false; } @@ -209,9 +203,6 @@ public function isMimeSupported($mimeType = '*') { return false; } - /** - * Check if a preview can be generated for a file - */ public function isAvailable(\OCP\Files\FileInfo $file, ?string $mimeType = null): bool { if (!$this->enablePreviews) { return false; @@ -233,10 +224,9 @@ public function isAvailable(\OCP\Files\FileInfo $file, ?string $mimeType = null) if (preg_match($supportedMimeType, $fileMimeType)) { foreach ($providers as $providerClosure) { $provider = $this->helper->getProvider($providerClosure); - if (!($provider instanceof IProviderV2)) { + if (!$provider) { continue; } - if ($provider->isAvailable($file)) { return true; } @@ -275,9 +265,9 @@ public function isAvailable(\OCP\Files\FileInfo $file, ?string $mimeType = null) * - OC\Preview\SVG * - OC\Preview\TIFF * - * @return array + * @return list> */ - protected function getEnabledDefaultProvider() { + protected function getEnabledDefaultProvider(): array { if ($this->defaultProviders !== null) { return $this->defaultProviders; } @@ -302,17 +292,16 @@ protected function getEnabledDefaultProvider() { if (in_array(Preview\Image::class, $this->defaultProviders)) { $this->defaultProviders = array_merge($this->defaultProviders, $imageProviders); } - $this->defaultProviders = array_unique($this->defaultProviders); - return $this->defaultProviders; + $this->defaultProviders = array_values(array_unique($this->defaultProviders)); + /** @var list> $providers */ + $providers = $this->defaultProviders; + return $providers; } /** * Register the default providers (if enabled) - * - * @param string $class - * @param string $mimeType */ - protected function registerCoreProvider($class, $mimeType, $options = []) { + protected function registerCoreProvider(string $class, string $mimeType, array $options = []): void { if (in_array(trim($class, '\\'), $this->getEnabledDefaultProvider())) { $this->registerProvider($mimeType, function () use ($class, $options) { return new $class($options); @@ -323,7 +312,7 @@ protected function registerCoreProvider($class, $mimeType, $options = []) { /** * Register the default providers (if enabled) */ - protected function registerCoreProviders() { + protected function registerCoreProviders(): void { if ($this->registeredCoreProviders) { return; } @@ -440,11 +429,11 @@ private function registerBootstrapProviders(): void { } $this->loadedBootstrapProviders[$key] = null; - $this->registerProvider($provider->getMimeTypeRegex(), function () use ($provider) { + $this->registerProvider($provider->getMimeTypeRegex(), function () use ($provider): IProviderV2|false { try { return $this->container->get($provider->getService()); - } catch (QueryException $e) { - return null; + } catch (NotFoundExceptionInterface) { + return false; } }); } diff --git a/lib/public/IPreview.php b/lib/public/IPreview.php index 3c9eadd45774a..56c31430f4959 100644 --- a/lib/public/IPreview.php +++ b/lib/public/IPreview.php @@ -10,14 +10,20 @@ namespace OCP; +use Closure; +use OCP\AppFramework\Attribute\Consumable; use OCP\Files\File; +use OCP\Files\FileInfo; use OCP\Files\NotFoundException; use OCP\Files\SimpleFS\ISimpleFile; +use OCP\Preview\IProviderV2; /** * This class provides functions to render and show thumbnails and previews of files * @since 6.0.0 + * @psalm-type ProviderClosure = Closure():(IProviderV2|false) */ +#[Consumable(since: '6.0.0')] interface IPreview { /** * @since 11.0.0 @@ -33,31 +39,27 @@ interface IPreview { * In order to improve lazy loading a closure can be registered which will be * called in case preview providers are actually requested * - * $callable has to return an instance of \OCP\Preview\IProvider - * * @param string $mimeTypeRegex Regex with the mime types that are supported by this provider - * @param \Closure $callable - * @return void + * @param ProviderClosure $callable * @since 8.1.0 * @see \OCP\AppFramework\Bootstrap\IRegistrationContext::registerPreviewProvider * * @deprecated 23.0.0 Register your provider via the IRegistrationContext when booting the app */ - public function registerProvider($mimeTypeRegex, \Closure $callable); + public function registerProvider(string $mimeTypeRegex, Closure $callable): void; /** * Get all providers - * @return array + * @return array> * @since 8.1.0 */ - public function getProviders(); + public function getProviders(): array; /** * Does the manager have any providers - * @return bool * @since 8.1.0 */ - public function hasProviders(); + public function hasProviders(): bool; /** * Returns a preview of a file @@ -65,50 +67,42 @@ public function hasProviders(); * The cache is searched first and if nothing usable was found then a preview is * generated by one of the providers * - * @param File $file - * @param int $width - * @param int $height - * @param bool $crop - * @param string $mode + * @param IPreview::MODE_* $mode * @param string $mimeType To force a given mimetype for the file (files_versions needs this) - * @param bool $cacheResult Whether or not to cache the preview on the filesystem. Default to true. Can be useful to set to false to limit the amount of stored previews. + * @param bool $cacheResult Whether to cache the preview on the filesystem. Default to true. Can be useful to set to false to limit the amount of stored previews. * @return ISimpleFile * @throws NotFoundException * @throws \InvalidArgumentException if the preview would be invalid (in case the original image is invalid) * @since 11.0.0 - \InvalidArgumentException was added in 12.0.0 * @since 32.0.0 - getPreview($cacheResult) added the $cacheResult argument to the signature */ - public function getPreview(File $file, $width = -1, $height = -1, $crop = false, $mode = IPreview::MODE_FILL, $mimeType = null, bool $cacheResult = true); + public function getPreview(File $file, int $width = -1, int $height = -1, bool $crop = false, string $mode = IPreview::MODE_FILL, ?string $mimeType = null, bool $cacheResult = true): ISimpleFile; /** * Returns true if the passed mime type is supported - * @param string $mimeType - * @return boolean + * @param string $mimeType A glob * @since 6.0.0 */ - public function isMimeSupported($mimeType = '*'); + public function isMimeSupported(string $mimeType = '*'): bool; /** * Check if a preview can be generated for a file * - * @param \OCP\Files\FileInfo $file + * @param FileInfo $file * @param string|null $mimeType To force a given mimetype for the file - * @return bool * @since 8.0.0 * @since 32.0.0 - isAvailable($mimeType) added the $mimeType argument to the signature */ - public function isAvailable(\OCP\Files\FileInfo $file, ?string $mimeType = null); + public function isAvailable(FileInfo $file, ?string $mimeType = null): bool; /** * Generates previews of a file * - * @param File $file * @param array $specifications - * @param string $mimeType * @return ISimpleFile the last preview that was generated * @throws NotFoundException * @throws \InvalidArgumentException if the preview would be invalid (in case the original image is invalid) * @since 19.0.0 */ - public function generatePreviews(File $file, array $specifications, $mimeType = null); + public function generatePreviews(File $file, array $specifications, ?string $mimeType = null): ISimpleFile; } diff --git a/lib/public/Preview/IProvider.php b/lib/public/Preview/IProvider.php deleted file mode 100644 index b06acfbbe5d11..0000000000000 --- a/lib/public/Preview/IProvider.php +++ /dev/null @@ -1,44 +0,0 @@ -