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

GraphQl-198: Products: access to related/up-sell/cross-sell product fields #371

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 8 additions & 39 deletions app/code/Magento/CatalogGraphQl/Model/Resolver/Product.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,13 @@

namespace Magento\CatalogGraphQl\Model\Resolver;

use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
use Magento\CatalogGraphQl\Model\Resolver\Product\ProductFieldsSelector;
use Magento\CatalogGraphQl\Model\Resolver\Products\DataProvider\Deferred\Product as ProductDataProvider;
use Magento\Framework\GraphQl\Config\Element\Field;
use Magento\Framework\GraphQl\Exception\GraphQlInputException;
use Magento\Framework\GraphQl\Query\FieldTranslator;
use Magento\Framework\GraphQl\Query\Resolver\Value;
use Magento\Framework\GraphQl\Query\Resolver\ValueFactory;
use Magento\Framework\GraphQl\Query\ResolverInterface;
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;

/**
* @inheritdoc
Expand All @@ -32,23 +31,23 @@ class Product implements ResolverInterface
private $valueFactory;

/**
* @var FieldTranslator
* @var ProductFieldsSelector
*/
private $fieldTranslator;
private $productFieldsSelector;

/**
* @param ProductDataProvider $productDataProvider
* @param ValueFactory $valueFactory
* @param FieldTranslator $fieldTranslator
* @param ProductFieldsSelector $productFieldsSelector
*/
public function __construct(
ProductDataProvider $productDataProvider,
ValueFactory $valueFactory,
FieldTranslator $fieldTranslator
ProductFieldsSelector $productFieldsSelector
) {
$this->productDataProvider = $productDataProvider;
$this->valueFactory = $valueFactory;
$this->fieldTranslator = $fieldTranslator;
$this->productFieldsSelector = $productFieldsSelector;
}

/**
Expand All @@ -60,7 +59,7 @@ public function resolve(Field $field, $context, ResolveInfo $info, array $value
throw new GraphQlInputException(__('No child sku found for product link.'));
}
$this->productDataProvider->addProductSku($value['sku']);
$fields = $this->getProductFields($info);
$fields = $this->productFieldsSelector->getProductFieldsFromInfo($info);
$this->productDataProvider->addEavAttributes($fields);

$result = function () use ($value) {
Expand All @@ -86,34 +85,4 @@ public function resolve(Field $field, $context, ResolveInfo $info, array $value

return $this->valueFactory->create($result);
}

/**
* Return field names for all requested product fields.
*
* @param ResolveInfo $info
* @return string[]
*/
private function getProductFields(ResolveInfo $info) : array
{
$fieldNames = [];
foreach ($info->fieldNodes as $node) {
if ($node->name->value !== 'product') {
continue;
}
foreach ($node->selectionSet->selections as $selectionNode) {
if ($selectionNode->kind === 'InlineFragment') {
foreach ($selectionNode->selectionSet->selections as $inlineSelection) {
if ($inlineSelection->kind === 'InlineFragment') {
continue;
}
$fieldNames[] = $this->fieldTranslator->translate($inlineSelection->name->value);
}
continue;
}
$fieldNames[] = $this->fieldTranslator->translate($selectionNode->name->value);
}
}

return $fieldNames;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);

namespace Magento\CatalogGraphQl\Model\Resolver\Product;

use Magento\Framework\GraphQl\Query\FieldTranslator;
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;

