Skip to content

Commit a7cc288

Browse files
Merge remote-tracking branch 'mainline/2.3-develop' into MAGETWO-87492_2.3-upgrade-changes
2 parents bd52197 + 92c3ac6 commit a7cc288

File tree

7 files changed

+271
-1
lines changed

7 files changed

+271
-1
lines changed
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
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\Category;
9+
10+
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
11+
use Magento\Framework\GraphQl\Config\Element\Field;
12+
use Magento\Framework\GraphQl\Query\Resolver\Value;
13+
use Magento\Framework\GraphQl\Query\Resolver\ValueFactory;
14+
use Magento\Framework\GraphQl\Query\ResolverInterface;
15+
16+
/**
17+
* Retrieves the sort fields data
18+
*/
19+
class SortFields implements ResolverInterface
20+
{
21+
/**
22+
* @var ValueFactory
23+
*/
24+
private $valueFactory;
25+
26+
/**
27+
* @var \Magento\Catalog\Model\Config
28+
*/
29+
private $catalogConfig;
30+
31+
/**
32+
* @var \Magento\Store\Model\StoreManagerInterface
33+
*/
34+
private $storeManager;
35+
36+
/**
37+
* @var \Magento\Catalog\Model\Category\Attribute\Source\Sortby
38+
*/
39+
private $sortbyAttributeSource;
40+
41+
/**
42+
* @param ValueFactory $valueFactory
43+
* @param \Magento\Catalog\Model\Config $catalogConfig
44+
* @param \Magento\Store\Model\StoreManagerInterface $storeManager
45+
* @oaram \Magento\Catalog\Model\Category\Attribute\Source\Sortby $sortbyAttributeSource
46+
*/
47+
public function __construct(
48+
ValueFactory $valueFactory,
49+
\Magento\Catalog\Model\Config $catalogConfig,
50+
\Magento\Store\Model\StoreManagerInterface $storeManager,
51+
\Magento\Catalog\Model\Category\Attribute\Source\Sortby $sortbyAttributeSource
52+
) {
53+
$this->valueFactory = $valueFactory;
54+
$this->catalogConfig = $catalogConfig;
55+
$this->storeManager = $storeManager;
56+
$this->sortbyAttributeSource = $sortbyAttributeSource;
57+
}
58+
59+
/**
60+
* {@inheritDoc}
61+
*/
62+
public function resolve(Field $field, $context, ResolveInfo $info, array $value = null, array $args = null) : Value
63+
{
64+
$sortFieldsOptions = $this->sortbyAttributeSource->getAllOptions();
65+
array_walk(
66+
$sortFieldsOptions,
67+
function (&$option) {
68+
$option['label'] = (string)$option['label'];
69+
}
70+
);
71+
$data = [
72+
'default' => $this->catalogConfig->getProductListDefaultSortBy($this->storeManager->getStore()->getId()),
73+
'options' => $sortFieldsOptions,
74+
];
75+
76+
$result = function () use ($data) {
77+
return $data;
78+
};
79+
80+
return $this->valueFactory->create($result);
81+
}
82+
}
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\Catalog\Model\Product;
11+
use Magento\Framework\GraphQl\Config\Element\Field;
12+
use Magento\Framework\GraphQl\Query\Resolver\Value;
13+
use Magento\Framework\GraphQl\Query\Resolver\ValueFactory;
14+
use Magento\Framework\GraphQl\Query\ResolverInterface;
15+
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
16+
17+
/**
18+
* Resolve data for product canonical URL
19+
*/
20+
class CanonicalUrl implements ResolverInterface
21+
{
22+
/**
23+
* @var ValueFactory
24+
*/
25+
private $valueFactory;
26+
27+
/**
28+
* @param ValueFactory $valueFactory
29+
*/
30+
public function __construct(
31+
ValueFactory $valueFactory
32+
) {
33+
$this->valueFactory = $valueFactory;
34+
}
35+
36+
/**
37+
* {@inheritdoc}
38+
*/
39+
public function resolve(
40+
Field $field,
41+
$context,
42+
ResolveInfo $info,
43+
array $value = null,
44+
array $args = null
45+
): Value {
46+
if (!isset($value['model'])) {
47+
$result = function () {
48+
return null;
49+
};
50+
return $this->valueFactory->create($result);
51+
}
52+
53+
/* @var $product Product */
54+
$product = $value['model'];
55+
$url = $product->getUrlModel()->getUrl($product, ['_ignore_category' => true]);
56+
$result = function () use ($url) {
57+
return $url;
58+
};
59+
60+
return $this->valueFactory->create($result);
61+
}
62+
}
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
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\Test\Unit\Model\Resolver\Product;
9+
10+
use Magento\CatalogGraphQl\Model\Resolver\Product\CanonicalUrl;
11+
use Magento\CatalogUrlRewrite\Model\ProductUrlPathGenerator;
12+
use Magento\Framework\GraphQl\Query\Resolver\Value;
13+
use Magento\Framework\GraphQl\Query\Resolver\ValueFactory;
14+
use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
15+
use Magento\Store\Model\StoreManagerInterface;
16+
use PHPUnit\Framework\TestCase;
17+
18+
class CanonicalUrlTest extends TestCase
19+
{
20+
/**
21+
* @var ObjectManager
22+
*/
23+
private $objectManager;
24+
25+
/**
26+
* @var CanonicalUrl
27+
*/
28+
private $subject;
29+
30+
/**
31+
* @var \PHPUnit_Framework_MockObject_MockObject
32+
*/
33+
private $mockValueFactory;
34+
35+
/**
36+
* @var \PHPUnit_Framework_MockObject_MockObject
37+
*/
38+
private $mockStoreManager;
39+
40+
public function testReturnsNullWhenNoProductAvailable()
41+
{
42+
$mockField = $this->getMockBuilder(\Magento\Framework\GraphQl\Config\Element\Field::class)
43+
->disableOriginalConstructor()
44+
->getMock();
45+
$mockInfo = $this->getMockBuilder(\Magento\Framework\GraphQl\Schema\Type\ResolveInfo::class)
46+
->disableOriginalConstructor()
47+
->getMock();
48+
49+
$this->mockValueFactory->method('create')->with(
50+
$this->callback(
51+
function ($param) {
52+
return $param() === null;
53+
}
54+
)
55+
);
56+
57+
$this->subject->resolve($mockField, '', $mockInfo, [], []);
58+
}
59+
60+
protected function setUp()
61+
{
62+
parent::setUp();
63+
$this->objectManager = new ObjectManager($this);
64+
$this->mockStoreManager = $this->getMockBuilder(StoreManagerInterface::class)->getMock();
65+
$this->mockValueFactory = $this->getMockBuilder(ValueFactory::class)
66+
->disableOriginalConstructor()
67+
->getMock();
68+
69+
$this->mockValueFactory->method('create')->willReturn(
70+
$this->objectManager->getObject(
71+
Value::class,
72+
['callback' => function () {
73+
return '';
74+
}]
75+
)
76+
);
77+
78+
$mockProductUrlPathGenerator = $this->getMockBuilder(ProductUrlPathGenerator::class)
79+
->disableOriginalConstructor()
80+
->getMock();
81+
$mockProductUrlPathGenerator->method('getUrlPathWithSuffix')->willReturn('product_url.html');
82+
83+
$this->subject = $this->objectManager->getObject(
84+
CanonicalUrl::class,
85+
[
86+
'valueFactory' => $this->mockValueFactory,
87+
'storeManager' => $this->mockStoreManager,
88+
'productUrlPathGenerator' => $mockProductUrlPathGenerator
89+
]
90+
);
91+
}
92+
}

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,7 @@ interface ProductInterface @typeResolver(class: "Magento\\CatalogGraphQl\\Model\
279279
gift_message_available: String @doc(description: "Indicates whether a gift message is available")
280280
manufacturer: Int @doc(description: "A number representing the product's manufacturer")
281281
categories: [CategoryInterface] @doc(description: "The categories assigned to a product") @resolver(class: "Magento\\CatalogGraphQl\\Model\\Resolver\\Category")
282+
canonical_url: String @doc(description: "Canonical URL") @resolver(class: "Magento\\CatalogGraphQl\\Model\\Resolver\\Product\\CanonicalUrl")
282283
}
283284

