Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,11 @@
import javax.annotation.PostConstruct;

import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.models.annotations.Model;

import com.adobe.cq.commerce.core.components.models.product.Product;
import com.adobe.cq.commerce.core.components.services.ComponentsConfiguration;
import com.adobe.cq.commerce.magento.graphql.ConfigurableProduct;
import com.adobe.cq.commerce.magento.graphql.GroupedProduct;
import com.adobe.cq.commerce.magento.graphql.ProductInterface;
Expand All @@ -33,15 +35,30 @@ public class ProductImpl extends com.adobe.cq.commerce.core.components.internal.

public static final String RESOURCE_TYPE = "core/cif/components/commerce/product/v2/product";

/**
* Name of the boolean configuration property controlling whether the Adobe Commerce Content Staging {@code staged}
* field is requested. Defaults to {@code true} to keep existing Adobe Commerce deployments unchanged. Magento Open
* Source backends, which do not support the {@code staged} field, must set this to {@code false}.
*/
protected static final String PN_ENABLE_STAGING = "enableContentStaging";

@PostConstruct
protected void initModel() {
super.initModel();
if (productRetriever != null) {
if (productRetriever != null && isStagingEnabled()) {
productRetriever.extendProductQueryWith(p -> p.staged());
productRetriever.extendVariantQueryWith(v -> v.staged());
}
}

private boolean isStagingEnabled() {
Resource contentResource = currentPage.adaptTo(Resource.class);
ComponentsConfiguration configProperties = contentResource != null
? contentResource.adaptTo(ComponentsConfiguration.class)
: null;
return configProperties != null ? configProperties.get(PN_ENABLE_STAGING, Boolean.TRUE) : Boolean.TRUE;
}

@Override
public Boolean isStaged() {
// A product is considered "staged" if the product itself or one of its variant or item is "staged"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,11 @@
import javax.annotation.PostConstruct;

import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.models.annotations.Model;

import com.adobe.cq.commerce.core.components.models.productlist.ProductList;
import com.adobe.cq.commerce.core.components.services.ComponentsConfiguration;

@Model(
adaptables = SlingHttpServletRequest.class,
Expand All @@ -31,15 +33,30 @@ public class ProductListImpl extends com.adobe.cq.commerce.core.components.inter

public static final String RESOURCE_TYPE = "core/cif/components/commerce/productlist/v2/productlist";

/**
* Name of the boolean configuration property controlling whether the Adobe Commerce Content Staging {@code staged}
* field is requested. Defaults to {@code true} to keep existing Adobe Commerce deployments unchanged. Magento Open
* Source backends, which do not support the {@code staged} field, must set this to {@code false}.
*/
protected static final String PN_ENABLE_STAGING = "enableContentStaging";

@PostConstruct
protected void initModel() {
super.initModel();
if (categoryRetriever != null) {
if (categoryRetriever != null && isStagingEnabled()) {
categoryRetriever.extendCategoryQueryWith(c -> c.staged());
categoryRetriever.extendProductQueryWith(p -> p.staged());
}
}

private boolean isStagingEnabled() {
Resource contentResource = currentPage.adaptTo(Resource.class);
ComponentsConfiguration configProperties = contentResource != null
? contentResource.adaptTo(ComponentsConfiguration.class)
: null;
return configProperties != null ? configProperties.get(PN_ENABLE_STAGING, Boolean.TRUE) : Boolean.TRUE;
}

@Override
public Boolean isStaged() {
return getCategory() != null ? Boolean.TRUE.equals(getCategory().getStaged()) : false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,11 +149,11 @@ public class ProductListImplTest {
private static final String PRODUCT_LIST_WITH_MULTIPLE_XF = "/content/pageA/jcr:content/root/responsivegrid/productlist_with_multiple_xf";

private Resource productListResource;
private Resource pageResource;
protected Resource pageResource;
protected ProductListImpl productListModel;
private CategoryTree category;
private Products products;
private GraphqlClient graphqlClient;
protected GraphqlClient graphqlClient;

@Mock
CloseableHttpClient httpClient;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,22 @@
package com.adobe.cq.commerce.core.components.internal.models.v2.product;

import java.io.IOException;
import java.util.List;

import org.apache.sling.api.resource.ValueMap;
import org.apache.sling.api.wrappers.ValueMapDecorator;
import org.junit.Assert;
import org.junit.Test;
import org.mockito.ArgumentCaptor;

import com.adobe.cq.commerce.core.components.services.ComponentsConfiguration;
import com.adobe.cq.commerce.graphql.client.GraphqlRequest;
import com.google.common.collect.ImmutableMap;

import static org.mockito.Matchers.any;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

public class ProductImplTest extends com.adobe.cq.commerce.core.components.internal.models.v1.product.ProductImplTest {

Expand All @@ -39,4 +55,43 @@ public void testGroupedProduct() throws IOException {
public void testBundleProduct() throws IOException {
testBundleProductImpl(true);
}

/**
* By default (no {@code enableContentStaging} configuration) the {@code staged} field is added to the product and
* variant queries so that the author-only "Staged" badge keeps working on Adobe Commerce deployments.
*/
@Test
public void testStagedFieldQueriedByDefault() {
Assert.assertTrue("staged must be queried by default", executedQueriesContainStaged());
}

/**
* When {@code enableContentStaging} is set to {@code false} (e.g. for Magento Open Source backends that do not
* support the Content Staging {@code staged} field), the {@code staged} field must not be added to any query so
* that the query stays schema-valid.
*/
@Test
public void testStagedFieldOmittedWhenStagingDisabled() {
ValueMap configMap = new ValueMapDecorator(ImmutableMap.of(
"cq:graphqlClient", "default",
"magentoStore", "my-store",
"enableUIDSupport", "true",
"enableContentStaging", false));
ComponentsConfiguration stagingDisabled = new ComponentsConfiguration(configMap);
when(pageResource.adaptTo(ComponentsConfiguration.class)).thenReturn(stagingDisabled);

Assert.assertFalse("staged must not be queried when content staging is disabled", executedQueriesContainStaged());
}

private boolean executedQueriesContainStaged() {
adaptToProduct();
// Trigger the product data fetch which executes the GraphQL query.
productModel.getName();

ArgumentCaptor<GraphqlRequest> captor = ArgumentCaptor.forClass(GraphqlRequest.class);
verify(graphqlClient, atLeastOnce()).execute(captor.capture(), any(), any(), any());

List<GraphqlRequest> requests = captor.getAllValues();
return requests.stream().anyMatch(request -> request.getQuery().contains("staged"));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,23 @@
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
package com.adobe.cq.commerce.core.components.internal.models.v2.productlist;

import java.util.List;

import org.apache.sling.api.resource.ValueMap;
import org.apache.sling.api.wrappers.ValueMapDecorator;
import org.junit.Assert;
import org.junit.Test;
import org.mockito.ArgumentCaptor;

import com.adobe.cq.commerce.core.components.services.ComponentsConfiguration;
import com.adobe.cq.commerce.graphql.client.GraphqlRequest;
import com.google.common.collect.ImmutableMap;

import static org.mockito.Matchers.any;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

public class ProductListImplTest extends com.adobe.cq.commerce.core.components.internal.models.v1.productlist.ProductListImplTest {

@Override
Expand All @@ -27,4 +44,42 @@ protected void adaptToProductList() {
public void testStagedData() {
testStagedDataImpl(true);
}

/**
* By default (no {@code enableContentStaging} configuration) the {@code staged} field is added to the queries so
* that the author-only "Staged" badge keeps working on Adobe Commerce deployments.
*/
@Test
public void testStagedFieldQueriedByDefault() {
Assert.assertTrue("staged must be queried by default", executedQueriesContainStaged());
}

/**
* When {@code enableContentStaging} is set to {@code false} (e.g. for Magento Open Source backends that do not
* support the Content Staging {@code staged} field), the {@code staged} field must not be added to any query so
* that the query stays schema-valid.
*/
@Test
public void testStagedFieldOmittedWhenStagingDisabled() {
ValueMap configMap = new ValueMapDecorator(ImmutableMap.of(
"cq:graphqlClient", "default",
"magentoStore", "my-store",
"enableUIDSupport", "true",
"enableContentStaging", false));
ComponentsConfiguration stagingDisabled = new ComponentsConfiguration(configMap);
when(pageResource.adaptTo(ComponentsConfiguration.class)).thenReturn(stagingDisabled);

Assert.assertFalse("staged must not be queried when content staging is disabled", executedQueriesContainStaged());
}

private boolean executedQueriesContainStaged() {
adaptToProductList();
productListModel.getProducts();

ArgumentCaptor<GraphqlRequest> captor = ArgumentCaptor.forClass(GraphqlRequest.class);
verify(graphqlClient, atLeastOnce()).execute(captor.capture(), any(), any(), any());

List<GraphqlRequest> requests = captor.getAllValues();
return requests.stream().anyMatch(request -> request.getQuery().contains("staged"));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,13 @@ Product (v2)
====
The version 2 of the product component extends the v1 product component by extending the v1 GraphQL query with the `staged` field introduced in Magento 2.4.2 Enterprise Edition (EE). This hence requires that the Magento backend is at least version 2.4.2 EE because the query with the `staged` field will be rejected by Magento versions not having this field in the GraphQL schema.

The `staged` field is only available on Adobe Commerce (formerly Magento EE) and does not exist in the Magento Open Source GraphQL schema. Requesting it against Magento Open Source results in a GraphQL validation error that breaks the product detail page. To support Magento Open Source, set the `enableContentStaging` property to `false` on the CIF commerce configuration; the `staged` field is then omitted from the product and variant queries and the "Staged" badge is not shown.

### CIF Commerce Configuration Properties
The following property is read from the CIF commerce configuration (`ComponentsConfiguration`):

1. `enableContentStaging` - when `true` (default), the `staged` field is added to the product and variant queries to drive the author-only "Staged" badge. Set to `false` for Magento Open Source backends, which do not support the `staged` field.

## BEM Description

In addition to the elements documented for the version 1 of the product component, version 2 introduces this extra element to display a "staged" flag. Note that this is only relevant for AEM author instances.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,19 @@ This hence requires that the Magento backend is at least version 2.4.2 EE
because the query with the `staged` field will be rejected by Magento versions
not having this field in the GraphQL schema.

The `staged` field is only available on Adobe Commerce (formerly Magento EE) and does not exist
in the Magento Open Source GraphQL schema. Requesting it against Magento Open Source results in a
GraphQL validation error that breaks the product list page. To support Magento Open Source, set the
`enableContentStaging` property to `false` on the CIF commerce configuration (see below); the
`staged` field is then omitted from the query and the "Staged" badge is not shown.

### CIF Commerce Configuration Properties
The following property is read from the CIF commerce configuration (`ComponentsConfiguration`):

1. `enableContentStaging` - when `true` (default), the `staged` field is added to the category and
product queries to drive the author-only "Staged" badge. Set to `false` for Magento Open Source
backends, which do not support the `staged` field.

### Component Policy Configuration Properties
The following configuration properties are used:

Expand Down
Loading