Skip to content

Commit

Permalink
Merge pull request #3 from luigisbox/backwards-compatibility
Browse files Browse the repository at this point in the history
Make integration compatible with older Magento versions
  • Loading branch information
specikrumpel authored Sep 19, 2024
2 parents 4db32e7 + 8a5baf6 commit bb24707
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 71 deletions.
148 changes: 81 additions & 67 deletions Model/Resolver/Product/ProductCustomAttributesLuigi.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,60 +7,68 @@

namespace Luigisbox\Integration\Model\Resolver\Product;

/**
* Requirements for GraphQL
*/
use Magento\GraphQl\Model\Query\ContextInterface;
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
use Magento\Framework\GraphQl\Config\Element\Field;
use Magento\Framework\GraphQl\Query\ResolverInterface;

/**
* Requirements to handle custom attributes (these classes/interfaces are present in older Magento versions)
*/
use Magento\Catalog\Api\Data\ProductAttributeInterface;
use Magento\Catalog\Model\FilterProductCustomAttribute;
use Magento\Catalog\Model\Product;
use Magento\CatalogGraphQl\Model\ProductDataProvider;
use Magento\Eav\Api\Data\AttributeInterface;
use Magento\EavGraphQl\Model\Output\Value\GetAttributeValueInterface;
use Magento\EavGraphQl\Model\Resolver\GetFilteredAttributes;
use Magento\GraphQl\Model\Query\ContextInterface;
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
use Magento\Framework\GraphQl\Config\Element\Field;
use Magento\Framework\GraphQl\Query\ResolverInterface;