284285
interface PhysicalProductInterface @typeResolver(class: "Magento\\CatalogGraphQl\\Model\\ProductInterfaceTypeResolverComposite") @doc(description: "PhysicalProductInterface contains attributes specific to tangible products") {
@@ -402,6 +403,7 @@ type Products @doc(description: "The Products object is the top-level object ret
402403
page_info: SearchResultPageInfo @doc(description: "An object that includes the page_info and currentPage values specified in the query")
403404
total_count: Int @doc(description: "The number of products returned")
404405
filters: [LayerFilter] @doc(description: "Layered navigation filters array")
406+
sort_fields: SortFields @doc(description: "An object that includes the default sort field and all available sort fields") @resolver(class: "Magento\\CatalogGraphQl\\Model\\Resolver\\Category\\SortFields")
405407
}
406408

407409
input ProductFilterInput @doc(description: "ProductFilterInput defines the filters to be used in the search. A filter contains at least one attribute, a comparison operator, and the value that is being searched for.") {
@@ -521,3 +523,13 @@ interface LayerFilterItemInterface @typeResolver(class: "Magento\\CatalogGraphQl
521523
type LayerFilterItem implements LayerFilterItemInterface {
522524

523525
}
526+
527+
type SortField {
528+
value: String @doc(description: "Attribute code of sort field")
529+
label: String @doc(description: "Label of sort field")
530+
}
531+
532+
type SortFields @doc(description: "SortFields contains a default value for sort fields and all available sort fields") {
533+
default: String @doc(description: "Default value of sort fields")
534+
options: [SortField] @doc(description: "Available sort fields")
535+
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,4 @@ type SearchResultPageInfo @doc(description: "SearchResultPageInfo provides navig
3030
enum SortEnum @doc(description: "This enumeration indicates whether to return results in ascending or descending order") {
3131
ASC
3232
DESC
33-
}
33+
}

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

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -512,6 +512,15 @@ public function testQueryProductsInCurrentPageSortedByPriceASC()
512512
page_size
513513
current_page
514514
}
515+
sort_fields
516+
{
517+
default
518+
options
519+
{
520+
value
521+
label
522+
}
523+
}
515524
}
516525
}
517526
QUERY;
@@ -530,6 +539,13 @@ public function testQueryProductsInCurrentPageSortedByPriceASC()
530539
$this->assertProductItems($filteredChildProducts, $response);
531540
$this->assertEquals(4, $response['products']['page_info']['page_size']);
532541
$this->assertEquals(1, $response['products']['page_info']['current_page']);
542+
$this->assertArrayHasKey('sort_fields', $response['products']);
543+
$this->assertArrayHasKey('options', $response['products']['sort_fields']);
544+
$this->assertArrayHasKey('default', $response['products']['sort_fields']);
545+
$this->assertEquals('position', $response['products']['sort_fields']['default']);
546+
$this->assertArrayHasKey('value', $response['products']['sort_fields']['options'][0]);
547+
$this->assertArrayHasKey('label', $response['products']['sort_fields']['options'][0]);
548+
$this->assertEquals('position', $response['products']['sort_fields']['options'][0]['value']);
533549
}
534550

535551
/**

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,7 @@ public function testQueryAllFieldsSimpleProduct()
227227
updated_at
228228
url_key
229229
url_path
230+
canonical_url
230231
websites { id name code sort_order default_group_id is_default }
231232
... on PhysicalProductInterface {
232233
weight
@@ -272,6 +273,11 @@ public function testQueryAllFieldsSimpleProduct()
272273
'Filter category',
273274
$responseObject->getData('products/items/0/categories/2/name')
274275
);
276+
$storeManager = ObjectManager::getInstance()->get(\Magento\Store\Model\StoreManagerInterface::class);
277+
self::assertEquals(
278+
$storeManager->getStore()->getBaseUrl() . 'simple-product.html',
279+
$responseObject->getData('products/items/0/canonical_url')
280+
);
275281
}
276282

277283
/**

0 commit comments

Comments
 (0)