Skip to content
This repository was archived by the owner on Apr 29, 2019. It is now read-only.

Commit d6c15d6

Browse files
Return full canonical product URL within product object
1 parent 4832a75 commit d6c15d6

File tree

4 files changed

+233
-0
lines changed

4 files changed

+233
-0
lines changed
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
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+
class CanonicalUrl implements ResolverInterface
18+
{
19+
/**
20+
* @var ValueFactory
21+
*/
22+
private $valueFactory;
23+
24+
/**
25+
* @param ValueFactory $valueFactory
26+
*/
27+
public function __construct(
28+
ValueFactory $valueFactory
29+
) {
30+
$this->valueFactory = $valueFactory;
31+
}
32+
33+
/**
34+
* Fetches the data from persistence models and format it according to the GraphQL schema.
35+
*
36+
* @param \Magento\Framework\GraphQl\Config\Element\Field $field
37+
* @param $context
38+
* @param ResolveInfo $info
39+
* @param array|null $value
40+
* @param array|null $args
41+
* @throws \Exception
42+
* @return Value
43+
*/
44+
public function resolve(
45+
Field $field,
46+
$context,
47+
ResolveInfo $info,
48+
array $value = null,
49+
array $args = null
50+
): Value {
51+
if (!isset($value['model'])) {
52+
$result = function () {
53+
return null;
54+
};
55+
return $this->valueFactory->create($result);
56+
}
57+
58+
/* @var $product Product */
59+
$product = $value['model'];
60+
$url = $product->getUrlModel()->getUrl($product, ['_ignore_category' => true]);
61+
$result = function () use ($url) {
62+
return $url;
63+
};
64+
65+
return $this->valueFactory->create($result);
66+
}
67+
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
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\Integration\Model;
9+
10+
use Magento\Framework\App\Request\Http as HttpRequest;
11+
use Magento\Framework\Serialize\SerializerInterface;
12+
use Magento\GraphQl\Controller\GraphQl as GraphQlController;
13+
use Magento\TestFramework\ObjectManager;
14+
use PHPUnit\Framework\TestCase;
15+
16+
class ProductsTest extends TestCase
17+
{
18+
/**
19+
* @var SerializerInterface
20+
*/
21+
private $jsonSerializer;
22+
/**
23+
* @var ObjectManager
24+
*/
25+
private $objectManager;
26+
/**
27+
* @var GraphQlController
28+
*/
29+
private $graphql;
30+
31+
protected function setUp() : void
32+
{
33+
$this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager();
34+
$this->graphql = $this->objectManager->get(\Magento\GraphQl\Controller\GraphQl::class);
35+
$this->jsonSerializer = $this->objectManager->get(SerializerInterface::class);
36+
}
37+
38+
/**
39+
* @magentoAppArea graphql
40+
* @magentoDataFixture Magento/CatalogUrlRewrite/_files/product_with_category.php
41+
* @magentoDbIsolation disabled
42+
* @magentoConfigFixture default_store catalog/seo/product_url_suffix .html
43+
*/
44+
public function testResponseContainsCanonicalURLs(): void
45+
{
46+
$fixtureSku = 'p002';
47+
$query = <<<QUERY
48+
{
49+
products(filter: {sku: {eq: "$fixtureSku"}})
50+
{
51+
items {
52+
sku
53+
canonical_url
54+
}
55+
}
56+
}
57+
QUERY;
58+
$postData = ['query' => $query];
59+
$request = $this->objectManager->get(HttpRequest::class);
60+
$request->setPathInfo('/graphql');
61+
$request->setContent(json_encode($postData));
62+
$headers = $this->objectManager->create(\Zend\Http\Headers::class)
63+
->addHeaders(['Content-Type' => 'application/json']);
64+
$request->setHeaders($headers);
65+
66+
$response = $this->graphql->dispatch($request);
67+
$output = $this->jsonSerializer->unserialize($response->getContent());
68+
$canonical_url = $output['data']['products']['items'][0]['canonical_url'];
69+
70+
$this->assertArrayNotHasKey('errors', $output, 'Response has errors');
71+
$this->assertEquals('http://localhost/index.php/' . $fixtureSku . '.html', $canonical_url);
72+
}
73+
}
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: 1 addition & 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") {

0 commit comments

Comments
 (0)