/**
*
* Format a product's custom attribute information to conform to GraphQL schema representation
* Format a product's custom attribute information to conform to GraphQL schema representation.
* This class returns product's custom attributes as JSON string, even if some of them are null.
* Only works in Magento v. 2.4.7. In older versions the response is always 'null' (as string).
*/
class ProductCustomAttributesLuigi implements ResolverInterface
{
/**
* @var GetAttributeValueInterface
* These attributes are used in Magento v. 2.4.7, because these class and interface only exists from that version
*/
private GetAttributeValueInterface $getAttributeValue;
private ?\Magento\EavGraphQl\Model\Output\Value\GetAttributeValueInterface $getAttributeValue = null;
private ?\Magento\EavGraphQl\Model\Resolver\GetFilteredAttributes $getFilteredAttributes = null;

/**
* @var ProductDataProvider
*/
private ProductDataProvider $productDataProvider;

/**
* @var GetFilteredAttributes
*/
private GetFilteredAttributes $getFilteredAttributes;

/**
* @var FilterProductCustomAttribute
*/
private FilterProductCustomAttribute $filterCustomAttribute;

/**
* @param GetAttributeValueInterface $getAttributeValue
* @param ProductDataProvider $productDataProvider
* @param GetFilteredAttributes $getFilteredAttributes
* @param FilterProductCustomAttribute $filterCustomAttribute
*/
public function __construct(
GetAttributeValueInterface $getAttributeValue,
ProductDataProvider $productDataProvider,
GetFilteredAttributes $getFilteredAttributes,
FilterProductCustomAttribute $filterCustomAttribute
) {
$this->getAttributeValue = $getAttributeValue;
$this->productDataProvider = $productDataProvider;
$this->getFilteredAttributes = $getFilteredAttributes;
$this->filterCustomAttribute = $filterCustomAttribute;

// Check if Magento version has the necessary classes/interfaces
if (interface_exists(\Magento\EavGraphQl\Model\Output\Value\GetAttributeValueInterface::class)) {
$this->getAttributeValue = \Magento\Framework\App\ObjectManager::getInstance()
->get(\Magento\EavGraphQl\Model\Output\Value\GetAttributeValueInterface::class);
}

if (class_exists(\Magento\EavGraphQl\Model\Resolver\GetFilteredAttributes::class)) {
$this->getFilteredAttributes = \Magento\Framework\App\ObjectManager::getInstance()
->get(\Magento\EavGraphQl\Model\Resolver\GetFilteredAttributes::class);
}
}

/**
Expand All @@ -81,55 +89,61 @@ public function resolve(
array $value = null,
array $args = null
) {
$filtersArgs = $args['filters'] ?? [];

$productCustomAttributes = $this->getFilteredAttributes->execute(
$filtersArgs,
ProductAttributeInterface::ENTITY_TYPE_CODE
);

$attributeCodes = array_map(
function (AttributeInterface $customAttribute) {
return $customAttribute->getAttributeCode();
},
$productCustomAttributes['items']
);

$filteredAttributeCodes = $this->filterCustomAttribute->execute(array_flip($attributeCodes));

/** @var Product $product */
$product = $value['model'];
$productData = $this->productDataProvider->getProductDataById((int)$product->getId());

$customAttributes = [];
foreach ($filteredAttributeCodes as $attributeCode => $value) {
if (!array_key_exists($attributeCode, $productData)) {
continue;
}
$attributeValue = $productData[$attributeCode];
if (is_array($attributeValue)) {
$attributeValue = implode(',', $attributeValue);
// If the classes exist, we can compute product's custom attributes
if ($this->getAttributeValue && $this->getFilteredAttributes) {
$filtersArgs = $args['filters'] ?? [];

$productCustomAttributes = $this->getFilteredAttributes->execute(
$filtersArgs,
ProductAttributeInterface::ENTITY_TYPE_CODE
);

$attributeCodes = array_map(
function (AttributeInterface $customAttribute) {
return $customAttribute->getAttributeCode();
},
$productCustomAttributes['items']
);

$filteredAttributeCodes = $this->filterCustomAttribute->execute(array_flip($attributeCodes));

/** @var Product $product */
$product = $value['model'];
$productData = $this->productDataProvider->getProductDataById((int)$product->getId());

$customAttributes = [];
foreach ($filteredAttributeCodes as $attributeCode => $value) {
if (!array_key_exists($attributeCode, $productData)) {
continue;
}
$attributeValue = $productData[$attributeCode];
if (is_array($attributeValue)) {
$attributeValue = implode(',', $attributeValue);
}
$customAttributes[] = [
'attribute_code' => $attributeCode,
'value' => $attributeValue
];
}
$customAttributes[] = [
'attribute_code' => $attributeCode,
'value' => $attributeValue
];

return json_encode([
'items' => array_map(
function (array $customAttribute) {
if (!is_null($customAttribute['value'])) {
return $this->getAttributeValue->execute(
ProductAttributeInterface::ENTITY_TYPE_CODE,
$customAttribute['attribute_code'],
$customAttribute['value']
);
};
},
$customAttributes
),
'errors' => $productCustomAttributes['errors']
]);
}

return [
'items' => array_map(
function (array $customAttribute) {
if (!is_null($customAttribute['value'])) {
return $this->getAttributeValue->execute(
ProductAttributeInterface::ENTITY_TYPE_CODE,
$customAttribute['attribute_code'],
$customAttribute['value']
);
};
},
$customAttributes
),
'errors' => $productCustomAttributes['errors']
];
// Fallback for older Magento versions
return "null";
}
}
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "luigisbox/magento2-integration",
"description": "Luigi's Box product discovery services integration",
"type": "magento2-module",
"version": "1.0.0",
"version": "1.1.0",
"license": ["MIT"],
"autoload": {
"files": [ "registration.php" ],
Expand Down
2 changes: 1 addition & 1 deletion etc/module.xml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
<module name="Luigisbox_Integration" setup_version="1.0.0">
<module name="Luigisbox_Integration" setup_version="1.1.0">
<sequence>
<module name="Magento_Integration"/>
</sequence>
Expand Down
4 changes: 2 additions & 2 deletions etc/schema.graphqls
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
interface ProductInterface {
custom_attributes_luigi(filters: AttributeFilterInput): ProductCustomAttributes
@doc(description: "Same as 'custom_attributesV2', but able to deal with null values.")
custom_attributes_luigi(filters: AttributeFilterInput): String
@doc(description: "Same as 'custom_attributesV2', but able to deal with null values. Returns the result as JSON string. Returns 'null' as string for versions 2.4.6 and lower.")
@resolver(class: "Luigisbox\\Integration\\Model\\Resolver\\Product\\ProductCustomAttributesLuigi")
}

0 comments on commit bb24707

Please sign in to comment.