0

In my schema.graphqls file I've created this Query

type Query {
 getLinkedProductsByGroups(groups: [String]): [LinkedProductsByGroup] @resolver(class: "Vendor\\ProductDisplay\\Model\\Resolver\\LinkedProductsByGroups")
}
type LinkedProductsByGroup {
 group: String
 products: [ProductInterface]
}

I've created my resolver

<?php
/*
 * Copyright (c) 2023. Vendor TECHNOLOGIES
 */
namespace Vendor\ProductDisplay\Model\Resolver;
use Vendor\ProductDisplay\Service\LinkedProductsLocator;
use Magento\Catalog\Api\ProductRepositoryInterface;
use Magento\CatalogGraphQl\Model\Resolver\Product\ProductFieldsSelector;
use Magento\CatalogGraphQl\Model\Resolver\Products\DataProvider\Deferred\Product as ProductDataProvider;
use Magento\CatalogGraphQl\Model\Resolver\Products\DataProvider\ProductSearch;
use Magento\Framework\Api\SearchCriteriaBuilderFactory;
use Magento\Framework\GraphQl\Config\Element\Field;
use Magento\Framework\GraphQl\Query\Resolver\BatchResolverInterface;
use Magento\Framework\GraphQl\Query\Resolver\BatchResponse;
use Magento\Framework\GraphQl\Query\Resolver\ContextInterface;
use Magento\Framework\GraphQl\Query\Resolver\ValueFactory;
use Magento\Framework\GraphQl\Query\ResolverInterface;
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
class LinkedProductsByGroups implements ResolverInterface
{
 protected LinkedProductsLocator $linkedProductsLocator;
 protected ProductRepositoryInterface $productRepository;
 protected SearchCriteriaBuilderFactory $searchCriteriaBuilderFactory;
 public function __construct(
 SearchCriteriaBuilderFactory $searchCriteriaBuilderFactory,
 ProductRepositoryInterface $productRepository,
 LinkedProductsLocator $linkedProductsLocator
 )
 {
 $this->linkedProductsLocator = $linkedProductsLocator;
 $this->searchCriteriaBuilderFactory = $searchCriteriaBuilderFactory;
 $this->productRepository = $productRepository;
 }
 public function resolve(Field $field, $context, ResolveInfo $info, array $value = null, array $args = null)
 {
 $result = [];
 $groups = $args['groups'];
 foreach ($groups as $group) {
 $resultItem = [];
 $resultItem['group'] = $group;
 $resultItem['products'] = [];
 //fetch related products
 $linkedProductIds = $this->linkedProductsLocator->getLinkedProductIdsByGroup($group);
 $scb = $this->searchCriteriaBuilderFactory->create();
 $scb->addFilter('entity_id', $linkedProductIds, 'in');
 $searchResults = $this->productRepository->getList($scb->create());
 if ($searchResults->getTotalCount() > 0) {
 foreach ($searchResults->getItems() as $item) {
 $data = $item->toArray();
 $data['model'] = 'product';
 $resultItem['products'][] = $data;
 }
 }
 $result[] = $resultItem;
 }
 return $result;
 }
}

This pretty much works but I have a problem fetching composite fields like price or small_image.

When I run my query without them everything is fine.

But with them I get this error

query {
 getLinkedProductsByGroups(groups: ["001021", "001107"]) {
 group
 products { 
 name
 sku
 small_image {
 url
 } 
 }
 }
}

This error comes up

