Expand my Community achievements bar.

SOLVED

How to get content of Fragment Reference in my content fragment using sling model?

Avatar

Level 3

I have a custom component of type 'Content Fragment List' that returns a list of content fragments.

 

Each content fragment has a data type 'Fragment Reference' that brings another content fragment with fields like Name, Direction, etc. How can I access the values of the content fragment added to my returning list fragment and display these values on the front-end?

NathanVieira_0-1691156072068.png


I am using the same structure as the core model 'Content Fragment List'.

 

package com.myproject.core.models.impl;

import java.util.*;
import javax.annotation.PostConstruct;
import javax.inject.Inject;
import javax.jcr.Session;
import org.apache.commons.lang3.StringUtils;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.models.annotations.Default;
import org.apache.sling.models.annotations.Exporter;
import org.apache.sling.models.annotations.Model;
import org.apache.sling.models.annotations.injectorspecific.InjectionStrategy;
import org.apache.sling.models.annotations.injectorspecific.Self;
import org.apache.sling.models.annotations.injectorspecific.SlingObject;
import org.apache.sling.models.annotations.injectorspecific.ValueMapValue;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;

import org.slf4j.LoggerFactory;
import com.adobe.cq.dam.cfm.converter.ContentTypeConverter;
import com.adobe.cq.export.json.ComponentExporter;
import com.adobe.cq.export.json.ExporterConstants;
import com.adobe.cq.wcm.core.components.util.AbstractComponentImpl;
import com.myproject.core.models.ContentFragmentList;
import com.myproject.core.models.DAMContentFragment;
import com.day.cq.commons.jcr.JcrConstants;
import com.day.cq.search.Predicate;
import com.day.cq.search.PredicateGroup;
import com.day.cq.search.Query;
import com.day.cq.search.QueryBuilder;
import com.day.cq.search.result.SearchResult;
import com.day.cq.tagging.TagConstants;
import static com.day.cq.dam.api.DamConstants.NT_DAM_ASSET;

@Model(
adaptables = SlingHttpServletRequest.class,
adapters = {
ContentFragmentList.class,
ComponentExporter.class
},

resourceType = {ContentFragmentListImpl.RESOURCE_TYPE_V1,ContentFragmentListImpl.RESOURCE_TYPE_V2}
)

