diff --git a/AdobeStockImage/Model/Extract/MediaGalleryAsset.php b/AdobeStockImage/Model/Extract/MediaGalleryAsset.php index 4348a58adbb5..34554245a911 100644 --- a/AdobeStockImage/Model/Extract/MediaGalleryAsset.php +++ b/AdobeStockImage/Model/Extract/MediaGalleryAsset.php @@ -51,6 +51,7 @@ public function convert(Document $document, array $additionalData = []): AssetIn return $this->assetFactory->create([ 'path' => $assetData['path'], 'title' => $assetData['title'], + 'description' => $assetData['description'], 'width' => $assetData['width'], 'height' => $assetData['height'], 'size' => $assetData['size'], diff --git a/AdobeStockImage/Model/SaveMediaGalleryAsset.php b/AdobeStockImage/Model/SaveMediaGalleryAsset.php index 4e75f17795b1..0372d430e6ad 100644 --- a/AdobeStockImage/Model/SaveMediaGalleryAsset.php +++ b/AdobeStockImage/Model/SaveMediaGalleryAsset.php @@ -15,6 +15,8 @@ use Magento\MediaGalleryApi\Api\SaveAssetsInterface; use Magento\MediaGallerySynchronizationApi\Model\GetContentHashInterface; use Magento\Framework\Exception\FileSystemException; +use Magento\MediaGalleryMetadataApi\Api\ExtractMetadataInterface; +use Magento\Framework\Api\AttributeValueFactory; /** * Process save action of the media gallery asset. @@ -31,6 +33,11 @@ class SaveMediaGalleryAsset */ private $documentToMediaGalleryAsset; + /** + * @var AttributeValueFactory + */ + private $attributeValueFactory; + /** * @var GetContentHashInterface */ @@ -41,22 +48,33 @@ class SaveMediaGalleryAsset */ private $fileSystem; + /** + * @var ExtractMetadataInterface + */ + private $extractMetadata; + /** * @param SaveAssetsInterface $saveMediaAsset * @param DocumentToMediaGalleryAsset $documentToMediaGalleryAsset * @param GetContentHashInterface $getContentHash * @param Filesystem $fileSystem + * @param ExtractMetadataInterface $extractMetadata + * @param AttributeValueFactory $attributeValueFactory */ public function __construct( SaveAssetsInterface $saveMediaAsset, DocumentToMediaGalleryAsset $documentToMediaGalleryAsset, GetContentHashInterface $getContentHash, - Filesystem $fileSystem + Filesystem $fileSystem, + ExtractMetadataInterface $extractMetadata, + AttributeValueFactory $attributeValueFactory ) { $this->saveMediaAsset = $saveMediaAsset; $this->documentToMediaGalleryAsset = $documentToMediaGalleryAsset; $this->getContentHash = $getContentHash; $this->fileSystem = $fileSystem; + $this->extractMetadata = $extractMetadata; + $this->attributeValueFactory = $attributeValueFactory; } /** @@ -79,6 +97,7 @@ public function execute(Document $document, string $destinationPath): void 'hash' => $this->hashImageContent($destinationPath) ]; + $document = $this->setDescriptionField($document, $destinationPath); $mediaGalleryAsset = $this->documentToMediaGalleryAsset->convert($document, $additionalData); $this->saveMediaAsset->execute([$mediaGalleryAsset]); } catch (\Exception $exception) { @@ -86,6 +105,27 @@ public function execute(Document $document, string $destinationPath): void } } + /** + * Set description from file metadata + * + * @param Document $document + * @param string $destinationPath + */ + private function setDescriptionField(Document $document, string $destinationPath): Document + { + $customAttributes = $document->getCustomAttributes(); + $mediaDirectory = $this->fileSystem->getDirectoryRead(DirectoryList::MEDIA); + $metadata = $this->extractMetadata->execute($mediaDirectory->getAbsolutePath($destinationPath)); + $attribute = $this->attributeValueFactory->create(); + + $attribute->setAttributeCode('description'); + $attribute->setValue($metadata->getDescription()); + $customAttributes['description'] = $attribute; + $document->setCustomAttributes($customAttributes); + + return $document; + } + /** * Calculates saved image file size. * diff --git a/AdobeStockImage/Test/Unit/Model/SaveMediaGalleryAssetTest.php b/AdobeStockImage/Test/Unit/Model/SaveMediaGalleryAssetTest.php index 32a10271b60a..e361a9aaeb13 100644 --- a/AdobeStockImage/Test/Unit/Model/SaveMediaGalleryAssetTest.php +++ b/AdobeStockImage/Test/Unit/Model/SaveMediaGalleryAssetTest.php @@ -20,6 +20,10 @@ use Magento\MediaGallerySynchronizationApi\Model\GetContentHashInterface; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; +use Magento\MediaGalleryMetadataApi\Api\ExtractMetadataInterface; +use Magento\Framework\Api\AttributeValueFactory; +use Magento\Framework\Api\AttributeValue; +use Magento\MediaGalleryMetadataApi\Api\Data\MetadataInterface; /** * Test saving a media gallery asset and return its id. @@ -57,6 +61,16 @@ class SaveMediaGalleryAssetTest extends TestCase */ private $getContentHash; + /** + * @var ExtractMetadataInterface|MockObject + */ + private $extractMetadata; + + /** + * @var AttributeValueFactory|MockObject + */ + private $attributeValueFactory; + /** * @inheritdoc */ @@ -67,13 +81,17 @@ protected function setUp(): void $this->converter = $this->createMock(DocumentToMediaGalleryAsset::class); $this->filesystem = $this->createMock(Filesystem::class); $this->mediaDirectory = $this->createMock(Read::class); + $this->extractMetadata = $this->createMock(ExtractMetadataInterface::class); + $this->attributeValueFactory = $this->createMock(AttributeValueFactory::class); $this->saveMediaAsset = (new ObjectManager($this))->getObject( SaveMediaGalleryAsset::class, [ 'saveMediaAsset' => $this->saveAssets, 'documentToMediaGalleryAsset' => $this->converter, - 'fileSystem' => $this->filesystem + 'fileSystem' => $this->filesystem, + 'extractMetadata' => $this->extractMetadata, + 'attributeValueFactory' => $this->attributeValueFactory ] ); $reflection = new \ReflectionClass(get_class($this->saveMediaAsset)); @@ -119,11 +137,31 @@ public function testExecute(): void 'size' => $fileSize, 'hash' => $this->getContentHash->execute($hash) ]; + $attributeMock = $this->createMock(AttributeValue::class); + $metadataMock = $this->createMock(MetadataInterface::class); + $document->expects($this->once()) + ->method('getCustomAttributes') + ->willReturn([]); + $this->extractMetadata->expects($this->once()) + ->method('execute') + ->willReturn($metadataMock); + $this->attributeValueFactory->expects($this->once()) + ->method('create') + ->willReturn($attributeMock); + $mediaGalleryAssetMock = $this->createMock(Asset::class); $this->converter->expects($this->once()) ->method('convert') ->with($document, $additionalData) ->willReturn($mediaGalleryAssetMock); + $attributeMock->expects($this->once()) + ->method('setAttributeCode'); + $attributeMock->expects($this->once()) + ->method('setValue'); + $metadataMock->expects($this->once()) + ->method('getDescription'); + $document->expects($this->once()) + ->method('setCustomAttributes'); $this->saveAssets->expects($this->once()) ->method('execute') diff --git a/AdobeStockImage/composer.json b/AdobeStockImage/composer.json index 8393a93f6f51..e83def750584 100644 --- a/AdobeStockImage/composer.json +++ b/AdobeStockImage/composer.json @@ -9,7 +9,8 @@ "magento/module-adobe-stock-image-api": "*", "magento/module-media-gallery-api": "*", "magento/module-media-gallery-synchronization-api": "*", - "magento/module-cms": "*" + "magento/module-cms": "*", + "magento/module-media-gallery-metadata-api": "*" }, "suggest": { "magento/module-catalog": "*" diff --git a/MediaGalleryCmsUi/Test/Mftf/Test/AdminMediaGalleryCmsUiUsedInPagesFilterTest.xml b/MediaGalleryCmsUi/Test/Mftf/Test/AdminMediaGalleryCmsUiUsedInPagesFilterTest.xml index c9a1b09ea7be..46a0aeee8c22 100644 --- a/MediaGalleryCmsUi/Test/Mftf/Test/AdminMediaGalleryCmsUiUsedInPagesFilterTest.xml +++ b/MediaGalleryCmsUi/Test/Mftf/Test/AdminMediaGalleryCmsUiUsedInPagesFilterTest.xml @@ -30,8 +30,7 @@ - - + diff --git a/MediaGalleryIntegration/Plugin/SaveBaseCategoryImageInformation.php b/MediaGalleryIntegration/Plugin/SaveBaseCategoryImageInformation.php index b548412c4ed0..5138fc131cdd 100644 --- a/MediaGalleryIntegration/Plugin/SaveBaseCategoryImageInformation.php +++ b/MediaGalleryIntegration/Plugin/SaveBaseCategoryImageInformation.php @@ -7,29 +7,17 @@ namespace Magento\MediaGalleryIntegration\Plugin; -use Magento\MediaGalleryApi\Api\SaveAssetsInterface; use Magento\MediaGalleryApi\Api\GetAssetsByPathsInterface; use Magento\MediaGalleryApi\Api\DeleteAssetsByPathsInterface; use Magento\Catalog\Model\ImageUploader; -use Magento\MediaGallerySynchronization\Model\CreateAssetFromFile; use Magento\Cms\Model\Wysiwyg\Images\Storage; -use Magento\MediaGallerySynchronization\Model\Filesystem\SplFileInfoFactory; +use Magento\MediaGallerySynchronizationApi\Api\SynchronizeFilesInterface; /** * Save base category image by SaveAssetsInterface. */ class SaveBaseCategoryImageInformation { - /** - * @var SplFileInfoFactory - */ - private $splFileInfoFactory; - - /** - * @var SaveAssetsInterface - */ - private $saveAsset; - /** * @var DeleteAssetsByPathsInterface */ @@ -39,39 +27,33 @@ class SaveBaseCategoryImageInformation * @var GetAssetsByPathsInterface */ private $getAssetsByPaths; - - /** - * @var CreateAssetFromFile - */ - private $createAssetFromFile; /** * @var Storage */ private $storage; + + /** + * @var SynchronizeFilesInterface + */ + private $synchronizeFiles; /** * @param DeleteAssetsByPathsInterface $deleteAssetsByPath * @param GetAssetsByPathsInterface $getAssetsByPaths - * @param SplFileInfoFactory $splFileInfoFactory - * @param CreateAssetFromFile $createAssetFromFile - * @param SaveAssetsInterface $saveAsset * @param Storage $storage + * @param SynchronizeFilesInterface $synchronizeFiles */ public function __construct( DeleteAssetsByPathsInterface $deleteAssetsByPath, GetAssetsByPathsInterface $getAssetsByPaths, - SplFileInfoFactory $splFileInfoFactory, - CreateAssetFromFile $createAssetFromFile, - SaveAssetsInterface $saveAsset, - Storage $storage + Storage $storage, + SynchronizeFilesInterface $synchronizeFiles ) { $this->deleteAssetsByPaths = $deleteAssetsByPath; $this->getAssetsByPaths = $getAssetsByPaths; - $this->splFileInfoFactory = $splFileInfoFactory; - $this->createAssetFromFile = $createAssetFromFile; - $this->saveAsset = $saveAsset; $this->storage = $storage; + $this->synchronizeFiles = $synchronizeFiles; } /** @@ -83,16 +65,14 @@ public function __construct( public function afterMoveFileFromTmp(ImageUploader $subject, string $imagePath): string { $absolutePath = $this->storage->getCmsWysiwygImages()->getStorageRoot() . $imagePath; - $file = $this->splFileInfoFactory->create($absolutePath); - $tmpPath = $subject->getBaseTmpPath() . '/' . $file->getFileName(); + $tmpPath = $subject->getBaseTmpPath() . '/' . substr(strrchr($imagePath, "/"), 1); $tmpAssets = $this->getAssetsByPaths->execute([$tmpPath]); if (!empty($tmpAssets)) { $this->deleteAssetsByPaths->execute([$tmpAssets[0]->getPath()]); } - - $this->saveAsset->execute([$this->createAssetFromFile->execute($file)]); - $this->storage->resizeFile($absolutePath); + + $this->synchronizeFiles->execute([$absolutePath]); return $imagePath; } diff --git a/MediaGalleryIntegration/Plugin/SaveImageInformation.php b/MediaGalleryIntegration/Plugin/SaveImageInformation.php index cabcf5a3b86f..afe98a5c886a 100644 --- a/MediaGalleryIntegration/Plugin/SaveImageInformation.php +++ b/MediaGalleryIntegration/Plugin/SaveImageInformation.php @@ -7,15 +7,13 @@ namespace Magento\MediaGalleryIntegration\Plugin; -use Magento\MediaGalleryApi\Api\SaveAssetsInterface; use Magento\Framework\File\Uploader; -use Magento\MediaGallerySynchronization\Model\CreateAssetFromFile; -use Magento\Cms\Model\Wysiwyg\Images\Storage; -use Magento\MediaGallerySynchronization\Model\Filesystem\SplFileInfoFactory; use Magento\MediaGalleryApi\Api\IsPathExcludedInterface; use Psr\Log\LoggerInterface; use Magento\Framework\Filesystem; use Magento\Framework\App\Filesystem\DirectoryList; +use Magento\MediaGalleryApi\Api\SaveAssetsInterface; +use Magento\MediaGallerySynchronizationApi\Api\SynchronizeFilesInterface; /** * Save image information by SaveAssetsInterface. @@ -29,26 +27,6 @@ class SaveImageInformation */ private $isPathExcluded; - /** - * @var SplFileInfoFactory - */ - private $splFileInfoFactory; - - /** - * @var SaveAssetsInterface - */ - private $saveAsset; - - /** - * @var CreateAssetFromFile - */ - private $createAssetFromFile; - - /** - * @var Storage - */ - private $storage; - /** * @var LoggerInterface */ @@ -58,32 +36,28 @@ class SaveImageInformation * @var Filesystem */ private $filesystem; - + + /** + * @var SynchronizeFilesInterface + */ + private $synchronizeFiles; + /** * @param Filesystem $filesystem * @param LoggerInterface $log * @param IsPathExcludedInterface $isPathExcluded - * @param SplFileInfoFactory $splFileInfoFactory - * @param CreateAssetFromFile $createAssetFromFile - * @param SaveAssetsInterface $saveAsset - * @param Storage $storage + * @param SynchronizeFilesInterface $synchronizeFiles */ public function __construct( Filesystem $filesystem, LoggerInterface $log, IsPathExcludedInterface $isPathExcluded, - SplFileInfoFactory $splFileInfoFactory, - CreateAssetFromFile $createAssetFromFile, - SaveAssetsInterface $saveAsset, - Storage $storage + SynchronizeFilesInterface $synchronizeFiles ) { $this->log = $log; $this->isPathExcluded = $isPathExcluded; - $this->splFileInfoFactory = $splFileInfoFactory; - $this->createAssetFromFile = $createAssetFromFile; - $this->saveAsset = $saveAsset; - $this->storage = $storage; $this->filesystem = $filesystem; + $this->synchronizeFiles = $synchronizeFiles; } /** @@ -95,12 +69,11 @@ public function __construct( */ public function afterSave(Uploader $subject, array $result): array { - $file = $this->splFileInfoFactory->create($result['path'] . '/' . $result['file']); - if (!$this->isApplicable($file->getPathName())) { + $path = $result['path'] . '/' . $result['file']; + if (!$this->isApplicable($path)) { return $result; } - $this->saveAsset->execute([$this->createAssetFromFile->execute($file)]); - $this->storage->resizeFile($result['path'] . '/' . $result['file']); + $this->synchronizeFiles->execute([$path]); return $result; } diff --git a/MediaGalleryIntegration/composer.json b/MediaGalleryIntegration/composer.json index c784dc652a0c..bb208c809d0d 100644 --- a/MediaGalleryIntegration/composer.json +++ b/MediaGalleryIntegration/composer.json @@ -7,7 +7,7 @@ "magento/module-media-gallery-ui-api": "*", "magento/module-cms": "*", "magento/module-media-gallery-api": "*", - "magento/module-media-gallery-synchronization": "*" + "magento/module-media-gallery-synchronization-api": "*" }, "suggest": { "magento/module-catalog": "*" diff --git a/MediaGalleryMetadata/etc/di.xml b/MediaGalleryMetadata/etc/di.xml index 62c1407f95e3..dd479307970b 100644 --- a/MediaGalleryMetadata/etc/di.xml +++ b/MediaGalleryMetadata/etc/di.xml @@ -82,4 +82,34 @@ + + + Magento\Framework\Filesystem\Driver\File + + + + + Magento\Framework\Filesystem\Driver\File + + + + + Magento\Framework\Filesystem\Driver\File + + + + + Magento\Framework\Filesystem\Driver\File + + + + + Magento\Framework\Filesystem\Driver\File + + + + + Magento\Framework\Filesystem\Driver\File + + diff --git a/MediaGallerySynchronization/Model/CreateAssetFromFile.php b/MediaGallerySynchronization/Model/CreateAssetFromFile.php index 7daf9a3aca3c..972dc2ed6389 100644 --- a/MediaGallerySynchronization/Model/CreateAssetFromFile.php +++ b/MediaGallerySynchronization/Model/CreateAssetFromFile.php @@ -18,6 +18,8 @@ use Magento\MediaGallerySynchronizationApi\Model\GetContentHashInterface; use Magento\Framework\Exception\LocalizedException; use Magento\Framework\Exception\FileSystemException; +use Magento\MediaGalleryMetadataApi\Api\ExtractMetadataInterface; +use Magento\MediaGalleryMetadataApi\Api\Data\MetadataInterface; /** * Create media asset object based on the file information @@ -55,25 +57,33 @@ class CreateAssetFromFile */ private $getContentHash; + /** + * @var ExtractMetadataInterface + */ + private $extractMetadata; + /** * @param Filesystem $filesystem * @param AssetInterfaceFactory $assetFactory * @param File $driver * @param GetAssetsByPathsInterface $getMediaGalleryAssetByPath * @param GetContentHashInterface $getContentHash + * @param ExtractMetadataInterface $extractMetadata */ public function __construct( Filesystem $filesystem, AssetInterfaceFactory $assetFactory, File $driver, GetAssetsByPathsInterface $getMediaGalleryAssetByPath, - GetContentHashInterface $getContentHash + GetContentHashInterface $getContentHash, + ExtractMetadataInterface $extractMetadata ) { $this->filesystem = $filesystem; $this->assetFactory = $assetFactory; $this->driver = $driver; $this->getMediaGalleryAssetByPath = $getMediaGalleryAssetByPath; $this->getContentHash = $getContentHash; + $this->extractMetadata = $extractMetadata; } /** @@ -89,13 +99,16 @@ public function execute(\SplFileInfo $file) $path = $file->getPath() . '/' . $file->getFileName(); [$width, $height] = getimagesize($path); - $asset = $this->getAsset($path); + + $metadata = $this->extractMetadata->execute($path); + return $this->assetFactory->create( [ 'id' => $asset ? $asset->getId() : null, 'path' => $this->getRelativePath($path), - 'title' => $asset ? $asset->getTitle() : $file->getBasename('.' . $file->getExtension()), + 'title' => $this->getAssetTitle($file, $asset, $metadata), + 'description' => $metadata->getDescription(), 'createdAt' => (new \DateTime())->setTimestamp($file->getCTime())->format('Y-m-d H:i:s'), 'updatedAt' => (new \DateTime())->setTimestamp($file->getMTime())->format('Y-m-d H:i:s'), 'width' => $width, @@ -108,6 +121,24 @@ public function execute(\SplFileInfo $file) ); } + /** + * Returns asset title from metadata if available + * + * @param \SplFileInfo $file + * @param null|AssetInterface $asset + * @param MetadataInterface $metadata + */ + private function getAssetTitle(\SplFileInfo $file, ?AssetInterface $asset, MetadataInterface $metadata): string + { + $title = $file->getBasename('.' . $file->getExtension()); + if ($asset) { + $title = $asset->getTitle(); + } elseif ($metadata->getTitle() !== "") { + $title = $metadata->getTitle(); + } + return $title; + } + /** * Returns asset if asset already exist by provided path * diff --git a/MediaGallerySynchronization/Model/FetchMediaStorageFileBatches.php b/MediaGallerySynchronization/Model/FetchMediaStorageFileBatches.php index e439ddc5fa54..df3674169c22 100644 --- a/MediaGallerySynchronization/Model/FetchMediaStorageFileBatches.php +++ b/MediaGallerySynchronization/Model/FetchMediaStorageFileBatches.php @@ -87,7 +87,7 @@ public function execute(): \Traversable continue; } - $batch[] = $file; + $batch[] = $file->getPath() . '/' . $file->getFileName(); if (++$i == $this->batchSize) { yield $batch; $i = 0; diff --git a/MediaGallerySynchronization/Model/ImportImageFileKeywords.php b/MediaGallerySynchronization/Model/ImportImageFileKeywords.php new file mode 100644 index 000000000000..ea84ce379431 --- /dev/null +++ b/MediaGallerySynchronization/Model/ImportImageFileKeywords.php @@ -0,0 +1,127 @@ +driver = $driver; + $this->filesystem = $filesystem; + $this->keywordFactory = $keywordFactory; + $this->extractMetadata = $extractMetadata; + $this->saveAssetKeywords = $saveAssetKeywords; + $this->assetKeywordsFactory = $assetKeywordsFactory; + $this->getAssetsByPaths = $getAssetsByPaths; + } + /** + * @inheritdoc + */ + public function execute(string $path): void + { + $keywords = []; + $metadata = $this->extractMetadata->execute($path); + + foreach ($metadata->getKeywords() as $keyword) { + $keywords[] = $this->keywordFactory->create( + [ + 'keyword' => $keyword + ] + ); + } + + $assetId = $this->getAssetsByPaths->execute([$this->getRelativePath($path)])[0]->getId(); + $assetKeywords = $this->assetKeywordsFactory->create([ + 'assetId' => $assetId, + 'keywords' => $keywords + ]); + + $this->saveAssetKeywords->execute([$assetKeywords]); + } + + /** + * Get correct path for media asset + * + * @param string $filePath + * @return string + */ + private function getRelativePath(string $filePath): string + { + $path = $this->filesystem->getDirectoryRead(DirectoryList::MEDIA)->getRelativePath($filePath); + + if ($this->driver->getParentDirectory($path) === '.') { + $path = '/' . $path; + } + + return $path; + } +} diff --git a/MediaGallerySynchronization/Model/ImportMediaAsset.php b/MediaGallerySynchronization/Model/ImportMediaAsset.php new file mode 100644 index 000000000000..98352ef01250 --- /dev/null +++ b/MediaGallerySynchronization/Model/ImportMediaAsset.php @@ -0,0 +1,57 @@ +splFileInfoFactory = $splFileInfoFactory; + $this->saveAssets = $saveAssets; + $this->createAssetFromFile = $createAssetFromFile; + } + + /** + * @inheritdoc + */ + public function execute(string $path): void + { + $file = $this->splFileInfoFactory->create($path); + $this->saveAssets->execute([$this->createAssetFromFile->execute($file)]); + } +} diff --git a/MediaGallerySynchronization/Model/SynchronizeFiles.php b/MediaGallerySynchronization/Model/SynchronizeFiles.php index 0ded52324fd7..6fc2829aa857 100644 --- a/MediaGallerySynchronization/Model/SynchronizeFiles.php +++ b/MediaGallerySynchronization/Model/SynchronizeFiles.php @@ -13,9 +13,10 @@ use Magento\Framework\Filesystem; use Magento\Framework\Filesystem\Driver\File; use Magento\MediaGalleryApi\Api\GetAssetsByPathsInterface; -use Magento\MediaGalleryApi\Api\SaveAssetsInterface; use Magento\MediaGallerySynchronizationApi\Api\SynchronizeFilesInterface; use Psr\Log\LoggerInterface; +use Magento\MediaGallerySynchronization\Model\Filesystem\SplFileInfoFactory; +use Magento\MediaGallerySynchronizationApi\Model\ImportFileComposite; /** * Synchronize files in media storage and media assets database records @@ -23,57 +24,57 @@ class SynchronizeFiles implements SynchronizeFilesInterface { /** - * @var CreateAssetFromFile - */ - private $createAssetFromFile; - - /** - * @var SaveAssetsInterface + * @var LoggerInterface */ - private $saveAsset; + private $log; /** - * @var LoggerInterface + * @var Filesystem */ - private $log; + private $filesystem; /** * @var GetAssetsByPathsInterface */ private $getAssetsByPaths; + + /** + * @var File + */ + private $driver; /** - * @var Filesystem + * @var SplFileInfoFactory */ - private $filesystem; + private $splFileInfoFactory; /** - * @var File + * @var ImportFileComposite */ - private $driver; + private $importFileComposite; /** * @param File $driver * @param Filesystem $filesystem - * @param GetAssetsByPathsInterface $getAssetsByPaths - * @param CreateAssetFromFile $createAssetFromFile - * @param SaveAssetsInterface $saveAsset * @param LoggerInterface $log + * @param SplFileInfoFactory $splFileInfoFactory + * @param GetAssetsByPathsInterface $getAssetsByPaths + * @param ImportFileComposite $importFileComposite */ public function __construct( File $driver, Filesystem $filesystem, + LoggerInterface $log, + SplFileInfoFactory $splFileInfoFactory, GetAssetsByPathsInterface $getAssetsByPaths, - CreateAssetFromFile $createAssetFromFile, - SaveAssetsInterface $saveAsset, - LoggerInterface $log + ImportFileComposite $importFileComposite ) { $this->driver = $driver; $this->filesystem = $filesystem; - $this->getAssetsByPaths = $getAssetsByPaths; - $this->createAssetFromFile = $createAssetFromFile; - $this->saveAsset = $saveAsset; $this->log = $log; + $this->splFileInfoFactory = $splFileInfoFactory; + $this->getAssetsByPaths = $getAssetsByPaths; + $this->importFileComposite = $importFileComposite; } /** @@ -82,17 +83,16 @@ public function __construct( public function execute(array $files): void { $assets = $this->getExistingAssets($files); - foreach ($files as $file) { - $path = $this->getFilePath($file); - $time = $this->getFileModificationTime($file); - if (isset($assets[$path]) && $time === $assets[$path]) { + foreach ($files as $filePath) { + $time = $this->getFileModificationTime($filePath); + if (isset($assets[$filePath]) && $time === $assets[$filePath]) { continue; } try { - $this->saveAsset->execute([$this->createAssetFromFile->execute($file)]); + $this->importFileComposite->execute($filePath); } catch (\Exception $exception) { $this->log->critical($exception); - $failedFiles[] = $file->getFilename(); + $failedFiles[] = $filePath; } } @@ -108,42 +108,32 @@ public function execute(array $files): void } } - /** - * Retrieve relative file path - * - * @param \SplFileInfo $file - * @return string - */ - private function getFilePath(\SplFileInfo $file): string - { - return $this->getRelativePath($file->getPath() . '/' . $file->getFileName()); - } - /** * Retrieve formatted file modification time * - * @param \SplFileInfo $file + * @param string $filePath * @return string */ - private function getFileModificationTime(\SplFileInfo $file): string + private function getFileModificationTime(string $filePath): string { - return (new \DateTime())->setTimestamp($file->getMTime())->format('Y-m-d H:i:s'); + $fileTime = $this->splFileInfoFactory->create($filePath)->getMTime(); + return (new \DateTime())->setTimestamp($fileTime)->format('Y-m-d H:i:s'); } /** * Return existing assets from files * - * @param \SplFileInfo[] $files + * @param string[] $filesPaths * @return array * @throws LocalizedException */ - private function getExistingAssets(array $files): array + private function getExistingAssets(array $filesPaths): array { $result = []; - $paths = array_map(function ($file) { - return $this->getFilePath($file); - }, $files); - + $paths = array_map(function ($filePath) { + return $this->getRelativePath($filePath); + }, $filesPaths); + $assets = $this->getAssetsByPaths->execute($paths); foreach ($assets as $asset) { @@ -156,12 +146,12 @@ private function getExistingAssets(array $files): array /** * Get correct path for media asset * - * @param string $file + * @param string $filePath * @return string */ - private function getRelativePath(string $file): string + private function getRelativePath(string $filePath): string { - $path = $this->filesystem->getDirectoryRead(DirectoryList::MEDIA)->getRelativePath($file); + $path = $this->filesystem->getDirectoryRead(DirectoryList::MEDIA)->getRelativePath($filePath); if ($this->driver->getParentDirectory($path) === '.') { $path = '/' . $path; diff --git a/MediaGallerySynchronization/composer.json b/MediaGallerySynchronization/composer.json index f9d642dd0256..e1d496236697 100644 --- a/MediaGallerySynchronization/composer.json +++ b/MediaGallerySynchronization/composer.json @@ -6,7 +6,8 @@ "magento/framework": "*", "magento/module-media-gallery-api": "*", "magento/module-media-gallery-synchronization-api": "*", - "magento/framework-message-queue": "*" + "magento/framework-message-queue": "*", + "magento/module-media-gallery-metadata-api": "*" }, "type": "magento2-module", "license": [ diff --git a/MediaGallerySynchronization/etc/di.xml b/MediaGallerySynchronization/etc/di.xml index a9d0a58edf78..601a3c4a6990 100644 --- a/MediaGallerySynchronization/etc/di.xml +++ b/MediaGallerySynchronization/etc/di.xml @@ -10,6 +10,14 @@ + + + + Magento\MediaGallerySynchronization\Model\ImportMediaAsset + Magento\MediaGallerySynchronization\Model\ImportImageFileKeywords + + + diff --git a/MediaGallerySynchronizationApi/Api/ImportFileInterface.php b/MediaGallerySynchronizationApi/Api/ImportFileInterface.php new file mode 100644 index 000000000000..0a309f51b16a --- /dev/null +++ b/MediaGallerySynchronizationApi/Api/ImportFileInterface.php @@ -0,0 +1,25 @@ +importers =$importers; + } + + /** + * Save file data + * + * @param string $path + * @throws LocalizedException + */ + public function execute(string $path): void + { + foreach ($this->importers as $importer) { + $importer->execute($path); + } + } +} diff --git a/MediaGalleryUi/Model/UploadImage.php b/MediaGalleryUi/Model/UploadImage.php index d16fa236986d..ea96bc956c0e 100644 --- a/MediaGalleryUi/Model/UploadImage.php +++ b/MediaGalleryUi/Model/UploadImage.php @@ -11,8 +11,6 @@ use Magento\Framework\App\Filesystem\DirectoryList; use Magento\Framework\Exception\LocalizedException; use Magento\Framework\Filesystem; -use Magento\MediaGallerySynchronizationApi\Api\SynchronizeFilesInterface; -use Magento\MediaGallerySynchronization\Model\Filesystem\SplFileInfoFactory; /** * Uploads an image to storage @@ -29,32 +27,16 @@ class UploadImage */ private $filesystem; - /** - * @var SplFileInfoFactory - */ - private $splFileInfoFactory; - - /** - * @var SynchronizeFilesInterface - */ - private $synchronizeFiles; - /** * @param Storage $imagesStorage - * @param SplFileInfoFactory $splFileInfoFactory * @param Filesystem $filesystem - * @param SynchronizeFilesInterface $synchronizeFiles */ public function __construct( Storage $imagesStorage, - SplFileInfoFactory $splFileInfoFactory, - Filesystem $filesystem, - SynchronizeFilesInterface $synchronizeFiles + Filesystem $filesystem ) { $this->imagesStorage = $imagesStorage; - $this->splFileInfoFactory = $splFileInfoFactory; $this->filesystem = $filesystem; - $this->synchronizeFiles = $synchronizeFiles; } /** @@ -70,14 +52,7 @@ public function execute(string $targetFolder, string $type = null): void if (!$mediaDirectory->isDirectory($targetFolder)) { throw new LocalizedException(__('Directory %1 does not exist in media directory.', $targetFolder)); } - $absolutePath = $mediaDirectory->getAbsolutePath($targetFolder); - $uploadResult = $this->imagesStorage->uploadFile($absolutePath, $type); - $this->synchronizeFiles->execute( - [ - $this->splFileInfoFactory->create( - $uploadResult['path'] . '/' . $uploadResult['file'] - ) - ] - ); + + $this->imagesStorage->uploadFile($mediaDirectory->getAbsolutePath($targetFolder), $type); } } diff --git a/MediaGalleryUi/Plugin/ResizeSyncedFiles.php b/MediaGalleryUi/Plugin/ResizeSyncedFiles.php index 93e426eb33ce..d90e1392370c 100644 --- a/MediaGalleryUi/Plugin/ResizeSyncedFiles.php +++ b/MediaGalleryUi/Plugin/ResizeSyncedFiles.php @@ -7,7 +7,7 @@ namespace Magento\MediaGalleryUi\Plugin; -use Magento\MediaGallerySynchronization\Model\SynchronizeFiles; +use Magento\MediaGallerySynchronizationApi\Api\SynchronizeFilesInterface; use Magento\Cms\Model\Wysiwyg\Images\Storage; class ResizeSyncedFiles @@ -30,14 +30,14 @@ public function __construct(Storage $storage) * * @param SynchronizeFiles $subject * @param \Closure $closure - * @param array $files + * @param array $filesPaths * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ - public function aroundExecute(SynchronizeFiles $subject, \Closure $closure, array $files) + public function aroundExecute(SynchronizeFilesInterface $subject, \Closure $closure, array $filesPaths) { - foreach ($files as $file) { - $this->storage->resizeFile($file->getPathName()); + foreach ($filesPaths as $path) { + $this->storage->resizeFile($path); } - return $closure($files); + return $closure($filesPaths); } } diff --git a/MediaGalleryUi/Test/Mftf/ActionGroup/AdminEnhancedMediaGalleryVerifyImageKeywordsActionGroup.xml b/MediaGalleryUi/Test/Mftf/ActionGroup/AdminEnhancedMediaGalleryVerifyImageKeywordsActionGroup.xml new file mode 100644 index 000000000000..0cb86ae80648 --- /dev/null +++ b/MediaGalleryUi/Test/Mftf/ActionGroup/AdminEnhancedMediaGalleryVerifyImageKeywordsActionGroup.xml @@ -0,0 +1,25 @@ + + + + + + + Verifies image keywords on the View Details panel + + + + + + + + grabDescription + {{keywords}} + + + diff --git a/MediaGalleryUi/Test/Mftf/ActionGroup/AdminEnhancedMediaGalleryVerifyImageTitleActionGroup.xml b/MediaGalleryUi/Test/Mftf/ActionGroup/AdminEnhancedMediaGalleryVerifyImageTitleActionGroup.xml new file mode 100644 index 000000000000..08dac976332e --- /dev/null +++ b/MediaGalleryUi/Test/Mftf/ActionGroup/AdminEnhancedMediaGalleryVerifyImageTitleActionGroup.xml @@ -0,0 +1,25 @@ + + + + + + + Verifies image title on the View Details panel + + + + + + + + grabImageTitle + {{title}} + + + diff --git a/MediaGalleryUi/Test/Mftf/Data/AdminEnhancedMediaGalleryImageData.xml b/MediaGalleryUi/Test/Mftf/Data/AdminEnhancedMediaGalleryImageData.xml index b296ecc6cdb0..f4f304aaa1a5 100644 --- a/MediaGalleryUi/Test/Mftf/Data/AdminEnhancedMediaGalleryImageData.xml +++ b/MediaGalleryUi/Test/Mftf/Data/AdminEnhancedMediaGalleryImageData.xml @@ -15,4 +15,12 @@ renamed title jpg + + Title of the magento image + Description of the magento image + magento3.jpg + Title of the magento image + jpg + magento, mediagallerymetadata + diff --git a/MediaGalleryUi/Test/Mftf/Section/AdminEnhancedMediaGalleryViewDetailsSection.xml b/MediaGalleryUi/Test/Mftf/Section/AdminEnhancedMediaGalleryViewDetailsSection.xml index 6cb17dc41a85..5baf261f965a 100644 --- a/MediaGalleryUi/Test/Mftf/Section/AdminEnhancedMediaGalleryViewDetailsSection.xml +++ b/MediaGalleryUi/Test/Mftf/Section/AdminEnhancedMediaGalleryViewDetailsSection.xml @@ -13,6 +13,7 @@ + diff --git a/MediaGalleryUi/Test/Mftf/Test/AdminEnhancedMediaGalleryUploadImageWithMetadataTest.xml b/MediaGalleryUi/Test/Mftf/Test/AdminEnhancedMediaGalleryUploadImageWithMetadataTest.xml new file mode 100644 index 000000000000..3b3e884edbda --- /dev/null +++ b/MediaGalleryUi/Test/Mftf/Test/AdminEnhancedMediaGalleryUploadImageWithMetadataTest.xml @@ -0,0 +1,43 @@ + + + + + + + + + + <stories value="Story 53 - Magento extracts image meta data from file"/> + <testCaseId value="https://studio.cucumber.io/projects/131313/test-plan/folders/1054245/scenarios/4653671"/> + <description value="Magento extracts image meta data from file"/> + <severity value="CRITICAL"/> + <group value="media_gallery_ui"/> + </annotations> + <before> + <actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/> + <actionGroup ref="AdminOpenStandaloneMediaGalleryActionGroup" stepKey="openMediaGallery"/> + </before> + <after> + <actionGroup ref="AdminEnhancedMediaGalleryImageDetailsDeleteActionGroup" stepKey="deleteImage"/> + </after> + + <actionGroup ref="AdminEnhancedMediaGalleryUploadImageActionGroup" stepKey="uploadImage"> + <argument name="image" value="ImageUpload3"/> + </actionGroup> + <actionGroup ref="AdminEnhancedMediaGalleryViewImageDetails" stepKey="viewImageDetails"/> + <actionGroup ref="AdminEnhancedMediaGalleryVerifyImageDescriptionActionGroup" stepKey="verifyImageDescription"> + <argument name="description" value="ImageMetadata.description"/> + </actionGroup> + <actionGroup ref="AdminEnhancedMediaGalleryVerifyImageKeywordsActionGroup" stepKey="verifyImageKeywords"> + <argument name="keywords" value="ImageMetadata.keywords"/> + </actionGroup> + <actionGroup ref="AdminEnhancedMediaGalleryVerifyImageTitleActionGroup" stepKey="verifyImageTitle"> + <argument name="title" value="ImageMetadata.title"/> + </actionGroup> + </test> +</tests> diff --git a/MediaGalleryUi/Test/Mftf/Test/AdminEnhancedMediaGalleryVerifyAssetFilterTest.xml b/MediaGalleryUi/Test/Mftf/Test/AdminEnhancedMediaGalleryVerifyAssetFilterTest.xml index 01798f38a698..69f879c60360 100644 --- a/MediaGalleryUi/Test/Mftf/Test/AdminEnhancedMediaGalleryVerifyAssetFilterTest.xml +++ b/MediaGalleryUi/Test/Mftf/Test/AdminEnhancedMediaGalleryVerifyAssetFilterTest.xml @@ -35,7 +35,7 @@ </actionGroup> <actionGroup ref="AdminEnhancedMediaGalleryEnableMassActionModeActionGroup" stepKey="enableMassActionToDeleteImages"/> <actionGroup ref="AdminEnhancedMediaGallerySelectImageForMassActionActionGroup" stepKey="selectFirstImageToDelete"> - <argument name="imageName" value="{{ImageUpload3.fileName}}"/> + <argument name="imageName" value="{{ImageMetadata.title}}"/> </actionGroup> <actionGroup ref="AdminEnhancedMediaGallerySelectImageForMassActionActionGroup" stepKey="selectSecondImageToDelete"> <argument name="imageName" value="{{ImageUpload_1.fileName}}"/> @@ -68,7 +68,7 @@ <actionGroup ref="AdminEnhancedMediaGalleryCategoryGridExpandFilterActionGroup" stepKey="expandFilters"/> <actionGroup ref="AdminEnhancedMediaGallerySelectUsedInFilterActionGroup" stepKey="setUsedInFilter"> <argument name="filterName" value="Asset"/> - <argument name="optionName" value="{{ImageUpload3.fileName}}"/> + <argument name="optionName" value="{{ImageMetadata.title}}"/> </actionGroup> <actionGroup ref="AdminEnhancedMediaGalleryCategoryGridApplyFiltersActionGroup" stepKey="applyFilters"/> diff --git a/MediaGalleryUi/Test/Mftf/Test/AdminMediaGalleryDeleteImageWithWarningPopupTest.xml b/MediaGalleryUi/Test/Mftf/Test/AdminMediaGalleryDeleteImageWithWarningPopupTest.xml index 7c07df1a447a..ffd187bf5267 100644 --- a/MediaGalleryUi/Test/Mftf/Test/AdminMediaGalleryDeleteImageWithWarningPopupTest.xml +++ b/MediaGalleryUi/Test/Mftf/Test/AdminMediaGalleryDeleteImageWithWarningPopupTest.xml @@ -24,6 +24,7 @@ <actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/> </before> <after> + <deleteData createDataKey="category" stepKey="deleteCategory"/> <magentoCLI command="config:set cms/wysiwyg/enabled disabled" stepKey="disableWYSIWYG"/> </after> diff --git a/MediaGalleryUi/Test/Mftf/Test/AdminMediaGalleryEditImageDetailsTest.xml b/MediaGalleryUi/Test/Mftf/Test/AdminMediaGalleryEditImageDetailsTest.xml index caba2e21d885..960443998d01 100644 --- a/MediaGalleryUi/Test/Mftf/Test/AdminMediaGalleryEditImageDetailsTest.xml +++ b/MediaGalleryUi/Test/Mftf/Test/AdminMediaGalleryEditImageDetailsTest.xml @@ -21,6 +21,7 @@ <before> <actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/> <actionGroup ref="AdminOpenStandaloneMediaGalleryActionGroup" stepKey="openMediaGallery"/> + <actionGroup ref="ResetAdminDataGridToDefaultViewActionGroup" stepKey="resetAdminDataGridToDefaultView"/> </before> <after> <actionGroup ref="AdminEnhancedMediaGalleryImageDetailsDeleteActionGroup" stepKey="deleteImage"/> diff --git a/MediaGalleryUi/Test/Mftf/Test/AdminMediaGalleryUploadCategoryImageTest.xml b/MediaGalleryUi/Test/Mftf/Test/AdminMediaGalleryUploadCategoryImageTest.xml index 7e58624cc145..0bf221870ede 100644 --- a/MediaGalleryUi/Test/Mftf/Test/AdminMediaGalleryUploadCategoryImageTest.xml +++ b/MediaGalleryUi/Test/Mftf/Test/AdminMediaGalleryUploadCategoryImageTest.xml @@ -24,6 +24,7 @@ </before> <after> <actionGroup ref="AdminOpenStandaloneMediaGalleryActionGroup" stepKey="openStandaloneMediaGallery"/> + <actionGroup ref="ResetAdminDataGridToDefaultViewActionGroup" stepKey="resetAdminDataGridToDefaultView"/> <actionGroup ref="AdminEnhancedMediaGalleryViewImageDetails" stepKey="viewContentImageDetails"/> <actionGroup ref="AdminEnhancedMediaGalleryImageDetailsDeleteActionGroup" stepKey="deleteCategoryImage"/> <deleteData createDataKey="category" stepKey="deleteCategory"/> diff --git a/MediaGalleryUi/Test/Mftf/Test/AdminMediaGalleryViewDetailsDeleteImageTest.xml b/MediaGalleryUi/Test/Mftf/Test/AdminMediaGalleryViewDetailsDeleteImageTest.xml index ea20142b5ad5..95ddcd2a2f98 100644 --- a/MediaGalleryUi/Test/Mftf/Test/AdminMediaGalleryViewDetailsDeleteImageTest.xml +++ b/MediaGalleryUi/Test/Mftf/Test/AdminMediaGalleryViewDetailsDeleteImageTest.xml @@ -23,12 +23,12 @@ <actionGroup ref="AdminOpenStandaloneMediaGalleryActionGroup" stepKey="openStandaloneMediaGallery"/> </before> <actionGroup ref="AdminEnhancedMediaGalleryUploadImageActionGroup" stepKey="uploadImage"> - <argument name="image" value="ImageUpload3"/> + <argument name="image" value="ImageUpload"/> </actionGroup> <actionGroup ref="AdminEnhancedMediaGalleryViewImageDetails" stepKey="viewImageDetails"/> <actionGroup ref="AdminEnhancedMediaGalleryImageDetailsDeleteActionGroup" stepKey="deleteImage"/> <actionGroup ref="AssertAdminEnhancedMediaGalleryImageDeletedActionGroup" stepKey="assertImageDeleted"> - <argument name="image" value="ImageUpload3"/> + <argument name="image" value="ImageUpload"/> </actionGroup> </test> </tests> diff --git a/MediaGalleryUi/Test/Unit/Model/UploadImageTest.php b/MediaGalleryUi/Test/Unit/Model/UploadImageTest.php index c260f78db724..ea0425a5e742 100644 --- a/MediaGalleryUi/Test/Unit/Model/UploadImageTest.php +++ b/MediaGalleryUi/Test/Unit/Model/UploadImageTest.php @@ -13,8 +13,6 @@ use Magento\Framework\Filesystem; use Magento\Framework\Filesystem\Directory\Read; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; -use Magento\MediaGallerySynchronizationApi\Api\SynchronizeFilesInterface; -use Magento\MediaGallerySynchronization\Model\Filesystem\SplFileInfoFactory; use Magento\MediaGalleryUi\Model\UploadImage; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; @@ -34,21 +32,11 @@ class UploadImageTest extends TestCase */ private $fileSystemMock; - /** - * @var SplFileInfoFactory|MockObject - */ - private $splFileInfoFactoryMock; - /** * @var Read|MockObject */ private $mediaDirectoryMock; - /** - * @var SynchronizeFilesInterface|MockObject - */ - private $synchronizeFilesMock; - /** * @var UploadImage */ @@ -61,17 +49,13 @@ protected function setUp(): void { $this->imagesStorageMock = $this->createMock(Storage::class); $this->fileSystemMock = $this->createMock(Filesystem::class); - $this->splFileInfoFactoryMock = $this->createMock(SplFileInfoFactory::class); $this->mediaDirectoryMock = $this->createMock(Read::class); - $this->synchronizeFilesMock = $this->createMock(SynchronizeFilesInterface::class); $this->uploadImage = (new ObjectManager($this))->getObject( UploadImage::class, [ 'imagesStorage' => $this->imagesStorageMock, - 'splFileInfoFactory' => $this->splFileInfoFactoryMock, 'filesystem' => $this->fileSystemMock, - 'synchronizeFiles' => $this->synchronizeFilesMock ] ); } @@ -108,12 +92,6 @@ public function testExecute(string $targetFolder, string $type = null, string $a ->with($absolutePath, $type) ->willReturn($uploadResult); - $fileInfoMock = $this->createMock(\SplFileInfo::class); - $this->splFileInfoFactoryMock->expects($this->once()) - ->method('create') - ->with($uploadResult['path'] . '/' . $uploadResult['file']) - ->willReturn($fileInfoMock); - $this->uploadImage->execute($targetFolder, $type); } diff --git a/MediaGalleryUi/composer.json b/MediaGalleryUi/composer.json index 7fc48e3d566c..40344ef14784 100644 --- a/MediaGalleryUi/composer.json +++ b/MediaGalleryUi/composer.json @@ -9,7 +9,6 @@ "magento/module-store": "*", "magento/module-media-gallery-ui-api": "*", "magento/module-media-gallery-api": "*", - "magento/module-media-gallery-synchronization": "*", "magento/module-media-gallery-synchronization-api": "*", "magento/module-media-content-api": "*", "magento/module-cms": "*" diff --git a/MediaGalleryUi/etc/di.xml b/MediaGalleryUi/etc/di.xml index 48cd74f63383..7c0a09e3a8ae 100644 --- a/MediaGalleryUi/etc/di.xml +++ b/MediaGalleryUi/etc/di.xml @@ -40,10 +40,9 @@ </argument> </arguments> </type> - <type name="Magento\MediaGallerySynchronization\Model\SynchronizeFiles"> + <type name="Magento\MediaGallerySynchronizationApi\Api\SynchronizeFilesInterface"> <plugin name="create_thumbnails_for_synced_fiels" type="Magento\MediaGalleryUi\Plugin\ResizeSyncedFiles"/> </type> - <type name="Magento\MediaGalleryUi\Model\AssetDetailsProvider\UsedIn"> <arguments> <argument name="contentTypes" xsi:type="array">