{
 "errors": [
 {
 "debugMessage": "Call to a member function getData() on string",
 "message": "Internal server error",
 "extensions": {
 "category": "internal"
 },
 "locations": [
 {
 "line": 8,
 "column": 11
 }
 ],
 "path": [
 "getLinkedProductsByGroups",
 0,
 "products",
 0,
 "small_image",
 "url"
 ]
 },
 {
 "debugMessage": "Call to a member function getData() on string",
 "message": "Internal server error",
 "extensions": {
 "category": "internal"
 },
 "locations": [
 {
 "line": 8,
 "column": 11
 }
 ],
 "path": [
 "getLinkedProductsByGroups",
 0,
 "products",
 1,
 "small_image",
 "url"
 ]
 },
 {
 "debugMessage": "Call to a member function getData() on string",
 "message": "Internal server error",
 "extensions": {
 "category": "internal"
 },
 "locations": [
 {
 "line": 8,
 "column": 11
 }
 ],
 "path": [
 "getLinkedProductsByGroups",
 0,
 "products",
 2,
 "small_image",
 "url"
 ]
 },
 {
 "debugMessage": "Call to a member function getData() on string",
 "message": "Internal server error",
 "extensions": {
 "category": "internal"
 },
 "locations": [
 {
 "line": 8,
 "column": 11
 }
 ],
 "path": [
 "getLinkedProductsByGroups",
 0,
 "products",
 3,
 "small_image",
 "url"
 ]
 },
 {
 "debugMessage": "Call to a member function getData() on string",
 "message": "Internal server error",
 "extensions": {
 "category": "internal"
 },
 "locations": [
 {
 "line": 8,
 "column": 11
 }
 ],
 "path": [
 "getLinkedProductsByGroups",
 0,
 "products",
 4,
 "small_image",
 "url"
 ]
 },
 {
 "debugMessage": "Call to a member function getData() on string",
 "message": "Internal server error",
 "extensions": {
 "category": "internal"
 },
 "locations": [
 {
 "line": 8,
 "column": 11
 }
 ],
 "path": [
 "getLinkedProductsByGroups",
 0,
 "products",
 5,
 "small_image",
 "url"
 ]
 },
 {
 "debugMessage": "Call to a member function getData() on string",
 "message": "Internal server error",
 "extensions": {
 "category": "internal"
 },
 "locations": [
 {
 "line": 8,
 "column": 11
 }
 ],
 "path": [
 "getLinkedProductsByGroups",
 0,
 "products",
 6,
 "small_image",
 "url"
 ]
 },
 {
 "debugMessage": "Call to a member function getData() on string",
 "message": "Internal server error",
 "extensions": {
 "category": "internal"
 },
 "locations": [
 {
 "line": 8,
 "column": 11
 }
 ],
 "path": [
 "getLinkedProductsByGroups",
 0,
 "products",
 7,
 "small_image",
 "url"
 ]
 },
 {
 "debugMessage": "Call to a member function getData() on string",
 "message": "Internal server error",
 "extensions": {
 "category": "internal"
 },
 "locations": [
 {
 "line": 8,
 "column": 11
 }
 ],
 "path": [
 "getLinkedProductsByGroups",
 0,
 "products",
 8,
 "small_image",
 "url"
 ]
 },
 {
 "debugMessage": "Call to a member function getData() on string",
 "message": "Internal server error",
 "extensions": {
 "category": "internal"
 },
 "locations": [
 {
 "line": 8,
 "column": 11
 }
 ],
 "path": [
 "getLinkedProductsByGroups",
 0,
 "products",
 9,
 "small_image",
 "url"
 ]
 },
 {
 "debugMessage": "Call to a member function getData() on string",
 "message": "Internal server error",
 "extensions": {
 "category": "internal"
 },
 "locations": [
 {
 "line": 8,
 "column": 11
 }
 ],
 "path": [
 "getLinkedProductsByGroups",
 0,
 "products",
 10,
 "small_image",
 "url"
 ]
 },
 {
 "debugMessage": "Call to a member function getData() on string",
 "message": "Internal server error",
 "extensions": {
 "category": "internal"
 },
 "locations": [
 {
 "line": 8,
 "column": 11
 }
 ],
 "path": [
 "getLinkedProductsByGroups",
 0,
 "products",
 11,
 "small_image",
 "url"
 ]
 },
 {
 "debugMessage": "Call to a member function getData() on string",
 "message": "Internal server error",
 "extensions": {
 "category": "internal"
 },
 "locations": [
 {
 "line": 8,
 "column": 11
 }
 ],
 "path": [
 "getLinkedProductsByGroups",
 1,
 "products",
 0,
 "small_image",
 "url"
 ]
 },
 {
 "debugMessage": "Call to a member function getData() on string",
 "message": "Internal server error",
 "extensions": {
 "category": "internal"
 },
 "locations": [
 {
 "line": 8,
 "column": 11
 }
 ],
 "path": [
 "getLinkedProductsByGroups",
 1,
 "products",
 1,
 "small_image",
 "url"
 ]
 },
 {
 "debugMessage": "Call to a member function getData() on string",
 "message": "Internal server error",
 "extensions": {
 "category": "internal"
 },
 "locations": [
 {
 "line": 8,
 "column": 11
 }
 ],
 "path": [
 "getLinkedProductsByGroups",
 1,
 "products",
 2,
 "small_image",
 "url"
 ]
 },
 {
 "debugMessage": "Call to a member function getData() on string",
 "message": "Internal server error",
 "extensions": {
 "category": "internal"
 },
 "locations": [
 {
 "line": 8,
 "column": 11
 }
 ],
 "path": [
 "getLinkedProductsByGroups",
 1,
 "products",
 3,
 "small_image",
 "url"
 ]
 },
 {
 "debugMessage": "Call to a member function getData() on string",
 "message": "Internal server error",
 "extensions": {
 "category": "internal"
 },
 "locations": [
 {
 "line": 8,
 "column": 11
 }
 ],
 "path": [
 "getLinkedProductsByGroups",
 1,
 "products",
 4,
 "small_image",
 "url"
 ]
 },
 {
 "debugMessage": "Call to a member function getData() on string",
 "message": "Internal server error",
 "extensions": {
 "category": "internal"
 },
 "locations": [
 {
 "line": 8,
 "column": 11
 }
 ],
 "path": [
 "getLinkedProductsByGroups",
 1,
 "products",
 5,
 "small_image",
 "url"
 ]
 },
 {
 "debugMessage": "Call to a member function getData() on string",
 "message": "Internal server error",
 "extensions": {
 "category": "internal"
 },
 "locations": [
 {
 "line": 8,
 "column": 11
 }
 ],
 "path": [
 "getLinkedProductsByGroups",
 1,
 "products",
 6,
 "small_image",
 "url"
 ]
 },
 {
 "debugMessage": "Call to a member function getData() on string",
 "message": "Internal server error",
 "extensions": {
 "category": "internal"
 },
 "locations": [
 {
 "line": 8,
 "column": 11
 }
 ],
 "path": [
 "getLinkedProductsByGroups",
 1,
 "products",
 7,
 "small_image",
 "url"
 ]
 }
 ],
 "data": {
 "getLinkedProductsByGroups": [
 {
 "group": "001021",
 "products": [
 {
 "name": "Bidi Badu Bella Women's Tech Neck T-shirt",
 "sku": "001021-PKIB",
 "small_image": {
 "url": null
 }
 },
 {
 "name": "Bidi Badu Bella Women's Tech Neck T-shirt",
 "sku": "001021-PKYW",
 "small_image": {
 "url": null
 }
 },
 {
 "name": "Bidi Badu Bella Women's Tech Neck T-shirt",
 "sku": "001021-PKDBL",
 "small_image": {
 "url": null
 }
 },
 {
 "name": "BIDI BADU Bella Tech Neck Women's T-shirt-XS",
 "sku": "001021-PKDBL-XS",
 "small_image": {
 "url": null
 }
 },
 {
 "name": "Bidi Badu Bella Women's Tech Neck T-shirt",
 "sku": "001021-BKDBL",
 "small_image": {
 "url": null
 }
 },
 {
 "name": "Bidi Badu Bella Women's Tech Neck T-shirt",
 "sku": "001021-DBPK",
 "small_image": {
 "url": null
 }
 },
 {
 "name": "Bidi Badu Bella Women's Tech Neck T-shirt",
 "sku": "001021-CON",
 "small_image": {
 "url": null
 }
 },
 {
 "name": "Bidi Badu Bella Women's Tech Neck T-shirt",
 "sku": "001021-GRCO",
 "small_image": {
 "url": null
 }
 },
 {
 "name": "Bidi Badu Bella Women's Tech Neck T-shirt",
 "sku": "001021-PKGR",
 "small_image": {
 "url": null
 }
 },
 {
 "name": "Bidi Badu Bella Tech Neck Women's T-shirt-XS",
 "sku": "001021-PKGR-XS",
 "small_image": {
 "url": null
 }
 },
 {
 "name": "Bidi Badu Bella Women's Tech Neck T-shirt",
 "sku": "001021-RDPK",
 "small_image": {
 "url": null
 }
 },
 {
 "name": "Bidi Badu Bella Women's Tech Neck T-shirt",
 "sku": "001021-ANDB",
 "small_image": {
 "url": null
 }
 }
 ]
 },
 {
 "group": "001107",
 "products": [
 {
 "name": "Bidi Badu Magu Crew Tech Sport Socks x 3",
 "sku": "001107-WH",
 "small_image": {
 "url": null
 }
 },
 {
 "name": "Bidi Badu Magu Crew Tech Socks - set of 3-39-42",
 "sku": "001107-WH-39-42",
 "small_image": {
 "url": null
 }
 },
 {
 "name": "Bidi Badu Magu Crew Tech Socks - set of 3-43-46",
 "sku": "001107-WH-43-46",
 "small_image": {
 "url": null
 }
 },
 {
 "name": "Bidi Badu Magu Crew Tech Socks - set of 3-46-50",
 "sku": "001107-WH-46-50",
 "small_image": {
 "url": null
 }
 },
 {
 "name": "Bidi Badu Magu Crew Tech Sport Socks x 3",
 "sku": "001107-BK",
 "small_image": {
 "url": null
 }
 },
 {
 "name": "Bidi Badu Magu Crew Tech Socks - set of 3-39-42",
 "sku": "001107-BK-39-42",
 "small_image": {
 "url": null
 }
 },
 {
 "name": "Bidi Badu Magu Crew Tech Socks - set of 3-43-46",
 "sku": "001107-BK-43-46",
 "small_image": {
 "url": null
 }
 },
 {
 "name": "Bidi Badu Magu Crew Tech Socks - set of 3-46-50",
 "sku": "001107-BK-46-50",
 "small_image": {
 "url": null
 }
 }
 ]
 }
 ]
 }
}

Of course I can't use the price / image fields directly because the ProductInterface type must have a sub-selection for them. But the toArray() and the getData() functions don't give the result as expected. So how do I make it convert the fields properly from the ProductInterface defined in the PHP classes, to the ProductInterface defined in GraphQl so that the result is correct?

asked May 10, 2023 at 2:06

1 Answer 1

0

To answer my own question there is a ProductDataProvider service for requesting the product information by ID.

\Magento\CatalogGraphQl\Model\ProductDataProvider

Using this function

\Magento\CatalogGraphQl\Model\ProductDataProvider::getProductDataById

Makes everything resolve correctly in the GraphQl resolver

Moreover I can modify my code to

 if ($searchResults->getTotalCount() > 0) {
 foreach ($searchResults->getItems() as $item) {
 $data = $item->toArray();
 $data['model'] = $item;
 $resultItem['products'][] = $data;
 }
 }

so that it works as well. The difference is that in the model key, the whole product object needs to be passed.

answered May 10, 2023 at 7:10

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.