public virtual void SaveItem(ItemDefinition itemDefinition, ItemChanges changes, CallContext context) { if (DisableSerialization) { return; } Assert.ArgumentNotNull(itemDefinition, "itemDefinition"); Assert.ArgumentNotNull(changes, "changes"); // get the item we're saving to evaluate with the predicate // NOTE: the item in this state may be incomplete as Sitecore can sometimes send partial item data and rely on changes to do the save // e.g. during package installations. So we have to merge the changes with any existing item data if we save it later, to keep it consistent. IItemData sourceItem = new ItemData(changes.Item); if (!_predicate.Includes(sourceItem).IsIncluded) { return; } string oldName = changes.Renamed ? changes.Properties["name"].OriginalValue.ToString() : string.Empty; if (changes.Renamed && !oldName.Equals(sourceItem.Name, StringComparison.Ordinal)) // it's a rename, in which the name actually changed (template builder will cause 'renames' for the same name!!!) { using (new DatabaseCacheDisabler()) { // disabling the DB caches while running this ensures that any children of the renamed item are retrieved with their proper post-rename paths and thus are not saved at their old location // this allows us to filter out any excluded children by predicate when the data store moves children var predicatedItem = new PredicateFilteredItemData(sourceItem, _predicate); _targetDataStore.MoveOrRenameItem(predicatedItem, changes.Item.Paths.ParentPath + "/" + oldName); } _logger.RenamedItem(_targetDataStore.FriendlyName, sourceItem, oldName); } else if (HasConsequentialChanges(changes)) // it's a simple update - but we reject it if only inconsequential fields (last updated, revision) were changed - again, template builder FTW { var existingSerializedItem = _targetDataStore.GetByPathAndId(sourceItem.Path, sourceItem.Id, sourceItem.DatabaseName); // generated an IItemData from the item changes we received, and apply those changes to the existing serialized item if any if (existingSerializedItem != null) { sourceItem = new ItemChangeApplyingItemData(existingSerializedItem, changes); } else { sourceItem = new ItemChangeApplyingItemData(changes); } _targetDataStore.Save(sourceItem); AddBlobsToCache(sourceItem); _logger.SavedItem(_targetDataStore.FriendlyName, sourceItem, "Saved"); } }
public void SaveItem(ItemDefinition itemDefinition, ItemChanges changes, CallContext context) { if (DisableSerialization) { return; } Assert.ArgumentNotNull(itemDefinition, "itemDefinition"); Assert.ArgumentNotNull(changes, "changes"); // get the item from the database (note: we don't allow TpSync to be a database here, because we handle that below) var sourceItem = GetSourceFromId(changes.Item.ID, allowTpSyncFallback: false); if (sourceItem == null) { if (DisableTransparentSync) { return; } // if TpSync is enabled, we wrap the item changes item directly; the TpSync item will NOT have the new changes as we need to write those here sourceItem = new ItemData(changes.Item); } if (!_predicate.Includes(sourceItem).IsIncluded) { return; } string oldName = changes.Renamed ? changes.Properties["name"].OriginalValue.ToString() : string.Empty; if (changes.Renamed && !oldName.Equals(sourceItem.Name, StringComparison.Ordinal)) // it's a rename, in which the name actually changed (template builder will cause 'renames' for the same name!!!) { using (new DatabaseCacheDisabler()) { // disabling the DB caches while running this ensures that any children of the renamed item are retrieved with their proper post-rename paths and thus are not saved at their old location // this allows us to filter out any excluded children by predicate when the data store moves children var predicatedItem = new PredicateFilteredItemData(sourceItem, _predicate); _targetDataStore.MoveOrRenameItem(predicatedItem, changes.Item.Paths.ParentPath + "/" + oldName); } _logger.RenamedItem(_targetDataStore.FriendlyName, sourceItem, oldName); } else if (HasConsequentialChanges(changes)) // it's a simple update - but we reject it if only inconsequential fields (last updated, revision) were changed - again, template builder FTW { _targetDataStore.Save(sourceItem); AddBlobsToCache(sourceItem); _logger.SavedItem(_targetDataStore.FriendlyName, sourceItem, "Saved"); } }
public void ShouldExcludeChildrenExcludedByPredicate() { var child = new FakeItem(); var parent = new FakeItem(children: new[] { child }); var predicate = Substitute.For <IPredicate>(); predicate.Includes(child).Returns(new PredicateResult(false)); Assert.NotEmpty(parent.GetChildren()); var filtered = new PredicateFilteredItemData(parent, predicate); Assert.Empty(filtered.GetChildren()); }
public void MoveItem(ItemDefinition itemDefinition, ItemDefinition destination, CallContext context) { if (DisableSerialization) { return; } Assert.ArgumentNotNull(itemDefinition, "itemDefinition"); var oldSourceItem = GetSourceFromId(itemDefinition.ID, true); // we use cache here because we want the old path var oldPath = oldSourceItem.Path; // NOTE: we cap the path here, because once we enter the cache-disabled section - to get the new paths for parent and children - the path cache updates and the old path is lost in oldSourceItem because it is reevaluated each time. var destinationItem = GetSourceFromId(destination.ID); if (!_predicate.Includes(destinationItem).IsIncluded) // if the destination we are moving to is NOT included for serialization, we delete the existing item { var existingItem = _targetDataStore.GetByPathAndId(oldSourceItem.Path, oldSourceItem.Id, oldSourceItem.DatabaseName); if (existingItem != null) { _targetDataStore.Remove(existingItem); _logger.MovedItemToNonIncludedLocation(_targetDataStore.FriendlyName, existingItem); } return; } using (new DatabaseCacheDisabler()) { // disabling the DB caches while running this ensures that any children of the moved item are retrieved with their proper post-rename paths and thus are not saved at their old location var sourceItem = GetSourceFromId(itemDefinition.ID); // re-get the item with cache disabled // this allows us to filter out any excluded children by predicate when the data store moves children var predicatedItem = new PredicateFilteredItemData(sourceItem, _predicate); _targetDataStore.MoveOrRenameItem(predicatedItem, oldPath); _logger.MovedItem(_targetDataStore.FriendlyName, sourceItem, destinationItem); } }
public virtual void MoveItem(ItemDefinition itemDefinition, ItemDefinition destination, CallContext context) { if (DisableSerialization) { return; } Assert.ArgumentNotNull(itemDefinition, "itemDefinition"); var sourceItem = GetSourceFromId(itemDefinition.ID, true); // we use cache here because we want the old path (no cache would have the new path); TpSync always has old path var oldPath = sourceItem.Path; // NOTE: we cap the path here, because Sitecore can change the item's path value as we're updating stuff. var destinationItem = GetSourceFromId(destination.ID); if (destinationItem == null) { return; // can occur with TpSync on, when this isn't the configuration we're moving for the data store will return null } // rebase the path to the new destination path (this handles children too) var rebasedSourceItem = new PathRebasingProxyItem(sourceItem, destinationItem.Path, destinationItem.Id); if (!_predicate.Includes(rebasedSourceItem).IsIncluded) { // if the destination we are moving to is NOT included for serialization, we delete the existing item from serialization var existingItem = _targetDataStore.GetByPathAndId(sourceItem.Path, sourceItem.Id, sourceItem.DatabaseName); if (existingItem != null) { _targetDataStore.Remove(existingItem); _logger.MovedItemToNonIncludedLocation(_targetDataStore.FriendlyName, existingItem); } return; } // this allows us to filter out any excluded children by predicate when the data store moves children var predicatedItem = new PredicateFilteredItemData(rebasedSourceItem, _predicate); _targetDataStore.MoveOrRenameItem(predicatedItem, oldPath); _logger.MovedItem(_targetDataStore.FriendlyName, predicatedItem, destinationItem); }
public virtual void SaveItem(ItemDefinition itemDefinition, ItemChanges changes, CallContext context) { if (DisableSerialization) { return; } Assert.ArgumentNotNull(itemDefinition, "itemDefinition"); Assert.ArgumentNotNull(changes, "changes"); // get the item we're saving to evaluate with the predicate // NOTE: the item in this state may be incomplete as Sitecore can sometimes send partial item data and rely on changes to do the save // e.g. during package installations. So we have to merge the changes with any existing item data if we save it later, to keep it consistent. IItemData sourceItem = new ItemData(changes.Item); if (!_predicate.Includes(sourceItem).IsIncluded) { return; } // reject if only inconsequential fields (e.g. last updated, revision) were changed - again, template builder FTW with the junk saves if (!HasConsequentialChanges(changes)) { return; } string existingItemPath = sourceItem.Path; // check if the save includes a rename as part of the operation, in which case we have to get the existing item, if any, from the OLD path pre-rename // note that if an item is renamed to the same name this will simply fall through as not a rename if (changes.Renamed) { string oldName = changes.Properties["name"].OriginalValue.ToString(); existingItemPath = changes.Item.Paths.ParentPath + "/" + oldName; } // we find the existing serialized item, with which we want to merge the item changes, if it exists. If not then the changes are the source of all truth. var existingSerializedItem = _targetDataStore.GetByPathAndId(existingItemPath, sourceItem.Id, sourceItem.DatabaseName); // generate an IItemData from the item changes we received, and apply those changes to the existing serialized item if any var changesAppliedItem = existingSerializedItem != null ? new ItemChangeApplyingItemData(existingSerializedItem, changes) : new ItemChangeApplyingItemData(changes); // put any media blob IDs on this item into the media blob cache (used for TpSync media - does not cache the blob just the filename it lives in) AddBlobsToCache(changesAppliedItem); // check for renamed item (existing path != source path -> rename) if (!existingItemPath.Equals(sourceItem.Path, StringComparison.Ordinal)) { // this allows us to filter out any excluded children when the data store moves children to the renamed path var predicatedItem = new PredicateFilteredItemData(changesAppliedItem, _predicate); // change the item's name before sending it to the data store (note: the data store will normalize any child paths for us) var alteredPathItem = new RenamedItemData(predicatedItem, sourceItem.Name); _targetDataStore.MoveOrRenameItem(alteredPathItem, existingItemPath); _logger.RenamedItem(_targetDataStore.FriendlyName, alteredPathItem, existingItemPath.Substring(existingItemPath.LastIndexOf('/') + 1)); return; } // if we get here, it's just a save, not a rename _targetDataStore.Save(changesAppliedItem); _logger.SavedItem(_targetDataStore.FriendlyName, changesAppliedItem, "Saved"); }