Magento – Create a custom graphql module with filter attributes magento 2

attributescustom-attributesgraphqlmagento2module

I need to get all attribute values of product based on the category id. I had implemented this logic in rest api but I couldn't find clear solution for graphql module.

My schema.graphqls file is below

type Query {
    productCollection (        
        filter: Int,       
    ): ProductCollection @resolver(class: "Rbj\\ProductsGraphQl\\Model\\Resolver\\ProductsResolver") @doc(description: "Get Product collection of a store")
}

type ProductCollection @doc(description: "product collection comment") {
    allProducts: [ProductRecord] @doc(description: "Product records with info")
}

type ProductRecord {

    display: String @doc(description: "Get Product name")
    value: String @doc(description: "Get Product image")
    count: String @doc(description: "Get cat level")

}

My ProductResolver model is below

<?php
declare(strict_types=1);

namespace Rbj\ProductsGraphQl\Model\Resolver;

use Magento\Framework\Exception\NoSuchEntityException;
use Magento\Framework\GraphQl\Config\Element\Field;
use Magento\Framework\GraphQl\Exception\GraphQlInputException;
use Magento\Framework\GraphQl\Exception\GraphQlNoSuchEntityException;
use Magento\Framework\GraphQl\Query\ResolverInterface;
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;

/**
 * Product collection resolver
 */
class ProductsResolver implements ResolverInterface
{
    public function __construct(
        \Magento\Catalog\Api\ProductRepositoryInterface $productRepository,
        \Magento\Framework\Api\SearchCriteriaBuilder $searchCriteriaBuilder
    ) {
        $this->productRepository = $productRepository;
        $this->searchCriteriaBuilder = $searchCriteriaBuilder;
    }

    /**
     * @inheritdoc
     */
    public function resolve(
        Field $field,
        $context,
        ResolveInfo $info,
        array $value = null,
        array $args = null,
        int $id
    ) {
        $productsData = $this->getProductsData($id);
        return $productsData;
    }

