/// <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); } }
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 } }; } } }