简体   繁体   中英

ComponentLink as metadata on Publication level, find the page where the corresponding Component is used

In a TBB I am trying to find a Page using the Criterias and Query, which is using a Component which has a certain TcmUri.

I searched for an example on sdllive but I didn't find any.

Can someone give me an example of how can I do this?

The complete scenario is this:

I have a ComponentLink set as a metadata field on a Publication. This ComponentLink is a Login Component. The page on which the Component is used gives the login functionality for the website. Now, I read the metadata from the publication when publishing the sitemaster, take the tcmId of the component used as ComponentLink (I already did this) and find the page that is using the Component (The login page) in order to get the path of this Login page and write it in web.config.

If the component is in a page as a Component Presentation, then why don't you just use Component Linking to find it? Store the URI of the component in Web.Config, if that's the easiest for you, then use something like this:

const string currentPageId = "tcm:6-123-64";
TcmUri itemUri = new TcmUri(ConfigurationManager.AppSettings["MyLoginComponent"]);
ComponentLink componentLink = new ComponentLink(itemUri.PublicationId);

string loginUrl =
    componentLink.GetLink(currentPageId, itemUri.ToString(), "tcm:0-0-0", "", "",
                          false, false).Url;

If you prefer to find this at publish time with a TBB:

RepositoryLocalObject context = null;
if (package.GetByName(Package.ComponentName) == null)
    context = (RepositoryLocalObject)engine.GetObject(
               package.GetByName(Package.ComponentName));
else
    context = (RepositoryLocalObject)engine.GetObject(
               package.GetByName(Package.ComponentName));

Repository contextPublication = context.ContextRepository;
if (contextPublication.Metadata == null) return;
ItemFields metadata = 
     new ItemFields(contextPublication.Metadata, contextPublication.MetadataSchema);
if (!metadata.Contains("MyLoginComponentField")) return;

ComponentLinkField myLoginComponentField = (ComponentLinkField)metadata["MyLoginComponentField"];
Component loginTarget = myLoginComponentField.Value;

UsingItemsFilter filter = new UsingItemsFilter(engine.GetSession())
                                {
                                    InRepository = contextPublication, 
                                    ItemTypes = new[] {ItemType.Page}
                                };

foreach (Page page in component.GetUsingItems(filter))
{
    string url = page.PublishLocationUrl;
}

If the component is used in more than one page, then this would contain the URL to the LAST page in the list - make sure this is not the case... I could have handled that properly in code, but I thought that I shouldn't do all your homework.

Nuno is right - Tridion's dynamic component linking feature will meet your needs exactly. Nuno's example uses application configuration data, but you can just as easily use publication data to reference your login component, as you have suggested in your question.

Sometimes you don't have an obvious component to link to on a page. For example, a home page, or a sub-site home page often doesn't actually have content. If this is so, then you can do just as well by putting a dummy component on the page which is your link target, and rendering it with a template that doesn't render any extra output.

I took the approach Nuno suggested and what I have now is the following:

        StringBuilder url = new StringBuilder();
        RepositoryLocalObject context = null;
        if (package.GetByName(Package.ComponentName) == null)
            context = (RepositoryLocalObject)engine.GetObject(
                       package.GetByName(Package.PageName));
        else
            context = (RepositoryLocalObject)engine.GetObject(
                       package.GetByName(Package.ComponentName));

        Repository contextPublication = context.ContextRepository;

        _log.Debug("Starting checking the metadata");
        if (contextPublication.Metadata != null)
        {
            ItemFields metadata =
             new ItemFields(contextPublication.Metadata, contextPublication.MetadataSchema);
            if (metadata.Contains("LoginPage"))
            {
                _log.Debug("LoginPage metadata field found in " + metadata.ToXml().OuterXml);
                ComponentLinkField myLoginComponentField = (ComponentLinkField)metadata["LoginPage"];
                Component loginTarget = myLoginComponentField.Value;

                UsingItemsFilter filter = new UsingItemsFilter(engine.GetSession())
                {

                   // InRepository = contextPublication,
                    ItemTypes = new[] { ItemType.Page }

                };

                foreach (comm.Page page in loginTarget.GetUsingItems(filter))
                {
                    if(PublishEngine.IsPublished(page))
                    {
                        url.Append(" url: ").Append(page.PublishLocationUrl);
                    }
                }
            }
        }
        return url.ToString();

For now I just read all the pages paths as a single string.

I managed to filter the version by implementing this method:

public static bool IsPageLastVersion(Page page)
    {
        bool isLastVersion = false;
        if (page != null)
        {
            List<VersionedItem> pageVersions = page.GetVersions().ToList();
            pageVersions.Sort((v1, v2) => v1.Version.CompareTo(v2.Version));
            int lastVersion = pageVersions.Last().Version;
            isLastVersion = lastVersion == page.Version;
        }
        return isLastVersion;
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM