Customize CIF Product Component to Query Custom Properties/Objects in AEM

 

Understanding and modifying the GraphQL queries is one of the key ways in which the CIF Core Components can be extended.

Your custom query :

 {
    products(
    filter: { sku: { eq: "YOUR_SKU" } }
    ) {
        items {
        name
        sku
        customProperty
		customObject{
				name,
				code
			}
        }
    }
}
Response :
 {
  "data": {
    "products": {
      "items": [
        {
          "name": "Product Name",
          "sku": "sku",
          "customProperty":"customVariableValue",
           "customObject": {
                 "name": "nameValue",
			     "code": "codeValue",
               }
        }
      ]
    }
  }
}
In order to achieve that AbstractQuery (com.shopify.graphql.support.AbstractQuery) abstract class provides two methods to query custom property and object respectively.
  •  addCustomSimpleField(String fieldName);
  •  addCustomObjectField(String fieldName, CustomFieldQueryDefinition queryDef);
Create your custom sling model interface by extending Core CIF Product model (com.adobe.cq.commerce.core.components.models.product.Product)
import com.adobe.cq.commerce.core.components.models.product.Product;

public interface CustomProduct extends Product {
	String getCustomProperty() throws SchemaViolationError;
String getCustomObject() throws SchemaViolationError; }

Implementation class: 

import java.util.List;
import java.util.Objects;

import javax.annotation.PostConstruct;

import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.models.annotations.Model;
import org.apache.sling.models.annotations.Via;
import org.apache.sling.models.annotations.injectorspecific.Self;
import org.apache.sling.models.annotations.via.ResourceSuperType;

import com.adobe.cq.commerce.core.components.models.common.Price;
import com.adobe.cq.commerce.core.components.models.product.Asset;
import com.adobe.cq.commerce.core.components.models.product.GroupItem;
import com.adobe.cq.commerce.core.components.models.product.Product;
import com.adobe.cq.commerce.core.components.models.product.Variant;
import com.adobe.cq.commerce.core.components.models.product.VariantAttribute;
import com.adobe.cq.commerce.core.components.models.retriever.AbstractProductRetriever;
import com.adobe.cq.commerce.core.components.storefrontcontext.ProductStorefrontContext;
import com.dsecom.webapp.dt.shop.core.models.CustomProduct;
import com.google.gson.JsonObject;
import com.shopify.graphql.support.SchemaViolationError;

@Model(adaptables = SlingHttpServletRequest.class, adapters = { Product.class, CustomProduct.class })
public class CustomProductImpl implements CustomProduct {

	private AbstractProductRetriever productRetriever;

	@Self
	@Via(type = ResourceSuperType.class)
	private Product product;

	@PostConstruct
	public void initModel() {
		productRetriever = product.getProductRetriever();
		if (Objects.nonNull(productRetriever)) {
			productRetriever.extendProductQueryWith(q -> q.addCustomSimpleField("customProperty")
					.addCustomObjectField("customObject", i -> i.addField("name").addField("code")));
		}
	}

	@Override
	public String getCustomProperty() throws SchemaViolationError {
		return productRetriever.fetchProduct().getAsString("customProperty");
	}

	@Override
	public String getCustomObject() throws SchemaViolationError {
		JsonObject customObject = (JsonObject) productRetriever.fetchProduct().get("customObject");
		// Rather than just returning the json you can create java POJO object and
		// return as per your needs.
		return customObject.toString();
	}

	@Override
	public Boolean getFound() {
		return product.getFound();
	}

	@Override
	public String getName() {
		return product.getName();
	}

	@Override
	public String getDescription() {
		return product.getDescription();
	}

	@Override
	public String getSku() {
		return product.getSku();
	}

	@Override
	public Price getPriceRange() {
		return product.getPriceRange();
	}

	@Override
	public Boolean getInStock() {
		return product.getInStock();
	}

	@Override
	public Boolean isConfigurable() {
		return product.isConfigurable();
	}

	@Override
	public Boolean isGroupedProduct() {
		return product.isGroupedProduct();
	}

	@Override
	public Boolean isVirtualProduct() {
		return product.isVirtualProduct();
	}

	@Override
	public Boolean isBundleProduct() {
		return product.isBundleProduct();
	}

	@Override
	public String getVariantsJson() {
		return product.getVariantsJson();
	}

	@Override
	public List<Variant> getVariants() {
		return product.getVariants();
	}

	@Override
	public List<GroupItem> getGroupedProductItems() {
		return product.getGroupedProductItems();
	}

	@Override
	public List<Asset> getAssets() {
		return product.getAssets();
	}

	@Override
	public String getAssetsJson() {
		return product.getAssetsJson();
	}

	@Override
	public List<VariantAttribute> getVariantAttributes() {
		return product.getVariantAttributes();
	}

	@Override
	public Boolean loadClientPrice() {
		return product.loadClientPrice();
	}

	@Override
	public AbstractProductRetriever getProductRetriever() {
		return product.getProductRetriever();
	}

	@Override
	public ProductStorefrontContext getStorefrontContext() {
		return product.getStorefrontContext();
	}

	@Override
	public String getMetaDescription() {
		return product.getMetaDescription();
	}

	@Override
	public String getMetaKeywords() {
		return product.getMetaKeywords();
	}

	@Override
	public String getMetaTitle() {
		return product.getMetaTitle();
	}

	@Override
	public String getCanonicalUrl() {
		return product.getCanonicalUrl();
	}
}
Create your proxy component using the core product component  and create your customized commerce product detail experience.  (/apps/core/cif/components/commerce/product)

  Hope this helps!!

  Happy Coding 🙏

                    
If you like my post and find it helpful, you can buy me a coffee.  

Comments