mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2025-09-24 13:33:34 +08:00
- Dynamic field metadata import/export and part definition storage/alteration.
--HG-- branch : dev
This commit is contained in:
@@ -1,8 +1,4 @@
|
|||||||
using System;
|
using Orchard.ContentManagement;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Web;
|
|
||||||
using Orchard.ContentManagement;
|
|
||||||
using Orchard.ContentManagement.Drivers;
|
using Orchard.ContentManagement.Drivers;
|
||||||
using Orchard.Core.Common.Models;
|
using Orchard.Core.Common.Models;
|
||||||
using Orchard.Core.Common.ViewModels;
|
using Orchard.Core.Common.ViewModels;
|
||||||
|
@@ -13,16 +13,19 @@ namespace Orchard.Core.Settings.Metadata {
|
|||||||
public class ContentDefinitionManager : Component, IContentDefinitionManager {
|
public class ContentDefinitionManager : Component, IContentDefinitionManager {
|
||||||
private readonly IRepository<ContentTypeDefinitionRecord> _typeDefinitionRepository;
|
private readonly IRepository<ContentTypeDefinitionRecord> _typeDefinitionRepository;
|
||||||
private readonly IRepository<ContentPartDefinitionRecord> _partDefinitionRepository;
|
private readonly IRepository<ContentPartDefinitionRecord> _partDefinitionRepository;
|
||||||
|
private readonly IRepository<ContentFieldDefinitionRecord> _fieldDefinitionRepository;
|
||||||
private readonly IMapper<XElement, IDictionary<string, string>> _settingsReader;
|
private readonly IMapper<XElement, IDictionary<string, string>> _settingsReader;
|
||||||
private readonly IMapper<IDictionary<string, string>, XElement> _settingsWriter;
|
private readonly IMapper<IDictionary<string, string>, XElement> _settingsWriter;
|
||||||
|
|
||||||
public ContentDefinitionManager(
|
public ContentDefinitionManager(
|
||||||
IRepository<ContentTypeDefinitionRecord> typeDefinitionRepository,
|
IRepository<ContentTypeDefinitionRecord> typeDefinitionRepository,
|
||||||
IRepository<ContentPartDefinitionRecord> partDefinitionRepository,
|
IRepository<ContentPartDefinitionRecord> partDefinitionRepository,
|
||||||
|
IRepository<ContentFieldDefinitionRecord> fieldDefinitionRepository,
|
||||||
IMapper<XElement, IDictionary<string, string>> settingsReader,
|
IMapper<XElement, IDictionary<string, string>> settingsReader,
|
||||||
IMapper<IDictionary<string, string>, XElement> settingsWriter) {
|
IMapper<IDictionary<string, string>, XElement> settingsWriter) {
|
||||||
_typeDefinitionRepository = typeDefinitionRepository;
|
_typeDefinitionRepository = typeDefinitionRepository;
|
||||||
_partDefinitionRepository = partDefinitionRepository;
|
_partDefinitionRepository = partDefinitionRepository;
|
||||||
|
_fieldDefinitionRepository = fieldDefinitionRepository;
|
||||||
_settingsReader = settingsReader;
|
_settingsReader = settingsReader;
|
||||||
_settingsWriter = settingsWriter;
|
_settingsWriter = settingsWriter;
|
||||||
}
|
}
|
||||||
@@ -48,7 +51,7 @@ namespace Orchard.Core.Settings.Metadata {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void StorePartDefinition(ContentPartDefinition contentPartDefinition) {
|
public void StorePartDefinition(ContentPartDefinition contentPartDefinition) {
|
||||||
throw new NotImplementedException();
|
Apply(contentPartDefinition, Acquire(contentPartDefinition));
|
||||||
}
|
}
|
||||||
|
|
||||||
private ContentTypeDefinitionRecord Acquire(ContentTypeDefinition contentTypeDefinition) {
|
private ContentTypeDefinitionRecord Acquire(ContentTypeDefinition contentTypeDefinition) {
|
||||||
@@ -69,6 +72,15 @@ namespace Orchard.Core.Settings.Metadata {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ContentFieldDefinitionRecord Acquire(ContentFieldDefinition contentFieldDefinition) {
|
||||||
|
var result = _fieldDefinitionRepository.Fetch(x => x.Name == contentFieldDefinition.Name).SingleOrDefault();
|
||||||
|
if (result == null) {
|
||||||
|
result = new ContentFieldDefinitionRecord { Name = contentFieldDefinition.Name };
|
||||||
|
_fieldDefinitionRepository.Create(result);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
private void Apply(ContentTypeDefinition model, ContentTypeDefinitionRecord record) {
|
private void Apply(ContentTypeDefinition model, ContentTypeDefinitionRecord record) {
|
||||||
record.Settings = _settingsWriter.Map(model.Settings).ToString();
|
record.Settings = _settingsWriter.Map(model.Settings).ToString();
|
||||||
|
|
||||||
@@ -95,7 +107,34 @@ namespace Orchard.Core.Settings.Metadata {
|
|||||||
record.Settings = Compose(_settingsWriter.Map(model.Settings));
|
record.Settings = Compose(_settingsWriter.Map(model.Settings));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void Apply(ContentPartDefinition model, ContentPartDefinitionRecord record) {
|
||||||
|
record.Settings = _settingsWriter.Map(model.Settings).ToString();
|
||||||
|
|
||||||
|
var toRemove = record.ContentPartFieldDefinitionRecords
|
||||||
|
.Where(fieldDefinitionRecord => !model.Fields.Any(field => fieldDefinitionRecord.ContentFieldDefinitionRecord.Name == field.FieldDefinition.Name))
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
foreach (var remove in toRemove) {
|
||||||
|
record.ContentPartFieldDefinitionRecords.Remove(remove);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var field in model.Fields) {
|
||||||
|
var fieldName = field.FieldDefinition.Name;
|
||||||
|
var partFieldRecord = record.ContentPartFieldDefinitionRecords.SingleOrDefault(r => r.ContentFieldDefinitionRecord.Name == fieldName);
|
||||||
|
if (partFieldRecord == null) {
|
||||||
|
partFieldRecord = new ContentPartFieldDefinitionRecord {
|
||||||
|
ContentFieldDefinitionRecord = Acquire(field.FieldDefinition),
|
||||||
|
Name = field.Name
|
||||||
|
};
|
||||||
|
record.ContentPartFieldDefinitionRecords.Add(partFieldRecord);
|
||||||
|
}
|
||||||
|
Apply(field, partFieldRecord);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Apply(ContentPartDefinition.Field model, ContentPartFieldDefinitionRecord record) {
|
||||||
|
record.Settings = Compose(_settingsWriter.Map(model.Settings));
|
||||||
|
}
|
||||||
|
|
||||||
ContentTypeDefinition Build(ContentTypeDefinitionRecord source) {
|
ContentTypeDefinition Build(ContentTypeDefinitionRecord source) {
|
||||||
return new ContentTypeDefinition(
|
return new ContentTypeDefinition(
|
||||||
|
@@ -1,8 +1,4 @@
|
|||||||
using System;
|
using System.IO;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Web;
|
|
||||||
using System.Web.Mvc;
|
using System.Web.Mvc;
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
using System.Xml.Linq;
|
using System.Xml.Linq;
|
||||||
@@ -59,6 +55,11 @@ namespace Orchard.DevTools.Controllers {
|
|||||||
var typeName = XmlConvert.DecodeName(element.Name.LocalName);
|
var typeName = XmlConvert.DecodeName(element.Name.LocalName);
|
||||||
_contentDefinitionManager.AlterTypeDefinition(typeName, alteration => _contentDefinitionReader.Merge(typeElement, alteration));
|
_contentDefinitionManager.AlterTypeDefinition(typeName, alteration => _contentDefinitionReader.Merge(typeElement, alteration));
|
||||||
}
|
}
|
||||||
|
foreach (var element in root.Elements("Parts").Elements()) {
|
||||||
|
var partElement = element;
|
||||||
|
var partName = XmlConvert.DecodeName(element.Name.LocalName);
|
||||||
|
_contentDefinitionManager.AlterPartDefinition(partName, alteration => _contentDefinitionReader.Merge(partElement, alteration));
|
||||||
|
}
|
||||||
return RedirectToAction("Index");
|
return RedirectToAction("Index");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,10 +1,11 @@
|
|||||||
using System.Collections.Generic;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Orchard.ContentManagement.MetaData.Models;
|
using Orchard.ContentManagement.MetaData.Models;
|
||||||
|
|
||||||
namespace Orchard.ContentManagement.MetaData.Builders {
|
namespace Orchard.ContentManagement.MetaData.Builders {
|
||||||
public class ContentPartDefinitionBuilder {
|
public class ContentPartDefinitionBuilder {
|
||||||
private readonly string _name;
|
private string _name;
|
||||||
private readonly IList<ContentPartDefinition.Field> _fields;
|
private readonly IList<ContentPartDefinition.Field> _fields;
|
||||||
private readonly IDictionary<string, string> _settings;
|
private readonly IDictionary<string, string> _settings;
|
||||||
|
|
||||||
@@ -28,10 +29,83 @@ namespace Orchard.ContentManagement.MetaData.Builders {
|
|||||||
return new ContentPartDefinition(_name, _fields, _settings);
|
return new ContentPartDefinition(_name, _fields, _settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ContentPartDefinitionBuilder Named(string name) {
|
||||||
|
_name = name;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ContentPartDefinitionBuilder RemoveField(string fieldName) {
|
||||||
|
var existingField = _fields.SingleOrDefault(x => x.FieldDefinition.Name == fieldName);
|
||||||
|
if (existingField != null) {
|
||||||
|
_fields.Remove(existingField);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public ContentPartDefinitionBuilder WithSetting(string name, string value) {
|
public ContentPartDefinitionBuilder WithSetting(string name, string value) {
|
||||||
_settings[name] = value;
|
_settings[name] = value;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ContentPartDefinitionBuilder WithField(string fieldName) {
|
||||||
|
return WithField(fieldName, configuration => { });
|
||||||
|
}
|
||||||
|
|
||||||
|
public ContentPartDefinitionBuilder WithField(string fieldName, Action<FieldConfigurer> configuration) {
|
||||||
|
var fieldDefinition = new ContentFieldDefinition(fieldName);
|
||||||
|
var existingField = _fields.SingleOrDefault(x => x.FieldDefinition.Name == fieldDefinition.Name);
|
||||||
|
if (existingField != null) {
|
||||||
|
_fields.Remove(existingField);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
existingField = new ContentPartDefinition.Field(fieldDefinition, fieldName, new Dictionary<string, string>());
|
||||||
|
}
|
||||||
|
var configurer = new FieldConfigurerImpl(existingField);
|
||||||
|
configuration(configurer);
|
||||||
|
_fields.Add(configurer.Build());
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract class FieldConfigurer {
|
||||||
|
protected readonly IDictionary<string, string> _settings;
|
||||||
|
|
||||||
|
protected FieldConfigurer(ContentPartDefinition.Field field) {
|
||||||
|
_settings = field.Settings.ToDictionary(kv => kv.Key, kv => kv.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public FieldConfigurer WithSetting(string name, string value) {
|
||||||
|
_settings[name] = value;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract FieldConfigurer OfType(ContentFieldDefinition fieldDefinition);
|
||||||
|
public abstract FieldConfigurer OfType(string fieldType);
|
||||||
|
}
|
||||||
|
|
||||||
|
class FieldConfigurerImpl : FieldConfigurer {
|
||||||
|
private ContentFieldDefinition _fieldDefinition;
|
||||||
|
private string _fieldName;
|
||||||
|
|
||||||
|
public FieldConfigurerImpl(ContentPartDefinition.Field field)
|
||||||
|
: base(field) {
|
||||||
|
_fieldDefinition = field.FieldDefinition;
|
||||||
|
_fieldName = field.Name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ContentPartDefinition.Field Build() {
|
||||||
|
return new ContentPartDefinition.Field(_fieldDefinition, _fieldName, _settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override FieldConfigurer OfType(ContentFieldDefinition fieldDefinition) {
|
||||||
|
_fieldDefinition = fieldDefinition;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override FieldConfigurer OfType(string fieldType) {
|
||||||
|
_fieldDefinition = new ContentFieldDefinition(fieldType);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -5,6 +5,7 @@ using Orchard.ContentManagement.MetaData.Models;
|
|||||||
namespace Orchard.ContentManagement.MetaData {
|
namespace Orchard.ContentManagement.MetaData {
|
||||||
public interface IContentDefinitionReader : IDependency {
|
public interface IContentDefinitionReader : IDependency {
|
||||||
void Merge(XElement source, ContentTypeDefinitionBuilder builder);
|
void Merge(XElement source, ContentTypeDefinitionBuilder builder);
|
||||||
|
void Merge(XElement source, ContentPartDefinitionBuilder builder);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class ContentDefinitionReaderExtensions {
|
public static class ContentDefinitionReaderExtensions {
|
||||||
|
@@ -1,5 +1,4 @@
|
|||||||
using System;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
using System.Xml.Linq;
|
using System.Xml.Linq;
|
||||||
using Orchard.ContentManagement.MetaData.Builders;
|
using Orchard.ContentManagement.MetaData.Builders;
|
||||||
@@ -28,5 +27,25 @@ namespace Orchard.ContentManagement.MetaData.Services {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Merge(XElement source, ContentPartDefinitionBuilder builder) {
|
||||||
|
builder.Named(XmlConvert.DecodeName(source.Name.LocalName));
|
||||||
|
foreach (var setting in _settingsReader.Map(source)) {
|
||||||
|
builder.WithSetting(setting.Key, setting.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var iter in source.Elements()) {
|
||||||
|
var fieldElement = iter;
|
||||||
|
string[] fieldParameters = fieldElement.Name.LocalName.Split('.');
|
||||||
|
builder.WithField(
|
||||||
|
XmlConvert.DecodeName(fieldParameters[0]),
|
||||||
|
fieldBuilder => {
|
||||||
|
foreach (var setting in _settingsReader.Map(fieldElement)) {
|
||||||
|
fieldBuilder.WithSetting(setting.Key, setting.Value);
|
||||||
|
}
|
||||||
|
fieldBuilder.OfType(fieldParameters[1]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -24,8 +24,8 @@ namespace Orchard.ContentManagement.MetaData.Services {
|
|||||||
public XElement Export(ContentPartDefinition partDefinition) {
|
public XElement Export(ContentPartDefinition partDefinition) {
|
||||||
var partElement = NewElement(partDefinition.Name, partDefinition.Settings);
|
var partElement = NewElement(partDefinition.Name, partDefinition.Settings);
|
||||||
foreach(var partField in partDefinition.Fields) {
|
foreach(var partField in partDefinition.Fields) {
|
||||||
var partFieldElement = NewElement(partField.Name, partField.Settings);
|
var attributeName = partField.Name + "." + partField.FieldDefinition.Name;
|
||||||
partFieldElement.SetAttributeValue("FieldType", partField.FieldDefinition.Name);
|
var partFieldElement = NewElement(attributeName, partField.Settings);
|
||||||
partElement.Add(partFieldElement);
|
partElement.Add(partFieldElement);
|
||||||
}
|
}
|
||||||
return partElement;
|
return partElement;
|
||||||
|
Reference in New Issue
Block a user