Skip to content

Commit 4d2a7b6

Browse files
committed
Merge remote-tracking branch 'origin/MC-15988' into badgers-pr
2 parents ec1d07a + de06e53 commit 4d2a7b6

File tree

8 files changed

+209
-22
lines changed

8 files changed

+209
-22
lines changed
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\CatalogGraphQl\Model;
9+
10+
use \Magento\Framework\GraphQl\Query\Resolver\TypeResolverInterface;
11+
12+
/**
13+
* Resolver for Media Gallery type.
14+
*/
15+
class MediaGalleryTypeResolver implements TypeResolverInterface
16+
{
17+
/**
18+
* @inheritdoc
19+
*
20+
* @param array $data
21+
* @return string
22+
*/
23+
public function resolveType(array $data) : string
24+
{
25+
// resolve type based on the data
26+
if (isset($data['media_type']) && $data['media_type'] == 'image') {
27+
return 'ProductImage';
28+
}
29+
if (isset($data['media_type']) && $data['media_type'] == 'external-video') {
30+
return 'ProductVideo';
31+
}
32+
}
33+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\CatalogGraphQl\Model\Resolver\Product;
9+
10+
use Magento\Framework\Exception\LocalizedException;
11+
use Magento\Framework\GraphQl\Query\Resolver\ContextInterface;
12+
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
13+
use Magento\Catalog\Api\Data\ProductInterface;
14+
use Magento\Framework\GraphQl\Config\Element\Field;
15+
use Magento\Framework\GraphQl\Query\ResolverInterface;
16+
17+
/**
18+
* @inheritdoc
19+
*
20+
* Format a product's media gallery information to conform to GraphQL schema representation
21+
*/
22+
class MediaGallery implements ResolverInterface
23+
{
24+
/**
25+
* @inheritdoc
26+
*
27+
* Format product's media gallery entry data to conform to GraphQL schema
28+
*
29+
* @param \Magento\Framework\GraphQl\Config\Element\Field $field
30+
* @param ContextInterface $context
31+
* @param ResolveInfo $info
32+
* @param array|null $value
33+
* @param array|null $args
34+
* @throws \Exception
35+
* @return array
36+
*/
37+
public function resolve(
38+
Field $field,
39+
$context,
40+
ResolveInfo $info,
41+
array $value = null,
42+
array $args = null
43+
) {
44+
if (!isset($value['model'])) {
45+
throw new LocalizedException(__('"model" value should be specified'));
46+
}
47+
48+
/** @var ProductInterface $product */
49+
$product = $value['model'];
50+
51+
$mediaGalleryEntries = [];
52+
foreach ($product->getMediaGalleryEntries() ?? [] as $key => $entry) {
53+
$mediaGalleryEntries[$key] = $entry->getData();
54+
$mediaGalleryEntries[$key]['model'] = $product;
55+
if ($entry->getExtensionAttributes() && $entry->getExtensionAttributes()->getVideoContent()) {
56+
$mediaGalleryEntries[$key]['video_content']
57+
= $entry->getExtensionAttributes()->getVideoContent()->getData();
58+
}
59+
}
60+
return $mediaGalleryEntries;
61+
}
62+
}

app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductImage/Label.php renamed to app/code/Magento/CatalogGraphQl/Model/Resolver/Product/MediaGallery/Label.php

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,18 @@
55
*/
66
declare(strict_types=1);
77

8-
namespace Magento\CatalogGraphQl\Model\Resolver\Product\ProductImage;
8+
namespace Magento\CatalogGraphQl\Model\Resolver\Product\MediaGallery;
99

1010
use Magento\Catalog\Model\Product;
1111
use Magento\Catalog\Model\ResourceModel\Product as ProductResourceModel;
1212
use Magento\Framework\Exception\LocalizedException;
1313
use Magento\Framework\GraphQl\Config\Element\Field;
1414
use Magento\Framework\GraphQl\Query\ResolverInterface;
1515
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
16+
use Magento\Store\Api\Data\StoreInterface;
1617

1718
/**
18-
* Returns product's image label
19+
* Return media label
1920
*/
2021
class Label implements ResolverInterface
2122
{
@@ -43,8 +44,9 @@ public function resolve(
4344
array $value = null,
4445
array $args = null
4546
) {
46-
if (!isset($value['image_type'])) {
47-
throw new LocalizedException(__('"image_type" value should be specified'));
47+
48+
if (isset($value['label'])) {
49+
return $value['label'];
4850
}
4951

5052
if (!isset($value['model'])) {
@@ -53,18 +55,16 @@ public function resolve(
5355

5456
/** @var Product $product */
5557
$product = $value['model'];
56-
$imageType = $value['image_type'];
57-
$imagePath = $product->getData($imageType);
5858
$productId = (int)$product->getEntityId();
59-
$storeId = (int)$context->getExtensionAttributes()->getStore()->getId();
60-
61-
// null if image is not set
62-
if (null === $imagePath) {
59+
/** @var StoreInterface $store */
60+
$store = $context->getExtensionAttributes()->getStore();
61+
$storeId = (int)$store->getId();
62+
if (!isset($value['image_type'])) {
6363
return $this->getAttributeValue($productId, 'name', $storeId);
6464
}
65-
65+
$imageType = $value['image_type'];
6666
$imageLabel = $this->getAttributeValue($productId, $imageType . '_label', $storeId);
67-
if (null === $imageLabel) {
67+
if ($imageLabel == null) {
6868
$imageLabel = $this->getAttributeValue($productId, 'name', $storeId);
6969
}
7070

app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductImage/Url.php renamed to app/code/Magento/CatalogGraphQl/Model/Resolver/Product/MediaGallery/Url.php

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
*/
66
declare(strict_types=1);
77

8-
namespace Magento\CatalogGraphQl\Model\Resolver\Product\ProductImage;
8+
namespace Magento\CatalogGraphQl\Model\Resolver\Product\MediaGallery;
99

1010
use Magento\Catalog\Model\Product;
1111
use Magento\Catalog\Model\Product\ImageFactory;
@@ -16,7 +16,7 @@
1616
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
1717

1818
/**
19-
* Returns product's image url
19+
* Returns media url
2020
*/
2121
class Url implements ResolverInterface
2222
{
@@ -51,7 +51,7 @@ public function resolve(
5151
array $value = null,
5252
array $args = null
5353
) {
54-
if (!isset($value['image_type'])) {
54+
if (!isset($value['image_type']) && !isset($value['file'])) {
5555
throw new LocalizedException(__('"image_type" value should be specified'));
5656
}
5757

@@ -61,9 +61,17 @@ public function resolve(
6161

6262
/** @var Product $product */
6363
$product = $value['model'];
64-
$imagePath = $product->getData($value['image_type']);
65-
66-
return $this->getImageUrl($value['image_type'], $imagePath);
64+
if (isset($value['image_type'])) {
65+
$imagePath = $product->getData($value['image_type']);
66+
return $this->getImageUrl($value['image_type'], $imagePath);
67+
}
68+
if (isset($value['file'])) {
69+
$image = $this->productImageFactory->create();
70+
$image->setDestinationSubdir('image')->setBaseFile($value['file']);
71+
$imageUrl = $image->getUrl();
72+
return $imageUrl;
73+
}
74+
return [];
6775
}
6876

6977
/**

app/code/Magento/CatalogGraphQl/Model/Resolver/Product/MediaGalleryEntries.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
* @inheritdoc
1919
*
2020
* Format a product's media gallery information to conform to GraphQL schema representation
21+
* @deprecated
2122
*/
2223
class MediaGalleryEntries implements ResolverInterface
2324
{

app/code/Magento/CatalogGraphQl/Model/Resolver/Products/DataProvider/Product.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,9 @@ public function getList(
8989
if (in_array('media_gallery_entries', $attributes)) {
9090
$collection->addMediaGalleryData();
9191
}
92+
if (in_array('media_gallery', $attributes)) {
93+
$collection->addMediaGalleryData();
94+
}
9295
if (in_array('options', $attributes)) {
9396
$collection->addOptionsToResult();
9497
}

app/code/Magento/CatalogGraphQl/etc/schema.graphqls

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -92,13 +92,14 @@ interface ProductInterface @typeResolver(class: "Magento\\CatalogGraphQl\\Model\
9292
type_id: String @doc(description: "One of simple, virtual, bundle, downloadable, grouped, or configurable.")
9393
websites: [Website] @doc(description: "An array of websites in which the product is available.") @resolver(class: "Magento\\CatalogGraphQl\\Model\\Resolver\\Product\\Websites")
9494
product_links: [ProductLinksInterface] @doc(description: "An array of ProductLinks objects.") @resolver(class: "Magento\\CatalogGraphQl\\Model\\Resolver\\Product\\ProductLinks")
95-
media_gallery_entries: [MediaGalleryEntry] @doc(description: "An array of MediaGalleryEntry objects.") @resolver(class: "Magento\\CatalogGraphQl\\Model\\Resolver\\Product\\MediaGalleryEntries")
95+
media_gallery_entries: [MediaGalleryEntry] @deprecated(reason: "Use product's `media_gallery` instead") @doc(description: "An array of MediaGalleryEntry objects.") @resolver(class: "Magento\\CatalogGraphQl\\Model\\Resolver\\Product\\MediaGalleryEntries")
9696
tier_prices: [ProductTierPrices] @doc(description: "An array of ProductTierPrices objects.") @resolver(class: "Magento\\CatalogGraphQl\\Model\\Resolver\\Product\\TierPrices")
9797
price: ProductPrices @doc(description: "A ProductPrices object, indicating the price of an item.") @resolver(class: "Magento\\CatalogGraphQl\\Model\\Resolver\\Product\\Price")
9898
gift_message_available: String @doc(description: "Indicates whether a gift message is available.")
9999
manufacturer: Int @doc(description: "A number representing the product's manufacturer.")
100100
categories: [CategoryInterface] @doc(description: "The categories assigned to a product.") @resolver(class: "Magento\\CatalogGraphQl\\Model\\Resolver\\Categories") @cache(cacheIdentity: "Magento\\CatalogGraphQl\\Model\\Resolver\\Category\\CategoriesIdentity")
101101
canonical_url: String @doc(description: "Canonical URL.") @resolver(class: "Magento\\CatalogGraphQl\\Model\\Resolver\\Product\\CanonicalUrl")
102+
media_gallery: [MediaGalleryInterface] @doc(description: "An array of Media Gallery objects.") @resolver(class: "Magento\\CatalogGraphQl\\Model\\Resolver\\Product\\MediaGallery")
102103
}
103104

104105
interface PhysicalProductInterface @typeResolver(class: "Magento\\CatalogGraphQl\\Model\\ProductInterfaceTypeResolverComposite") @doc(description: "PhysicalProductInterface contains attributes specific to tangible products.") {
@@ -184,9 +185,12 @@ type CustomizableFileValue @doc(description: "CustomizableFileValue defines the
184185
image_size_y: Int @doc(description: "The maximum height of an image.")
185186
}
186187

187-
type ProductImage @doc(description: "Product image information. Contains image relative path, URL and label.") {
188-
url: String @resolver(class: "Magento\\CatalogGraphQl\\Model\\Resolver\\Product\\ProductImage\\Url")
189-
label: String @resolver(class: "Magento\\CatalogGraphQl\\Model\\Resolver\\Product\\ProductImage\\Label")
188+
interface MediaGalleryInterface @doc(description: "Contains basic information about a product image or video.") @typeResolver(class: "Magento\\CatalogGraphQl\\Model\\MediaGalleryTypeResolver") {
189+
url: String @doc(description: "The URL of the product image or video.") @resolver(class: "Magento\\CatalogGraphQl\\Model\\Resolver\\Product\\MediaGallery\\Url")
190+
label: String @doc(description: "The label of the product image or video.") @resolver(class: "Magento\\CatalogGraphQl\\Model\\Resolver\\Product\\MediaGallery\\Label")
191+
}
192+
193+
type ProductImage implements MediaGalleryInterface @doc(description: "Product image information. Contains the image URL and label.") {
190194
}
191195

192196
interface CustomizableOptionInterface @typeResolver(class: "Magento\\CatalogGraphQl\\Model\\CustomizableOptionTypeResolver") @doc(description: "The CustomizableOptionInterface contains basic information about a customizable option. It can be implemented by several types of configurable options.") {
@@ -413,3 +417,7 @@ type StoreConfig @doc(description: "The type contains information about a store
413417
list_per_page : Int @doc(description: "Products per Page on List Default Value.")
414418
catalog_default_sort_by : String @doc(description: "Default Sort By.")
415419
}
420+
421+
type ProductVideo @doc(description: "Contains information about a product video.") implements MediaGalleryInterface {
422+
video_content: ProductMediaGalleryEntriesVideoContent @doc(description: "Contains a ProductMediaGalleryEntriesVideoContent object.")
423+
}

dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/MediaGalleryTest.php

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,78 @@ public function testMediaGalleryTypesAreCorrect()
8282
$this->assertEquals(['thumbnail', 'swatch_image'], $mediaGallery[1]['types']);
8383
}
8484

85+
/**
86+
* @magentoApiDataFixture Magento/Catalog/_files/product_with_multiple_images.php
87+
*/
88+
public function testMediaGallery()
89+
{
90+
$productSku = 'simple';
91+
$query = <<<QUERY
92+
{
93+
products(filter: {sku: {eq: "{$productSku}"}}) {
94+
items {
95+
media_gallery {
96+
label
97+
url
98+
}
99+
}
100+
}
101+
}
102+
QUERY;
103+
$response = $this->graphQlQuery($query);
104+
$this->assertNotEmpty($response['products']['items'][0]['media_gallery']);
105+
$mediaGallery = $response['products']['items'][0]['media_gallery'];
106+
$this->assertCount(2, $mediaGallery);
107+
$this->assertEquals('Image Alt Text', $mediaGallery[0]['label']);
108+
self::assertTrue($this->checkImageExists($mediaGallery[0]['url']));
109+
$this->assertEquals('Thumbnail Image', $mediaGallery[1]['label']);
110+
self::assertTrue($this->checkImageExists($mediaGallery[1]['url']));
111+
}
112+
113+
/**
114+
* @magentoApiDataFixture Magento/Catalog/_files/product_simple_with_media_gallery_entries.php
115+
*/
116+
public function testMediaGalleryForProductVideos()
117+
{
118+
$productSku = 'simple';
119+
$query = <<<QUERY
120+
{
121+
products(filter: {sku: {eq: "{$productSku}"}}) {
122+
items {
123+
media_gallery {
124+
label
125+
url
126+
... on ProductVideo {
127+
video_content {
128+
media_type
129+
video_provider
130+
video_url
131+
video_title
132+
video_description
133+
video_metadata
134+
}
135+
}
136+
}
137+
}
138+
}
139+
}
140+
QUERY;
141+
$response = $this->graphQlQuery($query);
142+
$this->assertNotEmpty($response['products']['items'][0]['media_gallery']);
143+
$mediaGallery = $response['products']['items'][0]['media_gallery'];
144+
$this->assertCount(1, $mediaGallery);
145+
$this->assertEquals('Video Label', $mediaGallery[0]['label']);
146+
self::assertTrue($this->checkImageExists($mediaGallery[0]['url']));
147+
$this->assertNotEmpty($mediaGallery[0]['video_content']);
148+
$video_content = $mediaGallery[0]['video_content'];
149+
$this->assertEquals('external-video', $video_content['media_type']);
150+
$this->assertEquals('youtube', $video_content['video_provider']);
151+
$this->assertEquals('http://www.youtube.com/v/tH_2PFNmWoga', $video_content['video_url']);
152+
$this->assertEquals('Video title', $video_content['video_title']);
153+
$this->assertEquals('Video description', $video_content['video_description']);
154+
$this->assertEquals('Video Metadata', $video_content['video_metadata']);
155+
}
156+
85157
/**
86158
* @magentoApiDataFixture Magento/Catalog/_files/product_with_image.php
87159
*/

0 commit comments

Comments
 (0)