Esempio n. 1
0
        public (Dictionary <VersionedAddress, object>, ItemVersion) ProcessContainers(IEnumerable <object> startContainers)
        {
            var         containers             = new Dictionary <VersionedAddress, object>();
            ItemVersion containerCommonVersion = null;

            // Ensure we have the start addresses
            if (startContainers != null)
            {
                foreach (var cont in startContainers)
                {
                    var cVersAddr = new VersionedAddress(System, cont);
                    if (!containers.ContainsKey(cVersAddr))
                    {
                        containers.Add(cVersAddr, cont);
                    }
                    else
                    {
                        log.Error("Duplicate versioned address: " + cVersAddr.ToString());
                    }

                    containerCommonVersion = containerCommonVersion == null ? cVersAddr.Version : containerCommonVersion.LeastAbstractCommonVersion(cVersAddr.Version);
                }
            }

            return(containers, containerCommonVersion);
        }
Esempio n. 2
0
        /// <summary>
        /// Starting from a list of addresses and optionally (or only) the containers at those addresses, fetch
        /// any containers necessary and any other containers required to supply redirected properties for them,
        /// obtain the contained content items and collate their properties, returning the content items at the
        /// addresses.
        /// </summary>
        /// <typeparam name="T">Type of content items to return</typeparam>
        /// <param name="startContainers">Initial list of containers if they are available</param>
        /// <param name="startAddresses">Initial list of addresses, which may be omitted and derived from containers</param>
        /// <returns>List of content items</returns>
        public IEnumerable <T> Collate <T>(IEnumerable <object> startContainers, IEnumerable <Address> startAddresses) where T : class
        {
            // place to store all the containers we have currently
            var containers = new Dictionary <VersionedAddress, object>();

            ItemVersion containerCommonVersion = null;

            // Ensure we have the start addresses
            if (startContainers != null)
            {
                containers             = startContainers.ToDictionary(sc => new VersionedAddress(sc), sc => sc);
                startAddresses         = containers.Keys.Select(va => va.Address).Distinct().ToList();
                containerCommonVersion = ItemVersion.LeastAbstractCommonVersion(containers.Keys.Select(va => va.Version));
            }

            var fetchAddrs = startAddresses
                             .GroupBy(a => a.Type.GetCustomAttributes <RedirectPropertySourceAttribute>())
                             .SelectMany(ag =>
                                         ag.SelectMany(a => ag.Key
                                                       .Select(attr => attr.Redirect(a))
                                                       .Concat(a)))
                             .Distinct()
                             .Except(containers.Keys.Select(va => va.Address))
                             .ToList();

            bool pushVersion = (startContainers != null);

            if (pushVersion) // Get containers in any version that might be relevant to a start container
            {
                VersionManager.Instance.PushState(VersioningMode.Specific, containerCommonVersion);
            }

            try
            {
                // Get all the containers for collation (if current version is not fully specified, may be multiple per address)
                foreach (var cont in Repository.Instance.Get(typeof(object), fetchAddrs))
                {
                    var va = new VersionedAddress(cont);
                    if (containers.ContainsKey(va))
                    {
                        log.Error("Duplicate versioned address in db: " + va.ToString());
                    }
                    else
                    {
                        containers.Add(new VersionedAddress(cont), cont);
                    }
                }
            }
            finally
            {
                if (pushVersion)
                {
                    VersionManager.Instance.PopState();
                }
            }

            var contLookup = containers.ToLookup(kvp => kvp.Key.Address.ToString(), kvp => kvp.Value);

            if (startContainers == null)
            {
                startContainers = startAddresses.SelectMany(a => contLookup[a.ToString()]);
            }

            // We have the data, now collate it into the content from the startContainers
            foreach (var addrTypeG in startAddresses.GroupBy(a => a.Type))
            {
                // Process all the start addresses of a given type

                Type contentType   = addrTypeG.Key;
                var  rpsAttributes = contentType
                                     .GetCustomAttributes(typeof(RedirectPropertySourceAttribute), false)
                                     .Cast <RedirectPropertySourceAttribute>()
                                     .ToList();

                foreach (var addr in addrTypeG)
                {
                    var primaryPath = addr.GetAsContentPath();
                    if (!contLookup.Contains(addr.ToString()))
                    {
                        continue;
                    }

                    foreach (var cont in contLookup[addr.ToString()])
                    {
                        object primaryContent = cont;

                        if (primaryContent is IContentContainer)
                        {
                            primaryContent = ((IContentContainer)primaryContent).GetContent();
                        }

                        foreach (var rpsAttribute in rpsAttributes)
                        {
                            var refAddress = new VersionedAddress(
                                rpsAttribute.ContentType ?? contentType,
                                PathFunctions.Redirect(primaryPath, rpsAttribute.SourceDescriptor),
                                new ItemVersion(cont)
                                );
                            if (refAddress.Address == addr) // redirected to itself, ignore
                            {
                                continue;
                            }
                            object refItem = containers.ContainsKey(refAddress) ? containers[refAddress] : null;
                            if (refItem is IContentContainer)
                            {
                                refItem = ((IContentContainer)refItem).GetContent();
                            }
                            if (refItem != null)
                            {
                                foreach (string propertyPath in rpsAttribute.PropertyPaths)
                                {
                                    var    toFromPaths = GetPaths(propertyPath);
                                    object val         = ReflectionX.GetPropertyValueByPath(refItem, toFromPaths[1]);
                                    var    piSet       = ReflectionX.GetPropertyByPath(primaryContent.GetType(), toFromPaths[0]);
                                    piSet.SetValue(primaryContent, val);
                                }
                            }
                        }

                        yield return(primaryContent as T);
                    }
                }
            }
        }