Refactored Import process.

* Added Imported event to Elements.
* Invoking Imported event at the end after all content items have been imported.

Fixes #5848.
This commit is contained in:
Sipke Schoorstra
2015-09-29 14:20:12 +01:00
parent 0ad1ef3098
commit 5d5f55f535
17 changed files with 192 additions and 54 deletions

View File

@@ -87,6 +87,18 @@ namespace Orchard.Layouts.Drivers {
context.Element(part.PartDefinition.Name).SetValue(exportableData);
}
protected override void Exported(ElementWrapperPart part, ExportContentContext context) {
var describeContext = CreateDescribeContext(part);
var descriptor = _elementManager.GetElementDescriptorByTypeName(describeContext, part.ElementTypeName);
var data = ElementDataHelper.Deserialize(part.ElementData);
var element = _elementManager.ActivateElement(descriptor, e => e.Data = data);
_elementManager.Exported(new[] { element }, new ExportLayoutContext());
var exportableData = _serializer.Serialize(element);
context.Element(part.PartDefinition.Name).SetValue(exportableData);
}
protected override void Importing(ElementWrapperPart part, ImportContentContext context) {
var root = context.Data.Element(part.PartDefinition.Name);
@@ -101,6 +113,20 @@ namespace Orchard.Layouts.Drivers {
part.ElementData = element.Data.Serialize();
}
protected override void Imported(ElementWrapperPart part, ImportContentContext context) {
var root = context.Data.Element(part.PartDefinition.Name);
if (root == null)
return;
var exportedData = root.Value;
var describeContext = CreateDescribeContext(part);
var element = _serializer.Deserialize(exportedData, describeContext);
_elementManager.Imported(new[] { element }, new ImportLayoutContext { Session = new ImportContentContextWrapper(context) });
part.ElementData = element.Data.Serialize();
}
private static DescribeElementsContext CreateDescribeContext(IContent part) {
return new DescribeElementsContext {
Content = part

View File

@@ -126,9 +126,7 @@ namespace Orchard.Layouts.Drivers {
protected override void Exporting(LayoutPart part, ExportContentContext context) {
_layoutManager.Exporting(new ExportLayoutContext { Layout = part });
context.Element(part.PartDefinition.Name).SetElementValue("LayoutData", part.LayoutData);
if (part.TemplateId != null) {
var template = part.ContentItem.ContentManager.Get(part.TemplateId.Value);
@@ -139,6 +137,12 @@ namespace Orchard.Layouts.Drivers {
}
}
protected override void Exported(LayoutPart part, ExportContentContext context) {
_layoutManager.Exported(new ExportLayoutContext { Layout = part });
context.Element(part.PartDefinition.Name).SetElementValue("LayoutData", part.LayoutData);
}
protected override void Importing(LayoutPart part, ImportContentContext context) {
// Don't do anything if the tag is not specified.
if (context.Data.Element(part.PartDefinition.Name) == null) {
@@ -156,6 +160,18 @@ namespace Orchard.Layouts.Drivers {
context.ImportAttribute(part.PartDefinition.Name, "TemplateId", s => part.TemplateId = GetTemplateId(context, s));
}
protected override void Imported(LayoutPart part, ImportContentContext context) {
// Don't do anything if the tag is not specified.
if (context.Data.Element(part.PartDefinition.Name) == null) {
return;
}
_layoutManager.Imported(new ImportLayoutContext {
Layout = part,
Session = new ImportContentContextWrapper(context)
});
}
private static int? GetTemplateId(ImportContentContext context, string templateIdentity) {
if (String.IsNullOrWhiteSpace(templateIdentity))
return null;

View File

@@ -298,7 +298,7 @@ namespace Orchard.Layouts.Drivers {
}
}
protected override void OnImporting(Projection element, ImportElementContext context) {
protected override void OnImported(Projection element, ImportElementContext context) {
var queryIdentity = context.ExportableData.Get("QueryId");
var query = queryIdentity != null ? context.Session.GetItemFromSession(queryIdentity) : default(ContentManagement.ContentItem);

View File

@@ -41,10 +41,18 @@ namespace Orchard.Layouts.Framework.Drivers {
OnExporting((TElement)context.Element, context);
}
public void Exported(ExportElementContext context) {
OnExported((TElement)context.Element, context);
}
public void Importing(ImportElementContext context) {
OnImporting((TElement)context.Element, context);
}
public void Imported(ImportElementContext context) {
OnImported((TElement)context.Element, context);
}
protected virtual EditorResult OnBuildEditor(TElement element, ElementEditorContext context) {
return null;
}
@@ -71,9 +79,15 @@ namespace Orchard.Layouts.Framework.Drivers {
protected virtual void OnExporting(TElement element, ExportElementContext context) {
}
protected virtual void OnExported(TElement element, ExportElementContext context) {
}
protected virtual void OnImporting(TElement element, ImportElementContext context) {
}
protected virtual void OnImported(TElement element, ImportElementContext context) {
}
protected EditorResult Editor(ElementEditorContext context, params dynamic[] editorShapes) {
foreach (var editorShape in editorShapes) {
if (String.IsNullOrWhiteSpace(editorShape.Metadata.Position)) {

View File

@@ -12,6 +12,8 @@ namespace Orchard.Layouts.Framework.Drivers {
void LayoutSaving(ElementSavingContext context);
void Removing(ElementRemovingContext context);
void Exporting(ExportElementContext context);
void Exported(ExportElementContext context);
void Importing(ImportElementContext context);
void Imported(ImportElementContext context);
}
}

View File

@@ -157,13 +157,26 @@ namespace Orchard.Layouts.Services {
InvokeDriver(elements, (driver, element) => {
var exportElementContext = new ExportElementContext {
Layout = context.Layout,
Element = element
Element = element,
ExportableData = element.ExportableData
};
driver.Exporting(exportElementContext);
element.ExportableData = new ElementDataDictionary(exportElementContext.ExportableData);
});
}
public void Exported(IEnumerable<Element> elements, ExportLayoutContext context) {
InvokeDriver(elements, (driver, element) => {
var exportElementContext = new ExportElementContext {
Layout = context.Layout,
Element = element,
ExportableData = element.ExportableData
};
driver.Exported(exportElementContext);
element.ExportableData = new ElementDataDictionary(exportElementContext.ExportableData);
});
}
public void Importing(IEnumerable<Element> elements, ImportLayoutContext context) {
InvokeDriver(elements, (driver, element) => {
var importElementContext = new ImportElementContext {
@@ -176,6 +189,18 @@ namespace Orchard.Layouts.Services {
});
}
public void Imported(IEnumerable<Element> elements, ImportLayoutContext context) {
InvokeDriver(elements, (driver, element) => {
var importElementContext = new ImportElementContext {
Layout = context.Layout,
Element = element,
ExportableData = element.ExportableData,
Session = context.Session
};
driver.Imported(importElementContext);
});
}
private IDictionary<string, Category> GetCategories() {
var providers = _categoryProviders.Value;
var categories = providers.SelectMany(x => x.GetCategories());

View File

@@ -23,6 +23,8 @@ namespace Orchard.Layouts.Services {
void Saving(LayoutSavingContext context);
void Removing(LayoutSavingContext context);
void Exporting(IEnumerable<Element> elements, ExportLayoutContext context);
void Exported(IEnumerable<Element> elements, ExportLayoutContext context);
void Importing(IEnumerable<Element> elements, ImportLayoutContext context);
void Imported(IEnumerable<Element> elements, ImportLayoutContext context);
}
}

View File

@@ -54,6 +54,8 @@ namespace Orchard.Layouts.Services {
IEnumerable<LayoutPart> GetTemplateClients(int templateId, VersionOptions versionOptions);
IEnumerable<Element> CreateDefaultLayout();
void Exporting(ExportLayoutContext context);
void Exported(ExportLayoutContext context);
void Importing(ImportLayoutContext context);
void Imported(ImportLayoutContext context);
}
}

View File

@@ -67,6 +67,14 @@ namespace Orchard.Layouts.Services {
context.Layout.LayoutData = _serializer.Serialize(elementTree);
}
public void Exported(ExportLayoutContext context) {
var elementTree = LoadElements(context.Layout).ToArray();
var elements = elementTree.Flatten().ToArray();
_elementManager.Exported(elements, context);
context.Layout.LayoutData = _serializer.Serialize(elementTree);
}
public void Importing(ImportLayoutContext context) {
var elementTree = LoadElements(context.Layout).ToArray();
var elements = elementTree.Flatten().ToArray();
@@ -75,6 +83,14 @@ namespace Orchard.Layouts.Services {
context.Layout.LayoutData = _serializer.Serialize(elementTree);
}
public void Imported(ImportLayoutContext context) {
var elementTree = LoadElements(context.Layout).ToArray();
var elements = elementTree.Flatten().ToArray();
_elementManager.Imported(elements, context);
context.Layout.LayoutData = _serializer.Serialize(elementTree);
}
public dynamic RenderLayout(string data, string displayType = null, IContent content = null) {
var elements = _serializer.Deserialize(data, new DescribeElementsContext { Content = content });
var layoutRoot = _elementDisplay.DisplayElements(elements, content, displayType);

View File

@@ -11,7 +11,6 @@ using Orchard.Projections.Descriptors.Property;
using Orchard.Projections.Models;
using Orchard.Projections.Services;
using Orchard.Projections.ViewModels;
using Orchard.Security;
using Orchard.UI.Admin;
using Orchard.UI.Notify;
@@ -96,9 +95,8 @@ namespace Orchard.Projections.Controllers {
if (!Services.Authorizer.Authorize(Permissions.ManageQueries, T("Not authorized to manage queries")))
return new HttpUnauthorizedResult();
// validating form values
// Validating form values.
model.Layout = _projectionManager.DescribeLayouts().SelectMany(x => x.Descriptors).FirstOrDefault(x => x.Category == model.Category && x.Type == model.Type);
_formManager.Validate(new ValidatingContext { FormName = model.Layout.Form, ModelState = ModelState, ValueProvider = ValueProvider });
var form = _formManager.Build(model.Layout.Form) ?? Services.New.EmptyForm();
@@ -107,13 +105,13 @@ namespace Orchard.Projections.Controllers {
model.Form = form;
if (ModelState.IsValid) {
var layoutRecord = new LayoutRecord { Category = model.Category, Type = model.Type };
var layoutRecord = new LayoutRecord { Guid = Guid.NewGuid().ToString() ,Category = model.Category, Type = model.Type };
var query = _queryService.GetQuery(model.QueryId);
query.Layouts.Add(layoutRecord);
var dictionary = formCollection.AllKeys.ToDictionary(key => key, formCollection.Get);
// save form parameters
// Save form parameters.
layoutRecord.State = FormParametersHelper.ToString(dictionary);
layoutRecord.Description = model.Description;
layoutRecord.Display = model.Display;
@@ -132,7 +130,7 @@ namespace Orchard.Projections.Controllers {
if (!Services.Authorizer.Authorize(Permissions.ManageQueries, T("Not authorized to manage queries")))
return new HttpUnauthorizedResult();
LayoutRecord layoutRecord = _repository.Get(id);
var layoutRecord = _repository.Get(id);
if (layoutRecord == null) {
return HttpNotFound();
@@ -140,7 +138,7 @@ namespace Orchard.Projections.Controllers {
var layoutDescriptor = _projectionManager.DescribeLayouts().SelectMany(x => x.Descriptors).FirstOrDefault(x => x.Category == layoutRecord.Category && x.Type == layoutRecord.Type);
// build the form, and let external components alter it
// Build the form, and let external components alter it.
var form = _formManager.Build(layoutDescriptor.Form) ?? Services.New.EmptyForm();
var viewModel = new LayoutEditViewModel {
@@ -156,7 +154,7 @@ namespace Orchard.Projections.Controllers {
GroupPropertyId = layoutRecord.GroupProperty == null ? 0 : layoutRecord.GroupProperty.Id
};
// bind form with existing values
// Bind form with existing values.
var parameters = FormParametersHelper.FromString(layoutRecord.State);
_formManager.Bind(form, new DictionaryValueProvider<string>(parameters, CultureInfo.InvariantCulture));
@@ -192,7 +190,7 @@ namespace Orchard.Projections.Controllers {
[HttpPost, ActionName("Edit")]
public ActionResult EditPost(LayoutEditViewModel model, FormCollection formCollection) {
// validating form values
// Validating form values.
var layout = _projectionManager.DescribeLayouts().SelectMany(x => x.Descriptors).FirstOrDefault(x => x.Category == model.Category && x.Type == model.Type);
_formManager.Validate(new ValidatingContext { FormName = layout.Form, ModelState = ModelState, ValueProvider = ValueProvider });
@@ -207,7 +205,7 @@ namespace Orchard.Projections.Controllers {
var dictionary = formCollection.AllKeys.ToDictionary(key => key, formCollection.Get);
// save form parameters
// Save form parameters.
layoutRecord.State = FormParametersHelper.ToString(dictionary);
layoutRecord.Description = model.Description;
layoutRecord.Display = model.Display;

View File

@@ -308,7 +308,7 @@ namespace Orchard.Projections.Drivers {
}
protected override void Imported(ProjectionPart part, ImportContentContext context) {
// assign the query only when everythin is imported
// Assign the query only when everything is imported.
var query = context.Attribute(part.PartDefinition.Name, "Query");
if (query != null) {
part.Record.QueryPartRecord = context.GetItemFromSession(query).As<QueryPart>().Record;

View File

@@ -65,12 +65,12 @@ namespace Orchard.Projections.Drivers {
}
return new XElement("SortCriterion",
new XAttribute("Category", sortCriterion.Category ?? ""),
new XAttribute("Description", sortCriterion.Description ?? ""),
new XAttribute("Position", sortCriterion.Position),
new XAttribute("State", state ?? ""),
new XAttribute("Type", sortCriterion.Type ?? "")
);
new XAttribute("Category", sortCriterion.Category ?? ""),
new XAttribute("Description", sortCriterion.Description ?? ""),
new XAttribute("Position", sortCriterion.Position),
new XAttribute("State", state ?? ""),
new XAttribute("Type", sortCriterion.Type ?? "")
);
})
),
new XElement("Layouts",
@@ -83,20 +83,21 @@ namespace Orchard.Projections.Drivers {
}
return new XElement("Layout",
// Attributes
new XAttribute("Category", layout.Category ?? ""),
new XAttribute("Description", layout.Description ?? ""),
new XAttribute("State", state ?? ""),
new XAttribute("Display", layout.Display),
new XAttribute("DisplayType", layout.DisplayType ?? ""),
new XAttribute("Type", layout.Type ?? ""),
// Attributes
new XAttribute("Guid", layout.Guid),
new XAttribute("Category", layout.Category ?? ""),
new XAttribute("Description", layout.Description ?? ""),
new XAttribute("State", state ?? ""),
new XAttribute("Display", layout.Display),
new XAttribute("DisplayType", layout.DisplayType ?? ""),
new XAttribute("Type", layout.Type ?? ""),
// Properties
new XElement("Properties", layout.Properties.Select(GetPropertyXml)),
// Properties
new XElement("Properties", layout.Properties.Select(GetPropertyXml)),
// Group
new XElement("Group", GetPropertyXml(layout.GroupProperty))
);
// Group
new XElement("Group", GetPropertyXml(layout.GroupProperty))
);
})
)
);
@@ -161,6 +162,7 @@ namespace Orchard.Projections.Drivers {
part.Record.Layouts.Clear();
foreach (var item in queryElement.Element("Layouts").Elements("Layout").Select(layout => {
var guid = layout.Attr("Guid");
var category = layout.Attribute("Category").Value;
var type = layout.Attribute("Type").Value;
var state = layout.Attribute("State").Value;
@@ -171,7 +173,7 @@ namespace Orchard.Projections.Drivers {
}
return new LayoutRecord {
Guid = guid,
Category = category,
Description = layout.Attribute("Description").Value,
Display = int.Parse(layout.Attribute("Display").Value),

View File

@@ -102,6 +102,7 @@ namespace Orchard.Projections {
SchemaBuilder.CreateTable("LayoutRecord",
table => table
.Column<int>("Id", c => c.PrimaryKey().Identity())
.Column<string>("Guid", c => c.WithLength(64))
.Column<string>("Category", c => c.WithLength(64))
.Column<string>("Type", c => c.WithLength(64))
.Column<string>("Description", c => c.WithLength(255))
@@ -112,6 +113,9 @@ namespace Orchard.Projections {
.Column<int>("GroupProperty_id")
);
SchemaBuilder.AlterTable("LayoutRecord", table => table
.CreateIndex("IDX_LR_GUID", "Guid"));
SchemaBuilder.CreateTable("PropertyRecord",
table => table
.Column<int>("Id", c => c.PrimaryKey().Identity())
@@ -262,16 +266,26 @@ namespace Orchard.Projections {
ContentDefinitionManager.AlterTypeDefinition("ProjectionPage", cfg => cfg.Listable());
return 3;
return 4;
}
public int UpdateFrom2() {
SchemaBuilder.AlterTable("ProjectionPartRecord",
table => table
.AlterColumn("PagerSuffix", c => c.WithType(DbType.String).WithLength(255))
);
SchemaBuilder.AlterTable("ProjectionPartRecord", table => table
.AlterColumn("PagerSuffix", c => c.WithType(DbType.String).WithLength(255))
);
return 3;
}
public int UpdateFrom3() {
SchemaBuilder.AlterTable("LayoutRecord", table => table
.AddColumn<string>("Guid", c => c.WithLength(64))
);
SchemaBuilder.AlterTable("LayoutRecord", table => table
.CreateIndex("IDX_LR_GUID", "Guid"));
return 4;
}
}
}

View File

@@ -9,6 +9,7 @@ namespace Orchard.Projections.Models {
}
public virtual int Id { get; set; }
public virtual string Guid { get; set; }
public virtual string Description { get; set; }
public virtual string Category { get; set; }
public virtual string Type { get; set; }

View File

@@ -1,7 +1,9 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Xml.Linq;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Handlers;
using Orchard.Data;
using Orchard.Localization;
using Orchard.Logging;
@@ -13,14 +15,17 @@ namespace Orchard.Recipes.Providers.Executors {
public class ContentStep : RecipeExecutionStep {
private readonly IOrchardServices _orchardServices;
private readonly ITransactionManager _transactionManager;
private readonly Lazy<IEnumerable<IContentHandler>> _handlers;
public ContentStep(
IOrchardServices orchardServices,
ITransactionManager transactionManager,
Lazy<IEnumerable<IContentHandler>> handlers,
RecipeExecutionLogger logger) : base(logger) {
_orchardServices = orchardServices;
_transactionManager = transactionManager;
_handlers = handlers;
BatchSize = 64;
}
@@ -40,6 +45,10 @@ namespace Orchard.Recipes.Providers.Executors {
get { return T("Provides additional configuration for the Content recipe step."); }
}
public IEnumerable<IContentHandler> Handlers {
get { return _handlers.Value; }
}
public int? BatchSize { get; set; }
public override dynamic BuildEditor(dynamic shapeFactory) {
@@ -89,6 +98,8 @@ namespace Orchard.Recipes.Providers.Executors {
// Run the import.
try {
var importedContentItems = new List<ImportContentContext>();
while (startIndex < elementDictionary.Count) {
Logger.Debug("Importing batch starting at index {0}.", startIndex);
importContentSession.InitializeBatch(startIndex, batchSize);
@@ -104,9 +115,17 @@ namespace Orchard.Recipes.Providers.Executors {
}
Logger.Information("Importing data item '{0}' (item {1}/{2}).", itemId, itemIndex + 1, elementDictionary.Count);
try {
_orchardServices.ContentManager.Import(
elementDictionary[nextIdentityValue],
importContentSession);
var contentElement = elementDictionary[nextIdentityValue];
_orchardServices.ContentManager.Import(contentElement, importContentSession, item => {
// Invoke 'Importing' on the content item,
var importContentContext = new ImportContentContext(item, contentElement, importContentSession);
foreach (var contentHandler in Handlers) {
contentHandler.Importing(importContentContext);
}
importedContentItems.Add(importContentContext);
});
}
catch (Exception ex) {
Logger.Error(ex, "Error while importing data item '{0}'.", itemId);
@@ -115,7 +134,6 @@ namespace Orchard.Recipes.Providers.Executors {
itemIndex++;
nextIdentity = importContentSession.GetNextInBatch();
}
startIndex += batchSize;
// Create a new transaction for each batch.
@@ -125,6 +143,13 @@ namespace Orchard.Recipes.Providers.Executors {
Logger.Debug("Finished importing batch starting at index {0}.", startIndex);
}
// Invoke 'Imported' event on all imported content items.
foreach (var importContentContext in importedContentItems) {
foreach (var contentHandler in Handlers) {
contentHandler.Imported(importContentContext);
}
}
}
catch (Exception) {
// Ensure a failed batch is rolled back.

View File

@@ -722,7 +722,7 @@ namespace Orchard.ContentManagement {
// Insert or Update imported data into the content manager.
// Call content item handlers.
public void Import(XElement element, ImportContentSession importContentSession) {
public void Import(XElement element, ImportContentSession importContentSession, Action<ContentItem> importItemCallback = null) {
var elementId = element.Attribute("Id");
if (elementId == null) {
return;
@@ -764,14 +764,8 @@ namespace Orchard.ContentManagement {
};
}
var context = new ImportContentContext(item, element, importContentSession);
foreach (var contentHandler in Handlers) {
contentHandler.Importing(context);
}
foreach (var contentHandler in Handlers) {
contentHandler.Imported(context);
}
if (importItemCallback != null)
importItemCallback(item);
var savedItem = Get(item.Id, VersionOptions.Latest);

View File

@@ -1,3 +1,4 @@
using System;
using System.Collections.Generic;
using System.Xml.Linq;
using Orchard.ContentManagement.MetaData.Models;
@@ -91,7 +92,7 @@ namespace Orchard.ContentManagement {
void Index(ContentItem contentItem, IDocumentIndex documentIndex);
XElement Export(ContentItem contentItem);
void Import(XElement element, ImportContentSession importContentSession);
void Import(XElement element, ImportContentSession importContentSession, Action<ContentItem> importItemCallback = null);
/// <summary>
/// Clears the current referenced content items