@Exporter(name = ExporterConstants.SLING_MODEL_EXPORTER_NAME, extensions = ExporterConstants.SLING_MODEL_EXTENSION)
public class ContentFragmentListImpl extends AbstractComponentImpl implements ContentFragmentList {

private static final Logger LOG = LoggerFactory.getLogger(ContentFragmentListImpl.class);
public static final String RESOURCE_TYPE_V1 = "core/wcm/components/contentfragmentlist/v1/contentfragmentlist";
public static final String RESOURCE_TYPE_V2 = "core/wcm/components/contentfragmentlist/v2/contentfragmentlist";

public static final String DEFAULT_DAM_PARENT_PATH = "/content/dam";
public static final int DEFAULT_MAX_ITEMS = -1;
@Self(injectionStrategy = InjectionStrategy.REQUIRED)

private SlingHttpServletRequest slingHttpServletRequest;

@Inject
private ContentTypeConverter contentTypeConverter;

@SlingObject
private ResourceResolver resourceResolver;

@ValueMapValue(name = ContentFragmentList.PN_MODEL_PATH, injectionStrategy = InjectionStrategy.OPTIONAL)
@Nullable
private String modelPath;

@ValueMapValue(name = ContentFragmentList.PN_ELEMENT_NAMES, injectionStrategy = InjectionStrategy.OPTIONAL)
@Nullable
private String[] elementNames;

@ValueMapValue(name = ContentFragmentList.PN_TAG_NAMES, injectionStrategy = InjectionStrategy.OPTIONAL)
@Nullable
private String[] tagNames;

@ValueMapValue(name = ContentFragmentList.PN_PARENT_PATH, injectionStrategy = InjectionStrategy.OPTIONAL)
@Nullable
private String parentPath;

@ValueMapValue(name = ContentFragmentList.PN_MAX_ITEMS, injectionStrategy = InjectionStrategy.OPTIONAL)
@Default(intValues = DEFAULT_MAX_ITEMS)
private int maxItems;

@ValueMapValue(name = ContentFragmentList.PN_ORDER_BY, injectionStrategy = InjectionStrategy.OPTIONAL)
@Default(values = JcrConstants.JCR_CREATED)
private String orderBy;

@ValueMapValue(name = ContentFragmentList.PN_SORT_ORDER, injectionStrategy = InjectionStrategy.OPTIONAL)
@Default(values = Predicate.SORT_ASCENDING)
private String sortOrder;
private final List<DAMContentFragment> items = new ArrayList<>();

@PostConstruct
private void initModel() {

// Default path limits search to DAM

if (StringUtils.isEmpty(parentPath)) {

parentPath = DEFAULT_DAM_PARENT_PATH;

}

if (StringUtils.isEmpty(modelPath)) {

LOG.warn("Please provide a model path");

return;

}

Session session = resourceResolver.adaptTo(Session.class);

if (session == null) {

LOG.warn("Session was null therefore no query was executed");

return;

}

QueryBuilder queryBuilder = resourceResolver.adaptTo(QueryBuilder.class);

if (queryBuilder == null) {

LOG.warn("Query builder was null therefore no query was executed");

return;

}

Map<String, String> queryParameterMap = new HashMap<>();

queryParameterMap.put("path", parentPath);

queryParameterMap.put("type", NT_DAM_ASSET);

queryParameterMap.put("p.limit", Integer.toString(maxItems));

queryParameterMap.put("1_property", JcrConstants.JCR_CONTENT + "/data/cq:model");

queryParameterMap.put("1_property.value", modelPath);

if (StringUtils.isNotEmpty(orderBy)) {

queryParameterMap.put("orderby", "@" + orderBy);

if (StringUtils.isNotEmpty(sortOrder)) {

queryParameterMap.put("orderby.sort", sortOrder);

}

}

ArrayList<String> allTags = new ArrayList<>();

if (tagNames != null && tagNames.length > 0) {

allTags.addAll(Arrays.asList(tagNames));

}

if (!allTags.isEmpty()) {

// Check for the taggable mixin

queryParameterMap.put("2_property", JcrConstants.JCR_CONTENT + "/metadata/" + JcrConstants.JCR_MIXINTYPES);

queryParameterMap.put("2_property.value", TagConstants.NT_TAGGABLE);

// Check for the actual tags (by default, tag are or'ed)

queryParameterMap.put("tagid.property", JcrConstants.JCR_CONTENT + "/metadata/cq:tags");

for (int i = 0; i < allTags.size(); i++) {

queryParameterMap.put(String.format("tagid.%d_value", i + 1), allTags.get(i));

}

queryParameterMap.put("tagid.and", "true");

}

PredicateGroup predicateGroup = PredicateGroup.create(queryParameterMap);

Query query = queryBuilder.createQuery(predicateGroup, session);

SearchResult searchResult = query.getResult();

LOG.debug("Query statement: '{}'", searchResult.getQueryStatement());

// Query builder has a leaking resource resolver, so the following work around is required.

ResourceResolver leakingResourceResolver = null;

try {

// Iterate over the hits if you need special information

Iterator<Resource> resourceIterator = searchResult.getResources();

while (resourceIterator.hasNext()) {

Resource resource = resourceIterator.next();

if (leakingResourceResolver == null) {

// Get a reference to QB's leaking resource resolver

leakingResourceResolver = resource.getResourceResolver();

}

DAMContentFragment contentFragmentModel = new DAMContentFragmentImpl(

resource, contentTypeConverter, null, elementNames);

items.add(contentFragmentModel);

}

} finally {

if (leakingResourceResolver != null) {

// Always close the leaking query builder resource resolver

leakingResourceResolver.close();

}

}

}

@NotNull

@Override

public Collection<DAMContentFragment> getListItems() {

return Collections.unmodifiableCollection(items);

}

@NotNull

@Override

public String getExportedType() {

return slingHttpServletRequest.getResource().getResourceType();

}

}
1 Accepted Solution

Avatar

Correct answer by
Level 9

if resource " /content/dam/myproject/sentido-camera-1" has a value then you should use common resource api to find this resource and take the value from that resource

https://developer.adobe.com/experience-manager/reference-materials/6-4/javadoc/org/apache/sling/api/...

 

or dam resource api similarly

View solution in original post

4 Replies

Avatar

Level 9

as a sample, you can retrieve associated content fragment via path (considering it has been associated as path in another content fragment)

 

//Get the resource of content fragment as below.
Resource fragmentResource = resourceResolver.getResource("/content/dam/fragments/my-test-fragment");

//Adapt it to a fragment resource
if (fragmentResource != null) {
    ContentFragment fragment = fragmentResource.adaptTo(ContentFragment.class);
    // the resource is now accessible through the API
}

Avatar

Level 3

And how can I access the path of the fragment path of the dynamically inserted content fragment?

The return of the information I have from content fragments is this, where 'sentido' is the label of the fragment reference, and its value is the path of the inserted fragment that I want to access the values such as Name, Direction, etc.

camera 1

Nome da câmera
       Camera 1
Ativa
       true
Imagem (opcional)
Rodovia1
sentido
       /content/dam/myproject/sentido-camera-1
Sentido (opcional)
Cidade mais próxima
        Cidade Camera 1
Descrição do quilômetro
         km 34 - SP
Coordenadas geográficas (opcional*)
Ordem (crescente)

 

Avatar

Correct answer by
Level 9

if resource " /content/dam/myproject/sentido-camera-1" has a value then you should use common resource api to find this resource and take the value from that resource

https://developer.adobe.com/experience-manager/reference-materials/6-4/javadoc/org/apache/sling/api/...

 

or dam resource api similarly

Avatar

Community Advisor

Hello @NathanVieira 

 

Please refer to the following Blog

https://kiransg.com/2021/11/13/aem-get-linked-content-fragments-content/

 

It shares a working code where Agents CF is linked to Car CF.

Concept of Synthetic resource is used fetch values of Agents CF via Sling Model

 

 


Aanchal Sikka