Created
May 13, 2021 00:15
-
-
Save 6ui11em/fc268d3d19c3dfa783eabf787d66de04 to your computer and use it in GitHub Desktop.
Magento 2: Add Youtube Video to product #video #magento2 #youtube
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/* Source: https://mage2.pro/t/topic/1741/11 */ | |
namespace Yourcompany\Yourmodule\Controller\Test; | |
use Magento\Framework\Api\Data\VideoContentInterface; | |
use Magento\Catalog\Api\Data\ProductAttributeMediaGalleryEntryInterface; | |
use Magento\Framework\App\Action\Context; | |
use Magento\ProductVideo\Model\Product\Attribute\Media\ExternalVideoEntryConverter; | |
use Magento\Store\Model\Store; | |
use Magento\Framework\Exception\InputException; | |
use Magento\Framework\Exception\StateException; | |
use Magento\Catalog\Api\Data\ProductInterface; | |
use Magento\Catalog\Api\Data\ProductInterfaceFactory; | |
class Test extends \Magento\Framework\App\Action\Action | |
{ | |
private $mimeTypes = [ | |
'png' => 'image/png', | |
'jpe' => 'image/jpeg', | |
'jpeg' => 'image/jpeg', | |
'jpg' => 'image/jpeg', | |
'gif' => 'image/gif', | |
'bmp' => 'image/bmp', | |
'ico' => 'image/vnd.microsoft.icon', | |
'tiff' => 'image/tiff', | |
'tif' => 'image/tiff', | |
'svg' => 'image/svg+xml', | |
'svgz' => 'image/svg+xml', | |
]; | |
private $defaultMimeType = 'application/octet-stream'; | |
private $productFactory; | |
private $externalVideoEntryConverter; | |
private $productRepository; | |
private $contentValidator; | |
private $curl; | |
private $imageContentFactory; | |
/** | |
* @param Context $context | |
* @param ProductInterfaceFactory $productFactory | |
* @param ExternalVideoEntryConverter $externalVideoEntryConverter | |
* @param \Magento\Catalog\Api\ProductRepositoryInterface $productRepository | |
* @param \Magento\Framework\Api\ImageContentValidatorInterface $contentValidator | |
* @param \Magento\Framework\HTTP\Adapter\Curl $curl | |
* @param \Magento\Framework\Api\Data\ImageContentInterfaceFactory $imageContentFactory | |
*/ | |
public function __construct( | |
Context $context, | |
ProductInterfaceFactory $productFactory, | |
ExternalVideoEntryConverter $externalVideoEntryConverter, | |
\Magento\Catalog\Api\ProductRepositoryInterface $productRepository, | |
\Magento\Framework\Api\ImageContentValidatorInterface $contentValidator, | |
\Magento\Framework\HTTP\Adapter\Curl $curl, | |
\Magento\Framework\Api\Data\ImageContentInterfaceFactory $imageContentFactory | |
) { | |
parent::__construct($context); | |
$this->productFactory = $productFactory; | |
$this->productRepository = $productRepository; | |
$this->externalVideoEntryConverter = $externalVideoEntryConverter; | |
$this->contentValidator = $contentValidator; | |
$this->curl = $curl; | |
$this->imageContentFactory = $imageContentFactory; | |
} | |
public function execute() | |
{ | |
$sampleProductId = 1; | |
/** @var ProductInterface $product */ | |
$sampleProduct = $this->productFactory->create()->load($sampleProductId); | |
// NB! Unless you have a multi store setup and need the video only for specific store, | |
// this has to be done or the video entry might get wrong store id (will only be visible on one store). | |
// See \Magento\ProductVideo\Model\Plugin\Catalog\Product\Gallery\CreateHandler function afterExecute(). | |
// However this is a hack and better way should be implemented to make sure video will get store id before save is called. | |
$sampleProduct->setStoreId(Store::DEFAULT_STORE_ID); | |
// Sample youtube video | |
$videoUrl = "https://www.youtube.com/watch?v=sGF6bOi1NfA"; | |
$videoId = "sGF6bOi1NfA"; | |
$videoLabel = "Cute pandas playing on the slide"; | |
$videoDescription = "What's more entertaining than watching a panda playing on a slide?"; | |
$videoProvider = "youtube"; | |
$thumbnailUrl = "https://i.ytimg.com/vi/sGF6bOi1NfA/hqdefault.jpg"; | |
// Check if video already exists, and if not, create a new one | |
if(!$this->isExistingVideo($sampleProduct, $videoUrl)){ | |
$videoEntry = $this->buildVideoEntry($sampleProduct, $videoUrl, $videoId, $videoLabel, $videoDescription, $videoProvider, $thumbnailUrl); | |
$this->addVideoForProduct($sampleProduct, $videoEntry); | |
}else{ | |
die('Video already exists!'); | |
} | |
} | |
/** | |
* @param ProductInterface $sampleProduct | |
* @param string $videoUrl | |
* @param string $videoId | |
* @param string $videoLabel | |
* @param string $videoDescription | |
* @param string $videoProvider | |
* @param string $thumbnailUrl | |
* | |
* @return ProductAttributeMediaGalleryEntryInterface | |
* @throws \Magento\Framework\Exception\LocalizedException | |
*/ | |
private function buildVideoEntry($sampleProduct, $videoUrl, $videoId, $videoLabel, $videoDescription, $videoProvider, $thumbnailUrl) | |
{ | |
// Build thumbnail image data for sample video | |
$parts = explode('/', $thumbnailUrl); | |
$thumbnailImageName = end($parts); | |
$thumbnailImage = $this->getRemoteImage($thumbnailUrl); // Fetch image from server | |
/** @var \Magento\Framework\Api\Data\ImageContentInterface $imageContent */ | |
$imageContent = $this->imageContentFactory->create(); | |
$imageContent->setName($videoProvider . '_' . $videoId) | |
->setType($this->getMimeContentType($thumbnailImageName)) | |
->setBase64EncodedData(base64_encode($thumbnailImage)); | |
// Build video data array for video entry converter | |
$generalMediaEntryData = [ | |
ProductAttributeMediaGalleryEntryInterface::LABEL => $videoLabel, | |
ProductAttributeMediaGalleryEntryInterface::TYPES => ['thumbnail', 'image', 'small_image'], // Optional, depends on what is wanted | |
ProductAttributeMediaGalleryEntryInterface::CONTENT => $imageContent, | |
ProductAttributeMediaGalleryEntryInterface::DISABLED => false | |
]; | |
$videoData = array_merge($generalMediaEntryData, [ | |
VideoContentInterface::TITLE => $videoLabel, | |
VideoContentInterface::DESCRIPTION => $videoDescription, | |
VideoContentInterface::PROVIDER => $videoProvider, | |
VideoContentInterface::METADATA => null, | |
VideoContentInterface::URL => $videoUrl, | |
VideoContentInterface::TYPE => ExternalVideoEntryConverter::MEDIA_TYPE_CODE, | |
]); | |
// Convert video data array to video entry | |
return $this->externalVideoEntryConverter->convertTo($sampleProduct, $videoData); | |
} | |
/** | |
* Copy of \Magento\Catalog\Api\ProductAttributeMediaGalleryManagementInterface create() function. | |
* Only difference is that we don't reload product with sku, and thus we don't lose store id 0 | |
* that we set earlier for sample product. | |
* | |
* @param ProductInterface $sampleProduct | |
* @param ProductAttributeMediaGalleryEntryInterface $videoEntry | |
* | |
* @return int|null | |
* @throws InputException | |
* @throws StateException | |
*/ | |
private function addVideoForProduct($sampleProduct, $videoEntry) | |
{ | |
/** @var $entry ProductAttributeMediaGalleryEntryInterface */ | |
$entryContent = $videoEntry->getContent(); | |
if (!$this->contentValidator->isValid($entryContent)) { | |
throw new InputException(__('The image content is not valid.')); | |
} | |
$existingMediaGalleryEntries = $sampleProduct->getMediaGalleryEntries(); | |
$existingEntryIds = []; | |
if ($existingMediaGalleryEntries == null) { | |
$existingMediaGalleryEntries = [$videoEntry]; | |
} else { | |
foreach ($existingMediaGalleryEntries as $existingEntries) { | |
$existingEntryIds[$existingEntries->getId()] = $existingEntries->getId(); | |
} | |
$existingMediaGalleryEntries[] = $videoEntry; | |
} | |
$sampleProduct->setMediaGalleryEntries($existingMediaGalleryEntries); | |
try { | |
$product = $this->productRepository->save($sampleProduct); | |
} catch (InputException $inputException) { | |
throw $inputException; | |
} catch (\Exception $e) { | |
throw new StateException(__('Cannot save product.')); | |
} | |
foreach ($product->getMediaGalleryEntries() as $entry) { | |
if (!isset($existingEntryIds[$entry->getId()])) { | |
return $entry->getId(); | |
} | |
} | |
throw new StateException(__('Failed to save new media gallery entry.')); | |
} | |
/** | |
* @param ProductInterface $sampleProduct | |
* @param string $url | |
* | |
* @return bool | |
*/ | |
private function isExistingVideo($sampleProduct, $url) | |
{ | |
if ($mediaEntries = $sampleProduct->getMediaGalleryEntries()) { | |
foreach($mediaEntries as $entryKey => $mediaEntry) { | |
if($mediaEntry->getMediaType() == ExternalVideoEntryConverter::MEDIA_TYPE_CODE) { | |
$videoUrl = $mediaEntry->getExtensionAttributes()->getVideoContent()->getVideoUrl(); | |
if($videoUrl == $url){ | |
return true; | |
} | |
} | |
} | |
} | |
return false; | |
} | |
/** | |
* @param string $fileUrl | |
* | |
* @return string | |
* @throws \Magento\Framework\Exception\LocalizedException | |
*/ | |
private function getRemoteImage($fileUrl) | |
{ | |
$this->curl->setConfig(['header' => false]); | |
$this->curl->write('GET', $fileUrl); | |
$image = $this->curl->read(); | |
if (empty($image)) { | |
throw new \Magento\Framework\Exception\LocalizedException( | |
__('Could not get preview image information. Please check your connection and try again.') | |
); | |
} | |
return $image; | |
} | |
/** | |
* @param string $filename | |
* | |
* @return string | |
*/ | |
private function getMimeContentType($filename) | |
{ | |
$parts = explode('.',$filename); | |
$ext = strtolower(array_pop($parts)); | |
if (array_key_exists($ext, $this->mimeTypes)) { | |
return $this->mimeTypes[$ext]; | |
} else { | |
return $this->defaultMimeType; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment