/// <summary>
        /// Builds a Page Data Model from a given CM Page object.
        /// </summary>
        /// <param name="pageModelData">The Page Data Model to build. Is <c>null</c> for the first Model Builder in the pipeline.</param>
        /// <param name="page">The CM Page.</param>
        /// <remarks>
        /// This Model Builder is designed to be the first in the pipeline and hence ignores the <paramref name="pageModelData"/> input value.
        /// </remarks>
        public void BuildPageModel(ref PageModelData pageModelData, Page page)
        {
            Logger.Debug($"BuildPageModel({page})");

            if (page == null)
            {
                pageModelData = null;
                return;
            }

            // We need Keyword XLinks for Keyword field expansion
            page.Load(LoadFlags.KeywordXlinks);

            StructureGroup structureGroup = (StructureGroup)page.OrganizationalItem;

            PageTemplate pt = page.PageTemplate;

            IDictionary <string, RegionModelData> regionModels = new Dictionary <string, RegionModelData>();

            AddPredefinedRegions(regionModels, pt);
            AddComponentPresentationRegions(regionModels, page);

            if (Utility.IsNativeRegionsAvailable(page))
            {
                var nativeRegionModels = GetNativeRegions(page.GetPropertyValue <IList <IRegion> >("Regions"));
                MergeNativeRegions(regionModels, nativeRegionModels);
            }

            AddIncludePageRegions(regionModels, pt);

            // Merge Page metadata and PT custom metadata
            ContentModelData ptCustomMetadata = ExtractCustomMetadata(pt.Metadata, excludeFields: _standardPageTemplateMetadataFields);
            ContentModelData pageMetadata     = BuildContentModel(page.Metadata, Pipeline.Settings.ExpandLinkDepth);

            string[]         duplicateFieldNames;
            ContentModelData pageModelMetadata = MergeFields(pageMetadata, ptCustomMetadata, out duplicateFieldNames);

            if (duplicateFieldNames.Length > 0)
            {
                string formattedDuplicateFieldNames = string.Join(", ", duplicateFieldNames);
                Logger.Debug($"Some custom metadata fields from {pt.FormatIdentifier()} are overridden by Page metadata: {formattedDuplicateFieldNames}");
            }

            string sequencePrefix;

            pageModelData = new PageModelData
            {
                Id               = GetDxaIdentifier(page),
                PageTemplate     = GetPageTemplateData(pt),
                StructureGroupId = GetDxaIdentifier(structureGroup),
                SchemaId         = GetDxaIdentifier(page.MetadataSchema),
                Meta             = null,                                                // Default Model builder does not set PageModel.Meta; see DefaultPageMetaModelBuilder.
                Title            = StripSequencePrefix(page.Title, out sequencePrefix), // See DefaultPageMetaModelBuilder
                UrlPath          = GetUrlPath(page),
                Regions          = regionModels.Values.ToList(),
                Metadata         = pageModelMetadata,
                MvcData          = GetPageMvcData(pt),
                XpmMetadata      = GetXpmMetadata(page)
            };
        }
        private void AddPredefinedRegions(IDictionary <string, RegionModelData> regionModels, PageTemplate pageTemplate)
        {
            IEnumerable <XmlElement> regionsMetadata = pageTemplate.Metadata.GetEmbeddedFieldValues("regions");

            if (regionsMetadata == null)
            {
                Logger.Debug($"No predefined Regions found in {pageTemplate.FormatIdentifier()}");
                return;
            }

            foreach (XmlElement regionMetadata in regionsMetadata)
            {
                string regionName = regionMetadata.GetTextFieldValue("name");
                string qualifiedRegionViewName = regionMetadata.GetTextFieldValue("view");
                string moduleName;
                string regionViewName = StripModuleName(qualifiedRegionViewName, out moduleName);

                if (string.IsNullOrEmpty(regionName))
                {
                    regionName = regionViewName;
                }

                if (regionModels.ContainsKey(regionName))
                {
                    throw new DxaException($"Duplicate predefined Region name '{regionName}' encountered in {pageTemplate.FormatIdentifier()}.");
                }

                RegionModelData regionModel = new RegionModelData
                {
                    Name    = regionName,
                    MvcData = new MvcData
                    {
                        ViewName = regionViewName,
                        AreaName = moduleName
                    },
                    Metadata = ExtractCustomMetadata(regionMetadata, excludeFields: _standardRegionMetadataFields),
                    Entities = new List <EntityModelData>()
                };

                regionModels.Add(regionName, regionModel);
            }
        }
        private void AddIncludePageRegions(IDictionary <string, RegionModelData> regionModels, PageTemplate pageTemplate)
        {
            IEnumerable <string> includes = pageTemplate.Metadata.GetTextFieldValues("includes"); // TODO: use external link field (?)

            if (includes == null)
            {
                Logger.Debug($"No include Pages found in {pageTemplate.FormatIdentifier()}");
                return;
            }

            foreach (string include in includes)
            {
                string includePageId;
                if (include.StartsWith(LegacyIncludePrefix))
                {
                    // Legacy include: publish path. Try to convert to WebDAV URL.
                    string      relativeUrl = include.Substring(LegacyIncludePrefix.Length).Replace('-', ' ');
                    Publication contextPub  = (Publication)pageTemplate.ContextRepository;
                    includePageId = $"/webdav/{contextPub.Title}/{contextPub.RootStructureGroup.Title}/_System/include/{relativeUrl}.tpg";
                    Logger.Debug($"Converted legacy Page include '{include}' to WebDAV URL '{includePageId}'.");
                }
                else
                {
                    includePageId = include;
                }

                Page includePage = (Page)Pipeline.Session.GetObject(includePageId);

                string moduleName;
                string regionViewName = StripModuleName(includePage.Title, out moduleName);
                string regionName     = regionViewName;

                if (regionModels.ContainsKey(regionName))
                {
                    // TODO: log this? Throw exception? Promote Region to Include Page Region?
                    Logger.Debug("TODO: merge include Page Region '{regionName}'");
                    continue;
                }

                RegionModelData includePageRegion = new RegionModelData
                {
                    Name    = regionName,
                    MvcData = new MvcData
                    {
                        ViewName = regionViewName,
                        AreaName = moduleName
                    },
                    IncludePageId = GetDxaIdentifier(includePage)
                };

                if (Pipeline.Settings.GenerateXpmMetadata)
                {
                    includePageRegion.XpmMetadata = new Dictionary <string, object>
                    {
                        { "IncludedFromPageID", GetTcmIdentifier(includePage) },
                        { "IncludedFromPageTitle", includePage.Title },
                        { "IncludedFromPageFileName", includePage.FileName }
                    };
                }
                regionModels.Add(regionName, includePageRegion);
            }
        }
Пример #4
0
        private void AddIncludePageRegions(IDictionary <string, RegionModelData> regionModels, PageTemplate pageTemplate)
        {
            IEnumerable <string> includes = pageTemplate.Metadata.GetTextFieldValues("includes"); // TODO: use external link field (?)

            if (includes == null)
            {
                Logger.Debug($"No include Pages found in {pageTemplate.FormatIdentifier()}");
                return;
            }

            Publication contextPub = (Publication)pageTemplate.ContextRepository;

            foreach (string include in includes)
            {
                string includePageId;
                if (TcmUri.IsValid(include) || include.StartsWith("/webdav/"))
                {
                    // TCM URI or WebDAV URL
                    includePageId = include;
                }
                else
                {
                    // Legacy include: publish path. Convert to WebDAV URL.
                    includePageId = ConvertPublishPathToWebDavUrl(include, contextPub);
                }

                Page includePage;
                try
                {
                    includePage = (Page)Pipeline.Session.GetObject(includePageId);
                    includePage.Load(LoadFlags.None); // Force load the Page
                }
                catch (Exception ex)
                {
                    throw new DxaException($"Unable to load include page for '{include}'", ex);
                }

                string moduleName;
                string regionViewName = StripModuleName(includePage.Title, out moduleName);
                string regionName     = regionViewName;

                RegionModelData includePageRegion;
                if (regionModels.TryGetValue(regionName, out includePageRegion))
                {
                    Logger.Debug($"Promoting Region '{regionName}' to Include Page Region.");
                }
                else
                {
                    includePageRegion = new RegionModelData
                    {
                        Name    = regionName,
                        MvcData = new MvcData
                        {
                            ViewName = regionViewName,
                            AreaName = moduleName
                        }
                    };
                    regionModels.Add(regionName, includePageRegion);
                }
                includePageRegion.IncludePageId = GetDxaIdentifier(includePage);

                if (Pipeline.Settings.GenerateXpmMetadata)
                {
                    includePageRegion.XpmMetadata = new Dictionary <string, object>
                    {
                        { "IncludedFromPageID", GetTcmIdentifier(includePage) },
                        { "IncludedFromPageTitle", includePage.Title },
                        { "IncludedFromPageFileName", includePage.FileName }
                    };
                }
            }
        }