/**
* Select Product Fields From Resolve Info
*/
class ProductFieldsSelector
{
/**
* @var FieldTranslator
*/
private $fieldTranslator;

/**
* @param FieldTranslator $fieldTranslator
*/
public function __construct(FieldTranslator $fieldTranslator)
{
$this->fieldTranslator = $fieldTranslator;
}

/**
* Return field names for all requested product fields.
*
* @param ResolveInfo $info
* @param string $productNodeName
* @return string[]
*/
public function getProductFieldsFromInfo(ResolveInfo $info, string $productNodeName = 'product') : array
{
$fieldNames = [];
foreach ($info->fieldNodes as $node) {
if ($node->name->value !== $productNodeName) {
continue;
}
foreach ($node->selectionSet->selections as $selectionNode) {
if ($selectionNode->kind === 'InlineFragment') {
foreach ($selectionNode->selectionSet->selections as $inlineSelection) {
if ($inlineSelection->kind === 'InlineFragment') {
continue;
}
$fieldNames[] = $this->fieldTranslator->translate($inlineSelection->name->value);
}
continue;
}
$fieldNames[] = $this->fieldTranslator->translate($selectionNode->name->value);
}
}

return $fieldNames;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);

namespace Magento\RelatedProductGraphQl\Model\DataProvider;

use Magento\Catalog\Model\Product;
use Magento\Catalog\Model\Product\Link;
use Magento\Catalog\Model\Product\LinkFactory;

/**
* Related Products Data Provider
*/
class RelatedProductDataProvider
{
/**
* @var LinkFactory
*/
private $linkFactory;

/**
* @param LinkFactory $linkFactory
*/
public function __construct(
LinkFactory $linkFactory
) {
$this->linkFactory = $linkFactory;
}

/**
* Related Products Data
*
* @param Product $product
* @param array $fields
* @param int $linkType
* @return array
*/
public function getData(Product $product, array $fields, int $linkType): array
{
$relatedProducts = $this->getRelatedProducts($product, $fields, $linkType);

$productsData = [];
foreach ($relatedProducts as $relatedProduct) {
$productData = $relatedProduct->getData();
$productData['model'] = $relatedProduct;
$productsData[] = $productData;
}
return $productsData;
}

/**
* Get Related Products
*
* @param Product $product
* @param array $fields
* @param int $linkType
* @return Product[]
*/
private function getRelatedProducts(Product $product, array $fields, int $linkType): array
{
/** @var Link $link */
$link = $this->linkFactory->create([ 'data' => [
'link_type_id' => $linkType,
]]);

$collection = $link->getProductCollection();
$collection->setIsStrongMode();
foreach ($fields as $field) {
$collection->addAttributeToSelect($field);
}
$collection->setProduct($product);

return $collection->getItems();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);

namespace Magento\RelatedProductGraphQl\Model\Resolver;

use Magento\Catalog\Model\Product\Link;
use Magento\CatalogGraphQl\Model\Resolver\Product\ProductFieldsSelector;
use Magento\Framework\Exception\LocalizedException;
use Magento\RelatedProductGraphQl\Model\DataProvider\RelatedProductDataProvider;
use Magento\Framework\GraphQl\Config\Element\Field;
use Magento\Framework\GraphQl\Query\ResolverInterface;
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;

/**
* CrossSell Products Resolver
*/
class CrossSellProducts implements ResolverInterface
{
/**
* @var ProductFieldsSelector
*/
private $productFieldsSelector;

/**
* @var RelatedProductDataProvider
*/
private $relatedProductDataProvider;

/**
* @param ProductFieldsSelector $productFieldsSelector
* @param RelatedProductDataProvider $relatedProductDataProvider
*/
public function __construct(
ProductFieldsSelector $productFieldsSelector,
RelatedProductDataProvider $relatedProductDataProvider
) {
$this->productFieldsSelector = $productFieldsSelector;
$this->relatedProductDataProvider = $relatedProductDataProvider;
}

/**
* @inheritdoc
*/
public function resolve(Field $field, $context, ResolveInfo $info, array $value = null, array $args = null)
{
if (!isset($value['model'])) {
throw new LocalizedException(__('"model" value should be specified'));
}
$product = $value['model'];
$fields = $this->productFieldsSelector->getProductFieldsFromInfo($info, 'crosssell_products');

$data = $this->relatedProductDataProvider->getData($product, $fields, Link::LINK_TYPE_CROSSSELL);
return $data;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);

namespace Magento\RelatedProductGraphQl\Model\Resolver;

use Magento\Catalog\Model\Product\Link;
use Magento\CatalogGraphQl\Model\Resolver\Product\ProductFieldsSelector;
use Magento\Framework\Exception\LocalizedException;
use Magento\RelatedProductGraphQl\Model\DataProvider\RelatedProductDataProvider;
use Magento\Framework\GraphQl\Config\Element\Field;
use Magento\Framework\GraphQl\Query\ResolverInterface;
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;

/**
* Related Products Resolver
*/
class RelatedProducts implements ResolverInterface
{
/**
* @var ProductFieldsSelector
*/
private $productFieldsSelector;

/**
* @var RelatedProductDataProvider
*/
private $relatedProductDataProvider;

/**
* @param ProductFieldsSelector $productFieldsSelector
* @param RelatedProductDataProvider $relatedProductDataProvider
*/
public function __construct(
ProductFieldsSelector $productFieldsSelector,
RelatedProductDataProvider $relatedProductDataProvider
) {
$this->productFieldsSelector = $productFieldsSelector;
$this->relatedProductDataProvider = $relatedProductDataProvider;
}

/**
* @inheritdoc
*/
public function resolve(Field $field, $context, ResolveInfo $info, array $value = null, array $args = null)
{
if (!isset($value['model'])) {
throw new LocalizedException(__('"model" value should be specified'));
}
$product = $value['model'];
$fields = $this->productFieldsSelector->getProductFieldsFromInfo($info, 'related_products');

$data = $this->relatedProductDataProvider->getData($product, $fields, Link::LINK_TYPE_RELATED);
return $data;
}
}
Loading