    /**
     * @return array
     * @throws GraphQlNoSuchEntityException
     */
    private function getProductsData($id)
    {
         $category = $id;

            $objectManager = \Magento\Framework\App\ObjectManager::getInstance();

            $filterableAttributes = $objectManager->getInstance()->get(\Magento\Catalog\Model\Layer\Category\FilterableAttributeList::class);

            $appState = $objectManager->getInstance()->get(\Magento\Framework\App\State::class);
            $layerResolver = $objectManager->getInstance()->get(\Magento\Catalog\Model\Layer\Resolver::class);
            $filterList = $objectManager->getInstance()->create(
                \Magento\Catalog\Model\Layer\FilterList::class,
                    [
                        'filterableAttributes' => $filterableAttributes
                    ]
                );      

                $layer = $layerResolver->get();
                $layer->setCurrentCategory($category);
                $filters = $filterList->getFilters($layer);
                $maxPrice = $layer->getProductCollection()->getMaxPrice();
                $minPrice = $layer->getProductCollection()->getMinPrice();  

            $i = 0;
        foreach($filters as $filter)
        {
            //$availablefilter = $filter->getRequestVar(); //Gives the request param name such as 'cat' for Category, 'price' for Price
            $availablefilter = (string)$filter->getName(); //Gives Display Name of the filter such as Category,Price etc.
            $items = $filter->getItems(); //Gives all available filter options in that particular filter
            $filterValues = array();
            $j = 0;
            foreach($items as $item)
            {


                $filterValues[$j]['display'] = strip_tags($item->getLabel());
                $filterValues[$j]['value']   = $item->getValue();
                $filterValues[$j]['count']   = $item->getCount(); //Gives no. of products in each filter options
                $j++;
            }

                $filterArray['availablefilter'][$availablefilter] =  $filterValues;

            $i++;
        }  


            return $filterArray;
            exit;
}

My Graphql query is below

{
  productCollection(filter:2){
    allProducts {

      display

    }
  }
}

The above php code returns me array for rest api but returns this below error when I tried to integrate with Graphql

"{\"messages\":{\"error\":[{\"code\":500,\"message\":\"Fatal Error: 'syntax error, unexpected end of file, expecting function (T_FUNCTION) or const (T_CONST)' in '\\/var\\/www\\/html\\/motomag\\/app\\/code\\/Rbj\\/ProductsGraphQl\\/Model\\/Resolver\\/ProductsResolver.php' on line 94\",\"trace\":\"Trace is not available.\"}]}}{\"messages\":{\"error\":[{\"code\":500,\"message\":\"Fatal Error: 'syntax error, unexpected end of file, expecting function (T_FUNCTION) or const (T_CONST)' in '\\/var\\/www\\/html\\/motomag\\/app\\/code\\/Rbj\\/ProductsGraphQl\\/Model\\/Resolver\\/ProductsResolver.php' on line 94\",\"trace\":\"Trace is not available.\"}]}}"

Best Answer

You can use native products graphql query by define the custom products attributes.Hope this may help some one.

This was little bit old question and you might found any solution. I Have done the same in my recent project.

For this i created a custom module.

1.Create custom module.

2.Define the attributes in di.xml.

3.Add the attributes to ProductFilterInput.

4.Create the ProductAttributeFilter.php file in the relevant directory as defined in di.xml.

5.Run the graphql query to get the result.

My di.xml file looks like below

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<virtualType name="Magento\Catalog\Model\Api\SearchCriteria\CollectionProcessor\ProductFilterProcessor" type="Magento\Eav\Model\Api\SearchCriteria\CollectionProcessor\FilterProcessor">
    <arguments>
        <argument name="customFilters" xsi:type="array">
            <item name="color" xsi:type="object">
                Ayakil\CatalogGraphQl\Model\Resolver\Products\SearchCriteria\CollectionProcessor\FilterProcessor\ProductAttributeFilter
            </item>
            <item name="size" xsi:type="object">
                Ayakil\CatalogGraphQl\Model\Resolver\Products\SearchCriteria\CollectionProcessor\FilterProcessor\ProductAttributeFilter
            </item>
            <item name="region" xsi:type="object">
                Ayakil\CatalogGraphQl\Model\Resolver\Products\SearchCriteria\CollectionProcessor\FilterProcessor\ProductAttributeFilter
            </item>
            <item name="language" xsi:type="object">
                Ayakil\CatalogGraphQl\Model\Resolver\Products\SearchCriteria\CollectionProcessor\FilterProcessor\ProductAttributeFilter
            </item>
        </argument>
    </arguments>
</virtualType>

Add the attributes to ProductFilterInput

input ProductFilterInput {
category_url_key: FilterTypeInput @doc(description: "Category url_key the product belongs to")
category_url_path: FilterTypeInput @doc(description: "Category url_path the product belongs to")
color: FilterTypeInput @doc(description: "Product color")
size: FilterTypeInput @doc(description: "Product size")
region: FilterTypeInput @doc(description: "Product Region")
language: FilterTypeInput @doc(description: "Product Language")
url_key: FilterTypeInput @doc(description: "Product url")
}

Create the ProductAttributeFilter.php file in the relevant directory as defined in di.xml.

<?php
declare(strict_types=1);
namespace Ayakil\CatalogGraphQl\Model\Resolver\Products\SearchCriteria\CollectionProcessor\FilterProcessor;
use Magento\Catalog\Model\Product\Attribute\Source\Status;
use Magento\Framework\Api\SearchCriteria\CollectionProcessor\FilterProcessor\CustomFilterInterface;
use Magento\Framework\Data\Collection\AbstractDb;
use Magento\Framework\Api\Filter;
use Magento\Catalog\Model\ResourceModel\Product\CollectionFactory;
use Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\Configurable;
use Magento\Framework\Registry;
/**
* Category filter allows to filter products collection using custom defined filters from search criteria.
*/
class ProductAttributeFilter implements CustomFilterInterface
{ 
protected $configurable;
protected $collectionFactory;
protected $registry;

public function __construct(
    Configurable $configurable,
    CollectionFactory $collectionFactory,
    \Psr\Log\LoggerInterface $logger,
    Registry $registry
) {
    $this->registry = $registry;
    $this->configurable = $configurable;
    $this->logger = $logger;
    $this->collectionFactory = $collectionFactory;
}

public function apply(Filter $filter, AbstractDb $collection)
{
    $conditionType = $filter->getConditionType();
    $attributeName = $filter->getField();
    $attributeValue = $filter->getValue();
    $category = $this->registry->registry('current_category');


    if($attributeName == 'language'){
        $conditions = [];
        foreach ($attributeValue as $value){
            $conditions[] = ['attribute'=>$attributeName, 'finset'=>$value];
        }
        $simpleSelect = $this->collectionFactory->create()
                        ->addAttributeToFilter($conditions);

    }else{
        $simpleSelect = $this->collectionFactory->create()
            ->addAttributeToFilter($attributeName, [$conditionType => $attributeValue]);
    }

    $simpleSelect->addAttributeToFilter('status', Status::STATUS_ENABLED);
    if ($category) {
        $simpleSelect->addCategoriesFilter(['in' => (int)$category->getId()]);
    }


    $arr =  $simpleSelect;
    $entity_ids = [];
    foreach ($arr->getData() as $a){
        $entity_ids[] = $a['entity_id'];
    }

    $collection->getSelect()->where($collection->getConnection()->prepareSqlCondition(
        'e.entity_id', ['in' => $entity_ids]
    ));

    return true;
}
}

After this want to pass the added attribute to products graphQl query to get the result. I have written an article How to filter product collection with default graphql products query? Hope this will help you to build up your task.

My query and answer as images enter image description here

enter image description here

Related Topic