Merge remote-tracking branch 'origin/v8/feature/media-tracking' into netcore/dev
# Conflicts: # src/Umbraco.Abstractions/Models/IDataValueEditor.cs # src/Umbraco.Abstractions/Models/RelationType.cs # src/Umbraco.Core/Contants-UdiEntityType.cs # src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs # src/Umbraco.Core/Udi.cs # src/Umbraco.Tests/Models/RelationTests.cs # src/Umbraco.Tests/Models/RelationTypeTests.cs # src/Umbraco.Tests/Persistence/Repositories/MediaRepositoryTest.cs # src/Umbraco.Tests/Persistence/Repositories/UserRepositoryTest.cs # src/Umbraco.Tests/Published/NestedContentTests.cs # src/Umbraco.Tests/PublishedContent/PublishedContentTestBase.cs # src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs # src/Umbraco.Tests/Services/ContentServicePerformanceTest.cs # src/Umbraco.Tests/Testing/UmbracoTestBase.cs # src/Umbraco.Tests/Web/TemplateUtilitiesTests.cs # src/Umbraco.Web/Editors/MediaController.cs # src/Umbraco.Web/PropertyEditors/GridPropertyEditor.cs # src/Umbraco.Web/PropertyEditors/NestedContentPropertyEditor.cs # src/Umbraco.Web/PropertyEditors/RichTextPropertyEditor.cs # src/Umbraco.Web/Runtime/WebInitialComposer.cs # src/Umbraco.Web/Templates/TemplateUtilities.cs # src/Umbraco.Web/UmbracoComponentRenderer.cs
This commit is contained in:
@@ -225,34 +225,65 @@ namespace Umbraco.Core
|
||||
public static class RelationTypes
|
||||
{
|
||||
/// <summary>
|
||||
/// ContentType name for default relation type "Relate Document On Copy".
|
||||
/// Name for default relation type "Related Media".
|
||||
/// </summary>
|
||||
public const string RelatedMediaName = "Related Media";
|
||||
|
||||
/// <summary>
|
||||
/// Alias for default relation type "Related Media"
|
||||
/// </summary>
|
||||
public const string RelatedMediaAlias = "umbMedia";
|
||||
|
||||
/// <summary>
|
||||
/// Name for default relation type "Related Document".
|
||||
/// </summary>
|
||||
public const string RelatedDocumentName = "Related Document";
|
||||
|
||||
/// <summary>
|
||||
/// Alias for default relation type "Related Document"
|
||||
/// </summary>
|
||||
public const string RelatedDocumentAlias = "umbDocument";
|
||||
|
||||
/// <summary>
|
||||
/// Name for default relation type "Relate Document On Copy".
|
||||
/// </summary>
|
||||
public const string RelateDocumentOnCopyName = "Relate Document On Copy";
|
||||
|
||||
/// <summary>
|
||||
/// ContentType alias for default relation type "Relate Document On Copy".
|
||||
/// Alias for default relation type "Relate Document On Copy".
|
||||
/// </summary>
|
||||
public const string RelateDocumentOnCopyAlias = "relateDocumentOnCopy";
|
||||
|
||||
/// <summary>
|
||||
/// ContentType name for default relation type "Relate Parent Document On Delete".
|
||||
/// Name for default relation type "Relate Parent Document On Delete".
|
||||
/// </summary>
|
||||
public const string RelateParentDocumentOnDeleteName = "Relate Parent Document On Delete";
|
||||
|
||||
/// <summary>
|
||||
/// ContentType alias for default relation type "Relate Parent Document On Delete".
|
||||
/// Alias for default relation type "Relate Parent Document On Delete".
|
||||
/// </summary>
|
||||
public const string RelateParentDocumentOnDeleteAlias = "relateParentDocumentOnDelete";
|
||||
|
||||
/// <summary>
|
||||
/// ContentType name for default relation type "Relate Parent Media Folder On Delete".
|
||||
/// Name for default relation type "Relate Parent Media Folder On Delete".
|
||||
/// </summary>
|
||||
public const string RelateParentMediaFolderOnDeleteName = "Relate Parent Media Folder On Delete";
|
||||
|
||||
/// <summary>
|
||||
/// ContentType alias for default relation type "Relate Parent Media Folder On Delete".
|
||||
/// Alias for default relation type "Relate Parent Media Folder On Delete".
|
||||
/// </summary>
|
||||
public const string RelateParentMediaFolderOnDeleteAlias = "relateParentMediaFolderOnDelete";
|
||||
|
||||
/// <summary>
|
||||
/// Returns the types of relations that are automatically tracked
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Developers should not manually use these relation types since they will all be cleared whenever an entity
|
||||
/// (content, media or member) is saved since they are auto-populated based on property values.
|
||||
/// </remarks>
|
||||
public static string[] AutomaticRelationTypes = new[] { RelatedMediaAlias, RelatedDocumentAlias };
|
||||
|
||||
//TODO: return a list of built in types so we can use that to prevent deletion in the uI
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
// need to keep it around in a field nor to make it readonly
|
||||
|
||||
|
||||
public const string Unknown = "unknown";
|
||||
public const string Unknown = "unknown";
|
||||
|
||||
// guid entity types
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
namespace Umbraco.Core.Models.Editors
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Represents an uploaded file for a property.
|
||||
/// </summary>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
/// Sets the parent entity.
|
||||
/// </summary>
|
||||
/// <remarks>Use this method to set the parent entity when the parent entity is known, but has not
|
||||
/// been persistent and does not yet have an identity. The parent identifier will we retrieved
|
||||
/// been persistent and does not yet have an identity. The parent identifier will be retrieved
|
||||
/// from the parent entity when needed. If the parent entity still does not have an entity by that
|
||||
/// time, an exception will be thrown by <see cref="ParentId"/> getter.</remarks>
|
||||
void SetParent(ITreeEntity parent);
|
||||
@@ -53,4 +53,4 @@
|
||||
/// </remarks>
|
||||
bool Trashed { get; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,6 @@
|
||||
namespace Umbraco.Core.Models.Entities
|
||||
{
|
||||
public class MemberEntitySlim : EntitySlim, IMemberEntitySlim
|
||||
public class MemberEntitySlim : ContentEntitySlim, IMemberEntitySlim
|
||||
{
|
||||
public string ContentTypeAlias { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public string ContentTypeIcon { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public string ContentTypeThumbnail { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,9 +3,11 @@ using System.ComponentModel.DataAnnotations;
|
||||
using System.Xml.Linq;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.Editors;
|
||||
using Umbraco.Core.Services;
|
||||
|
||||
namespace Umbraco.Core.PropertyEditors
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Represents an editor for editing data values.
|
||||
/// </summary>
|
||||
@@ -62,8 +64,26 @@ namespace Umbraco.Core.PropertyEditors
|
||||
|
||||
// TODO: / deal with this when unplugging the xml cache
|
||||
// why property vs propertyType? services should be injected! etc...
|
||||
IEnumerable<XElement> ConvertDbToXml(IProperty property, bool published);
|
||||
XNode ConvertDbToXml(IPropertyType propertyType, object value);
|
||||
string ConvertDbToString(IPropertyType propertyType, object value);
|
||||
|
||||
/// <summary>
|
||||
/// Used for serializing an <see cref="IContent"/> item for packaging
|
||||
/// </summary>
|
||||
/// <param name="property"></param>
|
||||
/// <param name="dataTypeService"></param>
|
||||
/// <param name="localizationService"></param>
|
||||
/// <param name="published"></param>
|
||||
/// <returns></returns>
|
||||
IEnumerable<XElement> ConvertDbToXml(IProperty property, IDataTypeService dataTypeService, ILocalizationService localizationService, bool published);
|
||||
|
||||
/// <summary>
|
||||
/// Used for serializing an <see cref="IContent"/> item for packaging
|
||||
/// </summary>
|
||||
/// <param name="propertyType"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="dataTypeService"></param>
|
||||
/// <returns></returns>
|
||||
XNode ConvertDbToXml(IPropertyType propertyType, object value, IDataTypeService dataTypeService);
|
||||
|
||||
string ConvertDbToString(IPropertyType propertyType, object value, IDataTypeService dataTypeService);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Runtime.Serialization;
|
||||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Core.Models.Entities;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
@@ -11,12 +12,18 @@ namespace Umbraco.Core.Models
|
||||
[DataMember]
|
||||
int ParentId { get; set; }
|
||||
|
||||
[DataMember]
|
||||
Guid ParentObjectType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Child Id of the Relation (Destination)
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
int ChildId { get; set; }
|
||||
|
||||
[DataMember]
|
||||
Guid ChildObjectType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the <see cref="RelationType"/> for the Relation
|
||||
/// </summary>
|
||||
|
||||
@@ -29,13 +29,13 @@ namespace Umbraco.Core.Models
|
||||
/// </summary>
|
||||
/// <remarks>Corresponds to the NodeObjectType in the umbracoNode table</remarks>
|
||||
[DataMember]
|
||||
Guid ParentObjectType { get; set; }
|
||||
Guid? ParentObjectType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Childs object type id
|
||||
/// </summary>
|
||||
/// <remarks>Corresponds to the NodeObjectType in the umbracoNode table</remarks>
|
||||
[DataMember]
|
||||
Guid ChildObjectType { get; set; }
|
||||
Guid? ChildObjectType { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,13 +17,36 @@ namespace Umbraco.Core.Models
|
||||
private IRelationType _relationType;
|
||||
private string _comment;
|
||||
|
||||
/// <summary>
|
||||
/// Constructor for constructing the entity to be created
|
||||
/// </summary>
|
||||
/// <param name="parentId"></param>
|
||||
/// <param name="childId"></param>
|
||||
/// <param name="relationType"></param>
|
||||
public Relation(int parentId, int childId, IRelationType relationType)
|
||||
{
|
||||
_parentId = parentId;
|
||||
_childId = childId;
|
||||
_relationType = relationType;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Constructor for reconstructing the entity from the data source
|
||||
/// </summary>
|
||||
/// <param name="parentId"></param>
|
||||
/// <param name="childId"></param>
|
||||
/// <param name="parentObjectType"></param>
|
||||
/// <param name="childObjectType"></param>
|
||||
/// <param name="relationType"></param>
|
||||
public Relation(int parentId, int childId, Guid parentObjectType, Guid childObjectType, IRelationType relationType)
|
||||
{
|
||||
_parentId = parentId;
|
||||
_childId = childId;
|
||||
_relationType = relationType;
|
||||
ParentObjectType = parentObjectType;
|
||||
ChildObjectType = childObjectType;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Parent Id of the Relation (Source)
|
||||
@@ -35,6 +58,9 @@ namespace Umbraco.Core.Models
|
||||
set => SetPropertyValueAndDetectChanges(value, ref _parentId, nameof(ParentId));
|
||||
}
|
||||
|
||||
[DataMember]
|
||||
public Guid ParentObjectType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Child Id of the Relation (Destination)
|
||||
/// </summary>
|
||||
@@ -45,6 +71,9 @@ namespace Umbraco.Core.Models
|
||||
set => SetPropertyValueAndDetectChanges(value, ref _childId, nameof(ChildId));
|
||||
}
|
||||
|
||||
[DataMember]
|
||||
public Guid ChildObjectType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the <see cref="RelationType"/> for the Relation
|
||||
/// </summary>
|
||||
|
||||
@@ -14,28 +14,24 @@ namespace Umbraco.Core.Models
|
||||
private string _name;
|
||||
private string _alias;
|
||||
private bool _isBidrectional;
|
||||
private Guid _parentObjectType;
|
||||
private Guid _childObjectType;
|
||||
private Guid? _parentObjectType;
|
||||
private Guid? _childObjectType;
|
||||
|
||||
public RelationType(Guid childObjectType, Guid parentObjectType, string alias)
|
||||
public RelationType(string alias, string name)
|
||||
: this(name, alias, false, null, null)
|
||||
{
|
||||
if (alias == null) throw new ArgumentNullException(nameof(alias));
|
||||
if (string.IsNullOrWhiteSpace(alias)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(alias));
|
||||
}
|
||||
|
||||
_childObjectType = childObjectType;
|
||||
_parentObjectType = parentObjectType;
|
||||
public RelationType(string name, string alias, bool isBidrectional, Guid? parentObjectType, Guid? childObjectType)
|
||||
{
|
||||
_name = name;
|
||||
_alias = alias;
|
||||
Name = _alias;
|
||||
_isBidrectional = isBidrectional;
|
||||
_parentObjectType = parentObjectType;
|
||||
_childObjectType = childObjectType;
|
||||
}
|
||||
|
||||
public RelationType(Guid childObjectType, Guid parentObjectType, string alias, string name)
|
||||
: this(childObjectType, parentObjectType, alias)
|
||||
{
|
||||
if (name == null) throw new ArgumentNullException(nameof(name));
|
||||
if (string.IsNullOrWhiteSpace(name)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(name));
|
||||
|
||||
Name = name;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Name of the RelationType
|
||||
@@ -72,7 +68,7 @@ namespace Umbraco.Core.Models
|
||||
/// </summary>
|
||||
/// <remarks>Corresponds to the NodeObjectType in the umbracoNode table</remarks>
|
||||
[DataMember]
|
||||
public Guid ParentObjectType
|
||||
public Guid? ParentObjectType
|
||||
{
|
||||
get => _parentObjectType;
|
||||
set => SetPropertyValueAndDetectChanges(value, ref _parentObjectType, nameof(ParentObjectType));
|
||||
@@ -83,7 +79,7 @@ namespace Umbraco.Core.Models
|
||||
/// </summary>
|
||||
/// <remarks>Corresponds to the NodeObjectType in the umbracoNode table</remarks>
|
||||
[DataMember]
|
||||
public Guid ChildObjectType
|
||||
public Guid? ChildObjectType
|
||||
{
|
||||
get => _childObjectType;
|
||||
set => SetPropertyValueAndDetectChanges(value, ref _childObjectType, nameof(ChildObjectType));
|
||||
|
||||
@@ -1,9 +1,33 @@
|
||||
using Umbraco.Core.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.Entities;
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
using Umbraco.Core.Services;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
public interface IRelationRepository : IReadWriteQueryRepository<int, IRelation>
|
||||
{
|
||||
IEnumerable<IRelation> GetPagedRelationsByQuery(IQuery<IRelation> query, long pageIndex, int pageSize, out long totalRecords, Ordering ordering);
|
||||
|
||||
/// <summary>
|
||||
/// Persist multiple <see cref="IRelation"/> at once
|
||||
/// </summary>
|
||||
/// <param name="relations"></param>
|
||||
void Save(IEnumerable<IRelation> relations);
|
||||
|
||||
/// <summary>
|
||||
/// Deletes all relations for a parent for any specified relation type alias
|
||||
/// </summary>
|
||||
/// <param name="parentId"></param>
|
||||
/// <param name="relationTypeAliases">
|
||||
/// A list of relation types to match for deletion, if none are specified then all relations for this parent id are deleted
|
||||
/// </param>
|
||||
void DeleteByParent(int parentId, params string[] relationTypeAliases);
|
||||
|
||||
IEnumerable<IUmbracoEntity> GetPagedParentEntitiesByChildId(int childId, long pageIndex, int pageSize, out long totalRecords, params Guid[] entityTypes);
|
||||
|
||||
IEnumerable<IUmbracoEntity> GetPagedChildEntitiesByParentId(int parentId, long pageIndex, int pageSize, out long totalRecords, params Guid[] entityTypes);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@ using Umbraco.Core.Manifest;
|
||||
|
||||
namespace Umbraco.Core.PropertyEditors
|
||||
{
|
||||
|
||||
|
||||
public class PropertyEditorCollection : BuilderCollectionBase<IDataEditor>
|
||||
{
|
||||
public PropertyEditorCollection(DataEditorCollection dataEditors, IManifestParser manifestParser)
|
||||
|
||||
@@ -8,136 +8,162 @@ namespace Umbraco.Core.Services
|
||||
public interface IRelationService : IService
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets a <see cref="Relation"/> by its Id
|
||||
/// Gets a <see cref="IRelation"/> by its Id
|
||||
/// </summary>
|
||||
/// <param name="id">Id of the <see cref="Relation"/></param>
|
||||
/// <returns>A <see cref="Relation"/> object</returns>
|
||||
/// <param name="id">Id of the <see cref="IRelation"/></param>
|
||||
/// <returns>A <see cref="IRelation"/> object</returns>
|
||||
IRelation GetById(int id);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a <see cref="RelationType"/> by its Id
|
||||
/// Gets a <see cref="IRelationType"/> by its Id
|
||||
/// </summary>
|
||||
/// <param name="id">Id of the <see cref="RelationType"/></param>
|
||||
/// <returns>A <see cref="RelationType"/> object</returns>
|
||||
/// <param name="id">Id of the <see cref="IRelationType"/></param>
|
||||
/// <returns>A <see cref="IRelationType"/> object</returns>
|
||||
IRelationType GetRelationTypeById(int id);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a <see cref="RelationType"/> by its Id
|
||||
/// Gets a <see cref="IRelationType"/> by its Id
|
||||
/// </summary>
|
||||
/// <param name="id">Id of the <see cref="RelationType"/></param>
|
||||
/// <returns>A <see cref="RelationType"/> object</returns>
|
||||
/// <param name="id">Id of the <see cref="IRelationType"/></param>
|
||||
/// <returns>A <see cref="IRelationType"/> object</returns>
|
||||
IRelationType GetRelationTypeById(Guid id);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a <see cref="RelationType"/> by its Alias
|
||||
/// Gets a <see cref="IRelationType"/> by its Alias
|
||||
/// </summary>
|
||||
/// <param name="alias">Alias of the <see cref="RelationType"/></param>
|
||||
/// <returns>A <see cref="RelationType"/> object</returns>
|
||||
/// <param name="alias">Alias of the <see cref="IRelationType"/></param>
|
||||
/// <returns>A <see cref="IRelationType"/> object</returns>
|
||||
IRelationType GetRelationTypeByAlias(string alias);
|
||||
|
||||
/// <summary>
|
||||
/// Gets all <see cref="Relation"/> objects
|
||||
/// Gets all <see cref="IRelation"/> objects
|
||||
/// </summary>
|
||||
/// <param name="ids">Optional array of integer ids to return relations for</param>
|
||||
/// <returns>An enumerable list of <see cref="Relation"/> objects</returns>
|
||||
/// <returns>An enumerable list of <see cref="IRelation"/> objects</returns>
|
||||
IEnumerable<IRelation> GetAllRelations(params int[] ids);
|
||||
|
||||
/// <summary>
|
||||
/// Gets all <see cref="Relation"/> objects by their <see cref="RelationType"/>
|
||||
/// Gets all <see cref="IRelation"/> objects by their <see cref="IRelationType"/>
|
||||
/// </summary>
|
||||
/// <param name="relationType"><see cref="RelationType"/> to retrieve Relations for</param>
|
||||
/// <returns>An enumerable list of <see cref="Relation"/> objects</returns>
|
||||
IEnumerable<IRelation> GetAllRelationsByRelationType(RelationType relationType);
|
||||
/// <param name="relationType"><see cref="IRelation"/> to retrieve Relations for</param>
|
||||
/// <returns>An enumerable list of <see cref="IRelation"/> objects</returns>
|
||||
IEnumerable<IRelation> GetAllRelationsByRelationType(IRelationType relationType);
|
||||
|
||||
/// <summary>
|
||||
/// Gets all <see cref="Relation"/> objects by their <see cref="RelationType"/>'s Id
|
||||
/// Gets all <see cref="IRelation"/> objects by their <see cref="IRelationType"/>'s Id
|
||||
/// </summary>
|
||||
/// <param name="relationTypeId">Id of the <see cref="RelationType"/> to retrieve Relations for</param>
|
||||
/// <returns>An enumerable list of <see cref="Relation"/> objects</returns>
|
||||
/// <param name="relationTypeId">Id of the <see cref="IRelationType"/> to retrieve Relations for</param>
|
||||
/// <returns>An enumerable list of <see cref="IRelation"/> objects</returns>
|
||||
IEnumerable<IRelation> GetAllRelationsByRelationType(int relationTypeId);
|
||||
|
||||
/// <summary>
|
||||
/// Gets all <see cref="Relation"/> objects
|
||||
/// Gets all <see cref="IRelation"/> objects
|
||||
/// </summary>
|
||||
/// <param name="ids">Optional array of integer ids to return relationtypes for</param>
|
||||
/// <returns>An enumerable list of <see cref="RelationType"/> objects</returns>
|
||||
/// <returns>An enumerable list of <see cref="IRelation"/> objects</returns>
|
||||
IEnumerable<IRelationType> GetAllRelationTypes(params int[] ids);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of <see cref="Relation"/> objects by their parent Id
|
||||
/// Gets a list of <see cref="IRelation"/> objects by their parent Id
|
||||
/// </summary>
|
||||
/// <param name="id">Id of the parent to retrieve relations for</param>
|
||||
/// <returns>An enumerable list of <see cref="Relation"/> objects</returns>
|
||||
/// <returns>An enumerable list of <see cref="IRelation"/> objects</returns>
|
||||
IEnumerable<IRelation> GetByParentId(int id);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of <see cref="Relation"/> objects by their parent entity
|
||||
/// Gets a list of <see cref="IRelation"/> objects by their parent Id
|
||||
/// </summary>
|
||||
/// <param name="id">Id of the parent to retrieve relations for</param>
|
||||
/// <param name="relationTypeAlias">Alias of the type of relation to retrieve</param>
|
||||
/// <returns>An enumerable list of <see cref="IRelation"/> objects</returns>
|
||||
IEnumerable<IRelation> GetByParentId(int id, string relationTypeAlias);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of <see cref="IRelation"/> objects by their parent entity
|
||||
/// </summary>
|
||||
/// <param name="parent">Parent Entity to retrieve relations for</param>
|
||||
/// <returns>An enumerable list of <see cref="Relation"/> objects</returns>
|
||||
/// <returns>An enumerable list of <see cref="IRelation"/> objects</returns>
|
||||
IEnumerable<IRelation> GetByParent(IUmbracoEntity parent);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of <see cref="Relation"/> objects by their parent entity
|
||||
/// Gets a list of <see cref="IRelation"/> objects by their parent entity
|
||||
/// </summary>
|
||||
/// <param name="parent">Parent Entity to retrieve relations for</param>
|
||||
/// <param name="relationTypeAlias">Alias of the type of relation to retrieve</param>
|
||||
/// <returns>An enumerable list of <see cref="Relation"/> objects</returns>
|
||||
/// <returns>An enumerable list of <see cref="IRelation"/> objects</returns>
|
||||
IEnumerable<IRelation> GetByParent(IUmbracoEntity parent, string relationTypeAlias);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of <see cref="Relation"/> objects by their child Id
|
||||
/// Gets a list of <see cref="IRelation"/> objects by their child Id
|
||||
/// </summary>
|
||||
/// <param name="id">Id of the child to retrieve relations for</param>
|
||||
/// <returns>An enumerable list of <see cref="Relation"/> objects</returns>
|
||||
/// <returns>An enumerable list of <see cref="IRelation"/> objects</returns>
|
||||
IEnumerable<IRelation> GetByChildId(int id);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of <see cref="Relation"/> objects by their child Entity
|
||||
/// Gets a list of <see cref="IRelation"/> objects by their child Id
|
||||
/// </summary>
|
||||
/// <param name="id">Id of the child to retrieve relations for</param>
|
||||
/// <param name="relationTypeAlias">Alias of the type of relation to retrieve</param>
|
||||
/// <returns>An enumerable list of <see cref="IRelation"/> objects</returns>
|
||||
IEnumerable<IRelation> GetByChildId(int id, string relationTypeAlias);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of <see cref="IRelation"/> objects by their child Entity
|
||||
/// </summary>
|
||||
/// <param name="child">Child Entity to retrieve relations for</param>
|
||||
/// <returns>An enumerable list of <see cref="Relation"/> objects</returns>
|
||||
/// <returns>An enumerable list of <see cref="IRelation"/> objects</returns>
|
||||
IEnumerable<IRelation> GetByChild(IUmbracoEntity child);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of <see cref="Relation"/> objects by their child Entity
|
||||
/// Gets a list of <see cref="IRelation"/> objects by their child Entity
|
||||
/// </summary>
|
||||
/// <param name="child">Child Entity to retrieve relations for</param>
|
||||
/// <param name="relationTypeAlias">Alias of the type of relation to retrieve</param>
|
||||
/// <returns>An enumerable list of <see cref="Relation"/> objects</returns>
|
||||
/// <returns>An enumerable list of <see cref="IRelation"/> objects</returns>
|
||||
IEnumerable<IRelation> GetByChild(IUmbracoEntity child, string relationTypeAlias);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of <see cref="Relation"/> objects by their child or parent Id.
|
||||
/// Gets a list of <see cref="IRelation"/> objects by their child or parent Id.
|
||||
/// Using this method will get you all relations regards of it being a child or parent relation.
|
||||
/// </summary>
|
||||
/// <param name="id">Id of the child or parent to retrieve relations for</param>
|
||||
/// <returns>An enumerable list of <see cref="Relation"/> objects</returns>
|
||||
/// <returns>An enumerable list of <see cref="IRelation"/> objects</returns>
|
||||
IEnumerable<IRelation> GetByParentOrChildId(int id);
|
||||
|
||||
IEnumerable<IRelation> GetByParentOrChildId(int id, string relationTypeAlias);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of <see cref="Relation"/> objects by the Name of the <see cref="RelationType"/>
|
||||
/// Gets a list of <see cref="IRelation"/> objects by the Name of the <see cref="IRelationType"/>
|
||||
/// </summary>
|
||||
/// <param name="relationTypeName">Name of the <see cref="RelationType"/> to retrieve Relations for</param>
|
||||
/// <returns>An enumerable list of <see cref="Relation"/> objects</returns>
|
||||
/// <param name="relationTypeName">Name of the <see cref="IRelationType"/> to retrieve Relations for</param>
|
||||
/// <returns>An enumerable list of <see cref="IRelation"/> objects</returns>
|
||||
IEnumerable<IRelation> GetByRelationTypeName(string relationTypeName);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of <see cref="Relation"/> objects by the Alias of the <see cref="RelationType"/>
|
||||
/// Gets a list of <see cref="IRelation"/> objects by the Alias of the <see cref="IRelationType"/>
|
||||
/// </summary>
|
||||
/// <param name="relationTypeAlias">Alias of the <see cref="RelationType"/> to retrieve Relations for</param>
|
||||
/// <returns>An enumerable list of <see cref="Relation"/> objects</returns>
|
||||
/// <param name="relationTypeAlias">Alias of the <see cref="IRelationType"/> to retrieve Relations for</param>
|
||||
/// <returns>An enumerable list of <see cref="IRelation"/> objects</returns>
|
||||
IEnumerable<IRelation> GetByRelationTypeAlias(string relationTypeAlias);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of <see cref="Relation"/> objects by the Id of the <see cref="RelationType"/>
|
||||
/// Gets a list of <see cref="IRelation"/> objects by the Id of the <see cref="IRelationType"/>
|
||||
/// </summary>
|
||||
/// <param name="relationTypeId">Id of the <see cref="RelationType"/> to retrieve Relations for</param>
|
||||
/// <returns>An enumerable list of <see cref="Relation"/> objects</returns>
|
||||
/// <param name="relationTypeId">Id of the <see cref="IRelationType"/> to retrieve Relations for</param>
|
||||
/// <returns>An enumerable list of <see cref="IRelation"/> objects</returns>
|
||||
IEnumerable<IRelation> GetByRelationTypeId(int relationTypeId);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a paged result of <see cref="IRelation"/>
|
||||
/// </summary>
|
||||
/// <param name="relationTypeId"></param>
|
||||
/// <param name="pageIndex"></param>
|
||||
/// <param name="pageSize"></param>
|
||||
/// <param name="totalChildren"></param>
|
||||
/// <returns></returns>
|
||||
IEnumerable<IRelation> GetPagedByRelationTypeId(int relationTypeId, long pageIndex, int pageSize, out long totalRecords, Ordering ordering = null);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Child object from a Relation as an <see cref="IUmbracoEntity"/>
|
||||
/// </summary>
|
||||
@@ -173,6 +199,26 @@ namespace Umbraco.Core.Services
|
||||
/// <returns>An enumerable list of <see cref="IUmbracoEntity"/></returns>
|
||||
IEnumerable<IUmbracoEntity> GetParentEntitiesFromRelations(IEnumerable<IRelation> relations);
|
||||
|
||||
/// <summary>
|
||||
/// Returns paged parent entities for a related child id
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <param name="pageIndex"></param>
|
||||
/// <param name="pageSize"></param>
|
||||
/// <param name="totalChildren"></param>
|
||||
/// <returns></returns>
|
||||
IEnumerable<IUmbracoEntity> GetPagedParentEntitiesByChildId(int id, long pageIndex, int pageSize, out long totalChildren, params UmbracoObjectTypes[] entityTypes);
|
||||
|
||||
/// <summary>
|
||||
/// Returns paged child entities for a related parent id
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <param name="pageIndex"></param>
|
||||
/// <param name="pageSize"></param>
|
||||
/// <param name="totalChildren"></param>
|
||||
/// <returns></returns>
|
||||
IEnumerable<IUmbracoEntity> GetPagedChildEntitiesByParentId(int id, long pageIndex, int pageSize, out long totalChildren, params UmbracoObjectTypes[] entityTypes);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Parent and Child objects from a list of Relations as a list of <see cref="IUmbracoEntity"/> objects.
|
||||
/// </summary>
|
||||
@@ -186,7 +232,7 @@ namespace Umbraco.Core.Services
|
||||
/// <param name="parentId">Id of the parent</param>
|
||||
/// <param name="childId">Id of the child</param>
|
||||
/// <param name="relationType">The type of relation to create</param>
|
||||
/// <returns>The created <see cref="Relation"/></returns>
|
||||
/// <returns>The created <see cref="IRelation"/></returns>
|
||||
IRelation Relate(int parentId, int childId, IRelationType relationType);
|
||||
|
||||
/// <summary>
|
||||
@@ -195,7 +241,7 @@ namespace Umbraco.Core.Services
|
||||
/// <param name="parent">Parent entity</param>
|
||||
/// <param name="child">Child entity</param>
|
||||
/// <param name="relationType">The type of relation to create</param>
|
||||
/// <returns>The created <see cref="Relation"/></returns>
|
||||
/// <returns>The created <see cref="IRelation"/></returns>
|
||||
IRelation Relate(IUmbracoEntity parent, IUmbracoEntity child, IRelationType relationType);
|
||||
|
||||
/// <summary>
|
||||
@@ -204,7 +250,7 @@ namespace Umbraco.Core.Services
|
||||
/// <param name="parentId">Id of the parent</param>
|
||||
/// <param name="childId">Id of the child</param>
|
||||
/// <param name="relationTypeAlias">Alias of the type of relation to create</param>
|
||||
/// <returns>The created <see cref="Relation"/></returns>
|
||||
/// <returns>The created <see cref="IRelation"/></returns>
|
||||
IRelation Relate(int parentId, int childId, string relationTypeAlias);
|
||||
|
||||
/// <summary>
|
||||
@@ -213,14 +259,14 @@ namespace Umbraco.Core.Services
|
||||
/// <param name="parent">Parent entity</param>
|
||||
/// <param name="child">Child entity</param>
|
||||
/// <param name="relationTypeAlias">Alias of the type of relation to create</param>
|
||||
/// <returns>The created <see cref="Relation"/></returns>
|
||||
/// <returns>The created <see cref="IRelation"/></returns>
|
||||
IRelation Relate(IUmbracoEntity parent, IUmbracoEntity child, string relationTypeAlias);
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether any relations exists for the passed in <see cref="RelationType"/>.
|
||||
/// Checks whether any relations exists for the passed in <see cref="IRelationType"/>.
|
||||
/// </summary>
|
||||
/// <param name="relationType"><see cref="RelationType"/> to check for relations</param>
|
||||
/// <returns>Returns <c>True</c> if any relations exists for the given <see cref="RelationType"/>, otherwise <c>False</c></returns>
|
||||
/// <param name="relationType"><see cref="IRelationType"/> to check for relations</param>
|
||||
/// <returns>Returns <c>True</c> if any relations exists for the given <see cref="IRelationType"/>, otherwise <c>False</c></returns>
|
||||
bool HasRelations(IRelationType relationType);
|
||||
|
||||
/// <summary>
|
||||
@@ -265,33 +311,35 @@ namespace Umbraco.Core.Services
|
||||
bool AreRelated(int parentId, int childId, string relationTypeAlias);
|
||||
|
||||
/// <summary>
|
||||
/// Saves a <see cref="Relation"/>
|
||||
/// Saves a <see cref="IRelation"/>
|
||||
/// </summary>
|
||||
/// <param name="relation">Relation to save</param>
|
||||
void Save(IRelation relation);
|
||||
|
||||
void Save(IEnumerable<IRelation> relations);
|
||||
|
||||
/// <summary>
|
||||
/// Saves a <see cref="RelationType"/>
|
||||
/// Saves a <see cref="IRelationType"/>
|
||||
/// </summary>
|
||||
/// <param name="relationType">RelationType to Save</param>
|
||||
void Save(IRelationType relationType);
|
||||
|
||||
/// <summary>
|
||||
/// Deletes a <see cref="Relation"/>
|
||||
/// Deletes a <see cref="IRelation"/>
|
||||
/// </summary>
|
||||
/// <param name="relation">Relation to Delete</param>
|
||||
void Delete(IRelation relation);
|
||||
|
||||
/// <summary>
|
||||
/// Deletes a <see cref="RelationType"/>
|
||||
/// Deletes a <see cref="IRelationType"/>
|
||||
/// </summary>
|
||||
/// <param name="relationType">RelationType to Delete</param>
|
||||
void Delete(IRelationType relationType);
|
||||
|
||||
/// <summary>
|
||||
/// Deletes all <see cref="Relation"/> objects based on the passed in <see cref="RelationType"/>
|
||||
/// Deletes all <see cref="IRelation"/> objects based on the passed in <see cref="IRelationType"/>
|
||||
/// </summary>
|
||||
/// <param name="relationType"><see cref="RelationType"/> to Delete Relations for</param>
|
||||
/// <param name="relationType"><see cref="IRelationType"/> to Delete Relations for</param>
|
||||
void DeleteRelationsOfType(IRelationType relationType);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
internal class UnknownTypeUdi : Udi
|
||||
public class UnknownTypeUdi : Udi
|
||||
{
|
||||
private UnknownTypeUdi()
|
||||
: base("unknown", "umb://unknown/")
|
||||
|
||||
@@ -26,10 +26,11 @@ namespace Umbraco.Core.Compose
|
||||
|
||||
if (relationType == null)
|
||||
{
|
||||
relationType = new RelationType(Constants.ObjectTypes.Document,
|
||||
relationType = new RelationType(Constants.Conventions.RelationTypes.RelateDocumentOnCopyAlias,
|
||||
Constants.Conventions.RelationTypes.RelateDocumentOnCopyName,
|
||||
true,
|
||||
Constants.ObjectTypes.Document,
|
||||
Constants.Conventions.RelationTypes.RelateDocumentOnCopyAlias,
|
||||
Constants.Conventions.RelationTypes.RelateDocumentOnCopyName) { IsBidirectional = true };
|
||||
Constants.ObjectTypes.Document);
|
||||
|
||||
relationService.Save(relationType);
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ namespace Umbraco.Core.Compose
|
||||
var documentObjectType = Constants.ObjectTypes.Document;
|
||||
const string relationTypeName = Constants.Conventions.RelationTypes.RelateParentDocumentOnDeleteName;
|
||||
|
||||
relationType = new RelationType(documentObjectType, documentObjectType, relationTypeAlias, relationTypeName);
|
||||
relationType = new RelationType(relationTypeName, relationTypeAlias, false, documentObjectType, documentObjectType);
|
||||
relationService.Save(relationType);
|
||||
}
|
||||
|
||||
@@ -106,7 +106,7 @@ namespace Umbraco.Core.Compose
|
||||
{
|
||||
var documentObjectType = Constants.ObjectTypes.Document;
|
||||
const string relationTypeName = Constants.Conventions.RelationTypes.RelateParentMediaFolderOnDeleteName;
|
||||
relationType = new RelationType(documentObjectType, documentObjectType, relationTypeAlias, relationTypeName);
|
||||
relationType = new RelationType(relationTypeName, relationTypeAlias, false, documentObjectType, documentObjectType);
|
||||
relationService.Save(relationType);
|
||||
}
|
||||
foreach (var item in e.MoveInfoCollection)
|
||||
|
||||
@@ -157,6 +157,9 @@ namespace Umbraco.Core.Composing
|
||||
public static DataEditorCollection DataEditors
|
||||
=> Factory.GetInstance<DataEditorCollection>();
|
||||
|
||||
public static DataValueReferenceFactoryCollection DataValueReferenceFactories
|
||||
=> Factory.GetInstance<DataValueReferenceFactoryCollection>();
|
||||
|
||||
public static PropertyEditorCollection PropertyEditors
|
||||
=> Factory.GetInstance<PropertyEditorCollection>();
|
||||
|
||||
|
||||
@@ -49,6 +49,13 @@ namespace Umbraco.Core
|
||||
public static DataEditorCollectionBuilder DataEditors(this Composition composition)
|
||||
=> composition.WithCollectionBuilder<DataEditorCollectionBuilder>();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the data value reference factory collection builder.
|
||||
/// </summary>
|
||||
/// <param name="composition">The composition.</param>
|
||||
public static DataValueReferenceFactoryCollectionBuilder DataValueReferenceFactories(this Composition composition)
|
||||
=> composition.WithCollectionBuilder<DataValueReferenceFactoryCollectionBuilder>();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the property value converters collection builder.
|
||||
/// </summary>
|
||||
|
||||
@@ -309,14 +309,27 @@ namespace Umbraco.Core.Migrations.Install
|
||||
private void CreateRelationTypeData()
|
||||
{
|
||||
var relationType = new RelationTypeDto { Id = 1, Alias = Constants.Conventions.RelationTypes.RelateDocumentOnCopyAlias, ChildObjectType = Constants.ObjectTypes.Document, ParentObjectType = Constants.ObjectTypes.Document, Dual = true, Name = Constants.Conventions.RelationTypes.RelateDocumentOnCopyName };
|
||||
relationType.UniqueId = (relationType.Alias + "____" + relationType.Name).ToGuid();
|
||||
relationType.UniqueId = CreateUniqueRelationTypeId(relationType.Alias, relationType.Name);
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.RelationType, "id", false, relationType);
|
||||
relationType = new RelationTypeDto { Id = 2, Alias = Constants.Conventions.RelationTypes.RelateParentDocumentOnDeleteAlias, ChildObjectType = Constants.ObjectTypes.Document, ParentObjectType = Constants.ObjectTypes.Document, Dual = false, Name = Constants.Conventions.RelationTypes.RelateParentDocumentOnDeleteName };
|
||||
relationType.UniqueId = (relationType.Alias + "____" + relationType.Name).ToGuid();
|
||||
relationType.UniqueId = CreateUniqueRelationTypeId(relationType.Alias, relationType.Name);
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.RelationType, "id", false, relationType);
|
||||
relationType = new RelationTypeDto { Id = 3, Alias = Constants.Conventions.RelationTypes.RelateParentMediaFolderOnDeleteAlias, ChildObjectType = Constants.ObjectTypes.Media, ParentObjectType = Constants.ObjectTypes.Media, Dual = false, Name = Constants.Conventions.RelationTypes.RelateParentMediaFolderOnDeleteName };
|
||||
relationType.UniqueId = (relationType.Alias + "____" + relationType.Name).ToGuid();
|
||||
relationType.UniqueId = CreateUniqueRelationTypeId(relationType.Alias, relationType.Name);
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.RelationType, "id", false, relationType);
|
||||
|
||||
relationType = new RelationTypeDto { Id = 4, Alias = Constants.Conventions.RelationTypes.RelatedMediaAlias, ChildObjectType = null, ParentObjectType = null, Dual = false, Name = Constants.Conventions.RelationTypes.RelatedMediaName };
|
||||
relationType.UniqueId = CreateUniqueRelationTypeId(relationType.Alias, relationType.Name);
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.RelationType, "id", false, relationType);
|
||||
|
||||
relationType = new RelationTypeDto { Id = 5, Alias = Constants.Conventions.RelationTypes.RelatedDocumentAlias, ChildObjectType = null, ParentObjectType = null, Dual = false, Name = Constants.Conventions.RelationTypes.RelatedDocumentName };
|
||||
relationType.UniqueId = CreateUniqueRelationTypeId(relationType.Alias, relationType.Name);
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.RelationType, "id", false, relationType);
|
||||
}
|
||||
|
||||
internal static Guid CreateUniqueRelationTypeId(string alias, string name)
|
||||
{
|
||||
return (alias + "____" + name).ToGuid();
|
||||
}
|
||||
|
||||
private void CreateKeyValueData()
|
||||
|
||||
@@ -184,6 +184,10 @@ namespace Umbraco.Core.Migrations.Upgrade
|
||||
To<RenameUserLoginDtoDateIndex>("{0372A42B-DECF-498D-B4D1-6379E907EB94}");
|
||||
To<FixContentNuCascade>("{5B1E0D93-F5A3-449B-84BA-65366B84E2D4}");
|
||||
|
||||
// to 8.5.0...
|
||||
To<UpdateRelationTypeTable>("{4759A294-9860-46BC-99F9-B4C975CAE580}");
|
||||
To<AddNewRelationTypes>("{0BC866BC-0665-487A-9913-0290BD0169AD}");
|
||||
|
||||
// to 8.6.0
|
||||
To<AddPropertyTypeValidationMessageColumns>("{3D67D2C8-5E65-47D0-A9E1-DC2EE0779D6B}");
|
||||
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
using Umbraco.Core.Migrations.Install;
|
||||
|
||||
namespace Umbraco.Core.Migrations.Upgrade.V_8_6_0
|
||||
{
|
||||
/// <summary>
|
||||
/// Ensures the new relation types are created
|
||||
/// </summary>
|
||||
public class AddNewRelationTypes : MigrationBase
|
||||
{
|
||||
public AddNewRelationTypes(IMigrationContext context)
|
||||
: base(context)
|
||||
{ }
|
||||
|
||||
public override void Migrate()
|
||||
{
|
||||
CreateRelation(
|
||||
Constants.Conventions.RelationTypes.RelatedMediaAlias,
|
||||
Constants.Conventions.RelationTypes.RelatedMediaName);
|
||||
|
||||
CreateRelation(
|
||||
Constants.Conventions.RelationTypes.RelatedDocumentAlias,
|
||||
Constants.Conventions.RelationTypes.RelatedDocumentName);
|
||||
}
|
||||
|
||||
private void CreateRelation(string alias, string name)
|
||||
{
|
||||
var uniqueId = DatabaseDataCreator.CreateUniqueRelationTypeId(alias ,name); //this is the same as how it installs so everything is consistent
|
||||
Insert.IntoTable(Constants.DatabaseSchema.Tables.RelationType)
|
||||
.Row(new { typeUniqueId = uniqueId, dual = 0, name, alias })
|
||||
.Do();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
using Umbraco.Core.Persistence.Dtos;
|
||||
|
||||
namespace Umbraco.Core.Migrations.Upgrade.V_8_6_0
|
||||
{
|
||||
|
||||
public class UpdateRelationTypeTable : MigrationBase
|
||||
{
|
||||
public UpdateRelationTypeTable(IMigrationContext context)
|
||||
: base(context)
|
||||
{ }
|
||||
|
||||
public override void Migrate()
|
||||
{
|
||||
|
||||
Alter.Table(Constants.DatabaseSchema.Tables.RelationType).AlterColumn("parentObjectType").AsGuid().Nullable().Do();
|
||||
Alter.Table(Constants.DatabaseSchema.Tables.RelationType).AlterColumn("childObjectType").AsGuid().Nullable().Do();
|
||||
|
||||
//TODO: We have to update this field to ensure it's not null, we can just copy across the name since that is not nullable
|
||||
|
||||
//drop index before we can alter the column
|
||||
if (IndexExists("IX_umbracoRelationType_alias"))
|
||||
Delete
|
||||
.Index("IX_umbracoRelationType_alias")
|
||||
.OnTable(Constants.DatabaseSchema.Tables.RelationType)
|
||||
.Do();
|
||||
//change the column to non nullable
|
||||
Alter.Table(Constants.DatabaseSchema.Tables.RelationType).AlterColumn("alias").AsString(100).NotNullable().Do();
|
||||
//re-create the index
|
||||
Create
|
||||
.Index("IX_umbracoRelationType_alias")
|
||||
.OnTable(Constants.DatabaseSchema.Tables.RelationType)
|
||||
.OnColumn("alias")
|
||||
.Ascending()
|
||||
.WithOptions().Unique().WithOptions().NonClustered()
|
||||
.Do();
|
||||
}
|
||||
}
|
||||
}
|
||||
70
src/Umbraco.Core/Models/Editors/UmbracoEntityReference.cs
Normal file
70
src/Umbraco.Core/Models/Editors/UmbracoEntityReference.cs
Normal file
@@ -0,0 +1,70 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Umbraco.Core.Models.Editors
|
||||
{
|
||||
/// <summary>
|
||||
/// Used to track reference to other entities in a property value
|
||||
/// </summary>
|
||||
public struct UmbracoEntityReference : IEquatable<UmbracoEntityReference>
|
||||
{
|
||||
private static readonly UmbracoEntityReference _empty = new UmbracoEntityReference(UnknownTypeUdi.Instance, string.Empty);
|
||||
|
||||
public UmbracoEntityReference(Udi udi, string relationTypeAlias)
|
||||
{
|
||||
Udi = udi ?? throw new ArgumentNullException(nameof(udi));
|
||||
RelationTypeAlias = relationTypeAlias ?? throw new ArgumentNullException(nameof(relationTypeAlias));
|
||||
}
|
||||
|
||||
public UmbracoEntityReference(Udi udi)
|
||||
{
|
||||
Udi = udi ?? throw new ArgumentNullException(nameof(udi));
|
||||
|
||||
switch (udi.EntityType)
|
||||
{
|
||||
case Constants.UdiEntityType.Media:
|
||||
RelationTypeAlias = Constants.Conventions.RelationTypes.RelatedMediaAlias;
|
||||
break;
|
||||
default:
|
||||
RelationTypeAlias = Constants.Conventions.RelationTypes.RelatedDocumentAlias;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public static UmbracoEntityReference Empty() => _empty;
|
||||
|
||||
public static bool IsEmpty(UmbracoEntityReference reference) => reference == Empty();
|
||||
|
||||
public Udi Udi { get; }
|
||||
public string RelationTypeAlias { get; }
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return obj is UmbracoEntityReference reference && Equals(reference);
|
||||
}
|
||||
|
||||
public bool Equals(UmbracoEntityReference other)
|
||||
{
|
||||
return EqualityComparer<Udi>.Default.Equals(Udi, other.Udi) &&
|
||||
RelationTypeAlias == other.RelationTypeAlias;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
var hashCode = -487348478;
|
||||
hashCode = hashCode * -1521134295 + EqualityComparer<Udi>.Default.GetHashCode(Udi);
|
||||
hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(RelationTypeAlias);
|
||||
return hashCode;
|
||||
}
|
||||
|
||||
public static bool operator ==(UmbracoEntityReference left, UmbracoEntityReference right)
|
||||
{
|
||||
return left.Equals(right);
|
||||
}
|
||||
|
||||
public static bool operator !=(UmbracoEntityReference left, UmbracoEntityReference right)
|
||||
{
|
||||
return !(left == right);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -41,7 +41,7 @@ namespace Umbraco.Core.Models
|
||||
/// </summary>
|
||||
public static UmbracoObjectTypes GetUmbracoObjectType(string name)
|
||||
{
|
||||
return (UmbracoObjectTypes) Enum.Parse(typeof (UmbracoObjectTypes), name, false);
|
||||
return (UmbracoObjectTypes) Enum.Parse(typeof (UmbracoObjectTypes), name, true);
|
||||
}
|
||||
|
||||
#region Guid object type utilities
|
||||
|
||||
@@ -34,5 +34,13 @@ namespace Umbraco.Core.Persistence.Dtos
|
||||
[Column("comment")]
|
||||
[Length(1000)]
|
||||
public string Comment { get; set; }
|
||||
|
||||
[ResultColumn]
|
||||
[Column("parentObjectType")]
|
||||
public Guid ParentObjectType { get; set; }
|
||||
|
||||
[ResultColumn]
|
||||
[Column("childObjectType")]
|
||||
public Guid ChildObjectType { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace Umbraco.Core.Persistence.Dtos
|
||||
[ExplicitColumns]
|
||||
internal class RelationTypeDto
|
||||
{
|
||||
public const int NodeIdSeed = 4;
|
||||
public const int NodeIdSeed = 10;
|
||||
|
||||
[Column("id")]
|
||||
[PrimaryKeyColumn(IdentitySeed = NodeIdSeed)]
|
||||
@@ -23,17 +23,20 @@ namespace Umbraco.Core.Persistence.Dtos
|
||||
public bool Dual { get; set; }
|
||||
|
||||
[Column("parentObjectType")]
|
||||
public Guid ParentObjectType { get; set; }
|
||||
[NullSetting(NullSetting = NullSettings.Null)]
|
||||
public Guid? ParentObjectType { get; set; }
|
||||
|
||||
[Column("childObjectType")]
|
||||
public Guid ChildObjectType { get; set; }
|
||||
[NullSetting(NullSetting = NullSettings.Null)]
|
||||
public Guid? ChildObjectType { get; set; }
|
||||
|
||||
[Column("name")]
|
||||
[NullSetting(NullSetting = NullSettings.NotNull)]
|
||||
[Index(IndexTypes.UniqueNonClustered, Name = "IX_umbracoRelationType_name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
[Column("alias")]
|
||||
[NullSetting(NullSetting = NullSettings.Null)]
|
||||
[NullSetting(NullSetting = NullSettings.NotNull)]
|
||||
[Length(100)]
|
||||
[Index(IndexTypes.UniqueNonClustered, Name = "IX_umbracoRelationType_alias")]
|
||||
public string Alias { get; set; }
|
||||
|
||||
@@ -3,20 +3,11 @@ using Umbraco.Core.Persistence.Dtos;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Factories
|
||||
{
|
||||
internal class RelationFactory
|
||||
internal static class RelationFactory
|
||||
{
|
||||
private readonly IRelationType _relationType;
|
||||
|
||||
public RelationFactory(IRelationType relationType)
|
||||
public static IRelation BuildEntity(RelationDto dto, IRelationType relationType)
|
||||
{
|
||||
_relationType = relationType;
|
||||
}
|
||||
|
||||
#region Implementation of IEntityFactory<Relation,RelationDto>
|
||||
|
||||
public IRelation BuildEntity(RelationDto dto)
|
||||
{
|
||||
var entity = new Relation(dto.ParentId, dto.ChildId, _relationType);
|
||||
var entity = new Relation(dto.ParentId, dto.ChildId, dto.ParentObjectType, dto.ChildObjectType, relationType);
|
||||
|
||||
try
|
||||
{
|
||||
@@ -37,7 +28,7 @@ namespace Umbraco.Core.Persistence.Factories
|
||||
}
|
||||
}
|
||||
|
||||
public RelationDto BuildDto(IRelation entity)
|
||||
public static RelationDto BuildDto(IRelation entity)
|
||||
{
|
||||
var dto = new RelationDto
|
||||
{
|
||||
@@ -54,6 +45,5 @@ namespace Umbraco.Core.Persistence.Factories
|
||||
return dto;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace Umbraco.Core.Persistence.Factories
|
||||
|
||||
public static IRelationType BuildEntity(RelationTypeDto dto)
|
||||
{
|
||||
var entity = new RelationType(dto.ChildObjectType, dto.ParentObjectType, dto.Alias);
|
||||
var entity = new RelationType(dto.Name, dto.Alias, dto.Dual, dto.ChildObjectType, dto.ParentObjectType);
|
||||
|
||||
try
|
||||
{
|
||||
@@ -17,8 +17,6 @@ namespace Umbraco.Core.Persistence.Factories
|
||||
|
||||
entity.Id = dto.Id;
|
||||
entity.Key = dto.UniqueId;
|
||||
entity.IsBidirectional = dto.Dual;
|
||||
entity.Name = dto.Name;
|
||||
|
||||
// reset dirty initial properties (U4-1946)
|
||||
entity.ResetDirtyProperties(false);
|
||||
|
||||
@@ -14,7 +14,21 @@ namespace Umbraco.Core.Persistence
|
||||
/// </summary>
|
||||
public static partial class NPocoDatabaseExtensions
|
||||
{
|
||||
// TODO: review NPoco native InsertBulk to replace the code below
|
||||
/// <summary>
|
||||
/// Configures NPoco's SqlBulkCopyHelper to use the correct SqlConnection and SqlTransaction instances from the underlying RetryDbConnection and ProfiledDbTransaction
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is required to use NPoco's own <see cref="Database.InsertBulk{T}(IEnumerable{T})" /> method because we use wrapped DbConnection and DbTransaction instances.
|
||||
/// NPoco's InsertBulk method only caters for efficient bulk inserting records for Sql Server, it does not cater for bulk inserting of records for
|
||||
/// any other database type and in which case will just insert records one at a time.
|
||||
/// NPoco's InsertBulk method also deals with updating the passed in entity's PK/ID once it's inserted whereas our own BulkInsertRecords methods
|
||||
/// do not handle this scenario.
|
||||
/// </remarks>
|
||||
public static void ConfigureNPocoBulkExtensions()
|
||||
{
|
||||
SqlBulkCopyHelper.SqlConnectionResolver = dbConn => GetTypedConnection<SqlConnection>(dbConn);
|
||||
SqlBulkCopyHelper.SqlTransactionResolver = dbTran => GetTypedTransaction<SqlTransaction>(dbTran);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Bulk-inserts records within a transaction.
|
||||
@@ -235,7 +249,7 @@ namespace Umbraco.Core.Persistence
|
||||
//we need to add column mappings here because otherwise columns will be matched by their order and if the order of them are different in the DB compared
|
||||
//to the order in which they are declared in the model then this will not work, so instead we will add column mappings by name so that this explicitly uses
|
||||
//the names instead of their ordering.
|
||||
foreach(var col in bulkReader.ColumnMappings)
|
||||
foreach (var col in bulkReader.ColumnMappings)
|
||||
{
|
||||
copy.ColumnMappings.Add(col.DestinationColumn, col.DestinationColumn);
|
||||
}
|
||||
|
||||
@@ -14,10 +14,6 @@ namespace Umbraco.Core.Persistence
|
||||
public static partial class NPocoSqlExtensions
|
||||
{
|
||||
|
||||
#region Special extensions
|
||||
|
||||
#endregion
|
||||
|
||||
#region Where
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using NPoco;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.Entities;
|
||||
@@ -15,10 +16,22 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
IEntitySlim Get(int id, Guid objectTypeId);
|
||||
IEntitySlim Get(Guid key, Guid objectTypeId);
|
||||
|
||||
IEnumerable<IEntitySlim> GetAll(Guid objectType, params int[] ids);
|
||||
IEnumerable<IEntitySlim> GetAll(Guid objectType, params int[] ids);
|
||||
IEnumerable<IEntitySlim> GetAll(Guid objectType, params Guid[] keys);
|
||||
|
||||
/// <summary>
|
||||
/// Gets entities for a query
|
||||
/// </summary>
|
||||
/// <param name="query"></param>
|
||||
/// <returns></returns>
|
||||
IEnumerable<IEntitySlim> GetByQuery(IQuery<IUmbracoEntity> query);
|
||||
|
||||
/// <summary>
|
||||
/// Gets entities for a query and a specific object type allowing the query to be slightly more optimized
|
||||
/// </summary>
|
||||
/// <param name="query"></param>
|
||||
/// <param name="objectType"></param>
|
||||
/// <returns></returns>
|
||||
IEnumerable<IEntitySlim> GetByQuery(IQuery<IUmbracoEntity> query, Guid objectType);
|
||||
|
||||
UmbracoObjectTypes GetObjectType(int id);
|
||||
@@ -30,7 +43,41 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
bool Exists(int id);
|
||||
bool Exists(Guid key);
|
||||
|
||||
/// <summary>
|
||||
/// Gets paged entities for a query and a subset of object types
|
||||
/// </summary>
|
||||
/// <param name="query"></param>
|
||||
/// <param name="objectTypes"></param>
|
||||
/// <param name="pageIndex"></param>
|
||||
/// <param name="pageSize"></param>
|
||||
/// <param name="totalRecords"></param>
|
||||
/// <param name="filter"></param>
|
||||
/// <param name="ordering"></param>
|
||||
/// <param name="sqlCustomization">
|
||||
/// A callback providing the ability to customize the generated SQL used to retrieve entities
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A collection of mixed entity types which would be of type <see cref="IEntitySlim"/>, <see cref="IDocumentEntitySlim"/>, <see cref="IMediaEntitySlim"/>,
|
||||
/// <see cref="IMemberEntitySlim"/>
|
||||
/// </returns>
|
||||
IEnumerable<IEntitySlim> GetPagedResultsByQuery(
|
||||
IQuery<IUmbracoEntity> query, Guid[] objectTypes, long pageIndex, int pageSize, out long totalRecords,
|
||||
IQuery<IUmbracoEntity> filter, Ordering ordering, Action<Sql<ISqlContext>> sqlCustomization = null);
|
||||
|
||||
/// <summary>
|
||||
/// Gets paged entities for a query and a specific object type
|
||||
/// </summary>
|
||||
/// <param name="query"></param>
|
||||
/// <param name="objectType"></param>
|
||||
/// <param name="pageIndex"></param>
|
||||
/// <param name="pageSize"></param>
|
||||
/// <param name="totalRecords"></param>
|
||||
/// <param name="filter"></param>
|
||||
/// <param name="ordering"></param>
|
||||
/// <returns></returns>
|
||||
IEnumerable<IEntitySlim> GetPagedResultsByQuery(IQuery<IUmbracoEntity> query, Guid objectType, long pageIndex, int pageSize, out long totalRecords,
|
||||
IQuery<IUmbracoEntity> filter, Ordering ordering);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Events;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.Editors;
|
||||
using Umbraco.Core.Models.Entities;
|
||||
using Umbraco.Core.Persistence.Dtos;
|
||||
using Umbraco.Core.Persistence.Factories;
|
||||
@@ -23,26 +24,48 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
internal sealed class ContentRepositoryBase
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// This is used for unit tests ONLY
|
||||
/// </summary>
|
||||
public static bool ThrowOnWarning = false;
|
||||
}
|
||||
|
||||
internal abstract class ContentRepositoryBase<TId, TEntity, TRepository> : NPocoRepositoryBase<TId, TEntity>, IContentRepository<TId, TEntity>
|
||||
where TEntity : class, IUmbracoEntity
|
||||
where TEntity : class, IContentBase
|
||||
where TRepository : class, IRepository
|
||||
{
|
||||
protected ContentRepositoryBase(IScopeAccessor scopeAccessor, AppCaches cache, ILanguageRepository languageRepository, ILogger logger)
|
||||
private readonly Lazy<PropertyEditorCollection> _propertyEditors;
|
||||
private readonly DataValueReferenceFactoryCollection _dataValueReferenceFactories;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="scopeAccessor"></param>
|
||||
/// <param name="cache"></param>
|
||||
/// <param name="logger"></param>
|
||||
/// <param name="languageRepository"></param>
|
||||
/// <param name="propertyEditors">
|
||||
/// Lazy property value collection - must be lazy because we have a circular dependency since some property editors require services, yet these services require property editors
|
||||
/// </param>
|
||||
protected ContentRepositoryBase(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger,
|
||||
ILanguageRepository languageRepository, IRelationRepository relationRepository, IRelationTypeRepository relationTypeRepository,
|
||||
Lazy<PropertyEditorCollection> propertyEditors, DataValueReferenceFactoryCollection dataValueReferenceFactories)
|
||||
: base(scopeAccessor, cache, logger)
|
||||
{
|
||||
LanguageRepository = languageRepository;
|
||||
RelationRepository = relationRepository;
|
||||
RelationTypeRepository = relationTypeRepository;
|
||||
_propertyEditors = propertyEditors;
|
||||
_dataValueReferenceFactories = dataValueReferenceFactories;
|
||||
}
|
||||
|
||||
protected abstract TRepository This { get; }
|
||||
|
||||
protected ILanguageRepository LanguageRepository { get; }
|
||||
protected IRelationRepository RelationRepository { get; }
|
||||
protected IRelationTypeRepository RelationTypeRepository { get; }
|
||||
|
||||
protected PropertyEditorCollection PropertyEditors => Current.PropertyEditors; // TODO: inject
|
||||
protected PropertyEditorCollection PropertyEditors => _propertyEditors.Value;
|
||||
|
||||
#region Versions
|
||||
|
||||
@@ -796,5 +819,56 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
protected void PersistRelations(TEntity entity)
|
||||
{
|
||||
// Get all references from our core built in DataEditors/Property Editors
|
||||
// Along with seeing if deverlopers want to collect additional references from the DataValueReferenceFactories collection
|
||||
var trackedRelations = new List<UmbracoEntityReference>();
|
||||
trackedRelations.AddRange(_dataValueReferenceFactories.GetAllReferences(entity.Properties, PropertyEditors));
|
||||
|
||||
//First delete all auto-relations for this entity
|
||||
RelationRepository.DeleteByParent(entity.Id, Constants.Conventions.RelationTypes.AutomaticRelationTypes);
|
||||
|
||||
if (trackedRelations.Count == 0) return;
|
||||
|
||||
trackedRelations = trackedRelations.Distinct().ToList();
|
||||
var udiToGuids = trackedRelations.Select(x => x.Udi as GuidUdi)
|
||||
.ToDictionary(x => (Udi)x, x => x.Guid);
|
||||
|
||||
//lookup in the DB all INT ids for the GUIDs and chuck into a dictionary
|
||||
var keyToIds = Database.Fetch<NodeIdKey>(Sql().Select<NodeDto>(x => x.NodeId, x => x.UniqueId).From<NodeDto>().WhereIn<NodeDto>(x => x.UniqueId, udiToGuids.Values))
|
||||
.ToDictionary(x => x.UniqueId, x => x.NodeId);
|
||||
|
||||
var allRelationTypes = RelationTypeRepository.GetMany(Array.Empty<int>())
|
||||
.ToDictionary(x => x.Alias, x => x);
|
||||
|
||||
var toSave = trackedRelations.Select(rel =>
|
||||
{
|
||||
if (!allRelationTypes.TryGetValue(rel.RelationTypeAlias, out var relationType))
|
||||
throw new InvalidOperationException($"The relation type {rel.RelationTypeAlias} does not exist");
|
||||
|
||||
if (!udiToGuids.TryGetValue(rel.Udi, out var guid))
|
||||
return null; // This shouldn't happen!
|
||||
|
||||
if (!keyToIds.TryGetValue(guid, out var id))
|
||||
return null; // This shouldn't happen!
|
||||
|
||||
return new Relation(entity.Id, id, relationType);
|
||||
}).WhereNotNull();
|
||||
|
||||
// Save bulk relations
|
||||
RelationRepository.Save(toSave);
|
||||
|
||||
}
|
||||
|
||||
private class NodeIdKey
|
||||
{
|
||||
[Column("id")]
|
||||
public int NodeId { get; set; }
|
||||
|
||||
[Column("uniqueId")]
|
||||
public Guid UniqueId { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Configuration.UmbracoSettings;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.PropertyEditors;
|
||||
using Umbraco.Core.Scoping;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
@@ -17,8 +18,10 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
/// </remarks>
|
||||
internal class DocumentBlueprintRepository : DocumentRepository, IDocumentBlueprintRepository
|
||||
{
|
||||
public DocumentBlueprintRepository(IScopeAccessor scopeAccessor, AppCaches appCaches, ILogger logger, IContentTypeRepository contentTypeRepository, ITemplateRepository templateRepository, ITagRepository tagRepository, ILanguageRepository languageRepository)
|
||||
: base(scopeAccessor, appCaches, logger, contentTypeRepository, templateRepository, tagRepository, languageRepository)
|
||||
public DocumentBlueprintRepository(IScopeAccessor scopeAccessor, AppCaches appCaches, ILogger logger,
|
||||
IContentTypeRepository contentTypeRepository, ITemplateRepository templateRepository, ITagRepository tagRepository, ILanguageRepository languageRepository, IRelationRepository relationRepository, IRelationTypeRepository relationTypeRepository,
|
||||
Lazy<PropertyEditorCollection> propertyEditorCollection, DataValueReferenceFactoryCollection dataValueReferenceFactories)
|
||||
: base(scopeAccessor, appCaches, logger, contentTypeRepository, templateRepository, tagRepository, languageRepository, relationRepository, relationTypeRepository, propertyEditorCollection, dataValueReferenceFactories)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ using Umbraco.Core.Persistence.Dtos;
|
||||
using Umbraco.Core.Persistence.Factories;
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
using Umbraco.Core.Persistence.SqlSyntax;
|
||||
using Umbraco.Core.PropertyEditors;
|
||||
using Umbraco.Core.Scoping;
|
||||
using Umbraco.Core.Services;
|
||||
|
||||
@@ -30,8 +31,23 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
private readonly ContentByGuidReadRepository _contentByGuidReadRepository;
|
||||
private readonly IScopeAccessor _scopeAccessor;
|
||||
|
||||
public DocumentRepository(IScopeAccessor scopeAccessor, AppCaches appCaches, ILogger logger, IContentTypeRepository contentTypeRepository, ITemplateRepository templateRepository, ITagRepository tagRepository, ILanguageRepository languageRepository)
|
||||
: base(scopeAccessor, appCaches, languageRepository, logger)
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="scopeAccessor"></param>
|
||||
/// <param name="appCaches"></param>
|
||||
/// <param name="logger"></param>
|
||||
/// <param name="contentTypeRepository"></param>
|
||||
/// <param name="templateRepository"></param>
|
||||
/// <param name="tagRepository"></param>
|
||||
/// <param name="languageRepository"></param>
|
||||
/// <param name="propertyEditors">
|
||||
/// Lazy property value collection - must be lazy because we have a circular dependency since some property editors require services, yet these services require property editors
|
||||
/// </param>
|
||||
public DocumentRepository(IScopeAccessor scopeAccessor, AppCaches appCaches, ILogger logger,
|
||||
IContentTypeRepository contentTypeRepository, ITemplateRepository templateRepository, ITagRepository tagRepository, ILanguageRepository languageRepository, IRelationRepository relationRepository, IRelationTypeRepository relationTypeRepository,
|
||||
Lazy<PropertyEditorCollection> propertyEditors, DataValueReferenceFactoryCollection dataValueReferenceFactories)
|
||||
: base(scopeAccessor, appCaches, logger, languageRepository, relationRepository, relationTypeRepository, propertyEditors, dataValueReferenceFactories)
|
||||
{
|
||||
_contentTypeRepository = contentTypeRepository ?? throw new ArgumentNullException(nameof(contentTypeRepository));
|
||||
_templateRepository = templateRepository ?? throw new ArgumentNullException(nameof(templateRepository));
|
||||
@@ -468,6 +484,8 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
ClearEntityTags(entity, _tagRepository);
|
||||
}
|
||||
|
||||
PersistRelations(entity);
|
||||
|
||||
entity.ResetDirtyProperties();
|
||||
|
||||
// troubleshooting
|
||||
@@ -671,6 +689,8 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
ClearEntityTags(entity, _tagRepository);
|
||||
}
|
||||
|
||||
PersistRelations(entity);
|
||||
|
||||
// TODO: note re. tags: explicitly unpublished entities have cleared tags, but masked or trashed entities *still* have tags in the db - so what?
|
||||
|
||||
entity.ResetDirtyProperties();
|
||||
|
||||
@@ -34,21 +34,33 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
protected ISqlSyntaxProvider SqlSyntax => _scopeAccessor.AmbientScope.SqlContext.SqlSyntax;
|
||||
|
||||
#region Repository
|
||||
|
||||
// get a page of entities
|
||||
|
||||
public IEnumerable<IEntitySlim> GetPagedResultsByQuery(IQuery<IUmbracoEntity> query, Guid objectType, long pageIndex, int pageSize, out long totalRecords,
|
||||
IQuery<IUmbracoEntity> filter, Ordering ordering)
|
||||
{
|
||||
var isContent = objectType == Constants.ObjectTypes.Document || objectType == Constants.ObjectTypes.DocumentBlueprint;
|
||||
var isMedia = objectType == Constants.ObjectTypes.Media;
|
||||
var isMember = objectType == Constants.ObjectTypes.Member;
|
||||
return GetPagedResultsByQuery(query, new[] { objectType }, pageIndex, pageSize, out totalRecords, filter, ordering);
|
||||
}
|
||||
|
||||
var sql = GetBaseWhere(isContent, isMedia, isMember, false, x =>
|
||||
// get a page of entities
|
||||
public IEnumerable<IEntitySlim> GetPagedResultsByQuery(IQuery<IUmbracoEntity> query, Guid[] objectTypes, long pageIndex, int pageSize, out long totalRecords,
|
||||
IQuery<IUmbracoEntity> filter, Ordering ordering, Action<Sql<ISqlContext>> sqlCustomization = null)
|
||||
{
|
||||
var isContent = objectTypes.Any(objectType => objectType == Constants.ObjectTypes.Document || objectType == Constants.ObjectTypes.DocumentBlueprint);
|
||||
var isMedia = objectTypes.Any(objectType => objectType == Constants.ObjectTypes.Media);
|
||||
var isMember = objectTypes.Any(objectType => objectType == Constants.ObjectTypes.Member);
|
||||
|
||||
var sql = GetBaseWhere(isContent, isMedia, isMember, false, s =>
|
||||
{
|
||||
if (filter == null) return;
|
||||
foreach (var filterClause in filter.GetWhereClauses())
|
||||
x.Where(filterClause.Item1, filterClause.Item2);
|
||||
}, objectType);
|
||||
sqlCustomization?.Invoke(s);
|
||||
|
||||
if (filter != null)
|
||||
{
|
||||
foreach (var filterClause in filter.GetWhereClauses())
|
||||
s.Where(filterClause.Item1, filterClause.Item2);
|
||||
}
|
||||
|
||||
|
||||
}, objectTypes);
|
||||
|
||||
ordering = ordering ?? Ordering.ByDefault();
|
||||
|
||||
@@ -69,35 +81,13 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
// for content we must query for ContentEntityDto entities to produce the correct culture variant entity names
|
||||
var pageIndexToFetch = pageIndex + 1;
|
||||
IEnumerable<BaseDto> dtos;
|
||||
if(isContent)
|
||||
{
|
||||
var page = Database.Page<ContentEntityDto>(pageIndexToFetch, pageSize, sql);
|
||||
dtos = page.Items;
|
||||
totalRecords = page.TotalItems;
|
||||
}
|
||||
else if (isMedia)
|
||||
{
|
||||
var page = Database.Page<MediaEntityDto>(pageIndexToFetch, pageSize, sql);
|
||||
dtos = page.Items;
|
||||
totalRecords = page.TotalItems;
|
||||
}
|
||||
else if (isMember)
|
||||
{
|
||||
var page = Database.Page<MemberEntityDto>(pageIndexToFetch, pageSize, sql);
|
||||
dtos = page.Items;
|
||||
totalRecords = page.TotalItems;
|
||||
}
|
||||
else
|
||||
{
|
||||
var page = Database.Page<BaseDto>(pageIndexToFetch, pageSize, sql);
|
||||
dtos = page.Items;
|
||||
totalRecords = page.TotalItems;
|
||||
}
|
||||
var page = Database.Page<GenericContentEntityDto>(pageIndexToFetch, pageSize, sql);
|
||||
dtos = page.Items;
|
||||
totalRecords = page.TotalItems;
|
||||
|
||||
var entities = dtos.Select(x => BuildEntity(isContent, isMedia, isMember, x)).ToArray();
|
||||
var entities = dtos.Select(BuildEntity).ToArray();
|
||||
|
||||
if (isContent)
|
||||
BuildVariants(entities.Cast<DocumentEntitySlim>());
|
||||
BuildVariants(entities.OfType<DocumentEntitySlim>());
|
||||
|
||||
return entities;
|
||||
}
|
||||
@@ -106,7 +96,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
{
|
||||
var sql = GetBaseWhere(false, false, false, false, key);
|
||||
var dto = Database.FirstOrDefault<BaseDto>(sql);
|
||||
return dto == null ? null : BuildEntity(false, false, false, dto);
|
||||
return dto == null ? null : BuildEntity(dto);
|
||||
}
|
||||
|
||||
|
||||
@@ -115,7 +105,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
//isContent is going to return a 1:M result now with the variants so we need to do different things
|
||||
if (isContent)
|
||||
{
|
||||
var cdtos = Database.Fetch<ContentEntityDto>(sql);
|
||||
var cdtos = Database.Fetch<DocumentEntityDto>(sql);
|
||||
|
||||
return cdtos.Count == 0 ? null : BuildVariants(BuildDocumentEntity(cdtos[0]));
|
||||
}
|
||||
@@ -126,7 +116,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
|
||||
if (dto == null) return null;
|
||||
|
||||
var entity = BuildEntity(false, isMedia, isMember, dto);
|
||||
var entity = BuildEntity(dto);
|
||||
|
||||
return entity;
|
||||
}
|
||||
@@ -145,7 +135,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
{
|
||||
var sql = GetBaseWhere(false, false, false, false, id);
|
||||
var dto = Database.FirstOrDefault<BaseDto>(sql);
|
||||
return dto == null ? null : BuildEntity(false, false, false, dto);
|
||||
return dto == null ? null : BuildEntity(dto);
|
||||
}
|
||||
|
||||
public IEntitySlim Get(int id, Guid objectTypeId)
|
||||
@@ -177,7 +167,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
//isContent is going to return a 1:M result now with the variants so we need to do different things
|
||||
if (isContent)
|
||||
{
|
||||
var cdtos = Database.Fetch<ContentEntityDto>(sql);
|
||||
var cdtos = Database.Fetch<DocumentEntityDto>(sql);
|
||||
|
||||
return cdtos.Count == 0
|
||||
? Enumerable.Empty<IEntitySlim>()
|
||||
@@ -188,7 +178,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
? (IEnumerable<BaseDto>)Database.Fetch<MediaEntityDto>(sql)
|
||||
: Database.Fetch<BaseDto>(sql);
|
||||
|
||||
var entities = dtos.Select(x => BuildEntity(false, isMedia, isMember, x)).ToArray();
|
||||
var entities = dtos.Select(BuildEntity).ToArray();
|
||||
|
||||
return entities;
|
||||
}
|
||||
@@ -232,7 +222,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
var sql = translator.Translate();
|
||||
sql = AddGroupBy(false, false, false, sql, true);
|
||||
var dtos = Database.Fetch<BaseDto>(sql);
|
||||
return dtos.Select(x => BuildEntity(false, false, false, x)).ToList();
|
||||
return dtos.Select(BuildEntity).ToList();
|
||||
}
|
||||
|
||||
public IEnumerable<IEntitySlim> GetByQuery(IQuery<IUmbracoEntity> query, Guid objectType)
|
||||
@@ -241,7 +231,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
var isMedia = objectType == Constants.ObjectTypes.Media;
|
||||
var isMember = objectType == Constants.ObjectTypes.Member;
|
||||
|
||||
var sql = GetBaseWhere(isContent, isMedia, isMember, false, null, objectType);
|
||||
var sql = GetBaseWhere(isContent, isMedia, isMember, false, null, new[] { objectType });
|
||||
|
||||
var translator = new SqlTranslator<IUmbracoEntity>(sql, query);
|
||||
sql = translator.Translate();
|
||||
@@ -355,14 +345,14 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
// gets the full sql for a given object type, with a given filter
|
||||
protected Sql<ISqlContext> GetFullSqlForEntityType(bool isContent, bool isMedia, bool isMember, Guid objectType, Action<Sql<ISqlContext>> filter)
|
||||
{
|
||||
var sql = GetBaseWhere(isContent, isMedia, isMember, false, filter, objectType);
|
||||
var sql = GetBaseWhere(isContent, isMedia, isMember, false, filter, new[] { objectType });
|
||||
return AddGroupBy(isContent, isMedia, isMember, sql, true);
|
||||
}
|
||||
|
||||
// gets the base SELECT + FROM [+ filter] sql
|
||||
// always from the 'current' content version
|
||||
protected Sql<ISqlContext> GetBase(bool isContent, bool isMedia, bool isMember, Action<Sql<ISqlContext>> filter, bool isCount = false)
|
||||
{
|
||||
{
|
||||
var sql = Sql();
|
||||
|
||||
if (isCount)
|
||||
@@ -400,15 +390,15 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
if (isContent || isMedia || isMember)
|
||||
{
|
||||
sql
|
||||
.InnerJoin<ContentVersionDto>().On<NodeDto, ContentVersionDto>((left, right) => left.NodeId == right.NodeId && right.Current)
|
||||
.InnerJoin<ContentDto>().On<NodeDto, ContentDto>((left, right) => left.NodeId == right.NodeId)
|
||||
.InnerJoin<ContentTypeDto>().On<ContentDto, ContentTypeDto>((left, right) => left.ContentTypeId == right.NodeId);
|
||||
.LeftJoin<ContentVersionDto>().On<NodeDto, ContentVersionDto>((left, right) => left.NodeId == right.NodeId && right.Current)
|
||||
.LeftJoin<ContentDto>().On<NodeDto, ContentDto>((left, right) => left.NodeId == right.NodeId)
|
||||
.LeftJoin<ContentTypeDto>().On<ContentDto, ContentTypeDto>((left, right) => left.ContentTypeId == right.NodeId);
|
||||
}
|
||||
|
||||
if (isContent)
|
||||
{
|
||||
sql
|
||||
.InnerJoin<DocumentDto>().On<NodeDto, DocumentDto>((left, right) => left.NodeId == right.NodeId);
|
||||
.LeftJoin<DocumentDto>().On<NodeDto, DocumentDto>((left, right) => left.NodeId == right.NodeId);
|
||||
}
|
||||
|
||||
if (isMedia)
|
||||
@@ -432,10 +422,14 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
|
||||
// gets the base SELECT + FROM [+ filter] + WHERE sql
|
||||
// for a given object type, with a given filter
|
||||
protected Sql<ISqlContext> GetBaseWhere(bool isContent, bool isMedia, bool isMember, bool isCount, Action<Sql<ISqlContext>> filter, Guid objectType)
|
||||
protected Sql<ISqlContext> GetBaseWhere(bool isContent, bool isMedia, bool isMember, bool isCount, Action<Sql<ISqlContext>> filter, Guid[] objectTypes)
|
||||
{
|
||||
return GetBase(isContent, isMedia, isMember, filter, isCount)
|
||||
.Where<NodeDto>(x => x.NodeObjectType == objectType);
|
||||
var sql = GetBase(isContent, isMedia, isMember, filter, isCount);
|
||||
if (objectTypes.Length > 0)
|
||||
{
|
||||
sql.WhereIn<NodeDto>(x => x.NodeObjectType, objectTypes);
|
||||
}
|
||||
return sql;
|
||||
}
|
||||
|
||||
// gets the base SELECT + FROM + WHERE sql
|
||||
@@ -509,8 +503,19 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
if (sql == null) throw new ArgumentNullException(nameof(sql));
|
||||
if (ordering == null) throw new ArgumentNullException(nameof(ordering));
|
||||
|
||||
// TODO: although this works for name, it probably doesn't work for others without an alias of some sort
|
||||
var orderBy = ordering.OrderBy;
|
||||
// TODO: although the default ordering string works for name, it wont work for others without a table or an alias of some sort
|
||||
// As more things are attempted to be sorted we'll prob have to add more expressions here
|
||||
string orderBy;
|
||||
switch (ordering.OrderBy.ToUpperInvariant())
|
||||
{
|
||||
case "PATH":
|
||||
orderBy = SqlSyntax.GetQuotedColumn(NodeDto.TableName, "path");
|
||||
break;
|
||||
|
||||
default:
|
||||
orderBy = ordering.OrderBy;
|
||||
break;
|
||||
}
|
||||
|
||||
if (ordering.Direction == Direction.Ascending)
|
||||
sql.OrderBy(orderBy);
|
||||
@@ -523,9 +528,17 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
#region Classes
|
||||
|
||||
/// <summary>
|
||||
/// The DTO used to fetch results for a content item with its variation info
|
||||
/// The DTO used to fetch results for a generic content item which could be either a document, media or a member
|
||||
/// </summary>
|
||||
private class ContentEntityDto : BaseDto
|
||||
private class GenericContentEntityDto : DocumentEntityDto
|
||||
{
|
||||
public string MediaPath { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The DTO used to fetch results for a document item with its variation info
|
||||
/// </summary>
|
||||
private class DocumentEntityDto : BaseDto
|
||||
{
|
||||
public ContentVariation Variations { get; set; }
|
||||
|
||||
@@ -533,11 +546,17 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
public bool Edited { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The DTO used to fetch results for a media item with its media path info
|
||||
/// </summary>
|
||||
private class MediaEntityDto : BaseDto
|
||||
{
|
||||
public string MediaPath { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The DTO used to fetch results for a member item
|
||||
/// </summary>
|
||||
private class MemberEntityDto : BaseDto
|
||||
{
|
||||
}
|
||||
@@ -588,13 +607,13 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
|
||||
#region Factory
|
||||
|
||||
private EntitySlim BuildEntity(bool isContent, bool isMedia, bool isMember, BaseDto dto)
|
||||
private EntitySlim BuildEntity(BaseDto dto)
|
||||
{
|
||||
if (isContent)
|
||||
if (dto.NodeObjectType == Constants.ObjectTypes.Document)
|
||||
return BuildDocumentEntity(dto);
|
||||
if (isMedia)
|
||||
if (dto.NodeObjectType == Constants.ObjectTypes.Media)
|
||||
return BuildMediaEntity(dto);
|
||||
if (isMember)
|
||||
if (dto.NodeObjectType == Constants.ObjectTypes.Member)
|
||||
return BuildMemberEntity(dto);
|
||||
|
||||
// EntitySlim does not track changes
|
||||
@@ -649,7 +668,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
var entity = new DocumentEntitySlim();
|
||||
BuildContentEntity(entity, dto);
|
||||
|
||||
if (dto is ContentEntityDto contentDto)
|
||||
if (dto is DocumentEntityDto contentDto)
|
||||
{
|
||||
// fill in the invariant info
|
||||
entity.Edited = contentDto.Edited;
|
||||
|
||||
@@ -11,6 +11,7 @@ using Umbraco.Core.Models.Entities;
|
||||
using Umbraco.Core.Persistence.Dtos;
|
||||
using Umbraco.Core.Persistence.Factories;
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
using Umbraco.Core.PropertyEditors;
|
||||
using Umbraco.Core.Scoping;
|
||||
using Umbraco.Core.Services;
|
||||
using static Umbraco.Core.Persistence.SqlExtensionsStatics;
|
||||
@@ -26,8 +27,9 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
private readonly ITagRepository _tagRepository;
|
||||
private readonly MediaByGuidReadRepository _mediaByGuidReadRepository;
|
||||
|
||||
public MediaRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger, IMediaTypeRepository mediaTypeRepository, ITagRepository tagRepository, ILanguageRepository languageRepository)
|
||||
: base(scopeAccessor, cache, languageRepository, logger)
|
||||
public MediaRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger, IMediaTypeRepository mediaTypeRepository, ITagRepository tagRepository, ILanguageRepository languageRepository, IRelationRepository relationRepository, IRelationTypeRepository relationTypeRepository,
|
||||
Lazy<PropertyEditorCollection> propertyEditorCollection, DataValueReferenceFactoryCollection dataValueReferenceFactories)
|
||||
: base(scopeAccessor, cache, logger, languageRepository, relationRepository, relationTypeRepository, propertyEditorCollection, dataValueReferenceFactories)
|
||||
{
|
||||
_mediaTypeRepository = mediaTypeRepository ?? throw new ArgumentNullException(nameof(mediaTypeRepository));
|
||||
_tagRepository = tagRepository ?? throw new ArgumentNullException(nameof(tagRepository));
|
||||
@@ -286,6 +288,8 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
// set tags
|
||||
SetEntityTags(entity, _tagRepository);
|
||||
|
||||
PersistRelations(entity);
|
||||
|
||||
OnUowRefreshedEntity(new ScopedEntityEventArgs(AmbientScope, entity));
|
||||
|
||||
entity.ResetDirtyProperties();
|
||||
@@ -342,6 +346,8 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
|
||||
SetEntityTags(entity, _tagRepository);
|
||||
|
||||
PersistRelations(entity);
|
||||
|
||||
OnUowRefreshedEntity(new ScopedEntityEventArgs(AmbientScope, entity));
|
||||
|
||||
entity.ResetDirtyProperties();
|
||||
|
||||
@@ -10,6 +10,7 @@ using Umbraco.Core.Models.Entities;
|
||||
using Umbraco.Core.Persistence.Dtos;
|
||||
using Umbraco.Core.Persistence.Factories;
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
using Umbraco.Core.PropertyEditors;
|
||||
using Umbraco.Core.Scoping;
|
||||
using Umbraco.Core.Services;
|
||||
using static Umbraco.Core.Persistence.SqlExtensionsStatics;
|
||||
@@ -25,8 +26,10 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
private readonly ITagRepository _tagRepository;
|
||||
private readonly IMemberGroupRepository _memberGroupRepository;
|
||||
|
||||
public MemberRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger, IMemberTypeRepository memberTypeRepository, IMemberGroupRepository memberGroupRepository, ITagRepository tagRepository, ILanguageRepository languageRepository)
|
||||
: base(scopeAccessor, cache, languageRepository, logger)
|
||||
public MemberRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger,
|
||||
IMemberTypeRepository memberTypeRepository, IMemberGroupRepository memberGroupRepository, ITagRepository tagRepository, ILanguageRepository languageRepository, IRelationRepository relationRepository, IRelationTypeRepository relationTypeRepository,
|
||||
Lazy<PropertyEditorCollection> propertyEditors, DataValueReferenceFactoryCollection dataValueReferenceFactories)
|
||||
: base(scopeAccessor, cache, logger, languageRepository, relationRepository, relationTypeRepository, propertyEditors, dataValueReferenceFactories)
|
||||
{
|
||||
_memberTypeRepository = memberTypeRepository ?? throw new ArgumentNullException(nameof(memberTypeRepository));
|
||||
_tagRepository = tagRepository ?? throw new ArgumentNullException(nameof(tagRepository));
|
||||
@@ -317,6 +320,8 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
|
||||
SetEntityTags(entity, _tagRepository);
|
||||
|
||||
PersistRelations(entity);
|
||||
|
||||
OnUowRefreshedEntity(new ScopedEntityEventArgs(AmbientScope, entity));
|
||||
|
||||
entity.ResetDirtyProperties();
|
||||
@@ -382,6 +387,8 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
|
||||
SetEntityTags(entity, _tagRepository);
|
||||
|
||||
PersistRelations(entity);
|
||||
|
||||
OnUowRefreshedEntity(new ScopedEntityEventArgs(AmbientScope, entity));
|
||||
|
||||
entity.ResetDirtyProperties();
|
||||
|
||||
@@ -9,7 +9,10 @@ using Umbraco.Core.Models.Entities;
|
||||
using Umbraco.Core.Persistence.Dtos;
|
||||
using Umbraco.Core.Persistence.Factories;
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
using Umbraco.Core.Persistence.SqlSyntax;
|
||||
using Umbraco.Core.Scoping;
|
||||
using Umbraco.Core.Services;
|
||||
using static Umbraco.Core.Persistence.SqlExtensionsStatics;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
{
|
||||
@@ -19,11 +22,13 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
internal class RelationRepository : NPocoRepositoryBase<int, IRelation>, IRelationRepository
|
||||
{
|
||||
private readonly IRelationTypeRepository _relationTypeRepository;
|
||||
private readonly IEntityRepository _entityRepository;
|
||||
|
||||
public RelationRepository(IScopeAccessor scopeAccessor, ILogger logger, IRelationTypeRepository relationTypeRepository)
|
||||
public RelationRepository(IScopeAccessor scopeAccessor, ILogger logger, IRelationTypeRepository relationTypeRepository, IEntityRepository entityRepository)
|
||||
: base(scopeAccessor, AppCaches.NoCache, logger)
|
||||
{
|
||||
_relationTypeRepository = relationTypeRepository;
|
||||
_entityRepository = entityRepository;
|
||||
}
|
||||
|
||||
#region Overrides of RepositoryBase<int,Relation>
|
||||
@@ -39,10 +44,9 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
|
||||
var relationType = _relationTypeRepository.Get(dto.RelationType);
|
||||
if (relationType == null)
|
||||
throw new Exception(string.Format("RelationType with Id: {0} doesn't exist", dto.RelationType));
|
||||
throw new InvalidOperationException(string.Format("RelationType with Id: {0} doesn't exist", dto.RelationType));
|
||||
|
||||
var factory = new RelationFactory(relationType);
|
||||
return DtoToEntity(dto, factory);
|
||||
return DtoToEntity(dto, relationType);
|
||||
}
|
||||
|
||||
protected override IEnumerable<IRelation> PerformGetAll(params int[] ids)
|
||||
@@ -67,26 +71,17 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
|
||||
private IEnumerable<IRelation> DtosToEntities(IEnumerable<RelationDto> dtos)
|
||||
{
|
||||
// in most cases, the relation type will be the same for all of them,
|
||||
// plus we've ordered the relations by type, so try to allocate as few
|
||||
// factories as possible - bearing in mind that relation types are cached
|
||||
RelationFactory factory = null;
|
||||
var relationTypeId = -1;
|
||||
//NOTE: This is N+1, BUT ALL relation types are cached so shouldn't matter
|
||||
|
||||
return dtos.Select(x =>
|
||||
{
|
||||
if (relationTypeId != x.RelationType)
|
||||
factory = new RelationFactory(_relationTypeRepository.Get(relationTypeId = x.RelationType));
|
||||
return DtoToEntity(x, factory);
|
||||
}).ToList();
|
||||
return dtos.Select(x => DtoToEntity(x, _relationTypeRepository.Get(x.RelationType))).ToList();
|
||||
}
|
||||
|
||||
private static IRelation DtoToEntity(RelationDto dto, RelationFactory factory)
|
||||
private static IRelation DtoToEntity(RelationDto dto, IRelationType relationType)
|
||||
{
|
||||
var entity = factory.BuildEntity(dto);
|
||||
var entity = RelationFactory.BuildEntity(dto, relationType);
|
||||
|
||||
// reset dirty initial properties (U4-1946)
|
||||
((BeingDirtyBase)entity).ResetDirtyProperties(false);
|
||||
entity.ResetDirtyProperties(false);
|
||||
|
||||
return entity;
|
||||
}
|
||||
@@ -97,14 +92,18 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
|
||||
protected override Sql<ISqlContext> GetBaseQuery(bool isCount)
|
||||
{
|
||||
var sql = Sql();
|
||||
if (isCount)
|
||||
{
|
||||
return Sql().SelectCount().From<RelationDto>();
|
||||
}
|
||||
|
||||
sql = isCount
|
||||
? sql.SelectCount()
|
||||
: sql.Select<RelationDto>();
|
||||
var sql = Sql().Select<RelationDto>()
|
||||
.AndSelect<NodeDto>("uchild", x => Alias(x.NodeObjectType, "childObjectType"))
|
||||
.AndSelect<NodeDto>("uparent", x => Alias(x.NodeObjectType, "parentObjectType"))
|
||||
.From<RelationDto>()
|
||||
.InnerJoin<NodeDto>("uchild").On<RelationDto, NodeDto>((rel, node) => rel.ChildId == node.NodeId, aliasRight: "uchild")
|
||||
.InnerJoin<NodeDto>("uparent").On<RelationDto, NodeDto>((rel, node) => rel.ParentId == node.NodeId, aliasRight: "uparent");
|
||||
|
||||
sql
|
||||
.From<RelationDto>();
|
||||
|
||||
return sql;
|
||||
}
|
||||
@@ -136,11 +135,12 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
{
|
||||
entity.AddingEntity();
|
||||
|
||||
var factory = new RelationFactory(entity.RelationType);
|
||||
var dto = factory.BuildDto(entity);
|
||||
var dto = RelationFactory.BuildDto(entity);
|
||||
|
||||
var id = Convert.ToInt32(Database.Insert(dto));
|
||||
|
||||
entity.Id = id;
|
||||
PopulateObjectTypes(entity);
|
||||
|
||||
entity.ResetDirtyProperties();
|
||||
}
|
||||
@@ -149,13 +149,192 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
{
|
||||
entity.UpdatingEntity();
|
||||
|
||||
var factory = new RelationFactory(entity.RelationType);
|
||||
var dto = factory.BuildDto(entity);
|
||||
var dto = RelationFactory.BuildDto(entity);
|
||||
Database.Update(dto);
|
||||
|
||||
PopulateObjectTypes(entity);
|
||||
|
||||
entity.ResetDirtyProperties();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Used for joining the entity query with relations for the paging methods
|
||||
/// </summary>
|
||||
/// <param name="sql"></param>
|
||||
private void SqlJoinRelations(Sql<ISqlContext> sql)
|
||||
{
|
||||
// add left joins for relation tables (this joins on both child or parent, so beware that this will normally return entities for
|
||||
// both sides of the relation type unless the IUmbracoEntity query passed in filters one side out).
|
||||
sql.LeftJoin<RelationDto>().On<NodeDto, RelationDto>((left, right) => left.NodeId == right.ChildId || left.NodeId == right.ParentId);
|
||||
sql.LeftJoin<RelationTypeDto>().On<RelationDto, RelationTypeDto>((left, right) => left.RelationType == right.Id);
|
||||
}
|
||||
|
||||
public IEnumerable<IUmbracoEntity> GetPagedParentEntitiesByChildId(int childId, long pageIndex, int pageSize, out long totalRecords, params Guid[] entityTypes)
|
||||
{
|
||||
// var contentObjectTypes = new[] { Constants.ObjectTypes.Document, Constants.ObjectTypes.Media, Constants.ObjectTypes.Member }
|
||||
// we could pass in the contentObjectTypes so that the entity repository sql is configured to do full entity lookups so that we get the full data
|
||||
// required to populate content, media or members, else we get the bare minimum data needed to populate an entity. BUT if we do this it
|
||||
// means that the SQL is less efficient and returns data that is probably not needed for what we need this lookup for. For the time being we
|
||||
// will just return the bare minimum entity data.
|
||||
|
||||
return _entityRepository.GetPagedResultsByQuery(Query<IUmbracoEntity>(), entityTypes, pageIndex, pageSize, out totalRecords, null, null, sql =>
|
||||
{
|
||||
SqlJoinRelations(sql);
|
||||
|
||||
sql.Where<RelationDto>(rel => rel.ChildId == childId);
|
||||
sql.Where<RelationDto, NodeDto>((rel, node) => rel.ParentId == childId || node.NodeId != childId);
|
||||
});
|
||||
}
|
||||
|
||||
public IEnumerable<IUmbracoEntity> GetPagedChildEntitiesByParentId(int parentId, long pageIndex, int pageSize, out long totalRecords, params Guid[] entityTypes)
|
||||
{
|
||||
// var contentObjectTypes = new[] { Constants.ObjectTypes.Document, Constants.ObjectTypes.Media, Constants.ObjectTypes.Member }
|
||||
// we could pass in the contentObjectTypes so that the entity repository sql is configured to do full entity lookups so that we get the full data
|
||||
// required to populate content, media or members, else we get the bare minimum data needed to populate an entity. BUT if we do this it
|
||||
// means that the SQL is less efficient and returns data that is probably not needed for what we need this lookup for. For the time being we
|
||||
// will just return the bare minimum entity data.
|
||||
|
||||
return _entityRepository.GetPagedResultsByQuery(Query<IUmbracoEntity>(), entityTypes, pageIndex, pageSize, out totalRecords, null, null, sql =>
|
||||
{
|
||||
SqlJoinRelations(sql);
|
||||
|
||||
sql.Where<RelationDto>(rel => rel.ParentId == parentId);
|
||||
sql.Where<RelationDto, NodeDto>((rel, node) => rel.ChildId == parentId || node.NodeId != parentId);
|
||||
});
|
||||
}
|
||||
|
||||
public void Save(IEnumerable<IRelation> relations)
|
||||
{
|
||||
foreach (var hasIdentityGroup in relations.GroupBy(r => r.HasIdentity))
|
||||
{
|
||||
if (hasIdentityGroup.Key)
|
||||
{
|
||||
// Do updates, we can't really do a bulk update so this is still a 1 by 1 operation
|
||||
// however we can bulk populate the object types. It might be possible to bulk update
|
||||
// with SQL but would be pretty ugly and we're not really too worried about that for perf,
|
||||
// it's the bulk inserts we care about.
|
||||
var asArray = hasIdentityGroup.ToArray();
|
||||
foreach (var relation in hasIdentityGroup)
|
||||
{
|
||||
relation.UpdatingEntity();
|
||||
var dto = RelationFactory.BuildDto(relation);
|
||||
Database.Update(dto);
|
||||
}
|
||||
PopulateObjectTypes(asArray);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Do bulk inserts
|
||||
var entitiesAndDtos = hasIdentityGroup.ToDictionary(
|
||||
r => // key = entity
|
||||
{
|
||||
r.AddingEntity();
|
||||
return r;
|
||||
},
|
||||
RelationFactory.BuildDto); // value = DTO
|
||||
|
||||
// Use NPoco's own InsertBulk command which will automatically re-populate the new Ids on the entities, our own
|
||||
// BulkInsertRecords does not cater for this.
|
||||
Database.InsertBulk(entitiesAndDtos.Values);
|
||||
|
||||
// All dtos now have IDs assigned
|
||||
foreach (var de in entitiesAndDtos)
|
||||
{
|
||||
// re-assign ID to the entity
|
||||
de.Key.Id = de.Value.Id;
|
||||
}
|
||||
|
||||
PopulateObjectTypes(entitiesAndDtos.Keys.ToArray());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<IRelation> GetPagedRelationsByQuery(IQuery<IRelation> query, long pageIndex, int pageSize, out long totalRecords, Ordering ordering)
|
||||
{
|
||||
var sql = GetBaseQuery(false);
|
||||
|
||||
if (ordering == null || ordering.IsEmpty)
|
||||
ordering = Ordering.By(SqlSyntax.GetQuotedColumn(Constants.DatabaseSchema.Tables.Relation, "id"));
|
||||
|
||||
var translator = new SqlTranslator<IRelation>(sql, query);
|
||||
sql = translator.Translate();
|
||||
|
||||
// apply ordering
|
||||
ApplyOrdering(ref sql, ordering);
|
||||
|
||||
var pageIndexToFetch = pageIndex + 1;
|
||||
var page = Database.Page<RelationDto>(pageIndexToFetch, pageSize, sql);
|
||||
var dtos = page.Items;
|
||||
totalRecords = page.TotalItems;
|
||||
|
||||
var relTypes = _relationTypeRepository.GetMany(dtos.Select(x => x.RelationType).Distinct().ToArray())
|
||||
.ToDictionary(x => x.Id, x => x);
|
||||
|
||||
var result = dtos.Select(r =>
|
||||
{
|
||||
if (!relTypes.TryGetValue(r.RelationType, out var relType))
|
||||
throw new InvalidOperationException(string.Format("RelationType with Id: {0} doesn't exist", r.RelationType));
|
||||
return DtoToEntity(r, relType);
|
||||
}).ToList();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
public void DeleteByParent(int parentId, params string[] relationTypeAliases)
|
||||
{
|
||||
var subQuery = Sql().Select<RelationDto>(x => x.Id)
|
||||
.From<RelationDto>()
|
||||
.InnerJoin<RelationTypeDto>().On<RelationDto, RelationTypeDto>(x => x.RelationType, x => x.Id)
|
||||
.Where<RelationDto>(x => x.ParentId == parentId);
|
||||
|
||||
if (relationTypeAliases.Length > 0)
|
||||
{
|
||||
subQuery.WhereIn<RelationTypeDto>(x => x.Alias, relationTypeAliases);
|
||||
}
|
||||
|
||||
Database.Execute(Sql().Delete<RelationDto>().WhereIn<RelationDto>(x => x.Id, subQuery));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used to populate the object types after insert/update
|
||||
/// </summary>
|
||||
/// <param name="entities"></param>
|
||||
private void PopulateObjectTypes(params IRelation[] entities)
|
||||
{
|
||||
var entityIds = entities.Select(x => x.ParentId).Concat(entities.Select(y => y.ChildId)).Distinct();
|
||||
|
||||
var nodes = Database.Fetch<NodeDto>(Sql().Select<NodeDto>().From<NodeDto>()
|
||||
.WhereIn<NodeDto>(x => x.NodeId, entityIds))
|
||||
.ToDictionary(x => x.NodeId, x => x.NodeObjectType);
|
||||
|
||||
foreach (var e in entities)
|
||||
{
|
||||
if (nodes.TryGetValue(e.ParentId, out var parentObjectType))
|
||||
{
|
||||
e.ParentObjectType = parentObjectType.GetValueOrDefault();
|
||||
}
|
||||
if (nodes.TryGetValue(e.ChildId, out var childObjectType))
|
||||
{
|
||||
e.ChildObjectType = childObjectType.GetValueOrDefault();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ApplyOrdering(ref Sql<ISqlContext> sql, Ordering ordering)
|
||||
{
|
||||
if (sql == null) throw new ArgumentNullException(nameof(sql));
|
||||
if (ordering == null) throw new ArgumentNullException(nameof(ordering));
|
||||
|
||||
// TODO: although this works for name, it probably doesn't work for others without an alias of some sort
|
||||
var orderBy = ordering.OrderBy;
|
||||
|
||||
if (ordering.Direction == Direction.Ascending)
|
||||
sql.OrderBy(orderBy);
|
||||
else
|
||||
sql.OrderByDescending(orderBy);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,7 +134,9 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
protected override void PersistNewItem(IRelationType entity)
|
||||
{
|
||||
entity.AddingEntity();
|
||||
|
||||
|
||||
CheckNullObjectTypeValues(entity);
|
||||
|
||||
var dto = RelationTypeFactory.BuildDto(entity);
|
||||
|
||||
var id = Convert.ToInt32(Database.Insert(dto));
|
||||
@@ -146,7 +148,9 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
protected override void PersistUpdatedItem(IRelationType entity)
|
||||
{
|
||||
entity.UpdatingEntity();
|
||||
|
||||
|
||||
CheckNullObjectTypeValues(entity);
|
||||
|
||||
var dto = RelationTypeFactory.BuildDto(entity);
|
||||
Database.Update(dto);
|
||||
|
||||
@@ -154,5 +158,13 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private void CheckNullObjectTypeValues(IRelationType entity)
|
||||
{
|
||||
if (entity.ParentObjectType.HasValue && entity.ParentObjectType == Guid.Empty)
|
||||
entity.ParentObjectType = null;
|
||||
if (entity.ChildObjectType.HasValue && entity.ChildObjectType == Guid.Empty)
|
||||
entity.ChildObjectType = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,6 +35,8 @@ namespace Umbraco.Core.Persistence.SqlSyntax
|
||||
/// </remarks>
|
||||
public static Sql GetDeleteSubquery(this ISqlSyntaxProvider sqlProvider, string tableName, string columnName, Sql subQuery, WhereInType whereInType = WhereInType.In)
|
||||
{
|
||||
//TODO: This is no longer necessary since this used to be a specific requirement for MySql!
|
||||
// Now we can do a Delete<T> + sub query, see RelationRepository.DeleteByParent for example
|
||||
|
||||
return
|
||||
new Sql(string.Format(
|
||||
|
||||
@@ -44,6 +44,8 @@ namespace Umbraco.Core.Persistence
|
||||
_commandRetryPolicy = commandRetryPolicy;
|
||||
|
||||
EnableSqlTrace = EnableSqlTraceDefault;
|
||||
|
||||
NPocoDatabaseExtensions.ConfigureNPocoBulkExtensions();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -57,6 +59,8 @@ namespace Umbraco.Core.Persistence
|
||||
_logger = logger;
|
||||
|
||||
EnableSqlTrace = EnableSqlTraceDefault;
|
||||
|
||||
NPocoDatabaseExtensions.ConfigureNPocoBulkExtensions();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -19,6 +19,7 @@ namespace Umbraco.Core.PropertyEditors
|
||||
public class DataEditor : IDataEditor
|
||||
{
|
||||
private IDictionary<string, object> _defaultConfiguration;
|
||||
private IDataValueEditor _dataValueEditor;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DataEditor"/> class.
|
||||
@@ -90,7 +91,7 @@ namespace Umbraco.Core.PropertyEditors
|
||||
/// simple enough for now.</para>
|
||||
/// </remarks>
|
||||
// TODO: point of that one? shouldn't we always configure?
|
||||
public IDataValueEditor GetValueEditor() => ExplicitValueEditor ?? CreateValueEditor();
|
||||
public IDataValueEditor GetValueEditor() => ExplicitValueEditor ?? (_dataValueEditor ?? (_dataValueEditor = CreateValueEditor()));
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <remarks>
|
||||
@@ -113,7 +114,7 @@ namespace Umbraco.Core.PropertyEditors
|
||||
return ExplicitValueEditor;
|
||||
|
||||
var editor = CreateValueEditor();
|
||||
((DataValueEditor) editor).Configuration = configuration; // TODO: casting is bad
|
||||
((DataValueEditor)editor).Configuration = configuration; // TODO: casting is bad
|
||||
return editor;
|
||||
}
|
||||
|
||||
@@ -163,7 +164,7 @@ namespace Umbraco.Core.PropertyEditors
|
||||
protected virtual IDataValueEditor CreateValueEditor()
|
||||
{
|
||||
if (Attribute == null)
|
||||
throw new InvalidOperationException("The editor does not specify a view.");
|
||||
throw new InvalidOperationException($"The editor is not attributed with {nameof(DataEditorAttribute)}");
|
||||
|
||||
return new DataValueEditor(Current.Services.DataTypeService, Current.Services.LocalizationService, Attribute);
|
||||
}
|
||||
@@ -175,7 +176,7 @@ namespace Umbraco.Core.PropertyEditors
|
||||
{
|
||||
var editor = new ConfigurationEditor();
|
||||
// pass the default configuration if this is not a property value editor
|
||||
if((Type & EditorType.PropertyValue) == 0)
|
||||
if ((Type & EditorType.PropertyValue) == 0)
|
||||
{
|
||||
editor.DefaultConfiguration = _defaultConfiguration;
|
||||
}
|
||||
|
||||
@@ -273,12 +273,14 @@ namespace Umbraco.Core.PropertyEditors
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// TODO: the methods below should be replaced by proper property value convert ToXPath usage!
|
||||
|
||||
/// <summary>
|
||||
/// Converts a property to Xml fragments.
|
||||
/// </summary>
|
||||
public IEnumerable<XElement> ConvertDbToXml(IProperty property, bool published)
|
||||
public IEnumerable<XElement> ConvertDbToXml(IProperty property, IDataTypeService dataTypeService,
|
||||
ILocalizationService localizationService, bool published)
|
||||
{
|
||||
published &= property.PropertyType.SupportsPublishing;
|
||||
|
||||
@@ -296,7 +298,7 @@ namespace Umbraco.Core.PropertyEditors
|
||||
if (pvalue.Segment != null)
|
||||
xElement.Add(new XAttribute("segment", pvalue.Segment));
|
||||
|
||||
var xValue = ConvertDbToXml(property.PropertyType, value);
|
||||
var xValue = ConvertDbToXml(property.PropertyType, value, dataTypeService);
|
||||
xElement.Add(xValue);
|
||||
|
||||
yield return xElement;
|
||||
@@ -312,12 +314,12 @@ namespace Umbraco.Core.PropertyEditors
|
||||
/// <para>Returns an XText or XCData instance which must be wrapped in a element.</para>
|
||||
/// <para>If the value is empty we will not return as CDATA since that will just take up more space in the file.</para>
|
||||
/// </remarks>
|
||||
public XNode ConvertDbToXml(IPropertyType propertyType, object value)
|
||||
public XNode ConvertDbToXml(IPropertyType propertyType, object value, IDataTypeService dataTypeService)
|
||||
{
|
||||
//check for null or empty value, we don't want to return CDATA if that is the case
|
||||
if (value == null || value.ToString().IsNullOrWhiteSpace())
|
||||
{
|
||||
return new XText(ConvertDbToString(propertyType, value));
|
||||
return new XText(ConvertDbToString(propertyType, value, dataTypeService));
|
||||
}
|
||||
|
||||
switch (ValueTypes.ToStorageType(ValueType))
|
||||
@@ -325,11 +327,11 @@ namespace Umbraco.Core.PropertyEditors
|
||||
case ValueStorageType.Date:
|
||||
case ValueStorageType.Integer:
|
||||
case ValueStorageType.Decimal:
|
||||
return new XText(ConvertDbToString(propertyType, value));
|
||||
return new XText(ConvertDbToString(propertyType, value, dataTypeService));
|
||||
case ValueStorageType.Nvarchar:
|
||||
case ValueStorageType.Ntext:
|
||||
//put text in cdata
|
||||
return new XCData(ConvertDbToString(propertyType, value));
|
||||
return new XCData(ConvertDbToString(propertyType, value, dataTypeService));
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
@@ -338,7 +340,7 @@ namespace Umbraco.Core.PropertyEditors
|
||||
/// <summary>
|
||||
/// Converts a property value to a string.
|
||||
/// </summary>
|
||||
public virtual string ConvertDbToString(IPropertyType propertyType, object value)
|
||||
public virtual string ConvertDbToString(IPropertyType propertyType, object value, IDataTypeService dataTypeService)
|
||||
{
|
||||
if (value == null)
|
||||
return string.Empty;
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.Editors;
|
||||
|
||||
namespace Umbraco.Core.PropertyEditors
|
||||
{
|
||||
public class DataValueReferenceFactoryCollection : BuilderCollectionBase<IDataValueReferenceFactory>
|
||||
{
|
||||
public DataValueReferenceFactoryCollection(IEnumerable<IDataValueReferenceFactory> items)
|
||||
: base(items)
|
||||
{ }
|
||||
|
||||
public IEnumerable<UmbracoEntityReference> GetAllReferences(IPropertyCollection properties, PropertyEditorCollection propertyEditors)
|
||||
{
|
||||
var trackedRelations = new List<UmbracoEntityReference>();
|
||||
|
||||
foreach (var p in properties)
|
||||
{
|
||||
if (!propertyEditors.TryGet(p.PropertyType.PropertyEditorAlias, out var editor)) continue;
|
||||
|
||||
//TODO: Support variants/segments! This is not required for this initial prototype which is why there is a check here
|
||||
if (!p.PropertyType.VariesByNothing()) continue;
|
||||
var val = p.GetValue(); // get the invariant value
|
||||
|
||||
var valueEditor = editor.GetValueEditor();
|
||||
if (valueEditor is IDataValueReference reference)
|
||||
{
|
||||
var refs = reference.GetReferences(val);
|
||||
trackedRelations.AddRange(refs);
|
||||
}
|
||||
|
||||
// Loop over collection that may be add to existing property editors
|
||||
// implementation of GetReferences in IDataValueReference.
|
||||
// Allows developers to add support for references by a
|
||||
// package /property editor that did not implement IDataValueReference themselves
|
||||
foreach (var item in this)
|
||||
{
|
||||
// Check if this value reference is for this datatype/editor
|
||||
// Then call it's GetReferences method - to see if the value stored
|
||||
// in the dataeditor/property has referecnes to media/content items
|
||||
if (item.IsForEditor(editor))
|
||||
trackedRelations.AddRange(item.GetDataValueReference().GetReferences(val));
|
||||
}
|
||||
}
|
||||
|
||||
return trackedRelations;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using Umbraco.Core.Composing;
|
||||
|
||||
namespace Umbraco.Core.PropertyEditors
|
||||
{
|
||||
public class DataValueReferenceFactoryCollectionBuilder : OrderedCollectionBuilderBase<DataValueReferenceFactoryCollectionBuilder, DataValueReferenceFactoryCollection, IDataValueReferenceFactory>
|
||||
{
|
||||
protected override DataValueReferenceFactoryCollectionBuilder This => this;
|
||||
}
|
||||
}
|
||||
18
src/Umbraco.Core/PropertyEditors/IDataValueReference.cs
Normal file
18
src/Umbraco.Core/PropertyEditors/IDataValueReference.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core.Models.Editors;
|
||||
|
||||
namespace Umbraco.Core.PropertyEditors
|
||||
{
|
||||
/// <summary>
|
||||
/// Resolve references from <see cref="IDataValueEditor"/> values
|
||||
/// </summary>
|
||||
public interface IDataValueReference
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns any references contained in the value
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
IEnumerable<UmbracoEntityReference> GetReferences(object value);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
namespace Umbraco.Core.PropertyEditors
|
||||
{
|
||||
public interface IDataValueReferenceFactory
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the DataValueReference lookup supports a datatype (data editor).
|
||||
/// </summary>
|
||||
/// <param name="dataType">The datatype.</param>
|
||||
/// <returns>A value indicating whether the converter supports a datatype.</returns>
|
||||
bool IsForEditor(IDataEditor dataEditor);
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
IDataValueReference GetDataValueReference();
|
||||
}
|
||||
}
|
||||
@@ -47,7 +47,7 @@ namespace Umbraco.Core.Runtime
|
||||
// register persistence mappers - required by database factory so needs to be done here
|
||||
// means the only place the collection can be modified is in a runtime - afterwards it
|
||||
// has been frozen and it is too late
|
||||
composition.WithCollectionBuilder<MapperCollectionBuilder>().AddCoreMappers();
|
||||
composition.Mappers().AddCoreMappers();
|
||||
|
||||
// register the scope provider
|
||||
composition.RegisterUnique<ScopeProvider>(); // implements both IScopeProvider and IScopeAccessor
|
||||
@@ -76,11 +76,15 @@ namespace Umbraco.Core.Runtime
|
||||
composition.ManifestFilters();
|
||||
|
||||
// properties and parameters derive from data editors
|
||||
composition.WithCollectionBuilder<DataEditorCollectionBuilder>()
|
||||
composition.DataEditors()
|
||||
.Add(() => composition.TypeLoader.GetDataEditors());
|
||||
composition.RegisterUnique<PropertyEditorCollection>();
|
||||
composition.RegisterUnique<ParameterEditorCollection>();
|
||||
|
||||
// Used to determine if a datatype/editor should be storing/tracking
|
||||
// references to media item/s
|
||||
composition.DataValueReferenceFactories();
|
||||
|
||||
// register a server registrar, by default it's the db registrar
|
||||
composition.RegisterUnique<IServerRegistrar>(f =>
|
||||
{
|
||||
@@ -109,13 +113,13 @@ namespace Umbraco.Core.Runtime
|
||||
factory.GetInstance<IHostingEnvironment>()
|
||||
));
|
||||
|
||||
composition.WithCollectionBuilder<CacheRefresherCollectionBuilder>()
|
||||
composition.CacheRefreshers()
|
||||
.Add(() => composition.TypeLoader.GetCacheRefreshers());
|
||||
|
||||
composition.WithCollectionBuilder<PackageActionCollectionBuilder>()
|
||||
composition.PackageActions()
|
||||
.Add(() => composition.TypeLoader.GetPackageActions());
|
||||
|
||||
composition.WithCollectionBuilder<PropertyValueConverterCollectionBuilder>()
|
||||
composition.PropertyValueConverters()
|
||||
.Append(composition.TypeLoader.GetTypes<IPropertyValueConverter>());
|
||||
|
||||
composition.RegisterUnique<IPublishedContentTypeFactory, PublishedContentTypeFactory>();
|
||||
@@ -123,7 +127,7 @@ namespace Umbraco.Core.Runtime
|
||||
composition.RegisterUnique<IShortStringHelper>(factory
|
||||
=> new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(factory.GetInstance<IUmbracoSettingsSection>())));
|
||||
|
||||
composition.WithCollectionBuilder<UrlSegmentProviderCollectionBuilder>()
|
||||
composition.UrlSegmentProviders()
|
||||
.Append<DefaultUrlSegmentProvider>();
|
||||
|
||||
composition.RegisterUnique<IMigrationBuilder>(factory => new MigrationBuilder(factory));
|
||||
|
||||
@@ -564,7 +564,7 @@ namespace Umbraco.Core.Services.Implement
|
||||
var propertyEditor = Current.PropertyEditors[propertyType.PropertyEditorAlias];
|
||||
return propertyEditor == null
|
||||
? Array.Empty<XElement>()
|
||||
: propertyEditor.GetValueEditor().ConvertDbToXml(property, published);
|
||||
: propertyEditor.GetValueEditor().ConvertDbToXml(property, _dataTypeService, _localizationService, published);
|
||||
}
|
||||
|
||||
// exports an IContent item descendants.
|
||||
|
||||
@@ -25,11 +25,7 @@ namespace Umbraco.Core.Services.Implement
|
||||
_entityService = entityService ?? throw new ArgumentNullException(nameof(entityService));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a <see cref="Relation"/> by its Id
|
||||
/// </summary>
|
||||
/// <param name="id">Id of the <see cref="Relation"/></param>
|
||||
/// <returns>A <see cref="Relation"/> object</returns>
|
||||
/// <inheritdoc />
|
||||
public IRelation GetById(int id)
|
||||
{
|
||||
using (var scope = ScopeProvider.CreateScope(autoComplete: true))
|
||||
@@ -38,11 +34,7 @@ namespace Umbraco.Core.Services.Implement
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a <see cref="RelationType"/> by its Id
|
||||
/// </summary>
|
||||
/// <param name="id">Id of the <see cref="RelationType"/></param>
|
||||
/// <returns>A <see cref="RelationType"/> object</returns>
|
||||
/// <inheritdoc />
|
||||
public IRelationType GetRelationTypeById(int id)
|
||||
{
|
||||
using (var scope = ScopeProvider.CreateScope(autoComplete: true))
|
||||
@@ -51,11 +43,7 @@ namespace Umbraco.Core.Services.Implement
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a <see cref="RelationType"/> by its Id
|
||||
/// </summary>
|
||||
/// <param name="id">Id of the <see cref="RelationType"/></param>
|
||||
/// <returns>A <see cref="RelationType"/> object</returns>
|
||||
/// <inheritdoc />
|
||||
public IRelationType GetRelationTypeById(Guid id)
|
||||
{
|
||||
using (var scope = ScopeProvider.CreateScope(autoComplete: true))
|
||||
@@ -64,25 +52,10 @@ namespace Umbraco.Core.Services.Implement
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a <see cref="RelationType"/> by its Alias
|
||||
/// </summary>
|
||||
/// <param name="alias">Alias of the <see cref="RelationType"/></param>
|
||||
/// <returns>A <see cref="RelationType"/> object</returns>
|
||||
public IRelationType GetRelationTypeByAlias(string alias)
|
||||
{
|
||||
using (var scope = ScopeProvider.CreateScope(autoComplete: true))
|
||||
{
|
||||
var query = Query<IRelationType>().Where(x => x.Alias == alias);
|
||||
return _relationTypeRepository.Get(query).FirstOrDefault();
|
||||
}
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public IRelationType GetRelationTypeByAlias(string alias) => GetRelationType(alias);
|
||||
|
||||
/// <summary>
|
||||
/// Gets all <see cref="Relation"/> objects
|
||||
/// </summary>
|
||||
/// <param name="ids">Optional array of integer ids to return relations for</param>
|
||||
/// <returns>An enumerable list of <see cref="Relation"/> objects</returns>
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<IRelation> GetAllRelations(params int[] ids)
|
||||
{
|
||||
using (var scope = ScopeProvider.CreateScope(autoComplete: true))
|
||||
@@ -91,21 +64,13 @@ namespace Umbraco.Core.Services.Implement
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets all <see cref="Relation"/> objects by their <see cref="RelationType"/>
|
||||
/// </summary>
|
||||
/// <param name="relationType"><see cref="RelationType"/> to retrieve Relations for</param>
|
||||
/// <returns>An enumerable list of <see cref="Relation"/> objects</returns>
|
||||
public IEnumerable<IRelation> GetAllRelationsByRelationType(RelationType relationType)
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<IRelation> GetAllRelationsByRelationType(IRelationType relationType)
|
||||
{
|
||||
return GetAllRelationsByRelationType(relationType.Id);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets all <see cref="Relation"/> objects by their <see cref="RelationType"/>'s Id
|
||||
/// </summary>
|
||||
/// <param name="relationTypeId">Id of the <see cref="RelationType"/> to retrieve Relations for</param>
|
||||
/// <returns>An enumerable list of <see cref="Relation"/> objects</returns>
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<IRelation> GetAllRelationsByRelationType(int relationTypeId)
|
||||
{
|
||||
using (var scope = ScopeProvider.CreateScope(autoComplete: true))
|
||||
@@ -115,11 +80,7 @@ namespace Umbraco.Core.Services.Implement
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets all <see cref="Relation"/> objects
|
||||
/// </summary>
|
||||
/// <param name="ids">Optional array of integer ids to return relationtypes for</param>
|
||||
/// <returns>An enumerable list of <see cref="RelationType"/> objects</returns>
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<IRelationType> GetAllRelationTypes(params int[] ids)
|
||||
{
|
||||
using (var scope = ScopeProvider.CreateScope(autoComplete: true))
|
||||
@@ -128,82 +89,65 @@ namespace Umbraco.Core.Services.Implement
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of <see cref="Relation"/> objects by their parent Id
|
||||
/// </summary>
|
||||
/// <param name="id">Id of the parent to retrieve relations for</param>
|
||||
/// <returns>An enumerable list of <see cref="Relation"/> objects</returns>
|
||||
public IEnumerable<IRelation> GetByParentId(int id)
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<IRelation> GetByParentId(int id) => GetByParentId(id, null);
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<IRelation> GetByParentId(int id, string relationTypeAlias)
|
||||
{
|
||||
using (var scope = ScopeProvider.CreateScope(autoComplete: true))
|
||||
{
|
||||
var query = Query<IRelation>().Where(x => x.ParentId == id);
|
||||
return _relationRepository.Get(query);
|
||||
if (relationTypeAlias.IsNullOrWhiteSpace())
|
||||
{
|
||||
var qry1 = Query<IRelation>().Where(x => x.ParentId == id);
|
||||
return _relationRepository.Get(qry1);
|
||||
}
|
||||
|
||||
var relationType = GetRelationType(relationTypeAlias);
|
||||
if (relationType == null)
|
||||
return Enumerable.Empty<IRelation>();
|
||||
|
||||
var qry2 = Query<IRelation>().Where(x => x.ParentId == id && x.RelationTypeId == relationType.Id);
|
||||
return _relationRepository.Get(qry2);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of <see cref="Relation"/> objects by their parent entity
|
||||
/// </summary>
|
||||
/// <param name="parent">Parent Entity to retrieve relations for</param>
|
||||
/// <returns>An enumerable list of <see cref="Relation"/> objects</returns>
|
||||
public IEnumerable<IRelation> GetByParent(IUmbracoEntity parent)
|
||||
{
|
||||
return GetByParentId(parent.Id);
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<IRelation> GetByParent(IUmbracoEntity parent) => GetByParentId(parent.Id);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of <see cref="Relation"/> objects by their parent entity
|
||||
/// </summary>
|
||||
/// <param name="parent">Parent Entity to retrieve relations for</param>
|
||||
/// <param name="relationTypeAlias">Alias of the type of relation to retrieve</param>
|
||||
/// <returns>An enumerable list of <see cref="Relation"/> objects</returns>
|
||||
public IEnumerable<IRelation> GetByParent(IUmbracoEntity parent, string relationTypeAlias)
|
||||
{
|
||||
return GetByParent(parent).Where(relation => relation.RelationType.Alias == relationTypeAlias);
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<IRelation> GetByParent(IUmbracoEntity parent, string relationTypeAlias) => GetByParentId(parent.Id, relationTypeAlias);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of <see cref="Relation"/> objects by their child Id
|
||||
/// </summary>
|
||||
/// <param name="id">Id of the child to retrieve relations for</param>
|
||||
/// <returns>An enumerable list of <see cref="Relation"/> objects</returns>
|
||||
public IEnumerable<IRelation> GetByChildId(int id)
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<IRelation> GetByChildId(int id) => GetByChildId(id, null);
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<IRelation> GetByChildId(int id, string relationTypeAlias)
|
||||
{
|
||||
using (var scope = ScopeProvider.CreateScope(autoComplete: true))
|
||||
{
|
||||
var query = Query<IRelation>().Where(x => x.ChildId == id);
|
||||
return _relationRepository.Get(query);
|
||||
if (relationTypeAlias.IsNullOrWhiteSpace())
|
||||
{
|
||||
var qry1 = Query<IRelation>().Where(x => x.ChildId == id);
|
||||
return _relationRepository.Get(qry1);
|
||||
}
|
||||
|
||||
var relationType = GetRelationType(relationTypeAlias);
|
||||
if (relationType == null)
|
||||
return Enumerable.Empty<IRelation>();
|
||||
|
||||
var qry2 = Query<IRelation>().Where(x => x.ChildId == id && x.RelationTypeId == relationType.Id);
|
||||
return _relationRepository.Get(qry2);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of <see cref="Relation"/> objects by their child Entity
|
||||
/// </summary>
|
||||
/// <param name="child">Child Entity to retrieve relations for</param>
|
||||
/// <returns>An enumerable list of <see cref="Relation"/> objects</returns>
|
||||
public IEnumerable<IRelation> GetByChild(IUmbracoEntity child)
|
||||
{
|
||||
return GetByChildId(child.Id);
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<IRelation> GetByChild(IUmbracoEntity child) => GetByChildId(child.Id);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of <see cref="Relation"/> objects by their child Entity
|
||||
/// </summary>
|
||||
/// <param name="child">Child Entity to retrieve relations for</param>
|
||||
/// <param name="relationTypeAlias">Alias of the type of relation to retrieve</param>
|
||||
/// <returns>An enumerable list of <see cref="Relation"/> objects</returns>
|
||||
public IEnumerable<IRelation> GetByChild(IUmbracoEntity child, string relationTypeAlias)
|
||||
{
|
||||
return GetByChild(child).Where(relation => relation.RelationType.Alias == relationTypeAlias);
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<IRelation> GetByChild(IUmbracoEntity child, string relationTypeAlias) => GetByChildId(child.Id, relationTypeAlias);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of <see cref="Relation"/> objects by their child or parent Id.
|
||||
/// Using this method will get you all relations regards of it being a child or parent relation.
|
||||
/// </summary>
|
||||
/// <param name="id">Id of the child or parent to retrieve relations for</param>
|
||||
/// <returns>An enumerable list of <see cref="Relation"/> objects</returns>
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<IRelation> GetByParentOrChildId(int id)
|
||||
{
|
||||
using (var scope = ScopeProvider.CreateScope(autoComplete: true))
|
||||
@@ -217,8 +161,7 @@ namespace Umbraco.Core.Services.Implement
|
||||
{
|
||||
using (var scope = ScopeProvider.CreateScope(autoComplete: true))
|
||||
{
|
||||
var rtQuery = Query<IRelationType>().Where(x => x.Alias == relationTypeAlias);
|
||||
var relationType = _relationTypeRepository.Get(rtQuery).FirstOrDefault();
|
||||
var relationType = GetRelationType(relationTypeAlias);
|
||||
if (relationType == null)
|
||||
return Enumerable.Empty<IRelation>();
|
||||
|
||||
@@ -227,16 +170,13 @@ namespace Umbraco.Core.Services.Implement
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of <see cref="Relation"/> objects by the Name of the <see cref="RelationType"/>
|
||||
/// </summary>
|
||||
/// <param name="relationTypeName">Name of the <see cref="RelationType"/> to retrieve Relations for</param>
|
||||
/// <returns>An enumerable list of <see cref="Relation"/> objects</returns>
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<IRelation> GetByRelationTypeName(string relationTypeName)
|
||||
{
|
||||
List<int> relationTypeIds;
|
||||
using (var scope = ScopeProvider.CreateScope(autoComplete: true))
|
||||
{
|
||||
//This is a silly query - but i guess it's needed in case someone has more than one relation with the same Name (not alias), odd.
|
||||
var query = Query<IRelationType>().Where(x => x.Name == relationTypeName);
|
||||
var relationTypes = _relationTypeRepository.Get(query);
|
||||
relationTypeIds = relationTypes.Select(x => x.Id).ToList();
|
||||
@@ -247,31 +187,17 @@ namespace Umbraco.Core.Services.Implement
|
||||
: GetRelationsByListOfTypeIds(relationTypeIds);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of <see cref="Relation"/> objects by the Alias of the <see cref="RelationType"/>
|
||||
/// </summary>
|
||||
/// <param name="relationTypeAlias">Alias of the <see cref="RelationType"/> to retrieve Relations for</param>
|
||||
/// <returns>An enumerable list of <see cref="Relation"/> objects</returns>
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<IRelation> GetByRelationTypeAlias(string relationTypeAlias)
|
||||
{
|
||||
List<int> relationTypeIds;
|
||||
using (var scope = ScopeProvider.CreateScope(autoComplete: true))
|
||||
{
|
||||
var query = Query<IRelationType>().Where(x => x.Alias == relationTypeAlias);
|
||||
var relationTypes = _relationTypeRepository.Get(query);
|
||||
relationTypeIds = relationTypes.Select(x => x.Id).ToList();
|
||||
}
|
||||
|
||||
return relationTypeIds.Count == 0
|
||||
var relationType = GetRelationType(relationTypeAlias);
|
||||
|
||||
return relationType == null
|
||||
? Enumerable.Empty<IRelation>()
|
||||
: GetRelationsByListOfTypeIds(relationTypeIds);
|
||||
: GetRelationsByListOfTypeIds(new[] { relationType.Id });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of <see cref="Relation"/> objects by the Id of the <see cref="RelationType"/>
|
||||
/// </summary>
|
||||
/// <param name="relationTypeId">Id of the <see cref="RelationType"/> to retrieve Relations for</param>
|
||||
/// <returns>An enumerable list of <see cref="Relation"/> objects</returns>
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<IRelation> GetByRelationTypeId(int relationTypeId)
|
||||
{
|
||||
using (var scope = ScopeProvider.CreateScope(autoComplete: true))
|
||||
@@ -281,37 +207,35 @@ namespace Umbraco.Core.Services.Implement
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Child object from a Relation as an <see cref="IUmbracoEntity"/>
|
||||
/// </summary>
|
||||
/// <param name="relation">Relation to retrieve child object from</param>
|
||||
/// <returns>An <see cref="IUmbracoEntity"/></returns>
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<IRelation> GetPagedByRelationTypeId(int relationTypeId, long pageIndex, int pageSize, out long totalRecords, Ordering ordering = null)
|
||||
{
|
||||
using (var scope = ScopeProvider.CreateScope(autoComplete: true))
|
||||
{
|
||||
var query = Query<IRelation>().Where(x => x.RelationTypeId == relationTypeId);
|
||||
return _relationRepository.GetPagedRelationsByQuery(query, pageIndex, pageSize, out totalRecords, ordering);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IUmbracoEntity GetChildEntityFromRelation(IRelation relation)
|
||||
{
|
||||
var objectType = ObjectTypes.GetUmbracoObjectType(relation.RelationType.ChildObjectType);
|
||||
var objectType = ObjectTypes.GetUmbracoObjectType(relation.ChildObjectType);
|
||||
return _entityService.Get(relation.ChildId, objectType);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Parent object from a Relation as an <see cref="IUmbracoEntity"/>
|
||||
/// </summary>
|
||||
/// <param name="relation">Relation to retrieve parent object from</param>
|
||||
/// <returns>An <see cref="IUmbracoEntity"/></returns>
|
||||
/// <inheritdoc />
|
||||
public IUmbracoEntity GetParentEntityFromRelation(IRelation relation)
|
||||
{
|
||||
var objectType = ObjectTypes.GetUmbracoObjectType(relation.RelationType.ParentObjectType);
|
||||
var objectType = ObjectTypes.GetUmbracoObjectType(relation.ParentObjectType);
|
||||
return _entityService.Get(relation.ParentId, objectType);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Parent and Child objects from a Relation as a <see cref="Tuple"/>"/> with <see cref="IUmbracoEntity"/>.
|
||||
/// </summary>
|
||||
/// <param name="relation">Relation to retrieve parent and child object from</param>
|
||||
/// <returns>Returns a Tuple with Parent (item1) and Child (item2)</returns>
|
||||
/// <inheritdoc />
|
||||
public Tuple<IUmbracoEntity, IUmbracoEntity> GetEntitiesFromRelation(IRelation relation)
|
||||
{
|
||||
var childObjectType = ObjectTypes.GetUmbracoObjectType(relation.RelationType.ChildObjectType);
|
||||
var parentObjectType = ObjectTypes.GetUmbracoObjectType(relation.RelationType.ParentObjectType);
|
||||
var childObjectType = ObjectTypes.GetUmbracoObjectType(relation.ChildObjectType);
|
||||
var parentObjectType = ObjectTypes.GetUmbracoObjectType(relation.ParentObjectType);
|
||||
|
||||
var child = _entityService.Get(relation.ChildId, childObjectType);
|
||||
var parent = _entityService.Get(relation.ParentId, parentObjectType);
|
||||
@@ -319,45 +243,63 @@ namespace Umbraco.Core.Services.Implement
|
||||
return new Tuple<IUmbracoEntity, IUmbracoEntity>(parent, child);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Child objects from a list of Relations as a list of <see cref="IUmbracoEntity"/> objects.
|
||||
/// </summary>
|
||||
/// <param name="relations">List of relations to retrieve child objects from</param>
|
||||
/// <returns>An enumerable list of <see cref="IUmbracoEntity"/></returns>
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<IUmbracoEntity> GetChildEntitiesFromRelations(IEnumerable<IRelation> relations)
|
||||
{
|
||||
foreach (var relation in relations)
|
||||
// Trying to avoid full N+1 lookups, so we'll group by the object type and then use the GetAll
|
||||
// method to lookup batches of entities for each parent object type
|
||||
|
||||
foreach (var groupedRelations in relations.GroupBy(x => ObjectTypes.GetUmbracoObjectType(x.ChildObjectType)))
|
||||
{
|
||||
var objectType = ObjectTypes.GetUmbracoObjectType(relation.RelationType.ChildObjectType);
|
||||
yield return _entityService.Get(relation.ChildId, objectType);
|
||||
var objectType = groupedRelations.Key;
|
||||
var ids = groupedRelations.Select(x => x.ChildId).ToArray();
|
||||
foreach (var e in _entityService.GetAll(objectType, ids))
|
||||
yield return e;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Parent objects from a list of Relations as a list of <see cref="IUmbracoEntity"/> objects.
|
||||
/// </summary>
|
||||
/// <param name="relations">List of relations to retrieve parent objects from</param>
|
||||
/// <returns>An enumerable list of <see cref="IUmbracoEntity"/></returns>
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<IUmbracoEntity> GetParentEntitiesFromRelations(IEnumerable<IRelation> relations)
|
||||
{
|
||||
foreach (var relation in relations)
|
||||
// Trying to avoid full N+1 lookups, so we'll group by the object type and then use the GetAll
|
||||
// method to lookup batches of entities for each parent object type
|
||||
|
||||
foreach (var groupedRelations in relations.GroupBy(x => ObjectTypes.GetUmbracoObjectType(x.ParentObjectType)))
|
||||
{
|
||||
var objectType = ObjectTypes.GetUmbracoObjectType(relation.RelationType.ParentObjectType);
|
||||
yield return _entityService.Get(relation.ParentId, objectType);
|
||||
var objectType = groupedRelations.Key;
|
||||
var ids = groupedRelations.Select(x => x.ParentId).ToArray();
|
||||
foreach (var e in _entityService.GetAll(objectType, ids))
|
||||
yield return e;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Parent and Child objects from a list of Relations as a list of <see cref="IUmbracoEntity"/> objects.
|
||||
/// </summary>
|
||||
/// <param name="relations">List of relations to retrieve parent and child objects from</param>
|
||||
/// <returns>An enumerable list of <see cref="Tuple"/> with <see cref="IUmbracoEntity"/></returns>
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<IUmbracoEntity> GetPagedParentEntitiesByChildId(int id, long pageIndex, int pageSize, out long totalChildren, params UmbracoObjectTypes[] entityTypes)
|
||||
{
|
||||
using (var scope = ScopeProvider.CreateScope(autoComplete: true))
|
||||
{
|
||||
return _relationRepository.GetPagedParentEntitiesByChildId(id, pageIndex, pageSize, out totalChildren, entityTypes.Select(x => x.GetGuid()).ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<IUmbracoEntity> GetPagedChildEntitiesByParentId(int id, long pageIndex, int pageSize, out long totalChildren, params UmbracoObjectTypes[] entityTypes)
|
||||
{
|
||||
using (var scope = ScopeProvider.CreateScope(autoComplete: true))
|
||||
{
|
||||
return _relationRepository.GetPagedChildEntitiesByParentId(id, pageIndex, pageSize, out totalChildren, entityTypes.Select(x => x.GetGuid()).ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<Tuple<IUmbracoEntity, IUmbracoEntity>> GetEntitiesFromRelations(IEnumerable<IRelation> relations)
|
||||
{
|
||||
//TODO: Argh! N+1
|
||||
|
||||
foreach (var relation in relations)
|
||||
{
|
||||
var childObjectType = ObjectTypes.GetUmbracoObjectType(relation.RelationType.ChildObjectType);
|
||||
var parentObjectType = ObjectTypes.GetUmbracoObjectType(relation.RelationType.ParentObjectType);
|
||||
var childObjectType = ObjectTypes.GetUmbracoObjectType(relation.ChildObjectType);
|
||||
var parentObjectType = ObjectTypes.GetUmbracoObjectType(relation.ParentObjectType);
|
||||
|
||||
var child = _entityService.Get(relation.ChildId, childObjectType);
|
||||
var parent = _entityService.Get(relation.ParentId, parentObjectType);
|
||||
@@ -366,19 +308,15 @@ namespace Umbraco.Core.Services.Implement
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Relates two objects by their entity Ids.
|
||||
/// </summary>
|
||||
/// <param name="parentId">Id of the parent</param>
|
||||
/// <param name="childId">Id of the child</param>
|
||||
/// <param name="relationType">The type of relation to create</param>
|
||||
/// <returns>The created <see cref="Relation"/></returns>
|
||||
/// <inheritdoc />
|
||||
public IRelation Relate(int parentId, int childId, IRelationType relationType)
|
||||
{
|
||||
// Ensure that the RelationType has an identity before using it to relate two entities
|
||||
if (relationType.HasIdentity == false)
|
||||
Save(relationType);
|
||||
|
||||
//TODO: We don't check if this exists first, it will throw some sort of data integrity exception if it already exists, is that ok?
|
||||
|
||||
var relation = new Relation(parentId, childId, relationType);
|
||||
|
||||
using (var scope = ScopeProvider.CreateScope())
|
||||
@@ -398,25 +336,13 @@ namespace Umbraco.Core.Services.Implement
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Relates two objects that are based on the <see cref="IUmbracoEntity"/> interface.
|
||||
/// </summary>
|
||||
/// <param name="parent">Parent entity</param>
|
||||
/// <param name="child">Child entity</param>
|
||||
/// <param name="relationType">The type of relation to create</param>
|
||||
/// <returns>The created <see cref="Relation"/></returns>
|
||||
/// <inheritdoc />
|
||||
public IRelation Relate(IUmbracoEntity parent, IUmbracoEntity child, IRelationType relationType)
|
||||
{
|
||||
return Relate(parent.Id, child.Id, relationType);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Relates two objects by their entity Ids.
|
||||
/// </summary>
|
||||
/// <param name="parentId">Id of the parent</param>
|
||||
/// <param name="childId">Id of the child</param>
|
||||
/// <param name="relationTypeAlias">Alias of the type of relation to create</param>
|
||||
/// <returns>The created <see cref="Relation"/></returns>
|
||||
/// <inheritdoc />
|
||||
public IRelation Relate(int parentId, int childId, string relationTypeAlias)
|
||||
{
|
||||
var relationType = GetRelationTypeByAlias(relationTypeAlias);
|
||||
@@ -426,13 +352,7 @@ namespace Umbraco.Core.Services.Implement
|
||||
return Relate(parentId, childId, relationType);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Relates two objects that are based on the <see cref="IUmbracoEntity"/> interface.
|
||||
/// </summary>
|
||||
/// <param name="parent">Parent entity</param>
|
||||
/// <param name="child">Child entity</param>
|
||||
/// <param name="relationTypeAlias">Alias of the type of relation to create</param>
|
||||
/// <returns>The created <see cref="Relation"/></returns>
|
||||
/// <inheritdoc />
|
||||
public IRelation Relate(IUmbracoEntity parent, IUmbracoEntity child, string relationTypeAlias)
|
||||
{
|
||||
var relationType = GetRelationTypeByAlias(relationTypeAlias);
|
||||
@@ -442,11 +362,7 @@ namespace Umbraco.Core.Services.Implement
|
||||
return Relate(parent.Id, child.Id, relationType);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether any relations exists for the passed in <see cref="RelationType"/>.
|
||||
/// </summary>
|
||||
/// <param name="relationType"><see cref="RelationType"/> to check for relations</param>
|
||||
/// <returns>Returns <c>True</c> if any relations exists for the given <see cref="RelationType"/>, otherwise <c>False</c></returns>
|
||||
/// <inheritdoc />
|
||||
public bool HasRelations(IRelationType relationType)
|
||||
{
|
||||
using (var scope = ScopeProvider.CreateScope(autoComplete: true))
|
||||
@@ -456,11 +372,7 @@ namespace Umbraco.Core.Services.Implement
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether any relations exists for the passed in Id.
|
||||
/// </summary>
|
||||
/// <param name="id">Id of an object to check relations for</param>
|
||||
/// <returns>Returns <c>True</c> if any relations exists with the given Id, otherwise <c>False</c></returns>
|
||||
/// <inheritdoc />
|
||||
public bool IsRelated(int id)
|
||||
{
|
||||
using (var scope = ScopeProvider.CreateScope(autoComplete: true))
|
||||
@@ -470,12 +382,7 @@ namespace Umbraco.Core.Services.Implement
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether two items are related
|
||||
/// </summary>
|
||||
/// <param name="parentId">Id of the Parent relation</param>
|
||||
/// <param name="childId">Id of the Child relation</param>
|
||||
/// <returns>Returns <c>True</c> if any relations exists with the given Ids, otherwise <c>False</c></returns>
|
||||
/// <inheritdoc />
|
||||
public bool AreRelated(int parentId, int childId)
|
||||
{
|
||||
using (var scope = ScopeProvider.CreateScope(autoComplete: true))
|
||||
@@ -485,13 +392,7 @@ namespace Umbraco.Core.Services.Implement
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether two items are related with a given relation type alias
|
||||
/// </summary>
|
||||
/// <param name="parentId">Id of the Parent relation</param>
|
||||
/// <param name="childId">Id of the Child relation</param>
|
||||
/// <param name="relationTypeAlias">Alias of the relation type</param>
|
||||
/// <returns>Returns <c>True</c> if any relations exists with the given Ids and relation type, otherwise <c>False</c></returns>
|
||||
/// <inheritdoc />
|
||||
public bool AreRelated(int parentId, int childId, string relationTypeAlias)
|
||||
{
|
||||
var relType = GetRelationTypeByAlias(relationTypeAlias);
|
||||
@@ -502,13 +403,7 @@ namespace Umbraco.Core.Services.Implement
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether two items are related with a given relation type
|
||||
/// </summary>
|
||||
/// <param name="parentId">Id of the Parent relation</param>
|
||||
/// <param name="childId">Id of the Child relation</param>
|
||||
/// <param name="relationType">Type of relation</param>
|
||||
/// <returns>Returns <c>True</c> if any relations exists with the given Ids and relation type, otherwise <c>False</c></returns>
|
||||
/// <inheritdoc />
|
||||
public bool AreRelated(int parentId, int childId, IRelationType relationType)
|
||||
{
|
||||
using (var scope = ScopeProvider.CreateScope(autoComplete: true))
|
||||
@@ -518,34 +413,20 @@ namespace Umbraco.Core.Services.Implement
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether two items are related
|
||||
/// </summary>
|
||||
/// <param name="parent">Parent entity</param>
|
||||
/// <param name="child">Child entity</param>
|
||||
/// <returns>Returns <c>True</c> if any relations exist between the entities, otherwise <c>False</c></returns>
|
||||
/// <inheritdoc />
|
||||
public bool AreRelated(IUmbracoEntity parent, IUmbracoEntity child)
|
||||
{
|
||||
return AreRelated(parent.Id, child.Id);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether two items are related
|
||||
/// </summary>
|
||||
/// <param name="parent">Parent entity</param>
|
||||
/// <param name="child">Child entity</param>
|
||||
/// <param name="relationTypeAlias">Alias of the type of relation to create</param>
|
||||
/// <returns>Returns <c>True</c> if any relations exist between the entities, otherwise <c>False</c></returns>
|
||||
/// <inheritdoc />
|
||||
public bool AreRelated(IUmbracoEntity parent, IUmbracoEntity child, string relationTypeAlias)
|
||||
{
|
||||
return AreRelated(parent.Id, child.Id, relationTypeAlias);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Saves a <see cref="Relation"/>
|
||||
/// </summary>
|
||||
/// <param name="relation">Relation to save</param>
|
||||
/// <inheritdoc />
|
||||
public void Save(IRelation relation)
|
||||
{
|
||||
using (var scope = ScopeProvider.CreateScope())
|
||||
@@ -564,10 +445,25 @@ namespace Umbraco.Core.Services.Implement
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Saves a <see cref="RelationType"/>
|
||||
/// </summary>
|
||||
/// <param name="relationType">RelationType to Save</param>
|
||||
public void Save(IEnumerable<IRelation> relations)
|
||||
{
|
||||
using (var scope = ScopeProvider.CreateScope())
|
||||
{
|
||||
var saveEventArgs = new SaveEventArgs<IRelation>(relations);
|
||||
if (scope.Events.DispatchCancelable(SavingRelation, this, saveEventArgs))
|
||||
{
|
||||
scope.Complete();
|
||||
return;
|
||||
}
|
||||
|
||||
_relationRepository.Save(relations);
|
||||
scope.Complete();
|
||||
saveEventArgs.CanCancel = false;
|
||||
scope.Events.Dispatch(SavedRelation, this, saveEventArgs);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Save(IRelationType relationType)
|
||||
{
|
||||
using (var scope = ScopeProvider.CreateScope())
|
||||
@@ -586,10 +482,7 @@ namespace Umbraco.Core.Services.Implement
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes a <see cref="Relation"/>
|
||||
/// </summary>
|
||||
/// <param name="relation">Relation to Delete</param>
|
||||
/// <inheritdoc />
|
||||
public void Delete(IRelation relation)
|
||||
{
|
||||
using (var scope = ScopeProvider.CreateScope())
|
||||
@@ -608,10 +501,7 @@ namespace Umbraco.Core.Services.Implement
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes a <see cref="RelationType"/>
|
||||
/// </summary>
|
||||
/// <param name="relationType">RelationType to Delete</param>
|
||||
/// <inheritdoc />
|
||||
public void Delete(IRelationType relationType)
|
||||
{
|
||||
using (var scope = ScopeProvider.CreateScope())
|
||||
@@ -630,10 +520,7 @@ namespace Umbraco.Core.Services.Implement
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes all <see cref="Relation"/> objects based on the passed in <see cref="RelationType"/>
|
||||
/// </summary>
|
||||
/// <param name="relationType"><see cref="RelationType"/> to Delete Relations for</param>
|
||||
/// <inheritdoc />
|
||||
public void DeleteRelationsOfType(IRelationType relationType)
|
||||
{
|
||||
var relations = new List<IRelation>();
|
||||
@@ -642,6 +529,8 @@ namespace Umbraco.Core.Services.Implement
|
||||
var query = Query<IRelation>().Where(x => x.RelationTypeId == relationType.Id);
|
||||
relations.AddRange(_relationRepository.Get(query).ToList());
|
||||
|
||||
//TODO: N+1, we should be able to do this in a single call
|
||||
|
||||
foreach (var relation in relations)
|
||||
_relationRepository.Delete(relation);
|
||||
|
||||
@@ -653,6 +542,15 @@ namespace Umbraco.Core.Services.Implement
|
||||
|
||||
#region Private Methods
|
||||
|
||||
private IRelationType GetRelationType(string relationTypeAlias)
|
||||
{
|
||||
using (var scope = ScopeProvider.CreateScope(autoComplete: true))
|
||||
{
|
||||
var query = Query<IRelationType>().Where(x => x.Alias == relationTypeAlias);
|
||||
return _relationTypeRepository.Get(query).FirstOrDefault();
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable<IRelation> GetRelationsByListOfTypeIds(IEnumerable<int> relationTypeIds)
|
||||
{
|
||||
var relations = new List<IRelation>();
|
||||
|
||||
@@ -161,8 +161,13 @@
|
||||
<Compile Include="Composing\LightInject\MixedLightInjectScopeManagerProvider.cs" />
|
||||
<Compile Include="IO\IOHelper.cs" />
|
||||
<Compile Include="Logging\Viewer\LogTimePeriod.cs" />
|
||||
<Compile Include="Manifest\DashboardAccessRuleConverter.cs" />
|
||||
<Compile Include="Manifest\DataEditorConverter.cs" />
|
||||
<Compile Include="Manifest\IPackageManifest.cs" />
|
||||
<Compile Include="Manifest\ManifestContentAppFactory.cs" />
|
||||
<Compile Include="Manifest\ManifestParser.cs" />
|
||||
<Compile Include="Manifest\ManifestWatcher.cs" />
|
||||
<Compile Include="Manifest\ValueValidatorConverter.cs" />
|
||||
<Compile Include="Migrations\IMigrationBuilder.cs" />
|
||||
<Compile Include="Migrations\Upgrade\Common\DeleteKeysAndIndexes.cs" />
|
||||
<Compile Include="Migrations\Upgrade\V_8_0_0\DataTypes\ContentPickerPreValueMigrator.cs" />
|
||||
@@ -180,6 +185,9 @@
|
||||
<Compile Include="Migrations\Upgrade\V_8_0_0\DataTypes\RichTextPreValueMigrator.cs" />
|
||||
<Compile Include="Migrations\Upgrade\V_8_0_0\DataTypes\DropDownFlexiblePreValueMigrator.cs" />
|
||||
<Compile Include="Migrations\Upgrade\V_8_0_0\MergeDateAndDateTimePropertyEditor.cs" />
|
||||
<Compile Include="Migrations\Upgrade\V_8_6_0\AddNewRelationTypes.cs" />
|
||||
<Compile Include="Migrations\Upgrade\V_8_6_0\UpdateRelationTypeTable.cs" />
|
||||
<Compile Include="Models\Editors\UmbracoEntityReference.cs" />
|
||||
<Compile Include="Migrations\Upgrade\V_8_0_0\DataTypes\PreValueMigratorBase.cs" />
|
||||
<Compile Include="Migrations\Upgrade\V_8_0_0\DataTypes\PreValueDto.cs" />
|
||||
<Compile Include="Migrations\Upgrade\V_8_0_0\PropertyEditorsMigrationBase.cs" />
|
||||
@@ -225,6 +233,10 @@
|
||||
<Compile Include="PropertyEditors\ValueConverters\SliderValueConverter.cs" />
|
||||
<Compile Include="PropertyEditors\ValueConverters\TagsValueConverter.cs" />
|
||||
<Compile Include="PropertyEditors\ValueConverters\TinyMceValueConverter.cs" />
|
||||
<Compile Include="PropertyEditors\DataValueReferenceFactoryCollection.cs" />
|
||||
<Compile Include="PropertyEditors\DataValueReferenceFactoryCollectionBuilder.cs" />
|
||||
<Compile Include="PropertyEditors\IDataValueReference.cs" />
|
||||
<Compile Include="PropertyEditors\IDataValueReferenceFactory.cs" />
|
||||
<Compile Include="Persistence\Dtos\PropertyTypeCommonDto.cs" />
|
||||
<Compile Include="Persistence\Factories\MacroFactory.cs" />
|
||||
<Compile Include="Persistence\Repositories\Implement\ContentTypeCommonRepository.cs" />
|
||||
@@ -239,7 +251,6 @@
|
||||
<Compile Include="StringExtensions.cs" />
|
||||
<Compile Include="Strings\DefaultUrlSegmentProvider.cs" />
|
||||
<Compile Include="Sync\RefreshInstructionEnvelope.cs" />
|
||||
<Compile Include="TypeExtensions.cs" />
|
||||
<Compile Include="TypeLoaderExtensions.cs" />
|
||||
<Compile Include="Logging\Viewer\CountingFilter.cs" />
|
||||
<Compile Include="Logging\Viewer\ErrorCounterFilter.cs" />
|
||||
@@ -261,8 +272,6 @@
|
||||
<Compile Include="Logging\Serilog\Enrichers\Log4NetLevelMapperEnricher.cs" />
|
||||
<Compile Include="Logging\Viewer\MessageTemplateFilter.cs" />
|
||||
<Compile Include="Logging\Viewer\SavedLogSearch.cs" />
|
||||
<Compile Include="Manifest\DashboardAccessRuleConverter.cs" />
|
||||
<Compile Include="Manifest\ManifestContentAppFactory.cs" />
|
||||
<Compile Include="Migrations\MergeBuilder.cs" />
|
||||
<Compile Include="Migrations\MigrationBase_Extra.cs" />
|
||||
<Compile Include="Migrations\PostMigrations\IPublishedSnapshotRebuilder.cs" />
|
||||
@@ -348,9 +357,6 @@
|
||||
<Compile Include="Logging\OwinLogger.cs" />
|
||||
<Compile Include="Logging\OwinLoggerFactory.cs" />
|
||||
<Compile Include="MainDom.cs" />
|
||||
<Compile Include="Manifest\ValueValidatorConverter.cs" />
|
||||
<Compile Include="Manifest\ManifestWatcher.cs" />
|
||||
<Compile Include="Manifest\DataEditorConverter.cs" />
|
||||
<Compile Include="Migrations\MigrationBuilder.cs" />
|
||||
<Compile Include="Migrations\MigrationPlan.cs" />
|
||||
<Compile Include="Migrations\Upgrade\UmbracoPlan.cs" />
|
||||
@@ -794,6 +800,7 @@
|
||||
<Compile Include="Sync\DatabaseServerMessenger.cs" />
|
||||
<Compile Include="Sync\RefreshInstruction.cs" />
|
||||
<Compile Include="Sync\ServerMessengerBase.cs" />
|
||||
<Compile Include="TypeExtensions.cs" />
|
||||
<Compile Include="UriExtensions.cs" />
|
||||
<Compile Include="Persistence\FaultHandling\RetryDbConnection.cs">
|
||||
<SubType>Component</SubType>
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace Umbraco.Tests.Models
|
||||
[Test]
|
||||
public void Can_Deep_Clone()
|
||||
{
|
||||
var item = new Relation(9, 8, new RelationType(Guid.NewGuid(), Guid.NewGuid(), "test")
|
||||
var item = new Relation(9, 8, new RelationType("test", "test", false, Guid.NewGuid(), Guid.NewGuid())
|
||||
{
|
||||
Id = 66
|
||||
})
|
||||
@@ -51,7 +51,7 @@ namespace Umbraco.Tests.Models
|
||||
[Test]
|
||||
public void Can_Serialize_Without_Error()
|
||||
{
|
||||
var item = new Relation(9, 8, new RelationType(Guid.NewGuid(), Guid.NewGuid(), "test")
|
||||
var item = new Relation(9, 8, new RelationType("test", "test", false, Guid.NewGuid(), Guid.NewGuid())
|
||||
{
|
||||
Id = 66
|
||||
})
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace Umbraco.Tests.Models
|
||||
[Test]
|
||||
public void Can_Deep_Clone()
|
||||
{
|
||||
var item = new RelationType(Guid.NewGuid(), Guid.NewGuid(), "test")
|
||||
var item = new RelationType("test", "test", false, Guid.NewGuid(), Guid.NewGuid())
|
||||
{
|
||||
Id = 66,
|
||||
CreateDate = DateTime.Now,
|
||||
@@ -47,7 +47,7 @@ namespace Umbraco.Tests.Models
|
||||
[Test]
|
||||
public void Can_Serialize_Without_Error()
|
||||
{
|
||||
var item = new RelationType(Guid.NewGuid(), Guid.NewGuid(), "test")
|
||||
var item = new RelationType("test", "test", false, Guid.NewGuid(), Guid.NewGuid())
|
||||
{
|
||||
Id = 66,
|
||||
CreateDate = DateTime.Now,
|
||||
|
||||
@@ -26,22 +26,22 @@ namespace Umbraco.Tests.Packaging
|
||||
public class PackageDataInstallationTests : TestWithSomeContentBase
|
||||
{
|
||||
[HideFromTypeFinder]
|
||||
[DataEditor("7e062c13-7c41-4ad9-b389-41d88aeef87c", "Editor1", "editor1")]
|
||||
public class Editor1 : DataEditor
|
||||
{
|
||||
public Editor1(ILogger logger)
|
||||
: base(logger)
|
||||
{
|
||||
Alias = "7e062c13-7c41-4ad9-b389-41d88aeef87c";
|
||||
}
|
||||
}
|
||||
|
||||
[HideFromTypeFinder]
|
||||
[DataEditor("d15e1281-e456-4b24-aa86-1dda3e4299d5", "Editor2", "editor2")]
|
||||
public class Editor2 : DataEditor
|
||||
{
|
||||
public Editor2(ILogger logger)
|
||||
: base(logger)
|
||||
{
|
||||
Alias = "d15e1281-e456-4b24-aa86-1dda3e4299d5";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Persistence.Dtos;
|
||||
using Umbraco.Core.Persistence.Repositories.Implement;
|
||||
using Umbraco.Core.PropertyEditors;
|
||||
using Umbraco.Core.Scoping;
|
||||
using Umbraco.Tests.TestHelpers;
|
||||
using Umbraco.Tests.TestHelpers.Entities;
|
||||
@@ -35,7 +36,12 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
var commonRepository = new ContentTypeCommonRepository(scopeAccessor, templateRepository, AppCaches.Disabled);
|
||||
contentTypeRepository = new ContentTypeRepository(scopeAccessor, AppCaches.Disabled, Logger, commonRepository, langRepository);
|
||||
var languageRepository = new LanguageRepository(scopeAccessor, AppCaches.Disabled, Logger);
|
||||
var repository = new DocumentRepository(scopeAccessor, AppCaches.Disabled, Logger, contentTypeRepository, templateRepository, tagRepository, languageRepository);
|
||||
var relationTypeRepository = new RelationTypeRepository(scopeAccessor, AppCaches.Disabled, Logger);
|
||||
var entityRepository = new EntityRepository(scopeAccessor);
|
||||
var relationRepository = new RelationRepository(scopeAccessor, Logger, relationTypeRepository, entityRepository);
|
||||
var propertyEditors = new Lazy<PropertyEditorCollection>(() => new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty<IDataEditor>())));
|
||||
var dataValueReferences = new DataValueReferenceFactoryCollection(Enumerable.Empty<IDataValueReferenceFactory>());
|
||||
var repository = new DocumentRepository(scopeAccessor, AppCaches.Disabled, Logger, contentTypeRepository, templateRepository, tagRepository, languageRepository, relationRepository, relationTypeRepository, propertyEditors, dataValueReferences);
|
||||
return repository;
|
||||
}
|
||||
|
||||
|
||||
@@ -69,7 +69,12 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
var commonRepository = new ContentTypeCommonRepository(scopeAccessor, templateRepository, appCaches);
|
||||
var languageRepository = new LanguageRepository(scopeAccessor, appCaches, Logger);
|
||||
contentTypeRepository = new ContentTypeRepository(scopeAccessor, appCaches, Logger, commonRepository, languageRepository);
|
||||
var repository = new DocumentRepository(scopeAccessor, appCaches, Logger, contentTypeRepository, templateRepository, tagRepository, languageRepository);
|
||||
var relationTypeRepository = new RelationTypeRepository(scopeAccessor, AppCaches.Disabled, Logger);
|
||||
var entityRepository = new EntityRepository(scopeAccessor);
|
||||
var relationRepository = new RelationRepository(scopeAccessor, Logger, relationTypeRepository, entityRepository);
|
||||
var propertyEditors = new Lazy<PropertyEditorCollection>(() => new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty<IDataEditor>())));
|
||||
var dataValueReferences = new DataValueReferenceFactoryCollection(Enumerable.Empty<IDataValueReferenceFactory>());
|
||||
var repository = new DocumentRepository(scopeAccessor, appCaches, Logger, contentTypeRepository, templateRepository, tagRepository, languageRepository, relationRepository, relationTypeRepository, propertyEditors, dataValueReferences);
|
||||
return repository;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using Moq;
|
||||
@@ -6,6 +7,7 @@ using NUnit.Framework;
|
||||
using Umbraco.Core.Configuration.UmbracoSettings;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Persistence.Repositories.Implement;
|
||||
using Umbraco.Core.PropertyEditors;
|
||||
using Umbraco.Core.Scoping;
|
||||
using Umbraco.Tests.TestHelpers;
|
||||
using Umbraco.Tests.TestHelpers.Entities;
|
||||
@@ -25,7 +27,12 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
var commonRepository = new ContentTypeCommonRepository(accessor, templateRepository, AppCaches);
|
||||
languageRepository = new LanguageRepository(accessor, Core.Cache.AppCaches.Disabled, Logger);
|
||||
contentTypeRepository = new ContentTypeRepository(accessor, Core.Cache.AppCaches.Disabled, Logger, commonRepository, languageRepository);
|
||||
documentRepository = new DocumentRepository(accessor, Core.Cache.AppCaches.Disabled, Logger, contentTypeRepository, templateRepository, tagRepository, languageRepository);
|
||||
var relationTypeRepository = new RelationTypeRepository(accessor, Core.Cache.AppCaches.Disabled, Logger);
|
||||
var entityRepository = new EntityRepository(accessor);
|
||||
var relationRepository = new RelationRepository(accessor, Logger, relationTypeRepository, entityRepository);
|
||||
var propertyEditors = new Lazy<PropertyEditorCollection>(() => new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty<IDataEditor>())));
|
||||
var dataValueReferences = new DataValueReferenceFactoryCollection(Enumerable.Empty<IDataValueReferenceFactory>());
|
||||
documentRepository = new DocumentRepository(accessor, Core.Cache.AppCaches.Disabled, Logger, contentTypeRepository, templateRepository, tagRepository, languageRepository, relationRepository, relationTypeRepository, propertyEditors, dataValueReferences);
|
||||
var domainRepository = new DomainRepository(accessor, Core.Cache.AppCaches.Disabled, Logger);
|
||||
return domainRepository;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.Entities;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Persistence.Repositories.Implement;
|
||||
using Umbraco.Core.Scoping;
|
||||
using Umbraco.Tests.TestHelpers;
|
||||
using Umbraco.Tests.TestHelpers.Entities;
|
||||
using Umbraco.Tests.Testing;
|
||||
|
||||
namespace Umbraco.Tests.Persistence.Repositories
|
||||
{
|
||||
[TestFixture]
|
||||
[UmbracoTest(Mapper = true, Database = UmbracoTestOptions.Database.NewSchemaPerTest)]
|
||||
public class EntityRepositoryTest : TestWithDatabaseBase
|
||||
{
|
||||
|
||||
private EntityRepository CreateRepository(IScopeAccessor scopeAccessor)
|
||||
{
|
||||
var entityRepository = new EntityRepository(scopeAccessor);
|
||||
return entityRepository;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Get_Paged_Mixed_Entities_By_Ids()
|
||||
{
|
||||
//Create content
|
||||
|
||||
var createdContent = new List<IContent>();
|
||||
var contentType = MockedContentTypes.CreateBasicContentType("blah");
|
||||
ServiceContext.ContentTypeService.Save(contentType);
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
var c1 = MockedContent.CreateBasicContent(contentType);
|
||||
ServiceContext.ContentService.Save(c1);
|
||||
createdContent.Add(c1);
|
||||
}
|
||||
|
||||
//Create media
|
||||
|
||||
var createdMedia = new List<IMedia>();
|
||||
var imageType = MockedContentTypes.CreateImageMediaType("myImage");
|
||||
ServiceContext.MediaTypeService.Save(imageType);
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
var c1 = MockedMedia.CreateMediaImage(imageType, -1);
|
||||
ServiceContext.MediaService.Save(c1);
|
||||
createdMedia.Add(c1);
|
||||
}
|
||||
|
||||
// Create members
|
||||
var memberType = MockedContentTypes.CreateSimpleMemberType("simple");
|
||||
ServiceContext.MemberTypeService.Save(memberType);
|
||||
var createdMembers = MockedMember.CreateSimpleMember(memberType, 10).ToList();
|
||||
ServiceContext.MemberService.Save(createdMembers);
|
||||
|
||||
var provider = TestObjects.GetScopeProvider(Logger);
|
||||
using (var scope = provider.CreateScope())
|
||||
{
|
||||
var repo = CreateRepository((IScopeAccessor)provider);
|
||||
|
||||
var ids = createdContent.Select(x => x.Id).Concat(createdMedia.Select(x => x.Id)).Concat(createdMembers.Select(x => x.Id));
|
||||
|
||||
var objectTypes = new[] { Constants.ObjectTypes.Document, Constants.ObjectTypes.Media, Constants.ObjectTypes.Member };
|
||||
|
||||
var query = SqlContext.Query<IUmbracoEntity>()
|
||||
.WhereIn(e => e.Id, ids);
|
||||
|
||||
var entities = repo.GetPagedResultsByQuery(query, objectTypes, 0, 20, out var totalRecords, null, null).ToList();
|
||||
|
||||
Assert.AreEqual(20, entities.Count);
|
||||
Assert.AreEqual(30, totalRecords);
|
||||
|
||||
//add the next page
|
||||
entities.AddRange(repo.GetPagedResultsByQuery(query, objectTypes, 1, 20, out totalRecords, null, null));
|
||||
|
||||
Assert.AreEqual(30, entities.Count);
|
||||
Assert.AreEqual(30, totalRecords);
|
||||
|
||||
var contentEntities = entities.OfType<IDocumentEntitySlim>().ToList();
|
||||
var mediaEntities = entities.OfType<IMediaEntitySlim>().ToList();
|
||||
var memberEntities = entities.OfType<IMemberEntitySlim>().ToList();
|
||||
|
||||
Assert.AreEqual(10, contentEntities.Count);
|
||||
Assert.AreEqual(10, mediaEntities.Count);
|
||||
Assert.AreEqual(10, memberEntities.Count);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,7 @@ using Umbraco.Core.Scoping;
|
||||
using Umbraco.Tests.Testing;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.PropertyEditors;
|
||||
|
||||
namespace Umbraco.Tests.Persistence.Repositories
|
||||
{
|
||||
@@ -39,7 +40,12 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
var languageRepository = new LanguageRepository(scopeAccessor, appCaches, Logger);
|
||||
mediaTypeRepository = new MediaTypeRepository(scopeAccessor, appCaches, Logger, commonRepository, languageRepository);
|
||||
var tagRepository = new TagRepository(scopeAccessor, appCaches, Logger);
|
||||
var repository = new MediaRepository(scopeAccessor, appCaches, Logger, mediaTypeRepository, tagRepository, Mock.Of<ILanguageRepository>());
|
||||
var relationTypeRepository = new RelationTypeRepository(scopeAccessor, AppCaches.Disabled, Logger);
|
||||
var entityRepository = new EntityRepository(scopeAccessor);
|
||||
var relationRepository = new RelationRepository(scopeAccessor, Logger, relationTypeRepository, entityRepository);
|
||||
var propertyEditors = new Lazy<PropertyEditorCollection>(() => new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty<IDataEditor>())));
|
||||
var dataValueReferences = new DataValueReferenceFactoryCollection(Enumerable.Empty<IDataValueReferenceFactory>());
|
||||
var repository = new MediaRepository(scopeAccessor, appCaches, Logger, mediaTypeRepository, tagRepository, Mock.Of<ILanguageRepository>(), relationRepository, relationTypeRepository, propertyEditors, dataValueReferences);
|
||||
return repository;
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ using Umbraco.Core.Persistence.Dtos;
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
using Umbraco.Core.Persistence.Repositories;
|
||||
using Umbraco.Core.Persistence.Repositories.Implement;
|
||||
using Umbraco.Core.PropertyEditors;
|
||||
using Umbraco.Core.Scoping;
|
||||
using Umbraco.Tests.TestHelpers;
|
||||
using Umbraco.Tests.TestHelpers.Entities;
|
||||
@@ -35,7 +36,12 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
memberTypeRepository = new MemberTypeRepository(accessor, AppCaches.Disabled, Logger, commonRepository, languageRepository);
|
||||
memberGroupRepository = new MemberGroupRepository(accessor, AppCaches.Disabled, Logger);
|
||||
var tagRepo = new TagRepository(accessor, AppCaches.Disabled, Logger);
|
||||
var repository = new MemberRepository(accessor, AppCaches.Disabled, Logger, memberTypeRepository, memberGroupRepository, tagRepo, Mock.Of<ILanguageRepository>());
|
||||
var relationTypeRepository = new RelationTypeRepository(accessor, AppCaches.Disabled, Logger);
|
||||
var entityRepository = new EntityRepository(accessor);
|
||||
var relationRepository = new RelationRepository(accessor, Logger, relationTypeRepository, entityRepository);
|
||||
var propertyEditors = new Lazy<PropertyEditorCollection>(() => new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty<IDataEditor>())));
|
||||
var dataValueReferences = new DataValueReferenceFactoryCollection(Enumerable.Empty<IDataValueReferenceFactory>());
|
||||
var repository = new MemberRepository(accessor, AppCaches.Disabled, Logger, memberTypeRepository, memberGroupRepository, tagRepo, Mock.Of<ILanguageRepository>(), relationRepository, relationTypeRepository, propertyEditors, dataValueReferences);
|
||||
return repository;
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ using Umbraco.Core.Configuration.UmbracoSettings;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Persistence.Repositories.Implement;
|
||||
using Umbraco.Core.PropertyEditors;
|
||||
using Umbraco.Core.Scoping;
|
||||
using Umbraco.Tests.TestHelpers;
|
||||
using Umbraco.Tests.TestHelpers.Entities;
|
||||
@@ -310,7 +311,12 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
var commonRepository = new ContentTypeCommonRepository(accessor, templateRepository, AppCaches);
|
||||
var languageRepository = new LanguageRepository(accessor, AppCaches, Logger);
|
||||
contentTypeRepository = new ContentTypeRepository(accessor, AppCaches, Logger, commonRepository, languageRepository);
|
||||
var repository = new DocumentRepository(accessor, AppCaches, Logger, contentTypeRepository, templateRepository, tagRepository, languageRepository);
|
||||
var relationTypeRepository = new RelationTypeRepository(accessor, AppCaches, Logger);
|
||||
var entityRepository = new EntityRepository(accessor);
|
||||
var relationRepository = new RelationRepository(accessor, Logger, relationTypeRepository, entityRepository);
|
||||
var propertyEditors = new Lazy<PropertyEditorCollection>(() => new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty<IDataEditor>())));
|
||||
var dataValueReferences = new DataValueReferenceFactoryCollection(Enumerable.Empty<IDataValueReferenceFactory>());
|
||||
var repository = new DocumentRepository(accessor, AppCaches, Logger, contentTypeRepository, templateRepository, tagRepository, languageRepository, relationRepository, relationTypeRepository, propertyEditors, dataValueReferences);
|
||||
return repository;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
@@ -6,6 +7,7 @@ using Umbraco.Core;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.Entities;
|
||||
using Umbraco.Core.Persistence.Dtos;
|
||||
using Umbraco.Core.Persistence.Repositories;
|
||||
using Umbraco.Core.Persistence.Repositories.Implement;
|
||||
@@ -31,7 +33,8 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
{
|
||||
var accessor = (IScopeAccessor) provider;
|
||||
relationTypeRepository = new RelationTypeRepository(accessor, AppCaches.Disabled, Mock.Of<ILogger>());
|
||||
var repository = new RelationRepository(accessor, Mock.Of<ILogger>(), relationTypeRepository);
|
||||
var entityRepository = new EntityRepository(accessor);
|
||||
var repository = new RelationRepository(accessor, Mock.Of<ILogger>(), relationTypeRepository, entityRepository);
|
||||
return repository;
|
||||
}
|
||||
|
||||
@@ -168,6 +171,156 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Get_Paged_Parent_Entities_By_Child_Id()
|
||||
{
|
||||
CreateTestDataForPagingTests(out var createdContent, out var createdMembers, out var createdMedia);
|
||||
|
||||
var provider = TestObjects.GetScopeProvider(Logger);
|
||||
using (var scope = provider.CreateScope())
|
||||
{
|
||||
var repository = CreateRepository(provider, out var relationTypeRepository);
|
||||
|
||||
// Get parent entities for child id
|
||||
var parents = repository.GetPagedParentEntitiesByChildId(createdMedia[0].Id, 0, 11, out var totalRecords).ToList();
|
||||
Assert.AreEqual(20, totalRecords);
|
||||
Assert.AreEqual(11, parents.Count);
|
||||
|
||||
//add the next page
|
||||
parents.AddRange(repository.GetPagedParentEntitiesByChildId(createdMedia[0].Id, 1, 11, out totalRecords));
|
||||
Assert.AreEqual(20, totalRecords);
|
||||
Assert.AreEqual(20, parents.Count);
|
||||
|
||||
var contentEntities = parents.OfType<IDocumentEntitySlim>().ToList();
|
||||
var mediaEntities = parents.OfType<IMediaEntitySlim>().ToList();
|
||||
var memberEntities = parents.OfType<IMemberEntitySlim>().ToList();
|
||||
|
||||
Assert.AreEqual(10, contentEntities.Count);
|
||||
Assert.AreEqual(0, mediaEntities.Count);
|
||||
Assert.AreEqual(10, memberEntities.Count);
|
||||
|
||||
//only of a certain type
|
||||
parents.AddRange(repository.GetPagedParentEntitiesByChildId(createdMedia[0].Id, 0, 100, out totalRecords, UmbracoObjectTypes.Document.GetGuid()));
|
||||
Assert.AreEqual(10, totalRecords);
|
||||
|
||||
parents.AddRange(repository.GetPagedParentEntitiesByChildId(createdMedia[0].Id, 0, 100, out totalRecords, UmbracoObjectTypes.Member.GetGuid()));
|
||||
Assert.AreEqual(10, totalRecords);
|
||||
|
||||
parents.AddRange(repository.GetPagedParentEntitiesByChildId(createdMedia[0].Id, 0, 100, out totalRecords, UmbracoObjectTypes.Media.GetGuid()));
|
||||
Assert.AreEqual(0, totalRecords);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Get_Paged_Parent_Child_Entities_With_Same_Entity_Relation()
|
||||
{
|
||||
//Create a media item and create a relationship between itself (parent -> child)
|
||||
var imageType = MockedContentTypes.CreateImageMediaType("myImage");
|
||||
ServiceContext.MediaTypeService.Save(imageType);
|
||||
var media = MockedMedia.CreateMediaImage(imageType, -1);
|
||||
ServiceContext.MediaService.Save(media);
|
||||
var relType = ServiceContext.RelationService.GetRelationTypeByAlias(Constants.Conventions.RelationTypes.RelatedMediaAlias);
|
||||
ServiceContext.RelationService.Relate(media.Id, media.Id, relType);
|
||||
|
||||
var provider = TestObjects.GetScopeProvider(Logger);
|
||||
using (var scope = provider.CreateScope())
|
||||
{
|
||||
var repository = CreateRepository(provider, out var relationTypeRepository);
|
||||
|
||||
// Get parent entities for child id
|
||||
var parents = repository.GetPagedParentEntitiesByChildId(media.Id, 0, 10, out var totalRecords).ToList();
|
||||
Assert.AreEqual(1, totalRecords);
|
||||
Assert.AreEqual(1, parents.Count);
|
||||
|
||||
// Get child entities for parent id
|
||||
var children = repository.GetPagedChildEntitiesByParentId(media.Id, 0, 10, out totalRecords).ToList();
|
||||
Assert.AreEqual(1, totalRecords);
|
||||
Assert.AreEqual(1, children.Count);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Get_Paged_Child_Entities_By_Parent_Id()
|
||||
{
|
||||
CreateTestDataForPagingTests(out var createdContent, out var createdMembers, out var createdMedia);
|
||||
|
||||
var provider = TestObjects.GetScopeProvider(Logger);
|
||||
using (var scope = provider.CreateScope())
|
||||
{
|
||||
var repository = CreateRepository(provider, out var relationTypeRepository);
|
||||
|
||||
// Get parent entities for child id
|
||||
var parents = repository.GetPagedChildEntitiesByParentId(createdContent[0].Id, 0, 6, out var totalRecords).ToList();
|
||||
Assert.AreEqual(10, totalRecords);
|
||||
Assert.AreEqual(6, parents.Count);
|
||||
|
||||
//add the next page
|
||||
parents.AddRange(repository.GetPagedChildEntitiesByParentId(createdContent[0].Id, 1, 6, out totalRecords));
|
||||
Assert.AreEqual(10, totalRecords);
|
||||
Assert.AreEqual(10, parents.Count);
|
||||
|
||||
var contentEntities = parents.OfType<IDocumentEntitySlim>().ToList();
|
||||
var mediaEntities = parents.OfType<IMediaEntitySlim>().ToList();
|
||||
var memberEntities = parents.OfType<IMemberEntitySlim>().ToList();
|
||||
|
||||
Assert.AreEqual(0, contentEntities.Count);
|
||||
Assert.AreEqual(10, mediaEntities.Count);
|
||||
Assert.AreEqual(0, memberEntities.Count);
|
||||
|
||||
//only of a certain type
|
||||
parents.AddRange(repository.GetPagedChildEntitiesByParentId(createdContent[0].Id, 0, 100, out totalRecords, UmbracoObjectTypes.Media.GetGuid()));
|
||||
Assert.AreEqual(10, totalRecords);
|
||||
|
||||
parents.AddRange(repository.GetPagedChildEntitiesByParentId(createdMembers[0].Id, 0, 100, out totalRecords, UmbracoObjectTypes.Media.GetGuid()));
|
||||
Assert.AreEqual(10, totalRecords);
|
||||
|
||||
parents.AddRange(repository.GetPagedChildEntitiesByParentId(createdContent[0].Id, 0, 100, out totalRecords, UmbracoObjectTypes.Member.GetGuid()));
|
||||
Assert.AreEqual(0, totalRecords);
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateTestDataForPagingTests(out List<IContent> createdContent, out List<IMember> createdMembers, out List<IMedia> createdMedia)
|
||||
{
|
||||
//Create content
|
||||
createdContent = new List<IContent>();
|
||||
var contentType = MockedContentTypes.CreateBasicContentType("blah");
|
||||
ServiceContext.ContentTypeService.Save(contentType);
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
var c1 = MockedContent.CreateBasicContent(contentType);
|
||||
ServiceContext.ContentService.Save(c1);
|
||||
createdContent.Add(c1);
|
||||
}
|
||||
|
||||
//Create media
|
||||
createdMedia = new List<IMedia>();
|
||||
var imageType = MockedContentTypes.CreateImageMediaType("myImage");
|
||||
ServiceContext.MediaTypeService.Save(imageType);
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
var c1 = MockedMedia.CreateMediaImage(imageType, -1);
|
||||
ServiceContext.MediaService.Save(c1);
|
||||
createdMedia.Add(c1);
|
||||
}
|
||||
|
||||
// Create members
|
||||
var memberType = MockedContentTypes.CreateSimpleMemberType("simple");
|
||||
ServiceContext.MemberTypeService.Save(memberType);
|
||||
createdMembers = MockedMember.CreateSimpleMember(memberType, 10).ToList();
|
||||
ServiceContext.MemberService.Save(createdMembers);
|
||||
|
||||
var relType = ServiceContext.RelationService.GetRelationTypeByAlias(Constants.Conventions.RelationTypes.RelatedMediaAlias);
|
||||
|
||||
// Relate content to media
|
||||
foreach (var content in createdContent)
|
||||
foreach (var media in createdMedia)
|
||||
ServiceContext.RelationService.Relate(content.Id, media.Id, relType);
|
||||
// Relate members to media
|
||||
foreach (var member in createdMembers)
|
||||
foreach (var media in createdMedia)
|
||||
ServiceContext.RelationService.Relate(member.Id, media.Id, relType);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Can_Perform_Exists_On_RelationRepository()
|
||||
{
|
||||
@@ -260,14 +413,24 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
|
||||
public void CreateTestData()
|
||||
{
|
||||
var relateContent = new RelationType(Constants.ObjectTypes.Document, new Guid("C66BA18E-EAF3-4CFF-8A22-41B16D66A972"), "relateContentOnCopy") { IsBidirectional = true, Name = "Relate Content on Copy" };
|
||||
var relateContentType = new RelationType(Constants.ObjectTypes.DocumentType, new Guid("A2CB7800-F571-4787-9638-BC48539A0EFB"), "relateContentTypeOnCopy") { IsBidirectional = true, Name = "Relate ContentType on Copy" };
|
||||
var relateContent = new RelationType(
|
||||
"Relate Content on Copy", "relateContentOnCopy", true,
|
||||
Constants.ObjectTypes.Document,
|
||||
new Guid("C66BA18E-EAF3-4CFF-8A22-41B16D66A972"));
|
||||
|
||||
var relateContentType = new RelationType("Relate ContentType on Copy",
|
||||
"relateContentTypeOnCopy",
|
||||
true,
|
||||
Constants.ObjectTypes.DocumentType,
|
||||
new Guid("A2CB7800-F571-4787-9638-BC48539A0EFB"));
|
||||
|
||||
var provider = TestObjects.GetScopeProvider(Logger);
|
||||
using (var scope = provider.CreateScope())
|
||||
{
|
||||
var relationTypeRepository = new RelationTypeRepository((IScopeAccessor) provider, AppCaches.Disabled, Mock.Of<ILogger>());
|
||||
var relationRepository = new RelationRepository((IScopeAccessor) provider, Mock.Of<ILogger>(), relationTypeRepository);
|
||||
var accessor = (IScopeAccessor)provider;
|
||||
var relationTypeRepository = new RelationTypeRepository(accessor, AppCaches.Disabled, Mock.Of<ILogger>());
|
||||
var entityRepository = new EntityRepository(accessor);
|
||||
var relationRepository = new RelationRepository(accessor, Mock.Of<ILogger>(), relationTypeRepository, entityRepository);
|
||||
|
||||
relationTypeRepository.Save(relateContent);
|
||||
relationTypeRepository.Save(relateContentType);
|
||||
|
||||
@@ -42,9 +42,7 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
var repository = CreateRepository(provider);
|
||||
|
||||
// Act
|
||||
var relateMemberToContent = new RelationType(Constants.ObjectTypes.Member,
|
||||
Constants.ObjectTypes.Document,
|
||||
"relateMemberToContent") { IsBidirectional = true, Name = "Relate Member to Content" };
|
||||
var relateMemberToContent = new RelationType("Relate Member to Content", "relateMemberToContent", true, Constants.ObjectTypes.Member, Constants.ObjectTypes.Document);
|
||||
|
||||
repository.Save(relateMemberToContent);
|
||||
|
||||
@@ -135,7 +133,7 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
Assert.That(relationTypes, Is.Not.Null);
|
||||
Assert.That(relationTypes.Any(), Is.True);
|
||||
Assert.That(relationTypes.Any(x => x == null), Is.False);
|
||||
Assert.That(relationTypes.Count(), Is.EqualTo(5));
|
||||
Assert.That(relationTypes.Count(), Is.EqualTo(7));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -226,8 +224,8 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
|
||||
public void CreateTestData()
|
||||
{
|
||||
var relateContent = new RelationType(Constants.ObjectTypes.Document, new Guid("C66BA18E-EAF3-4CFF-8A22-41B16D66A972"), "relateContentOnCopy") { IsBidirectional = true, Name = "Relate Content on Copy" };
|
||||
var relateContentType = new RelationType(Constants.ObjectTypes.DocumentType, new Guid("A2CB7800-F571-4787-9638-BC48539A0EFB"), "relateContentTypeOnCopy") { IsBidirectional = true, Name = "Relate ContentType on Copy" };
|
||||
var relateContent = new RelationType("Relate Content on Copy", "relateContentOnCopy", true, Constants.ObjectTypes.Document, new Guid("C66BA18E-EAF3-4CFF-8A22-41B16D66A972"));
|
||||
var relateContentType = new RelationType("Relate ContentType on Copy", "relateContentTypeOnCopy", true, Constants.ObjectTypes.DocumentType, new Guid("A2CB7800-F571-4787-9638-BC48539A0EFB"));
|
||||
|
||||
var provider = TestObjects.GetScopeProvider(Logger);
|
||||
using (var scope = ScopeProvider.CreateScope())
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Linq;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core.Cache;
|
||||
@@ -7,6 +8,7 @@ using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Persistence.Repositories;
|
||||
using Umbraco.Core.Persistence.Repositories.Implement;
|
||||
using Umbraco.Core.PropertyEditors;
|
||||
using Umbraco.Core.Scoping;
|
||||
using Umbraco.Tests.TestHelpers;
|
||||
using Umbraco.Tests.TestHelpers.Entities;
|
||||
@@ -74,7 +76,7 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
var provider = TestObjects.GetScopeProvider(Logger);
|
||||
using (ScopeProvider.CreateScope())
|
||||
{
|
||||
var contentRepository = CreateContentRepository(provider, out var contentTypeRepository);
|
||||
var contentRepository = CreateDocumentRepository(provider, out var contentTypeRepository);
|
||||
|
||||
// create data to relate to
|
||||
var contentType = MockedContentTypes.CreateSimpleContentType("test", "Test");
|
||||
@@ -104,7 +106,7 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
var provider = TestObjects.GetScopeProvider(Logger);
|
||||
using (ScopeProvider.CreateScope())
|
||||
{
|
||||
var contentRepository = CreateContentRepository(provider, out var contentTypeRepository);
|
||||
var contentRepository = CreateDocumentRepository(provider, out var contentTypeRepository);
|
||||
|
||||
//create data to relate to
|
||||
var contentType = MockedContentTypes.CreateSimpleContentType("test", "Test");
|
||||
@@ -143,7 +145,7 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
var provider = TestObjects.GetScopeProvider(Logger);
|
||||
using (ScopeProvider.CreateScope())
|
||||
{
|
||||
var contentRepository = CreateContentRepository(provider, out var contentTypeRepository);
|
||||
var contentRepository = CreateDocumentRepository(provider, out var contentTypeRepository);
|
||||
|
||||
//create data to relate to
|
||||
var contentType = MockedContentTypes.CreateSimpleContentType("test", "Test");
|
||||
@@ -185,7 +187,7 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
var provider = TestObjects.GetScopeProvider(Logger);
|
||||
using (ScopeProvider.CreateScope())
|
||||
{
|
||||
var contentRepository = CreateContentRepository(provider, out var contentTypeRepository);
|
||||
var contentRepository = CreateDocumentRepository(provider, out var contentTypeRepository);
|
||||
|
||||
//create data to relate to
|
||||
var contentType = MockedContentTypes.CreateSimpleContentType("test", "Test");
|
||||
@@ -225,7 +227,7 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
var provider = TestObjects.GetScopeProvider(Logger);
|
||||
using (ScopeProvider.CreateScope())
|
||||
{
|
||||
var contentRepository = CreateContentRepository(provider, out var contentTypeRepository);
|
||||
var contentRepository = CreateDocumentRepository(provider, out var contentTypeRepository);
|
||||
|
||||
//create data to relate to
|
||||
var contentType = MockedContentTypes.CreateSimpleContentType("test", "Test");
|
||||
@@ -261,7 +263,7 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
var provider = TestObjects.GetScopeProvider(Logger);
|
||||
using (ScopeProvider.CreateScope())
|
||||
{
|
||||
var contentRepository = CreateContentRepository(provider, out var contentTypeRepository);
|
||||
var contentRepository = CreateDocumentRepository(provider, out var contentTypeRepository);
|
||||
|
||||
//create data to relate to
|
||||
var contentType = MockedContentTypes.CreateSimpleContentType("test", "Test");
|
||||
@@ -305,7 +307,7 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
var provider = TestObjects.GetScopeProvider(Logger);
|
||||
using (ScopeProvider.CreateScope())
|
||||
{
|
||||
var contentRepository = CreateContentRepository(provider, out var contentTypeRepository);
|
||||
var contentRepository = CreateDocumentRepository(provider, out var contentTypeRepository);
|
||||
|
||||
//create data to relate to
|
||||
var contentType = MockedContentTypes.CreateSimpleContentType("test", "Test");
|
||||
@@ -349,7 +351,7 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
var provider = TestObjects.GetScopeProvider(Logger);
|
||||
using (ScopeProvider.CreateScope())
|
||||
{
|
||||
var contentRepository = CreateContentRepository(provider, out var contentTypeRepository);
|
||||
var contentRepository = CreateDocumentRepository(provider, out var contentTypeRepository);
|
||||
|
||||
//create data to relate to
|
||||
var contentType = MockedContentTypes.CreateSimpleContentType("test", "Test");
|
||||
@@ -394,7 +396,7 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
var provider = TestObjects.GetScopeProvider(Logger);
|
||||
using (ScopeProvider.CreateScope())
|
||||
{
|
||||
var contentRepository = CreateContentRepository(provider, out var contentTypeRepository);
|
||||
var contentRepository = CreateDocumentRepository(provider, out var contentTypeRepository);
|
||||
|
||||
//create data to relate to
|
||||
var contentType = MockedContentTypes.CreateSimpleContentType("test", "Test");
|
||||
@@ -429,7 +431,7 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
var provider = TestObjects.GetScopeProvider(Logger);
|
||||
using (ScopeProvider.CreateScope())
|
||||
{
|
||||
var contentRepository = CreateContentRepository(provider, out var contentTypeRepository);
|
||||
var contentRepository = CreateDocumentRepository(provider, out var contentTypeRepository);
|
||||
|
||||
//create data to relate to
|
||||
var contentType = MockedContentTypes.CreateSimpleContentType("test", "Test");
|
||||
@@ -469,7 +471,7 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
var provider = TestObjects.GetScopeProvider(Logger);
|
||||
using (ScopeProvider.CreateScope())
|
||||
{
|
||||
var contentRepository = CreateContentRepository(provider, out var contentTypeRepository);
|
||||
var contentRepository = CreateDocumentRepository(provider, out var contentTypeRepository);
|
||||
|
||||
//create data to relate to
|
||||
var contentType = MockedContentTypes.CreateSimpleContentType("test", "Test");
|
||||
@@ -513,7 +515,7 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
var provider = TestObjects.GetScopeProvider(Logger);
|
||||
using (ScopeProvider.CreateScope())
|
||||
{
|
||||
var contentRepository = CreateContentRepository(provider, out var contentTypeRepository);
|
||||
var contentRepository = CreateDocumentRepository(provider, out var contentTypeRepository);
|
||||
|
||||
//create data to relate to
|
||||
var contentType = MockedContentTypes.CreateSimpleContentType("test", "Test");
|
||||
@@ -557,7 +559,7 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
var provider = TestObjects.GetScopeProvider(Logger);
|
||||
using (ScopeProvider.CreateScope())
|
||||
{
|
||||
var contentRepository = CreateContentRepository(provider, out var contentTypeRepository);
|
||||
var contentRepository = CreateDocumentRepository(provider, out var contentTypeRepository);
|
||||
|
||||
//create data to relate to
|
||||
var contentType = MockedContentTypes.CreateSimpleContentType("test", "Test");
|
||||
@@ -601,7 +603,7 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
var provider = TestObjects.GetScopeProvider(Logger);
|
||||
using (ScopeProvider.CreateScope())
|
||||
{
|
||||
var contentRepository = CreateContentRepository(provider, out var contentTypeRepository);
|
||||
var contentRepository = CreateDocumentRepository(provider, out var contentTypeRepository);
|
||||
|
||||
//create data to relate to
|
||||
var contentType = MockedContentTypes.CreateSimpleContentType("test", "Test");
|
||||
@@ -646,7 +648,7 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
var provider = TestObjects.GetScopeProvider(Logger);
|
||||
using (ScopeProvider.CreateScope())
|
||||
{
|
||||
var contentRepository = CreateContentRepository(provider, out var contentTypeRepository);
|
||||
var contentRepository = CreateDocumentRepository(provider, out var contentTypeRepository);
|
||||
var mediaRepository = CreateMediaRepository(provider, out var mediaTypeRepository);
|
||||
|
||||
//create data to relate to
|
||||
@@ -703,7 +705,7 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
var provider = TestObjects.GetScopeProvider(Logger);
|
||||
using (ScopeProvider.CreateScope())
|
||||
{
|
||||
var contentRepository = CreateContentRepository(provider, out var contentTypeRepository);
|
||||
var contentRepository = CreateDocumentRepository(provider, out var contentTypeRepository);
|
||||
var mediaRepository = CreateMediaRepository(provider, out var mediaTypeRepository);
|
||||
|
||||
//create data to relate to
|
||||
@@ -755,7 +757,7 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
var provider = TestObjects.GetScopeProvider(Logger);
|
||||
using (var scope = ScopeProvider.CreateScope())
|
||||
{
|
||||
var contentRepository = CreateContentRepository(provider, out var contentTypeRepository);
|
||||
var contentRepository = CreateDocumentRepository(provider, out var contentTypeRepository);
|
||||
|
||||
//create data to relate to
|
||||
var contentType = MockedContentTypes.CreateSimpleContentType("test", "Test");
|
||||
@@ -791,7 +793,7 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
var provider = TestObjects.GetScopeProvider(Logger);
|
||||
using (ScopeProvider.CreateScope())
|
||||
{
|
||||
var contentRepository = CreateContentRepository(provider, out var contentTypeRepository);
|
||||
var contentRepository = CreateDocumentRepository(provider, out var contentTypeRepository);
|
||||
var mediaRepository = CreateMediaRepository(provider, out var mediaTypeRepository);
|
||||
|
||||
//create data to relate to
|
||||
@@ -871,7 +873,7 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
var provider = TestObjects.GetScopeProvider(Logger);
|
||||
using (ScopeProvider.CreateScope())
|
||||
{
|
||||
var contentRepository = CreateContentRepository(provider, out var contentTypeRepository);
|
||||
var contentRepository = CreateDocumentRepository(provider, out var contentTypeRepository);
|
||||
var mediaRepository = CreateMediaRepository(provider, out var mediaTypeRepository);
|
||||
|
||||
//create data to relate to
|
||||
@@ -950,7 +952,7 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
return new TagRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger);
|
||||
}
|
||||
|
||||
private DocumentRepository CreateContentRepository(IScopeProvider provider, out ContentTypeRepository contentTypeRepository)
|
||||
private DocumentRepository CreateDocumentRepository(IScopeProvider provider, out ContentTypeRepository contentTypeRepository)
|
||||
{
|
||||
var accessor = (IScopeAccessor) provider;
|
||||
var templateRepository = new TemplateRepository(accessor, AppCaches.Disabled, Logger, TestObjects.GetFileSystemsMock(), IOHelper);
|
||||
@@ -958,7 +960,12 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
var commonRepository = new ContentTypeCommonRepository(accessor, templateRepository, AppCaches.Disabled);
|
||||
var languageRepository = new LanguageRepository(accessor, AppCaches.Disabled, Logger);
|
||||
contentTypeRepository = new ContentTypeRepository(accessor, AppCaches.Disabled, Logger, commonRepository, languageRepository);
|
||||
var repository = new DocumentRepository(accessor, AppCaches.Disabled, Logger, contentTypeRepository, templateRepository, tagRepository, languageRepository);
|
||||
var relationTypeRepository = new RelationTypeRepository(accessor, AppCaches.Disabled, Logger);
|
||||
var entityRepository = new EntityRepository(accessor);
|
||||
var relationRepository = new RelationRepository(accessor, Logger, relationTypeRepository, entityRepository);
|
||||
var propertyEditors = new Lazy<PropertyEditorCollection>(() => new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty<IDataEditor>())));
|
||||
var dataValueReferences = new DataValueReferenceFactoryCollection(Enumerable.Empty<IDataValueReferenceFactory>());
|
||||
var repository = new DocumentRepository(accessor, AppCaches.Disabled, Logger, contentTypeRepository, templateRepository, tagRepository, languageRepository, relationRepository, relationTypeRepository, propertyEditors, dataValueReferences);
|
||||
return repository;
|
||||
}
|
||||
|
||||
@@ -970,7 +977,12 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
var commonRepository = new ContentTypeCommonRepository(accessor, templateRepository, AppCaches.Disabled);
|
||||
var languageRepository = new LanguageRepository(accessor, AppCaches.Disabled, Logger);
|
||||
mediaTypeRepository = new MediaTypeRepository(accessor, AppCaches.Disabled, Logger, commonRepository, languageRepository);
|
||||
var repository = new MediaRepository(accessor, AppCaches.Disabled, Logger, mediaTypeRepository, tagRepository, Mock.Of<ILanguageRepository>());
|
||||
var relationTypeRepository = new RelationTypeRepository(accessor, AppCaches.Disabled, Logger);
|
||||
var entityRepository = new EntityRepository(accessor);
|
||||
var relationRepository = new RelationRepository(accessor, Logger, relationTypeRepository, entityRepository);
|
||||
var propertyEditors = new Lazy<PropertyEditorCollection>(() => new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty<IDataEditor>())));
|
||||
var dataValueReferences = new DataValueReferenceFactoryCollection(Enumerable.Empty<IDataValueReferenceFactory>());
|
||||
var repository = new MediaRepository(accessor, AppCaches.Disabled, Logger, mediaTypeRepository, tagRepository, Mock.Of<ILanguageRepository>(), relationRepository, relationTypeRepository, propertyEditors, dataValueReferences);
|
||||
return repository;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Persistence.Repositories;
|
||||
using Umbraco.Core.Persistence.Repositories.Implement;
|
||||
using Umbraco.Core.PropertyEditors;
|
||||
using Umbraco.Core.Scoping;
|
||||
using Umbraco.Tests.TestHelpers;
|
||||
using Umbraco.Tests.TestHelpers.Entities;
|
||||
@@ -238,11 +239,16 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
{
|
||||
var templateRepository = CreateRepository(ScopeProvider);
|
||||
|
||||
var tagRepository = new TagRepository((IScopeAccessor) ScopeProvider, AppCaches.Disabled, Logger);
|
||||
var tagRepository = new TagRepository(ScopeProvider, AppCaches.Disabled, Logger);
|
||||
var commonRepository = new ContentTypeCommonRepository(ScopeProvider, templateRepository, AppCaches);
|
||||
var languageRepository = new LanguageRepository((IScopeAccessor) ScopeProvider, AppCaches.Disabled, Logger);
|
||||
var contentTypeRepository = new ContentTypeRepository((IScopeAccessor) ScopeProvider, AppCaches.Disabled, Logger, commonRepository, languageRepository);
|
||||
var contentRepo = new DocumentRepository((IScopeAccessor) ScopeProvider, AppCaches.Disabled, Logger, contentTypeRepository, templateRepository, tagRepository, languageRepository);
|
||||
var languageRepository = new LanguageRepository(ScopeProvider, AppCaches.Disabled, Logger);
|
||||
var contentTypeRepository = new ContentTypeRepository(ScopeProvider, AppCaches.Disabled, Logger, commonRepository, languageRepository);
|
||||
var relationTypeRepository = new RelationTypeRepository(ScopeProvider, AppCaches.Disabled, Logger);
|
||||
var entityRepository = new EntityRepository(ScopeProvider);
|
||||
var relationRepository = new RelationRepository(ScopeProvider, Logger, relationTypeRepository, entityRepository);
|
||||
var propertyEditors = new Lazy<PropertyEditorCollection>(() => new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty<IDataEditor>())));
|
||||
var dataValueReferences = new DataValueReferenceFactoryCollection(Enumerable.Empty<IDataValueReferenceFactory>());
|
||||
var contentRepo = new DocumentRepository(ScopeProvider, AppCaches.Disabled, Logger, contentTypeRepository, templateRepository, tagRepository, languageRepository, relationRepository, relationTypeRepository, propertyEditors, dataValueReferences);
|
||||
|
||||
var contentType = MockedContentTypes.CreateSimpleContentType("umbTextpage2", "Textpage");
|
||||
ServiceContext.FileService.SaveTemplate(contentType.DefaultTemplate); // else, FK violation on contentType!
|
||||
|
||||
@@ -14,6 +14,8 @@ using Umbraco.Tests.TestHelpers;
|
||||
using Umbraco.Tests.TestHelpers.Entities;
|
||||
using Umbraco.Tests.Testing;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.PropertyEditors;
|
||||
using System;
|
||||
using Umbraco.Core.Configuration;
|
||||
|
||||
namespace Umbraco.Tests.Persistence.Repositories
|
||||
@@ -30,7 +32,12 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
var languageRepository = new LanguageRepository(accessor, AppCaches, Logger);
|
||||
mediaTypeRepository = new MediaTypeRepository(accessor, AppCaches, Mock.Of<ILogger>(), commonRepository, languageRepository);
|
||||
var tagRepository = new TagRepository(accessor, AppCaches, Mock.Of<ILogger>());
|
||||
var repository = new MediaRepository(accessor, AppCaches, Mock.Of<ILogger>(), mediaTypeRepository, tagRepository, Mock.Of<ILanguageRepository>());
|
||||
var relationTypeRepository = new RelationTypeRepository(accessor, AppCaches.Disabled, Logger);
|
||||
var entityRepository = new EntityRepository(accessor);
|
||||
var relationRepository = new RelationRepository(accessor, Logger, relationTypeRepository, entityRepository);
|
||||
var propertyEditors = new Lazy<PropertyEditorCollection>(() => new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty<IDataEditor>())));
|
||||
var dataValueReferences = new DataValueReferenceFactoryCollection(Enumerable.Empty<IDataValueReferenceFactory>());
|
||||
var repository = new MediaRepository(accessor, AppCaches, Mock.Of<ILogger>(), mediaTypeRepository, tagRepository, Mock.Of<ILanguageRepository>(), relationRepository, relationTypeRepository, propertyEditors, dataValueReferences);
|
||||
return repository;
|
||||
}
|
||||
|
||||
@@ -48,7 +55,12 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
var commonRepository = new ContentTypeCommonRepository(accessor, templateRepository, AppCaches);
|
||||
var languageRepository = new LanguageRepository(accessor, AppCaches, Logger);
|
||||
contentTypeRepository = new ContentTypeRepository(accessor, AppCaches, Logger, commonRepository, languageRepository);
|
||||
var repository = new DocumentRepository(accessor, AppCaches, Logger, contentTypeRepository, templateRepository, tagRepository, languageRepository);
|
||||
var relationTypeRepository = new RelationTypeRepository(accessor, AppCaches.Disabled, Logger);
|
||||
var entityRepository = new EntityRepository(accessor);
|
||||
var relationRepository = new RelationRepository(accessor, Logger, relationTypeRepository, entityRepository);
|
||||
var propertyEditors = new Lazy<PropertyEditorCollection>(() => new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty<IDataEditor>())));
|
||||
var dataValueReferences = new DataValueReferenceFactoryCollection(Enumerable.Empty<IDataValueReferenceFactory>());
|
||||
var repository = new DocumentRepository(accessor, AppCaches, Logger, contentTypeRepository, templateRepository, tagRepository, languageRepository, relationRepository, relationTypeRepository, propertyEditors, dataValueReferences);
|
||||
return repository;
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ using Umbraco.Web.PropertyEditors;
|
||||
|
||||
namespace Umbraco.Tests.PropertyEditors
|
||||
{
|
||||
|
||||
[TestFixture]
|
||||
public class ImageCropperTest
|
||||
{
|
||||
|
||||
@@ -51,7 +51,7 @@ namespace Umbraco.Tests.PropertyEditors
|
||||
|
||||
var valueEditor = dataType.Editor.GetValueEditor();
|
||||
((DataValueEditor) valueEditor).Configuration = dataType.Configuration;
|
||||
var result = valueEditor.ConvertDbToString(prop.PropertyType, prop.GetValue());
|
||||
var result = valueEditor.ConvertDbToString(prop.PropertyType, prop.GetValue(), dataTypeService);
|
||||
|
||||
Assert.AreEqual("Value 1,Value 2,Value 3", result);
|
||||
}
|
||||
@@ -78,7 +78,7 @@ namespace Umbraco.Tests.PropertyEditors
|
||||
var prop = new Property(1, new PropertyType(dataType));
|
||||
prop.SetValue("Value 2");
|
||||
|
||||
var result = dataType.Editor.GetValueEditor().ConvertDbToString(prop.PropertyType, prop.GetValue());
|
||||
var result = dataType.Editor.GetValueEditor().ConvertDbToString(prop.PropertyType, prop.GetValue(), dataTypeService);
|
||||
|
||||
Assert.AreEqual("Value 2", result);
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace Umbraco.Tests.Published
|
||||
var localizationService = Mock.Of<ILocalizationService>();
|
||||
|
||||
PropertyEditorCollection editors = null;
|
||||
var editor = new NestedContentPropertyEditor(logger, new Lazy<PropertyEditorCollection>(() => editors), Mock.Of<IDataTypeService>(), localizationService);
|
||||
var editor = new NestedContentPropertyEditor(logger, new Lazy<PropertyEditorCollection>(() => editors), Mock.Of<IDataTypeService>(), Mock.Of<IContentTypeService>(), localizationService);
|
||||
editors = new PropertyEditorCollection(new DataEditorCollection(new DataEditor[] { editor }));
|
||||
|
||||
var dataType1 = new DataType(editor)
|
||||
|
||||
@@ -11,6 +11,7 @@ using Umbraco.Core.Models;
|
||||
using Umbraco.Web.PropertyEditors;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Web;
|
||||
using Umbraco.Web.Templates;
|
||||
|
||||
namespace Umbraco.Tests.PublishedContent
|
||||
{
|
||||
@@ -38,7 +39,12 @@ namespace Umbraco.Tests.PublishedContent
|
||||
base.Initialize();
|
||||
|
||||
var converters = Factory.GetInstance<PropertyValueConverterCollection>();
|
||||
var umbracoContextAccessor = Mock.Of<IUmbracoContextAccessor>();
|
||||
var logger = Mock.Of<ILogger>();
|
||||
|
||||
var imageSourceParser = new HtmlImageSourceParser(umbracoContextAccessor);
|
||||
var pastedImages = new RichTextEditorPastedImages(umbracoContextAccessor, logger, IOHelper, Mock.Of<IMediaService>(), Mock.Of<IContentTypeBaseServiceProvider>());
|
||||
var localLinkParser = new HtmlLocalLinkParser(umbracoContextAccessor);
|
||||
var dataTypeService = new TestObjects.TestDataTypeService(
|
||||
new DataType(new RichTextPropertyEditor(
|
||||
Mock.Of<ILogger>(),
|
||||
@@ -46,7 +52,9 @@ namespace Umbraco.Tests.PublishedContent
|
||||
Mock.Of<IContentTypeBaseServiceProvider>(),
|
||||
Mock.Of<IUmbracoContextAccessor>(),
|
||||
Mock.Of<IDataTypeService>(),
|
||||
Mock.Of<ILocalizationService>())) { Id = 1 });
|
||||
Mock.Of<ILocalizationService>(),
|
||||
imageSourceParser, localLinkParser, pastedImages)) { Id = 1 });
|
||||
|
||||
|
||||
var publishedContentTypeFactory = new PublishedContentTypeFactory(Mock.Of<IPublishedModelFactory>(), converters, dataTypeService);
|
||||
|
||||
|
||||
@@ -20,11 +20,13 @@ using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Core.Services.Implement;
|
||||
using Umbraco.Core.Strings;
|
||||
using Umbraco.Tests.TestHelpers;
|
||||
using Umbraco.Tests.Testing;
|
||||
using Umbraco.Web.Models.PublishedContent;
|
||||
using Umbraco.Web.PropertyEditors;
|
||||
using Umbraco.Web.Templates;
|
||||
|
||||
namespace Umbraco.Tests.PublishedContent
|
||||
{
|
||||
@@ -49,15 +51,18 @@ namespace Umbraco.Tests.PublishedContent
|
||||
var mediaService = Mock.Of<IMediaService>();
|
||||
var contentTypeBaseServiceProvider = Mock.Of<IContentTypeBaseServiceProvider>();
|
||||
var umbracoContextAccessor = Mock.Of<IUmbracoContextAccessor>();
|
||||
var imageSourceParser = new HtmlImageSourceParser(umbracoContextAccessor);
|
||||
var pastedImages = new RichTextEditorPastedImages(umbracoContextAccessor, logger, IOHelper, mediaService, contentTypeBaseServiceProvider);
|
||||
var linkParser = new HtmlLocalLinkParser(umbracoContextAccessor);
|
||||
var localizationService = Mock.Of<ILocalizationService>();
|
||||
|
||||
var dataTypeService = new TestObjects.TestDataTypeService(
|
||||
new DataType(new VoidEditor(logger)) { Id = 1 },
|
||||
new DataType(new TrueFalsePropertyEditor(logger)) { Id = 1001 },
|
||||
new DataType(new RichTextPropertyEditor(logger, mediaService, contentTypeBaseServiceProvider, umbracoContextAccessor, Mock.Of<IDataTypeService>(), localizationService)) { Id = 1002 },
|
||||
new DataType(new RichTextPropertyEditor(logger, mediaService, contentTypeBaseServiceProvider, umbracoContextAccessor, Mock.Of<IDataTypeService>(), localizationService, imageSourceParser, linkParser, pastedImages)) { Id = 1002 },
|
||||
new DataType(new IntegerPropertyEditor(logger)) { Id = 1003 },
|
||||
new DataType(new TextboxPropertyEditor(logger, Mock.Of<IDataTypeService>(), localizationService)) { Id = 1004 },
|
||||
new DataType(new MediaPickerPropertyEditor(logger)) { Id = 1005 });
|
||||
new DataType(new MediaPickerPropertyEditor(logger, Mock.Of<IDataTypeService>(), localizationService)) { Id = 1005 });
|
||||
Composition.RegisterUnique<IDataTypeService>(f => dataTypeService);
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Persistence.Dtos;
|
||||
using Umbraco.Core.Persistence.Repositories;
|
||||
using Umbraco.Core.Persistence.Repositories.Implement;
|
||||
using Umbraco.Core.PropertyEditors;
|
||||
using Umbraco.Core.Scoping;
|
||||
using Umbraco.Tests.TestHelpers;
|
||||
using Umbraco.Tests.TestHelpers.Entities;
|
||||
@@ -39,6 +40,23 @@ namespace Umbraco.Tests.Services
|
||||
Composition.Register<IProfiler, TestProfiler>();
|
||||
}
|
||||
|
||||
private DocumentRepository CreateDocumentRepository(IScopeProvider provider)
|
||||
{
|
||||
var accessor = (IScopeAccessor)provider;
|
||||
var tRepository = new TemplateRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger, TestObjects.GetFileSystemsMock(), IOHelper);
|
||||
var tagRepo = new TagRepository(accessor, AppCaches.Disabled, Logger);
|
||||
var commonRepository = new ContentTypeCommonRepository(accessor, tRepository, AppCaches);
|
||||
var languageRepository = new LanguageRepository(accessor, AppCaches.Disabled, Logger);
|
||||
var ctRepository = new ContentTypeRepository(accessor, AppCaches.Disabled, Logger, commonRepository, languageRepository);
|
||||
var relationTypeRepository = new RelationTypeRepository(accessor, AppCaches.Disabled, Logger);
|
||||
var entityRepository = new EntityRepository(accessor);
|
||||
var relationRepository = new RelationRepository(accessor, Logger, relationTypeRepository, entityRepository);
|
||||
var propertyEditors = new Lazy<PropertyEditorCollection>(() => new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty<IDataEditor>())));
|
||||
var dataValueReferences = new DataValueReferenceFactoryCollection(Enumerable.Empty<IDataValueReferenceFactory>());
|
||||
var repository = new DocumentRepository(accessor, AppCaches.Disabled, Logger, ctRepository, tRepository, tagRepo, languageRepository, relationRepository, relationTypeRepository, propertyEditors, dataValueReferences);
|
||||
return repository;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Profiler()
|
||||
{
|
||||
@@ -163,12 +181,7 @@ namespace Umbraco.Tests.Services
|
||||
var provider = TestObjects.GetScopeProvider(Logger);
|
||||
using (var scope = provider.CreateScope())
|
||||
{
|
||||
var tRepository = new TemplateRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger, TestObjects.GetFileSystemsMock(), IOHelper);
|
||||
var tagRepo = new TagRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger);
|
||||
var commonRepository = new ContentTypeCommonRepository((IScopeAccessor)provider, tRepository, AppCaches);
|
||||
var languageRepository = new LanguageRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger);
|
||||
var ctRepository = new ContentTypeRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger, commonRepository, languageRepository);
|
||||
var repository = new DocumentRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger, ctRepository, tRepository, tagRepo, languageRepository);
|
||||
var repository = CreateDocumentRepository(provider);
|
||||
|
||||
// Act
|
||||
Stopwatch watch = Stopwatch.StartNew();
|
||||
@@ -197,12 +210,7 @@ namespace Umbraco.Tests.Services
|
||||
var provider = TestObjects.GetScopeProvider(Logger);
|
||||
using (var scope = provider.CreateScope())
|
||||
{
|
||||
var tRepository = new TemplateRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger, TestObjects.GetFileSystemsMock(), IOHelper);
|
||||
var tagRepo = new TagRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger);
|
||||
var commonRepository = new ContentTypeCommonRepository((IScopeAccessor)provider, tRepository, AppCaches);
|
||||
var languageRepository = new LanguageRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger);
|
||||
var ctRepository = new ContentTypeRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger, commonRepository, languageRepository);
|
||||
var repository = new DocumentRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger, ctRepository, tRepository, tagRepo, languageRepository);
|
||||
var repository = CreateDocumentRepository(provider);
|
||||
|
||||
// Act
|
||||
Stopwatch watch = Stopwatch.StartNew();
|
||||
@@ -229,12 +237,7 @@ namespace Umbraco.Tests.Services
|
||||
var provider = TestObjects.GetScopeProvider(Logger);
|
||||
using (var scope = provider.CreateScope())
|
||||
{
|
||||
var tRepository = new TemplateRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger, TestObjects.GetFileSystemsMock(), IOHelper);
|
||||
var tagRepo = new TagRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger);
|
||||
var commonRepository = new ContentTypeCommonRepository((IScopeAccessor) provider, tRepository, AppCaches);
|
||||
var languageRepository = new LanguageRepository((IScopeAccessor)provider, AppCaches.Disabled, Logger);
|
||||
var ctRepository = new ContentTypeRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger, commonRepository, languageRepository);
|
||||
var repository = new DocumentRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger, ctRepository, tRepository, tagRepo, languageRepository);
|
||||
var repository = CreateDocumentRepository(provider);
|
||||
|
||||
// Act
|
||||
var contents = repository.GetMany();
|
||||
@@ -264,12 +267,7 @@ namespace Umbraco.Tests.Services
|
||||
var provider = TestObjects.GetScopeProvider(Logger);
|
||||
using (var scope = provider.CreateScope())
|
||||
{
|
||||
var tRepository = new TemplateRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger, TestObjects.GetFileSystemsMock(), IOHelper);
|
||||
var tagRepo = new TagRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger);
|
||||
var commonRepository = new ContentTypeCommonRepository((IScopeAccessor)provider, tRepository, AppCaches);
|
||||
var languageRepository = new LanguageRepository((IScopeAccessor)provider, AppCaches.Disabled, Logger);
|
||||
var ctRepository = new ContentTypeRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger, commonRepository, languageRepository);
|
||||
var repository = new DocumentRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger, ctRepository, tRepository, tagRepo, languageRepository);
|
||||
var repository = CreateDocumentRepository(provider);
|
||||
|
||||
// Act
|
||||
var contents = repository.GetMany();
|
||||
|
||||
@@ -448,6 +448,47 @@ namespace Umbraco.Tests.Services
|
||||
Assert.That(content.HasIdentity, Is.False);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Automatically_Track_Relations()
|
||||
{
|
||||
var mt = MockedContentTypes.CreateSimpleMediaType("testMediaType", "Test Media Type");
|
||||
ServiceContext.MediaTypeService.Save(mt);
|
||||
var m1 = MockedMedia.CreateSimpleMedia(mt, "hello 1", -1);
|
||||
var m2 = MockedMedia.CreateSimpleMedia(mt, "hello 1", -1);
|
||||
ServiceContext.MediaService.Save(m1);
|
||||
ServiceContext.MediaService.Save(m2);
|
||||
|
||||
var ct = MockedContentTypes.CreateTextPageContentType("richTextTest");
|
||||
ct.AllowedTemplates = Enumerable.Empty<ITemplate>();
|
||||
|
||||
ServiceContext.ContentTypeService.Save(ct);
|
||||
|
||||
var c1 = MockedContent.CreateTextpageContent(ct, "my content 1", -1);
|
||||
ServiceContext.ContentService.Save(c1);
|
||||
|
||||
var c2 = MockedContent.CreateTextpageContent(ct, "my content 2", -1);
|
||||
|
||||
//'bodyText' is a property with a RTE property editor which we knows tracks relations
|
||||
c2.Properties["bodyText"].SetValue(@"<p>
|
||||
<img src='/media/12312.jpg' data-udi='umb://media/" + m1.Key.ToString("N") + @"' />
|
||||
</p><p><img src='/media/234234.jpg' data-udi=""umb://media/" + m2.Key.ToString("N") + @""" />
|
||||
</p>
|
||||
<p>
|
||||
<a href=""{locallink:umb://document/" + c1.Key.ToString("N") + @"}"">hello</a>
|
||||
</p>");
|
||||
|
||||
ServiceContext.ContentService.Save(c2);
|
||||
|
||||
var relations = ServiceContext.RelationService.GetByParentId(c2.Id).ToList();
|
||||
Assert.AreEqual(3, relations.Count);
|
||||
Assert.AreEqual(Constants.Conventions.RelationTypes.RelatedMediaAlias, relations[0].RelationType.Alias);
|
||||
Assert.AreEqual(m1.Id, relations[0].ChildId);
|
||||
Assert.AreEqual(Constants.Conventions.RelationTypes.RelatedMediaAlias, relations[1].RelationType.Alias);
|
||||
Assert.AreEqual(m2.Id, relations[1].ChildId);
|
||||
Assert.AreEqual(Constants.Conventions.RelationTypes.RelatedDocumentAlias, relations[2].RelationType.Alias);
|
||||
Assert.AreEqual(c1.Id, relations[2].ChildId);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Can_Create_Content_Without_Explicitly_Set_User()
|
||||
{
|
||||
@@ -1778,7 +1819,7 @@ namespace Umbraco.Tests.Services
|
||||
admin.StartContentIds = new[] {content1.Id};
|
||||
ServiceContext.UserService.Save(admin);
|
||||
|
||||
ServiceContext.RelationService.Save(new RelationType(Constants.ObjectTypes.Document, Constants.ObjectTypes.Document, "test"));
|
||||
ServiceContext.RelationService.Save(new RelationType("test", "test", false, Constants.ObjectTypes.Document, Constants.ObjectTypes.Document));
|
||||
Assert.IsNotNull(ServiceContext.RelationService.Relate(content1, content2, "test"));
|
||||
|
||||
ServiceContext.PublicAccessService.Save(new PublicAccessEntry(content1, content2, content2, new List<PublicAccessRule>
|
||||
@@ -3166,7 +3207,12 @@ namespace Umbraco.Tests.Services
|
||||
var commonRepository = new ContentTypeCommonRepository(accessor, templateRepository, AppCaches);
|
||||
var languageRepository = new LanguageRepository(accessor, AppCaches.Disabled, Logger);
|
||||
contentTypeRepository = new ContentTypeRepository(accessor, AppCaches.Disabled, Logger, commonRepository, languageRepository);
|
||||
var repository = new DocumentRepository(accessor, AppCaches.Disabled, Logger, contentTypeRepository, templateRepository, tagRepository, languageRepository);
|
||||
var relationTypeRepository = new RelationTypeRepository(accessor, AppCaches.Disabled, Logger);
|
||||
var entityRepository = new EntityRepository(accessor);
|
||||
var relationRepository = new RelationRepository(accessor, Logger, relationTypeRepository, entityRepository);
|
||||
var propertyEditors = new Lazy<PropertyEditorCollection>(() => new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty<IDataEditor>())));
|
||||
var dataValueReferences = new DataValueReferenceFactoryCollection(Enumerable.Empty<IDataValueReferenceFactory>());
|
||||
var repository = new DocumentRepository(accessor, AppCaches.Disabled, Logger, contentTypeRepository, templateRepository, tagRepository, languageRepository, relationRepository, relationTypeRepository, propertyEditors, dataValueReferences);
|
||||
return repository;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,27 +1,247 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Tests.TestHelpers;
|
||||
using Umbraco.Tests.TestHelpers.Entities;
|
||||
using Umbraco.Tests.Testing;
|
||||
|
||||
namespace Umbraco.Tests.Services
|
||||
{
|
||||
[TestFixture]
|
||||
[Apartment(ApartmentState.STA)]
|
||||
[UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerFixture)]
|
||||
[UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)]
|
||||
public class RelationServiceTests : TestWithSomeContentBase
|
||||
{
|
||||
|
||||
[Test]
|
||||
public void Get_Paged_Relations_By_Relation_Type()
|
||||
{
|
||||
//Create content
|
||||
var createdContent = new List<IContent>();
|
||||
var contentType = MockedContentTypes.CreateBasicContentType("blah");
|
||||
ServiceContext.ContentTypeService.Save(contentType);
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
var c1 = MockedContent.CreateBasicContent(contentType);
|
||||
ServiceContext.ContentService.Save(c1);
|
||||
createdContent.Add(c1);
|
||||
}
|
||||
|
||||
//Create media
|
||||
var createdMedia = new List<IMedia>();
|
||||
var imageType = MockedContentTypes.CreateImageMediaType("myImage");
|
||||
ServiceContext.MediaTypeService.Save(imageType);
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
var c1 = MockedMedia.CreateMediaImage(imageType, -1);
|
||||
ServiceContext.MediaService.Save(c1);
|
||||
createdMedia.Add(c1);
|
||||
}
|
||||
|
||||
var relType = ServiceContext.RelationService.GetRelationTypeByAlias(Constants.Conventions.RelationTypes.RelatedMediaAlias);
|
||||
|
||||
// Relate content to media
|
||||
foreach (var content in createdContent)
|
||||
foreach (var media in createdMedia)
|
||||
ServiceContext.RelationService.Relate(content.Id, media.Id, relType);
|
||||
|
||||
var paged = ServiceContext.RelationService.GetPagedByRelationTypeId(relType.Id, 0, 51, out var totalRecs).ToList();
|
||||
|
||||
Assert.AreEqual(100, totalRecs);
|
||||
Assert.AreEqual(51, paged.Count);
|
||||
|
||||
//next page
|
||||
paged.AddRange(ServiceContext.RelationService.GetPagedByRelationTypeId(relType.Id, 1, 51, out totalRecs));
|
||||
|
||||
Assert.AreEqual(100, totalRecs);
|
||||
Assert.AreEqual(100, paged.Count);
|
||||
|
||||
Assert.IsTrue(createdContent.Select(x => x.Id).ContainsAll(paged.Select(x => x.ParentId)));
|
||||
Assert.IsTrue(createdMedia.Select(x => x.Id).ContainsAll(paged.Select(x => x.ChildId)));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Return_List_Of_Content_Items_Where_Media_Item_Referenced()
|
||||
{
|
||||
var mt = MockedContentTypes.CreateSimpleMediaType("testMediaType", "Test Media Type");
|
||||
ServiceContext.MediaTypeService.Save(mt);
|
||||
var m1 = MockedMedia.CreateSimpleMedia(mt, "hello 1", -1);
|
||||
ServiceContext.MediaService.Save(m1);
|
||||
|
||||
var ct = MockedContentTypes.CreateTextPageContentType("richTextTest");
|
||||
ct.AllowedTemplates = Enumerable.Empty<ITemplate>();
|
||||
ServiceContext.ContentTypeService.Save(ct);
|
||||
|
||||
void createContentWithMediaRefs()
|
||||
{
|
||||
var content = MockedContent.CreateTextpageContent(ct, "my content 2", -1);
|
||||
//'bodyText' is a property with a RTE property editor which we knows automatically tracks relations
|
||||
content.Properties["bodyText"].SetValue(@"<p>
|
||||
<img src='/media/12312.jpg' data-udi='umb://media/" + m1.Key.ToString("N") + @"' />
|
||||
</p>");
|
||||
ServiceContext.ContentService.Save(content);
|
||||
}
|
||||
|
||||
for (var i = 0; i < 6; i++)
|
||||
createContentWithMediaRefs(); //create 6 content items referencing the same media
|
||||
|
||||
var relations = ServiceContext.RelationService.GetByChildId(m1.Id, Constants.Conventions.RelationTypes.RelatedMediaAlias).ToList();
|
||||
Assert.AreEqual(6, relations.Count);
|
||||
|
||||
var entities = ServiceContext.RelationService.GetParentEntitiesFromRelations(relations).ToList();
|
||||
Assert.AreEqual(6, entities.Count);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Can_Create_RelationType_Without_Name()
|
||||
{
|
||||
var rs = ServiceContext.RelationService;
|
||||
var rt = new RelationType(Constants.ObjectTypes.Document, Constants.ObjectTypes.Document, "repeatedEventOccurence");
|
||||
IRelationType rt = new RelationType("Test", "repeatedEventOccurence", false, Constants.ObjectTypes.Document, Constants.ObjectTypes.Media);
|
||||
|
||||
Assert.DoesNotThrow(() => rs.Save(rt));
|
||||
|
||||
Assert.AreEqual(rt.Name, "repeatedEventOccurence");
|
||||
//re-get
|
||||
rt = ServiceContext.RelationService.GetRelationTypeById(rt.Id);
|
||||
|
||||
Assert.AreEqual("Test", rt.Name);
|
||||
Assert.AreEqual("repeatedEventOccurence", rt.Alias);
|
||||
Assert.AreEqual(false, rt.IsBidirectional);
|
||||
Assert.AreEqual(Constants.ObjectTypes.Document, rt.ChildObjectType.Value);
|
||||
Assert.AreEqual(Constants.ObjectTypes.Media, rt.ParentObjectType.Value);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Create_Relation_Type_Without_Object_Types()
|
||||
{
|
||||
var rs = ServiceContext.RelationService;
|
||||
IRelationType rt = new RelationType("repeatedEventOccurence", "repeatedEventOccurence", false, null, null);
|
||||
|
||||
Assert.DoesNotThrow(() => rs.Save(rt));
|
||||
|
||||
//re-get
|
||||
rt = ServiceContext.RelationService.GetRelationTypeById(rt.Id);
|
||||
|
||||
Assert.IsNull(rt.ChildObjectType);
|
||||
Assert.IsNull(rt.ParentObjectType);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Relation_Returns_Parent_Child_Object_Types_When_Creating()
|
||||
{
|
||||
var r = CreateAndSaveRelation("Test", "test");
|
||||
|
||||
Assert.AreEqual(Constants.ObjectTypes.Document, r.ParentObjectType);
|
||||
Assert.AreEqual(Constants.ObjectTypes.Media, r.ChildObjectType);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Relation_Returns_Parent_Child_Object_Types_When_Getting()
|
||||
{
|
||||
var r = CreateAndSaveRelation("Test", "test");
|
||||
|
||||
// re-get
|
||||
r = ServiceContext.RelationService.GetById(r.Id);
|
||||
|
||||
Assert.AreEqual(Constants.ObjectTypes.Document, r.ParentObjectType);
|
||||
Assert.AreEqual(Constants.ObjectTypes.Media, r.ChildObjectType);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Insert_Bulk_Relations()
|
||||
{
|
||||
var rs = ServiceContext.RelationService;
|
||||
|
||||
var newRelations = CreateRelations(10);
|
||||
|
||||
Assert.IsTrue(newRelations.All(x => !x.HasIdentity));
|
||||
|
||||
ServiceContext.RelationService.Save(newRelations);
|
||||
|
||||
Assert.IsTrue(newRelations.All(x => x.HasIdentity));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Update_Bulk_Relations()
|
||||
{
|
||||
var rs = ServiceContext.RelationService;
|
||||
|
||||
var date = DateTime.Now.AddDays(-10);
|
||||
var newRelations = CreateRelations(10);
|
||||
foreach (var r in newRelations)
|
||||
{
|
||||
r.CreateDate = date;
|
||||
r.UpdateDate = date;
|
||||
}
|
||||
|
||||
//insert
|
||||
ServiceContext.RelationService.Save(newRelations);
|
||||
Assert.IsTrue(newRelations.All(x => x.UpdateDate == date));
|
||||
|
||||
var newDate = DateTime.Now.AddDays(-5);
|
||||
foreach (var r in newRelations)
|
||||
r.UpdateDate = newDate;
|
||||
|
||||
//update
|
||||
ServiceContext.RelationService.Save(newRelations);
|
||||
Assert.IsTrue(newRelations.All(x => x.UpdateDate == newDate));
|
||||
}
|
||||
|
||||
private IRelation CreateAndSaveRelation(string name, string alias)
|
||||
{
|
||||
var rs = ServiceContext.RelationService;
|
||||
var rt = new RelationType(name, alias, false, null, null);
|
||||
rs.Save(rt);
|
||||
|
||||
var ct = MockedContentTypes.CreateBasicContentType();
|
||||
ServiceContext.ContentTypeService.Save(ct);
|
||||
|
||||
var mt = MockedContentTypes.CreateImageMediaType("img");
|
||||
ServiceContext.MediaTypeService.Save(mt);
|
||||
|
||||
var c1 = MockedContent.CreateBasicContent(ct);
|
||||
var c2 = MockedMedia.CreateMediaImage(mt, -1);
|
||||
ServiceContext.ContentService.Save(c1);
|
||||
ServiceContext.MediaService.Save(c2);
|
||||
|
||||
var r = new Relation(c1.Id, c2.Id, rt);
|
||||
ServiceContext.RelationService.Save(r);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a bunch of content/media items return relation objects for them (unsaved)
|
||||
/// </summary>
|
||||
/// <param name="count"></param>
|
||||
/// <returns></returns>
|
||||
private IEnumerable<IRelation> CreateRelations(int count)
|
||||
{
|
||||
var rs = ServiceContext.RelationService;
|
||||
var rtName = Guid.NewGuid().ToString();
|
||||
var rt = new RelationType(rtName, rtName, false, null, null);
|
||||
rs.Save(rt);
|
||||
|
||||
var ct = MockedContentTypes.CreateBasicContentType();
|
||||
ServiceContext.ContentTypeService.Save(ct);
|
||||
|
||||
var mt = MockedContentTypes.CreateImageMediaType("img");
|
||||
ServiceContext.MediaTypeService.Save(mt);
|
||||
|
||||
return Enumerable.Range(1, count).Select(index =>
|
||||
{
|
||||
var c1 = MockedContent.CreateBasicContent(ct);
|
||||
var c2 = MockedMedia.CreateMediaImage(mt, -1);
|
||||
ServiceContext.ContentService.Save(c1);
|
||||
ServiceContext.MediaService.Save(c2);
|
||||
|
||||
return new Relation(c1.Id, c2.Id, rt);
|
||||
}).ToList();
|
||||
}
|
||||
|
||||
//TODO: Create a relation for entities of the wrong Entity Type (GUID) based on the Relation Type's defined parent/child object types
|
||||
}
|
||||
}
|
||||
|
||||
120
src/Umbraco.Tests/Templates/HtmlImageSourceParserTests.cs
Normal file
120
src/Umbraco.Tests/Templates/HtmlImageSourceParserTests.cs
Normal file
@@ -0,0 +1,120 @@
|
||||
using Umbraco.Core.Logging;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Tests.Testing.Objects.Accessors;
|
||||
using Umbraco.Web.Templates;
|
||||
using Umbraco.Web;
|
||||
using Umbraco.Core.Models.PublishedContent;
|
||||
using Umbraco.Web.Routing;
|
||||
using Umbraco.Tests.Testing.Objects;
|
||||
using System.Web;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Web.PropertyEditors;
|
||||
|
||||
namespace Umbraco.Tests.Templates
|
||||
{
|
||||
|
||||
|
||||
[TestFixture]
|
||||
public class HtmlImageSourceParserTests
|
||||
{
|
||||
[Test]
|
||||
public void Returns_Udis_From_Data_Udi_Html_Attributes()
|
||||
{
|
||||
var input = @"<p>
|
||||
<div>
|
||||
<img src='/media/12312.jpg' data-udi='umb://media/D4B18427A1544721B09AC7692F35C264' />
|
||||
</div>
|
||||
</p><p><img src='/media/234234.jpg' data-udi=""umb://media-type/B726D735E4C446D58F703F3FBCFC97A5"" /></p>";
|
||||
|
||||
var logger = Mock.Of<ILogger>();
|
||||
var umbracoContextAccessor = new TestUmbracoContextAccessor();
|
||||
var imageSourceParser = new HtmlImageSourceParser(umbracoContextAccessor);
|
||||
|
||||
var result = imageSourceParser.FindUdisFromDataAttributes(input).ToList();
|
||||
Assert.AreEqual(2, result.Count);
|
||||
Assert.AreEqual(UdiParser.Parse("umb://media/D4B18427A1544721B09AC7692F35C264"), result[0]);
|
||||
Assert.AreEqual(UdiParser.Parse("umb://media-type/B726D735E4C446D58F703F3FBCFC97A5"), result[1]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Remove_Image_Sources()
|
||||
{
|
||||
var logger = Mock.Of<ILogger>();
|
||||
var umbracoContextAccessor = new TestUmbracoContextAccessor();
|
||||
var imageSourceParser = new HtmlImageSourceParser(umbracoContextAccessor);
|
||||
|
||||
var result = imageSourceParser.RemoveImageSources(@"<p>
|
||||
<div>
|
||||
<img src=""/media/12354/test.jpg"" />
|
||||
</div></p>
|
||||
<p>
|
||||
<div><img src=""/media/987645/test.jpg"" data-udi=""umb://media/81BB2036-034F-418B-B61F-C7160D68DCD4"" /></div>
|
||||
</p>");
|
||||
|
||||
Assert.AreEqual(@"<p>
|
||||
<div>
|
||||
<img src=""/media/12354/test.jpg"" />
|
||||
</div></p>
|
||||
<p>
|
||||
<div><img src="""" data-udi=""umb://media/81BB2036-034F-418B-B61F-C7160D68DCD4"" /></div>
|
||||
</p>", result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Ensure_Image_Sources()
|
||||
{
|
||||
//setup a mock url provider which we'll use for testing
|
||||
|
||||
var mediaType = new PublishedContentType(777, "image", PublishedItemType.Media, Enumerable.Empty<string>(), Enumerable.Empty<PublishedPropertyType>(), ContentVariation.Nothing);
|
||||
var media = new Mock<IPublishedContent>();
|
||||
media.Setup(x => x.ContentType).Returns(mediaType);
|
||||
var mediaUrlProvider = new Mock<IMediaUrlProvider>();
|
||||
mediaUrlProvider.Setup(x => x.GetMediaUrl(It.IsAny<UmbracoContext>(), It.IsAny<IPublishedContent>(), It.IsAny<string>(), It.IsAny<UrlMode>(), It.IsAny<string>(), It.IsAny<Uri>()))
|
||||
.Returns(UrlInfo.Url("/media/1001/my-image.jpg"));
|
||||
|
||||
var umbracoContextAccessor = new TestUmbracoContextAccessor();
|
||||
|
||||
var umbracoContextFactory = TestUmbracoContextFactory.Create(
|
||||
mediaUrlProvider: mediaUrlProvider.Object,
|
||||
umbracoContextAccessor: umbracoContextAccessor);
|
||||
|
||||
using (var reference = umbracoContextFactory.EnsureUmbracoContext(Mock.Of<HttpContextBase>()))
|
||||
{
|
||||
var mediaCache = Mock.Get(reference.UmbracoContext.Media);
|
||||
mediaCache.Setup(x => x.GetById(It.IsAny<Guid>())).Returns(media.Object);
|
||||
|
||||
var imageSourceParser = new HtmlImageSourceParser(umbracoContextAccessor);
|
||||
|
||||
var result = imageSourceParser.EnsureImageSources(@"<p>
|
||||
<div>
|
||||
<img src="""" />
|
||||
</div></p>
|
||||
<p>
|
||||
<div><img src="""" data-udi=""umb://media/81BB2036-034F-418B-B61F-C7160D68DCD4"" /></div>
|
||||
</p>
|
||||
<p>
|
||||
<div><img src=""?width=100"" data-udi=""umb://media/81BB2036-034F-418B-B61F-C7160D68DCD4"" /></div>
|
||||
</p>");
|
||||
|
||||
Assert.AreEqual(@"<p>
|
||||
<div>
|
||||
<img src="""" />
|
||||
</div></p>
|
||||
<p>
|
||||
<div><img src=""/media/1001/my-image.jpg"" data-udi=""umb://media/81BB2036-034F-418B-B61F-C7160D68DCD4"" /></div>
|
||||
</p>
|
||||
<p>
|
||||
<div><img src=""/media/1001/my-image.jpg?width=100"" data-udi=""umb://media/81BB2036-034F-418B-B61F-C7160D68DCD4"" /></div>
|
||||
</p>", result);
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
94
src/Umbraco.Tests/Templates/HtmlLocalLinkParserTests.cs
Normal file
94
src/Umbraco.Tests/Templates/HtmlLocalLinkParserTests.cs
Normal file
@@ -0,0 +1,94 @@
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.PublishedContent;
|
||||
using Umbraco.Tests.Testing.Objects;
|
||||
using Umbraco.Tests.Testing.Objects.Accessors;
|
||||
using Umbraco.Web;
|
||||
using Umbraco.Web.Routing;
|
||||
using Umbraco.Web.Templates;
|
||||
|
||||
namespace Umbraco.Tests.Templates
|
||||
{
|
||||
[TestFixture]
|
||||
public class HtmlLocalLinkParserTests
|
||||
{
|
||||
[Test]
|
||||
public void Returns_Udis_From_LocalLinks()
|
||||
{
|
||||
var input = @"<p>
|
||||
<div>
|
||||
<img src='/media/12312.jpg' data-udi='umb://media/D4B18427A1544721B09AC7692F35C264' />
|
||||
<a href=""{locallink:umb://document/C093961595094900AAF9170DDE6AD442}"">hello</a>
|
||||
</div>
|
||||
</p><p><img src='/media/234234.jpg' data-udi=""umb://media-type/B726D735E4C446D58F703F3FBCFC97A5"" />
|
||||
<a href=""{locallink:umb://document-type/2D692FCB070B4CDA92FB6883FDBFD6E2}"">hello</a>
|
||||
</p>";
|
||||
|
||||
var umbracoContextAccessor = new TestUmbracoContextAccessor();
|
||||
var parser = new HtmlLocalLinkParser(umbracoContextAccessor);
|
||||
|
||||
var result = parser.FindUdisFromLocalLinks(input).ToList();
|
||||
|
||||
Assert.AreEqual(2, result.Count);
|
||||
Assert.AreEqual(UdiParser.Parse("umb://document/C093961595094900AAF9170DDE6AD442"), result[0]);
|
||||
Assert.AreEqual(UdiParser.Parse("umb://document-type/2D692FCB070B4CDA92FB6883FDBFD6E2"), result[1]);
|
||||
}
|
||||
|
||||
[TestCase("", "")]
|
||||
[TestCase("hello href=\"{localLink:1234}\" world ", "hello href=\"/my-test-url\" world ")]
|
||||
[TestCase("hello href=\"{localLink:umb://document/9931BDE0-AAC3-4BAB-B838-909A7B47570E}\" world ", "hello href=\"/my-test-url\" world ")]
|
||||
[TestCase("hello href=\"{localLink:umb://document/9931BDE0AAC34BABB838909A7B47570E}\" world ", "hello href=\"/my-test-url\" world ")]
|
||||
[TestCase("hello href=\"{localLink:umb://media/9931BDE0AAC34BABB838909A7B47570E}\" world ", "hello href=\"/media/1001/my-image.jpg\" world ")]
|
||||
//this one has an invalid char so won't match
|
||||
[TestCase("hello href=\"{localLink:umb^://document/9931BDE0-AAC3-4BAB-B838-909A7B47570E}\" world ", "hello href=\"{localLink:umb^://document/9931BDE0-AAC3-4BAB-B838-909A7B47570E}\" world ")]
|
||||
[TestCase("hello href=\"{localLink:umb://document-type/9931BDE0-AAC3-4BAB-B838-909A7B47570E}\" world ", "hello href=\"#\" world ")]
|
||||
public void ParseLocalLinks(string input, string result)
|
||||
{
|
||||
//setup a mock url provider which we'll use for testing
|
||||
var contentUrlProvider = new Mock<IUrlProvider>();
|
||||
contentUrlProvider
|
||||
.Setup(x => x.GetUrl(It.IsAny<UmbracoContext>(), It.IsAny<IPublishedContent>(), It.IsAny<UrlMode>(), It.IsAny<string>(), It.IsAny<Uri>()))
|
||||
.Returns(UrlInfo.Url("/my-test-url"));
|
||||
var contentType = new PublishedContentType(666, "alias", PublishedItemType.Content, Enumerable.Empty<string>(), Enumerable.Empty<PublishedPropertyType>(), ContentVariation.Nothing);
|
||||
var publishedContent = new Mock<IPublishedContent>();
|
||||
publishedContent.Setup(x => x.Id).Returns(1234);
|
||||
publishedContent.Setup(x => x.ContentType).Returns(contentType);
|
||||
|
||||
var mediaType = new PublishedContentType(777, "image", PublishedItemType.Media, Enumerable.Empty<string>(), Enumerable.Empty<PublishedPropertyType>(), ContentVariation.Nothing);
|
||||
var media = new Mock<IPublishedContent>();
|
||||
media.Setup(x => x.ContentType).Returns(mediaType);
|
||||
var mediaUrlProvider = new Mock<IMediaUrlProvider>();
|
||||
mediaUrlProvider.Setup(x => x.GetMediaUrl(It.IsAny<UmbracoContext>(), It.IsAny<IPublishedContent>(), It.IsAny<string>(), It.IsAny<UrlMode>(), It.IsAny<string>(), It.IsAny<Uri>()))
|
||||
.Returns(UrlInfo.Url("/media/1001/my-image.jpg"));
|
||||
|
||||
var umbracoContextAccessor = new TestUmbracoContextAccessor();
|
||||
|
||||
var umbracoContextFactory = TestUmbracoContextFactory.Create(
|
||||
urlProvider: contentUrlProvider.Object,
|
||||
mediaUrlProvider: mediaUrlProvider.Object,
|
||||
umbracoContextAccessor: umbracoContextAccessor);
|
||||
|
||||
using (var reference = umbracoContextFactory.EnsureUmbracoContext(Mock.Of<HttpContextBase>()))
|
||||
{
|
||||
var contentCache = Mock.Get(reference.UmbracoContext.Content);
|
||||
contentCache.Setup(x => x.GetById(It.IsAny<int>())).Returns(publishedContent.Object);
|
||||
contentCache.Setup(x => x.GetById(It.IsAny<Guid>())).Returns(publishedContent.Object);
|
||||
|
||||
var mediaCache = Mock.Get(reference.UmbracoContext.Media);
|
||||
mediaCache.Setup(x => x.GetById(It.IsAny<int>())).Returns(media.Object);
|
||||
mediaCache.Setup(x => x.GetById(It.IsAny<Guid>())).Returns(media.Object);
|
||||
|
||||
var linkParser = new HtmlLocalLinkParser(umbracoContextAccessor);
|
||||
|
||||
var output = linkParser.EnsureInternalLinks(input);
|
||||
|
||||
Assert.AreEqual(result, output);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,15 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Models.PublishedContent;
|
||||
using Umbraco.Core.Scoping;
|
||||
using Umbraco.Web;
|
||||
using Umbraco.Web.PublishedCache.NuCache;
|
||||
using Umbraco.Web.PublishedCache.NuCache.DataSource;
|
||||
|
||||
namespace Umbraco.Tests.Testing.Objects
|
||||
{
|
||||
|
||||
internal class TestDataSource : IDataSource
|
||||
{
|
||||
public TestDataSource(params ContentNodeKit[] kits)
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
using Moq;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Configuration.UmbracoSettings;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Tests.TestHelpers;
|
||||
using Umbraco.Tests.Testing.Objects.Accessors;
|
||||
using Umbraco.Web;
|
||||
using Umbraco.Web.PublishedCache;
|
||||
using Umbraco.Web.Routing;
|
||||
|
||||
namespace Umbraco.Tests.Testing.Objects
|
||||
{
|
||||
/// <summary>
|
||||
/// Simplify creating test UmbracoContext's
|
||||
/// </summary>
|
||||
public class TestUmbracoContextFactory
|
||||
{
|
||||
public static IUmbracoContextFactory Create(IGlobalSettings globalSettings = null, IUrlProvider urlProvider = null,
|
||||
IMediaUrlProvider mediaUrlProvider = null,
|
||||
IUmbracoContextAccessor umbracoContextAccessor = null)
|
||||
{
|
||||
if (globalSettings == null) globalSettings = SettingsForTests.GenerateMockGlobalSettings();
|
||||
if (urlProvider == null) urlProvider = Mock.Of<IUrlProvider>();
|
||||
if (mediaUrlProvider == null) mediaUrlProvider = Mock.Of<IMediaUrlProvider>();
|
||||
if (umbracoContextAccessor == null) umbracoContextAccessor = new TestUmbracoContextAccessor();
|
||||
|
||||
var contentCache = new Mock<IPublishedContentCache>();
|
||||
var mediaCache = new Mock<IPublishedMediaCache>();
|
||||
var snapshot = new Mock<IPublishedSnapshot>();
|
||||
snapshot.Setup(x => x.Content).Returns(contentCache.Object);
|
||||
snapshot.Setup(x => x.Media).Returns(mediaCache.Object);
|
||||
var snapshotService = new Mock<IPublishedSnapshotService>();
|
||||
snapshotService.Setup(x => x.CreatePublishedSnapshot(It.IsAny<string>())).Returns(snapshot.Object);
|
||||
|
||||
var umbracoContextFactory = new UmbracoContextFactory(
|
||||
umbracoContextAccessor,
|
||||
snapshotService.Object,
|
||||
new TestVariationContextAccessor(),
|
||||
new TestDefaultCultureAccessor(),
|
||||
Mock.Of<IUmbracoSettingsSection>(section => section.WebRouting == Mock.Of<IWebRoutingSection>(routingSection => routingSection.UrlProviderMode == "Auto")),
|
||||
globalSettings,
|
||||
new UrlProviderCollection(new[] { urlProvider }),
|
||||
new MediaUrlProviderCollection(new[] { mediaUrlProvider }),
|
||||
Mock.Of<IUserService>());
|
||||
|
||||
return umbracoContextFactory;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -44,6 +44,8 @@ using Umbraco.Web.Hosting;
|
||||
using Umbraco.Web.Sections;
|
||||
using Current = Umbraco.Core.Composing.Current;
|
||||
using FileSystems = Umbraco.Core.IO.FileSystems;
|
||||
using Umbraco.Web.Templates;
|
||||
using Umbraco.Web.PropertyEditors;
|
||||
using Umbraco.Core.Dictionary;
|
||||
using Umbraco.Net;
|
||||
|
||||
@@ -244,6 +246,9 @@ namespace Umbraco.Tests.Testing
|
||||
Composition.RegisterUnique(_ => Umbraco.Web.Composing.Current.UmbracoContextAccessor);
|
||||
Composition.RegisterUnique<IPublishedRouter, PublishedRouter>();
|
||||
Composition.WithCollectionBuilder<ContentFinderCollectionBuilder>();
|
||||
|
||||
Composition.DataValueReferenceFactories();
|
||||
|
||||
Composition.RegisterUnique<IContentLastChanceFinder, TestLastChanceFinder>();
|
||||
Composition.RegisterUnique<IVariationContextAccessor, TestVariationContextAccessor>();
|
||||
Composition.RegisterUnique<IPublishedSnapshotAccessor, TestPublishedSnapshotAccessor>();
|
||||
@@ -260,6 +265,11 @@ namespace Umbraco.Tests.Testing
|
||||
.Append<TranslationSection>();
|
||||
Composition.RegisterUnique<ISectionService, SectionService>();
|
||||
|
||||
Composition.RegisterUnique<HtmlLocalLinkParser>();
|
||||
Composition.RegisterUnique<HtmlUrlParser>();
|
||||
Composition.RegisterUnique<HtmlImageSourceParser>();
|
||||
Composition.RegisterUnique<RichTextEditorPastedImages>();
|
||||
|
||||
}
|
||||
|
||||
protected virtual void ComposeMisc()
|
||||
|
||||
@@ -144,6 +144,7 @@
|
||||
<Compile Include="Models\VariationTests.cs" />
|
||||
<Compile Include="Persistence\Mappers\MapperTestBase.cs" />
|
||||
<Compile Include="Persistence\Repositories\DocumentRepositoryTest.cs" />
|
||||
<Compile Include="Persistence\Repositories\EntityRepositoryTest.cs" />
|
||||
<Compile Include="PublishedContent\NuCacheChildrenTests.cs" />
|
||||
<Compile Include="PublishedContent\PublishedContentLanguageVariantTests.cs" />
|
||||
<Compile Include="PublishedContent\PublishedContentSnapshotTestBase.cs" />
|
||||
@@ -164,6 +165,7 @@
|
||||
<Compile Include="Services\MemberGroupServiceTests.cs" />
|
||||
<Compile Include="Services\MediaTypeServiceTests.cs" />
|
||||
<Compile Include="Services\PropertyValidationServiceTests.cs" />
|
||||
<Compile Include="Templates\HtmlLocalLinkParserTests.cs" />
|
||||
<Compile Include="TestHelpers\RandomIdRamDirectory.cs" />
|
||||
<Compile Include="Testing\Objects\TestDataSource.cs" />
|
||||
<Compile Include="Published\PublishedSnapshotTestObjects.cs" />
|
||||
@@ -217,6 +219,7 @@
|
||||
<Compile Include="Testing\Objects\Accessors\TestVariationContextAccessor.cs" />
|
||||
<Compile Include="Testing\ContentBaseExtensions.cs" />
|
||||
<Compile Include="Testing\Objects\Accessors\TestDefaultCultureAccessor.cs" />
|
||||
<Compile Include="Testing\Objects\TestUmbracoContextFactory.cs" />
|
||||
<Compile Include="Testing\TestDatabase.cs" />
|
||||
<Compile Include="Testing\TestingTests\NUnitTests.cs" />
|
||||
<Compile Include="Persistence\LocksTests.cs" />
|
||||
@@ -258,6 +261,7 @@
|
||||
<Compile Include="Web\Controllers\UsersControllerTests.cs" />
|
||||
<Compile Include="Web\HealthChecks\HealthCheckResultsTests.cs" />
|
||||
<Compile Include="Web\HttpCookieExtensionsTests.cs" />
|
||||
<Compile Include="Templates\HtmlImageSourceParserTests.cs" />
|
||||
<Compile Include="Web\Mvc\HtmlStringUtilitiesTests.cs" />
|
||||
<Compile Include="Web\ModelStateExtensionsTests.cs" />
|
||||
<Compile Include="Web\Mvc\RenderIndexActionSelectorAttributeTests.cs" />
|
||||
@@ -503,7 +507,6 @@
|
||||
<Compile Include="Composing\TypeFinderTests.cs" />
|
||||
<Compile Include="Routing\UmbracoModuleTests.cs" />
|
||||
<Compile Include="CoreThings\VersionExtensionTests.cs" />
|
||||
<Compile Include="Web\TemplateUtilitiesTests.cs" />
|
||||
<Compile Include="Web\UrlHelperExtensionTests.cs" />
|
||||
<Compile Include="Web\WebExtensionMethodTests.cs" />
|
||||
<Compile Include="CoreThings\XmlExtensionsTests.cs" />
|
||||
|
||||
@@ -1,84 +0,0 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Configuration.UmbracoSettings;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.PublishedContent;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Tests.TestHelpers;
|
||||
using Umbraco.Tests.Testing.Objects.Accessors;
|
||||
using Umbraco.Web;
|
||||
using Umbraco.Web.PublishedCache;
|
||||
using Umbraco.Web.Routing;
|
||||
using Umbraco.Web.Templates;
|
||||
|
||||
namespace Umbraco.Tests.Web
|
||||
{
|
||||
[TestFixture]
|
||||
public class TemplateUtilitiesTests
|
||||
{
|
||||
[SetUp]
|
||||
public void SetUp()
|
||||
{
|
||||
UdiParser.ResetUdiTypes();
|
||||
}
|
||||
|
||||
|
||||
[TestCase("", "")]
|
||||
[TestCase("hello href=\"{localLink:1234}\" world ", "hello href=\"/my-test-url\" world ")]
|
||||
[TestCase("hello href=\"{localLink:umb://document/9931BDE0-AAC3-4BAB-B838-909A7B47570E}\" world ", "hello href=\"/my-test-url\" world ")]
|
||||
[TestCase("hello href=\"{localLink:umb://document/9931BDE0AAC34BABB838909A7B47570E}\" world ", "hello href=\"/my-test-url\" world ")]
|
||||
[TestCase("hello href=\"{localLink:umb://media/9931BDE0AAC34BABB838909A7B47570E}\" world ", "hello href=\"/media/1001/my-image.jpg\" world ")]
|
||||
//this one has an invalid char so won't match
|
||||
[TestCase("hello href=\"{localLink:umb^://document/9931BDE0-AAC3-4BAB-B838-909A7B47570E}\" world ", "hello href=\"{localLink:umb^://document/9931BDE0-AAC3-4BAB-B838-909A7B47570E}\" world ")]
|
||||
[TestCase("hello href=\"{localLink:umb://document-type/9931BDE0-AAC3-4BAB-B838-909A7B47570E}\" world ", "hello href=\"#\" world ")]
|
||||
public void ParseLocalLinks(string input, string result)
|
||||
{
|
||||
//setup a mock url provider which we'll use for testing
|
||||
var testUrlProvider = new Mock<IUrlProvider>();
|
||||
testUrlProvider
|
||||
.Setup(x => x.GetUrl(It.IsAny<UmbracoContext>(), It.IsAny<IPublishedContent>(), It.IsAny<UrlMode>(), It.IsAny<string>(), It.IsAny<Uri>()))
|
||||
.Returns((UmbracoContext umbCtx, IPublishedContent content, UrlMode mode, string culture, Uri url) => UrlInfo.Url("/my-test-url"));
|
||||
|
||||
var globalSettings = SettingsForTests.GenerateMockGlobalSettings();
|
||||
|
||||
var contentType = new PublishedContentType(666, "alias", PublishedItemType.Content, Enumerable.Empty<string>(), Enumerable.Empty<PublishedPropertyType>(), ContentVariation.Nothing);
|
||||
var publishedContent = Mock.Of<IPublishedContent>();
|
||||
Mock.Get(publishedContent).Setup(x => x.Id).Returns(1234);
|
||||
Mock.Get(publishedContent).Setup(x => x.ContentType).Returns(contentType);
|
||||
var contentCache = Mock.Of<IPublishedContentCache>();
|
||||
Mock.Get(contentCache).Setup(x => x.GetById(It.IsAny<int>())).Returns(publishedContent);
|
||||
Mock.Get(contentCache).Setup(x => x.GetById(It.IsAny<Guid>())).Returns(publishedContent);
|
||||
var snapshot = Mock.Of<IPublishedSnapshot>();
|
||||
Mock.Get(snapshot).Setup(x => x.Content).Returns(contentCache);
|
||||
var snapshotService = Mock.Of<IPublishedSnapshotService>();
|
||||
Mock.Get(snapshotService).Setup(x => x.CreatePublishedSnapshot(It.IsAny<string>())).Returns(snapshot);
|
||||
var media = Mock.Of<IPublishedContent>();
|
||||
Mock.Get(media).Setup(x => x.Url).Returns("/media/1001/my-image.jpg");
|
||||
var mediaCache = Mock.Of<IPublishedMediaCache>();
|
||||
Mock.Get(mediaCache).Setup(x => x.GetById(It.IsAny<Guid>())).Returns(media);
|
||||
|
||||
var umbracoContextAccessor = new TestUmbracoContextAccessor();
|
||||
var umbracoContextFactory = new UmbracoContextFactory(
|
||||
umbracoContextAccessor,
|
||||
snapshotService,
|
||||
new TestVariationContextAccessor(),
|
||||
new TestDefaultCultureAccessor(),
|
||||
Mock.Of<IUmbracoSettingsSection>(section => section.WebRouting == Mock.Of<IWebRoutingSection>(routingSection => routingSection.UrlProviderMode == "Auto")),
|
||||
globalSettings,
|
||||
new UrlProviderCollection(new[] { testUrlProvider.Object }),
|
||||
new MediaUrlProviderCollection(Enumerable.Empty<IMediaUrlProvider>()),
|
||||
Mock.Of<IUserService>());
|
||||
|
||||
using (var reference = umbracoContextFactory.EnsureUmbracoContext(Mock.Of<HttpContextBase>()))
|
||||
{
|
||||
var output = TemplateUtilities.ParseInternalLinks(input, reference.UmbracoContext.UrlProvider, mediaCache);
|
||||
|
||||
Assert.AreEqual(result, output);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,30 @@
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
function MediaNodeInfoDirective($timeout, $location, eventsService, userService, dateHelper, editorService, mediaHelper) {
|
||||
function MediaNodeInfoDirective($timeout, $location, eventsService, userService, dateHelper, editorService, mediaHelper, mediaResource, $q) {
|
||||
|
||||
function link(scope, element, attrs, ctrl) {
|
||||
|
||||
var evts = [];
|
||||
|
||||
scope.allowChangeMediaType = false;
|
||||
scope.loading = true;
|
||||
|
||||
scope.changeContentPageNumber = changeContentPageNumber;
|
||||
scope.contentOptions = {};
|
||||
scope.contentOptions.entityType = "DOCUMENT";
|
||||
scope.hasContentReferences = false;
|
||||
|
||||
scope.changeMediaPageNumber = changeMediaPageNumber;
|
||||
scope.mediaOptions = {};
|
||||
scope.mediaOptions.entityType = "MEDIA";
|
||||
scope.hasMediaReferences = false;
|
||||
|
||||
scope.changeMemberPageNumber = changeMemberPageNumber;
|
||||
scope.memberOptions = {};
|
||||
scope.memberOptions.entityType = "MEMBER";
|
||||
scope.hasMemberReferences = false;
|
||||
|
||||
|
||||
function onInit() {
|
||||
|
||||
@@ -94,6 +111,45 @@
|
||||
setMediaExtension();
|
||||
});
|
||||
|
||||
function changeContentPageNumber(pageNumber) {
|
||||
scope.contentOptions.pageNumber = pageNumber;
|
||||
loadContentRelations();
|
||||
}
|
||||
|
||||
function changeMediaPageNumber(pageNumber) {
|
||||
scope.mediaOptions.pageNumber = pageNumber;
|
||||
loadMediaRelations();
|
||||
}
|
||||
|
||||
function changeMemberPageNumber(pageNumber) {
|
||||
scope.memberOptions.pageNumber = pageNumber;
|
||||
loadMemberRelations();
|
||||
}
|
||||
|
||||
function loadContentRelations() {
|
||||
return mediaResource.getPagedReferences(scope.node.id, scope.contentOptions)
|
||||
.then(function (data) {
|
||||
scope.contentReferences = data;
|
||||
scope.hasContentReferences = data.items.length > 0;
|
||||
});
|
||||
}
|
||||
|
||||
function loadMediaRelations() {
|
||||
return mediaResource.getPagedReferences(scope.node.id, scope.mediaOptions)
|
||||
.then(function (data) {
|
||||
scope.mediaReferences = data;
|
||||
scope.hasMediaReferences = data.items.length > 0;
|
||||
});
|
||||
}
|
||||
|
||||
function loadMemberRelations() {
|
||||
return mediaResource.getPagedReferences(scope.node.id, scope.memberOptions)
|
||||
.then(function (data) {
|
||||
scope.memberReferences = data;
|
||||
scope.hasMemberReferences = data.items.length > 0;
|
||||
});
|
||||
}
|
||||
|
||||
//ensure to unregister from all events!
|
||||
scope.$on('$destroy', function () {
|
||||
for (var e in evts) {
|
||||
@@ -102,6 +158,18 @@
|
||||
});
|
||||
|
||||
onInit();
|
||||
|
||||
// load media type references when the 'info' tab is first activated/switched to
|
||||
evts.push(eventsService.on("app.tabChange", function (event, args) {
|
||||
$timeout(function () {
|
||||
if (args.alias === "umbInfo") {
|
||||
|
||||
$q.all([loadContentRelations(), loadMediaRelations(), loadMemberRelations()]).then(function () {
|
||||
scope.loading = false;
|
||||
});
|
||||
}
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
var directive = {
|
||||
|
||||
@@ -552,6 +552,36 @@ function mediaResource($q, $http, umbDataFormatter, umbRequestHelper) {
|
||||
"Search",
|
||||
args)),
|
||||
'Failed to retrieve media items for search: ' + query);
|
||||
},
|
||||
|
||||
getPagedReferences: function (id, options) {
|
||||
|
||||
var defaults = {
|
||||
pageSize: 25,
|
||||
pageNumber: 1,
|
||||
entityType: "DOCUMENT"
|
||||
};
|
||||
if (options === undefined) {
|
||||
options = {};
|
||||
}
|
||||
//overwrite the defaults if there are any specified
|
||||
angular.extend(defaults, options);
|
||||
//now copy back to the options we will use
|
||||
options = defaults;
|
||||
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.get(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"mediaApiBaseUrl",
|
||||
"GetPagedReferences",
|
||||
{
|
||||
id: id,
|
||||
entityType: options.entityType,
|
||||
pageNumber: options.pageNumber,
|
||||
pageSize: options.pageSize
|
||||
}
|
||||
)),
|
||||
"Failed to retrieve usages for media of id " + id);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
@@ -114,6 +114,34 @@ function relationTypeResource($q, $http, umbRequestHelper, umbDataFormatter) {
|
||||
$http.post(umbRequestHelper.getApiUrl("relationTypeApiBaseUrl", "DeleteById", [{ id: id }])),
|
||||
"Failed to delete item " + id
|
||||
);
|
||||
},
|
||||
|
||||
getPagedResults: function (id, options) {
|
||||
|
||||
var defaults = {
|
||||
pageSize: 25,
|
||||
pageNumber: 1
|
||||
};
|
||||
if (options === undefined) {
|
||||
options = {};
|
||||
}
|
||||
//overwrite the defaults if there are any specified
|
||||
angular.extend(defaults, options);
|
||||
//now copy back to the options we will use
|
||||
options = defaults;
|
||||
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.get(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"relationTypeApiBaseUrl",
|
||||
"GetPagedResults",
|
||||
{
|
||||
id: id,
|
||||
pageNumber: options.pageNumber,
|
||||
pageSize: options.pageSize
|
||||
}
|
||||
)),
|
||||
'Failed to get paged relations for id ' + id);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
@@ -1,20 +1,25 @@
|
||||
<div class="umb-package-details">
|
||||
<div class="umb-package-details__main-content">
|
||||
<umb-box data-element="node-info-urls">
|
||||
|
||||
<umb-load-indicator ng-if="loading === true"></umb-load-indicator>
|
||||
|
||||
<!-- Main Column -->
|
||||
<div class="umb-package-details__main-content" ng-if="loading === false">
|
||||
|
||||
<!-- Links -->
|
||||
<umb-box data-element="node-info-urls" class="mb4">
|
||||
<umb-box-header title-key="general_links"></umb-box-header>
|
||||
<umb-box-content class="block-form">
|
||||
|
||||
<umb-empty-state
|
||||
ng-if="!nodeUrl"
|
||||
size="small">
|
||||
<umb-empty-state ng-if="!nodeUrl"
|
||||
size="small">
|
||||
<localize key="content_noMediaLink"></localize>
|
||||
</umb-empty-state>
|
||||
|
||||
<ul ng-if="nodeUrl" class="nav nav-stacked" style="margin-bottom: 0;">
|
||||
<li>
|
||||
<a ng-attr-href="{{node.extension !== 'svg' ? nodeUrl : undefined}}" ng-click="node.extension === 'svg' && openSVG()" target="_blank">
|
||||
<i class="icon icon-out"></i>
|
||||
<span>{{nodeFileName}}</span>
|
||||
<i class="icon icon-out"></i>
|
||||
<span>{{nodeFileName}}</span>
|
||||
|
||||
</a>
|
||||
</li>
|
||||
@@ -23,9 +28,132 @@
|
||||
</umb-box-content>
|
||||
</umb-box>
|
||||
|
||||
<!-- Media Tracking (NO Items) -->
|
||||
<umb-box ng-if="(hasContentReferences === false) && (hasMediaReferences === false) && (hasMemberReferences === false) && loading === false">
|
||||
<umb-box-header title-key="references_tabName"></umb-box-header>
|
||||
<umb-box-content>
|
||||
<umb-empty-state size="small">
|
||||
This Media item has no references.
|
||||
</umb-empty-state>
|
||||
</umb-box-content>
|
||||
</umb-box>
|
||||
|
||||
<!-- Media Tracking (With Items) -->
|
||||
<div ng-if="loading === false">
|
||||
<!-- Content -->
|
||||
<div ng-if="contentReferences.items.length > 0">
|
||||
|
||||
<h5 class="mt0" style="margin-bottom: 20px;">
|
||||
<localize key="references_labelUsedByDocuments">Used in Documents</localize>
|
||||
</h5>
|
||||
|
||||
<div class="umb-table">
|
||||
<div class="umb-table-head">
|
||||
<div class="umb-table-row">
|
||||
<div class="umb-table-cell"></div>
|
||||
<div class="umb-table-cell umb-table__name not-fixed"><localize key="general_name">Name</localize></div>
|
||||
<div class="umb-table-cell"><localize key="content_alias">Alias</localize></div>
|
||||
<div class="umb-table-cell umb-table-cell--nano"><localize key="general_open" style="visibility:hidden;">Open</localize></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="umb-table-body">
|
||||
<div class="umb-table-row" ng-repeat="reference in contentReferences.items">
|
||||
<div class="umb-table-cell"><i class="umb-table-body__icon {{reference.icon}}"></i></div>
|
||||
<div class="umb-table-cell umb-table__name"><span>{{::reference.name}}</span></div>
|
||||
<div class="umb-table-cell"><span title="{{::reference.alias}}">{{::reference.alias}}</span></div>
|
||||
<div class="umb-table-cell umb-table-cell--nano"><a ng-href="#/content/content/edit/{{::reference.id}}"><localize key="general_open">Open</localize></a></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Pagination -->
|
||||
<div class="flex justify-center">
|
||||
<umb-pagination ng-if="contentReferences.totalPages"
|
||||
page-number="contentReferences.pageNumber"
|
||||
total-pages="contentReferences.totalPages"
|
||||
on-change="changeContentPageNumber(pageNumber)">
|
||||
</umb-pagination>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Members -->
|
||||
<div ng-if="memberReferences.items.length > 0">
|
||||
|
||||
<h5 class="mt0" style="margin-bottom: 20px;">
|
||||
<localize key="references_labelUsedByMembers">Used in Members</localize>
|
||||
</h5>
|
||||
|
||||
<div class="umb-table">
|
||||
<div class="umb-table-head">
|
||||
<div class="umb-table-row">
|
||||
<div class="umb-table-cell"></div>
|
||||
<div class="umb-table-cell umb-table__name not-fixed"><localize key="general_name">Name</localize></div>
|
||||
<div class="umb-table-cell"><localize key="content_alias">Alias</localize></div>
|
||||
<div class="umb-table-cell umb-table-cell--nano"><localize key="general_open" style="visibility:hidden;">Open</localize></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="umb-table-body">
|
||||
<div class="umb-table-row" ng-repeat="reference in memberReferences.items">
|
||||
<div class="umb-table-cell"><i class="umb-table-body__icon {{reference.icon}}"></i></div>
|
||||
<div class="umb-table-cell umb-table__name"><span>{{::reference.name}}</span></div>
|
||||
<div class="umb-table-cell"><span title="{{::reference.alias}}">{{::reference.alias}}</span></div>
|
||||
<div class="umb-table-cell umb-table-cell--nano"><a href="#/member/member/edit/{{::reference.key}}"><localize key="general_open">Open</localize></a></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Pagination -->
|
||||
<div class="flex justify-center">
|
||||
<umb-pagination ng-if="memberReferences.totalPages"
|
||||
page-number="memberReferences.pageNumber"
|
||||
total-pages="memberReferences.totalPages"
|
||||
on-change="changeMemberPageNumber(pageNumber)">
|
||||
</umb-pagination>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Media -->
|
||||
<div ng-if="mediaReferences.items.length > 0">
|
||||
|
||||
<h5 class="mt0" style="margin-bottom: 20px;">
|
||||
<localize key="references_labelUsedByMedia">Used in Media</localize>
|
||||
</h5>
|
||||
|
||||
<div class="umb-table">
|
||||
<div class="umb-table-head">
|
||||
<div class="umb-table-row">
|
||||
<div class="umb-table-cell"></div>
|
||||
<div class="umb-table-cell umb-table__name not-fixed"><localize key="general_name">Name</localize></div>
|
||||
<div class="umb-table-cell"><localize key="content_alias">Alias</localize></div>
|
||||
<div class="umb-table-cell umb-table-cell--nano"><localize key="general_open" style="visibility:hidden;">Open</localize></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="umb-table-body">
|
||||
<div class="umb-table-row" ng-repeat="reference in mediaReferences.items">
|
||||
<div class="umb-table-cell"><i class="umb-table-body__icon {{reference.icon}}"></i></div>
|
||||
<div class="umb-table-cell umb-table__name"><span>{{::reference.name}}</span></div>
|
||||
<div class="umb-table-cell"><span title="{{::reference.alias}}">{{::reference.alias}}</span></div>
|
||||
<div class="umb-table-cell umb-table-cell--nano"><a href="#/media/media/edit/{{::reference.id}}"><localize key="general_open">Open</localize></a></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Pagination -->
|
||||
<div class="flex justify-center">
|
||||
<umb-pagination ng-if="mediaReferences.totalPages"
|
||||
page-number="mediaReferences.pageNumber"
|
||||
total-pages="mediaReferences.totalPages"
|
||||
on-change="changeMediaPageNumber(pageNumber)">
|
||||
</umb-pagination>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="umb-package-details__sidebar">
|
||||
<!-- Sidebar -->
|
||||
<div class="umb-package-details__sidebar" ng-if="loading === false">
|
||||
<!-- General Info -->
|
||||
<umb-box data-element="node-info-general">
|
||||
<umb-box-header title-key="general_general"></umb-box-header>
|
||||
<umb-box-content class="block-form">
|
||||
@@ -39,12 +167,11 @@
|
||||
</umb-control-group>
|
||||
|
||||
<umb-control-group data-element="node-info-media-type" label="@content_mediatype">
|
||||
<umb-node-preview
|
||||
style="max-width: 100%; margin-bottom: 0px;"
|
||||
icon="node.icon"
|
||||
name="node.contentTypeName"
|
||||
allow-open="allowChangeMediaType"
|
||||
on-open="openMediaType(mediaType)">
|
||||
<umb-node-preview style="max-width: 100%; margin-bottom: 0px;"
|
||||
icon="node.icon"
|
||||
name="node.contentTypeName"
|
||||
allow-open="allowChangeMediaType"
|
||||
on-open="openMediaType(mediaType)">
|
||||
</umb-node-preview>
|
||||
</umb-control-group>
|
||||
|
||||
|
||||
@@ -31,8 +31,7 @@
|
||||
<umb-control-group label="@relationType_parent">
|
||||
<select name="relationType-parent"
|
||||
ng-model="vm.relationType.parentObjectType"
|
||||
class="umb-property-editor umb-dropdown"
|
||||
required>
|
||||
class="umb-property-editor umb-dropdown">
|
||||
<option ng-repeat="objectType in vm.objectTypes" value="{{objectType.id}}">{{objectType.name}}</option>
|
||||
</select>
|
||||
</umb-control-group>
|
||||
@@ -41,8 +40,7 @@
|
||||
<umb-control-group label="@relationType_child">
|
||||
<select name="relationType-child"
|
||||
ng-model="vm.relationType.childObjectType"
|
||||
class="umb-property-editor umb-dropdown"
|
||||
required>
|
||||
class="umb-property-editor umb-dropdown">
|
||||
<option ng-repeat="objectType in vm.objectTypes" value="{{objectType.id}}">{{objectType.name}}</option>
|
||||
</select>
|
||||
</umb-control-group>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* @description
|
||||
* The controller for editing relation types.
|
||||
*/
|
||||
function RelationTypeEditController($scope, $routeParams, relationTypeResource, editorState, navigationService, dateHelper, userService, entityResource, formHelper, contentEditingHelper, localizationService) {
|
||||
function RelationTypeEditController($scope, $routeParams, relationTypeResource, editorState, navigationService, dateHelper, userService, entityResource, formHelper, contentEditingHelper, localizationService, eventsService) {
|
||||
|
||||
var vm = this;
|
||||
|
||||
@@ -21,6 +21,10 @@ function RelationTypeEditController($scope, $routeParams, relationTypeResource,
|
||||
|
||||
function init() {
|
||||
vm.page.loading = true;
|
||||
vm.relationsLoading = true;
|
||||
|
||||
vm.changePageNumber = changePageNumber;
|
||||
vm.options = {};
|
||||
|
||||
var labelKeys = [
|
||||
"relationType_tabRelationType",
|
||||
@@ -45,17 +49,39 @@ function RelationTypeEditController($scope, $routeParams, relationTypeResource,
|
||||
];
|
||||
});
|
||||
|
||||
// load references when the 'relations' tab is first activated/switched to
|
||||
eventsService.on("app.tabChange", function (event, args) {
|
||||
if (args.alias === "relations") {
|
||||
loadRelations();
|
||||
}
|
||||
});
|
||||
|
||||
// Inital page/overview API call of relation type
|
||||
relationTypeResource.getById($routeParams.id)
|
||||
.then(function(data) {
|
||||
.then(function (data) {
|
||||
bindRelationType(data);
|
||||
vm.page.loading = false;
|
||||
});
|
||||
}
|
||||
|
||||
function bindRelationType(relationType) {
|
||||
formatDates(relationType.relations);
|
||||
getRelationNames(relationType);
|
||||
function changePageNumber(pageNumber) {
|
||||
vm.options.pageNumber = pageNumber;
|
||||
loadRelations();
|
||||
}
|
||||
|
||||
|
||||
/** Loads in the references one time when content app changed */
|
||||
function loadRelations() {
|
||||
relationTypeResource.getPagedResults($routeParams.id, vm.options)
|
||||
.then(function (data) {
|
||||
formatDates(data.items);
|
||||
vm.relationsLoading = false;
|
||||
vm.relations = data;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function bindRelationType(relationType) {
|
||||
// Convert property value to string, since the umb-radiobutton component at the moment only handle string values.
|
||||
// Sometime later the umb-radiobutton might be able to handle value as boolean.
|
||||
relationType.isBidirectional = (relationType.isBidirectional || false).toString();
|
||||
@@ -70,7 +96,7 @@ function RelationTypeEditController($scope, $routeParams, relationTypeResource,
|
||||
}
|
||||
|
||||
function formatDates(relations) {
|
||||
if(relations) {
|
||||
if (relations) {
|
||||
userService.getCurrentUser().then(function (currentUser) {
|
||||
angular.forEach(relations, function (relation) {
|
||||
relation.timestampFormatted = dateHelper.getLocalDate(relation.createDate, currentUser.locale, 'LLL');
|
||||
@@ -79,41 +105,6 @@ function RelationTypeEditController($scope, $routeParams, relationTypeResource,
|
||||
}
|
||||
}
|
||||
|
||||
function getRelationNames(relationType) {
|
||||
if (relationType.relations) {
|
||||
// can we grab app entity types in one go?
|
||||
if (relationType.parentObjectType === relationType.childObjectType) {
|
||||
// yep, grab the distinct list of parent and child entities
|
||||
var entityIds = _.uniq(_.union(_.pluck(relationType.relations, "parentId"), _.pluck(relationType.relations, "childId")));
|
||||
entityResource.getByIds(entityIds, relationType.parentObjectTypeName).then(function (entities) {
|
||||
updateRelationNames(relationType, entities);
|
||||
});
|
||||
} else {
|
||||
// nope, grab the parent and child entities individually
|
||||
var parentEntityIds = _.uniq(_.pluck(relationType.relations, "parentId"));
|
||||
var childEntityIds = _.uniq(_.pluck(relationType.relations, "childId"));
|
||||
entityResource.getByIds(parentEntityIds, relationType.parentObjectTypeName).then(function (entities) {
|
||||
updateRelationNames(relationType, entities);
|
||||
});
|
||||
entityResource.getByIds(childEntityIds, relationType.childObjectTypeName).then(function (entities) {
|
||||
updateRelationNames(relationType, entities);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function updateRelationNames(relationType, entities) {
|
||||
var entitiesById = _.indexBy(entities, "id");
|
||||
_.each(relationType.relations, function(relation) {
|
||||
if (entitiesById[relation.parentId]) {
|
||||
relation.parentName = entitiesById[relation.parentId].name;
|
||||
}
|
||||
if (entitiesById[relation.childId]) {
|
||||
relation.childName = entitiesById[relation.childId].name;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function saveRelationType() {
|
||||
|
||||
if (formHelper.submitForm({ scope: $scope, statusMessage: "Saving..." })) {
|
||||
|
||||
@@ -1,28 +1,39 @@
|
||||
<umb-box>
|
||||
<umb-load-indicator ng-if="model.relationsLoading"></umb-load-indicator>
|
||||
|
||||
<umb-box ng-if="model.relationsLoading === false">
|
||||
<umb-box-content class="block-form">
|
||||
|
||||
<umb-empty-state size="small" ng-if="model.relationType.relations.length === 0">
|
||||
<umb-empty-state size="small" ng-if="model.relations.totalItems === 0">
|
||||
<localize key="relationType_noRelations">No relations for this relation type.</localize>
|
||||
</umb-empty-state>
|
||||
|
||||
<!-- Relations -->
|
||||
<umb-control-group label="@relationType_relations" ng-if="model.relationType.relations.length > 0">
|
||||
<div>
|
||||
<table class="table">
|
||||
<tr>
|
||||
<th><localize key="relationType_parent">Parent</localize></th>
|
||||
<th><localize key="relationType_child">Child</localize></th>
|
||||
<th><localize key="relationType_created">Created</localize></th>
|
||||
<th><localize key="relationType_comment">Comment</localize></th>
|
||||
</tr>
|
||||
<tr ng-repeat="relation in model.relationType.relations">
|
||||
<td>{{relation.parentName}}</td>
|
||||
<td>{{relation.childName}}</td>
|
||||
<td>{{relation.timestampFormatted}}</td>
|
||||
<td>{{relation.comment}}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</umb-control-group>
|
||||
<umb-control-group label="@relationType_relations" ng-if="model.relations.items.length > 0">
|
||||
<div>
|
||||
<table class="table">
|
||||
<tr>
|
||||
<th><localize key="relationType_parent">Parent</localize></th>
|
||||
<th><localize key="relationType_child">Child</localize></th>
|
||||
<th><localize key="relationType_created">Created</localize></th>
|
||||
<th><localize key="relationType_comment">Comment</localize></th>
|
||||
</tr>
|
||||
<tr ng-repeat="relation in model.relations.items">
|
||||
<td>{{relation.parentName}}</td>
|
||||
<td>{{relation.childName}}</td>
|
||||
<td>{{relation.timestampFormatted}}</td>
|
||||
<td>{{relation.comment}}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- Pagination -->
|
||||
<div class="flex justify-center">
|
||||
<umb-pagination ng-if="model.relations.totalPages"
|
||||
page-number="model.relations.pageNumber"
|
||||
total-pages="model.relations.totalPages"
|
||||
on-change="model.changePageNumber(pageNumber)">
|
||||
</umb-pagination>
|
||||
</div>
|
||||
</umb-control-group>
|
||||
</umb-box-content>
|
||||
</umb-box>
|
||||
|
||||
@@ -2189,6 +2189,9 @@ To manage your website, simply open the Umbraco back office and start adding con
|
||||
<key alias="labelUsedByMemberTypes">Used in Member Types</key>
|
||||
<key alias="noMemberTypes">No references to Member Types.</key>
|
||||
<key alias="usedByProperties">Used by</key>
|
||||
<key alias="labelUsedByDocuments">Used in Documents</key>
|
||||
<key alias="labelUsedByMembers">Used in Members</key>
|
||||
<key alias="labelUsedByMedia">Used in Media</key>
|
||||
</area>
|
||||
<area alias="logViewer">
|
||||
<key alias="logLevels">Log Levels</key>
|
||||
|
||||
@@ -2205,6 +2205,9 @@ To manage your website, simply open the Umbraco back office and start adding con
|
||||
<key alias="labelUsedByMemberTypes">Used in Member Types</key>
|
||||
<key alias="noMemberTypes">No references to Member Types.</key>
|
||||
<key alias="usedByProperties">Used by</key>
|
||||
<key alias="labelUsedByDocuments">Used in Documents</key>
|
||||
<key alias="labelUsedByMembers">Used in Members</key>
|
||||
<key alias="labelUsedByMedia">Used in Media</key>
|
||||
</area>
|
||||
<area alias="logViewer">
|
||||
<key alias="logLevels">Log Levels</key>
|
||||
|
||||
@@ -182,6 +182,8 @@ namespace Umbraco.Web.Composing
|
||||
|
||||
public static DataEditorCollection DataEditors => CoreCurrent.DataEditors;
|
||||
|
||||
public static DataValueReferenceFactoryCollection DataValueReferenceFactories => CoreCurrent.DataValueReferenceFactories;
|
||||
|
||||
public static PropertyEditorCollection PropertyEditors => CoreCurrent.PropertyEditors;
|
||||
|
||||
public static ParameterEditorCollection ParameterEditors => CoreCurrent.ParameterEditors;
|
||||
|
||||
@@ -663,6 +663,9 @@ namespace Umbraco.Web.Editors
|
||||
if (pageSize <= 0)
|
||||
throw new HttpResponseException(HttpStatusCode.NotFound);
|
||||
|
||||
// re-normalize since NULL can be passed in
|
||||
filter = filter ?? string.Empty;
|
||||
|
||||
var objectType = ConvertToObjectType(type);
|
||||
if (objectType.HasValue)
|
||||
{
|
||||
|
||||
@@ -35,6 +35,7 @@ using Umbraco.Core.PropertyEditors;
|
||||
using Umbraco.Web.ContentApps;
|
||||
using Umbraco.Web.Editors.Binders;
|
||||
using Umbraco.Web.Editors.Filters;
|
||||
using Umbraco.Core.Models.Entities;
|
||||
using Constants = Umbraco.Core.Constants;
|
||||
using Umbraco.Core.Dictionary;
|
||||
|
||||
@@ -943,5 +944,31 @@ namespace Umbraco.Web.Editors
|
||||
|
||||
return hasPathAccess;
|
||||
}
|
||||
|
||||
public PagedResult<EntityBasic> GetPagedReferences(int id, string entityType, int pageNumber = 1, int pageSize = 100)
|
||||
{
|
||||
if (pageNumber <= 0 || pageSize <= 0)
|
||||
{
|
||||
throw new NotSupportedException("Both pageNumber and pageSize must be greater than zero");
|
||||
}
|
||||
|
||||
var objectType = ObjectTypes.GetUmbracoObjectType(entityType);
|
||||
var udiType = ObjectTypes.GetUdiType(objectType);
|
||||
|
||||
var relations = Services.RelationService.GetPagedParentEntitiesByChildId(id, pageNumber - 1, pageSize, out var totalRecords, objectType);
|
||||
|
||||
return new PagedResult<EntityBasic>(totalRecords, pageNumber, pageSize)
|
||||
{
|
||||
Items = relations.Cast<ContentEntitySlim>().Select(rel => new EntityBasic
|
||||
{
|
||||
Id = rel.Id,
|
||||
Key = rel.Key,
|
||||
Udi = Udi.Create(udiType, rel.Key),
|
||||
Icon = rel.ContentTypeIcon,
|
||||
Name = rel.Name,
|
||||
Alias = rel.ContentTypeAlias
|
||||
})
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,12 +3,14 @@ using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Web.Http;
|
||||
using System.Linq;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Web.Models.ContentEditing;
|
||||
using Umbraco.Web.Mvc;
|
||||
@@ -45,14 +47,28 @@ namespace Umbraco.Web.Editors
|
||||
throw new HttpResponseException(HttpStatusCode.NotFound);
|
||||
}
|
||||
|
||||
var relations = Services.RelationService.GetByRelationTypeId(relationType.Id);
|
||||
|
||||
var display = Mapper.Map<IRelationType, RelationTypeDisplay>(relationType);
|
||||
display.Relations = Mapper.MapEnumerable<IRelation, RelationDisplay>(relations);
|
||||
|
||||
|
||||
return display;
|
||||
}
|
||||
|
||||
public PagedResult<RelationDisplay> GetPagedResults(int id, int pageNumber = 1, int pageSize = 100)
|
||||
{
|
||||
|
||||
if (pageNumber <= 0 || pageSize <= 0)
|
||||
{
|
||||
throw new NotSupportedException("Both pageNumber and pageSize must be greater than zero");
|
||||
}
|
||||
|
||||
// Ordering do we need to pass through?
|
||||
var relations = Services.RelationService.GetPagedByRelationTypeId(id, pageNumber -1, pageSize, out long totalRecords);
|
||||
|
||||
return new PagedResult<RelationDisplay>(totalRecords, pageNumber, pageSize)
|
||||
{
|
||||
Items = relations.Select(x => Mapper.Map<RelationDisplay>(x))
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of object types which can be associated via relations.
|
||||
/// </summary>
|
||||
@@ -84,11 +100,7 @@ namespace Umbraco.Web.Editors
|
||||
/// <returns>A <see cref="HttpResponseMessage"/> containing the persisted relation type's ID.</returns>
|
||||
public HttpResponseMessage PostCreate(RelationTypeSave relationType)
|
||||
{
|
||||
var relationTypePersisted = new RelationType(relationType.ChildObjectType, relationType.ParentObjectType, relationType.Name.ToSafeAlias(true))
|
||||
{
|
||||
Name = relationType.Name,
|
||||
IsBidirectional = relationType.IsBidirectional
|
||||
};
|
||||
var relationTypePersisted = new RelationType(relationType.Name, relationType.Name.ToSafeAlias(true), relationType.IsBidirectional, relationType.ChildObjectType, relationType.ParentObjectType);
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace Umbraco.Web.Models.ContentEditing
|
||||
/// </summary>
|
||||
/// <remarks>Corresponds to the NodeObjectType in the umbracoNode table</remarks>
|
||||
[DataMember(Name = "parentObjectType", IsRequired = true)]
|
||||
public Guid ParentObjectType { get; set; }
|
||||
public Guid? ParentObjectType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Parent's object type name.
|
||||
@@ -38,7 +38,7 @@ namespace Umbraco.Web.Models.ContentEditing
|
||||
/// </summary>
|
||||
/// <remarks>Corresponds to the NodeObjectType in the umbracoNode table</remarks>
|
||||
[DataMember(Name = "childObjectType", IsRequired = true)]
|
||||
public Guid ChildObjectType { get; set; }
|
||||
public Guid? ChildObjectType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Child's object type name.
|
||||
@@ -47,13 +47,6 @@ namespace Umbraco.Web.Models.ContentEditing
|
||||
[ReadOnly(true)]
|
||||
public string ChildObjectTypeName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the relations associated with this relation type.
|
||||
/// </summary>
|
||||
[DataMember(Name = "relations")]
|
||||
[ReadOnly(true)]
|
||||
public IEnumerable<RelationDisplay> Relations { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// This is used to add custom localized messages/strings to the response for the app to use for localized UI purposes.
|
||||
/// </summary>
|
||||
|
||||
@@ -16,12 +16,12 @@ namespace Umbraco.Web.Models.ContentEditing
|
||||
/// Gets or sets the parent object type ID.
|
||||
/// </summary>
|
||||
[DataMember(Name = "parentObjectType", IsRequired = false)]
|
||||
public Guid ParentObjectType { get; set; }
|
||||
public Guid? ParentObjectType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the child object type ID.
|
||||
/// </summary>
|
||||
[DataMember(Name = "childObjectType", IsRequired = false)]
|
||||
public Guid ChildObjectType { get; set; }
|
||||
public Guid? ChildObjectType { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -234,11 +234,11 @@ namespace Umbraco.Web.Models.Mapping
|
||||
{
|
||||
switch (entity)
|
||||
{
|
||||
case ContentEntitySlim contentEntity:
|
||||
// NOTE: this case covers both content and media entities
|
||||
return contentEntity.ContentTypeIcon;
|
||||
case MemberEntitySlim memberEntity:
|
||||
case IMemberEntitySlim memberEntity:
|
||||
return memberEntity.ContentTypeIcon.IfNullOrWhiteSpace(Constants.Icons.Member);
|
||||
case IContentEntitySlim contentEntity:
|
||||
// NOTE: this case covers both content and media entities
|
||||
return contentEntity.ContentTypeIcon;
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
@@ -1,12 +1,23 @@
|
||||
using Umbraco.Core;
|
||||
using System.Linq;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Mapping;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Web.Models.ContentEditing;
|
||||
|
||||
namespace Umbraco.Web.Models.Mapping
|
||||
{
|
||||
internal class RelationMapDefinition : IMapDefinition
|
||||
{
|
||||
private readonly IEntityService _entityService;
|
||||
private readonly IRelationService _relationService;
|
||||
|
||||
public RelationMapDefinition(IEntityService entityService, IRelationService relationService)
|
||||
{
|
||||
_entityService = entityService;
|
||||
_relationService = relationService;
|
||||
}
|
||||
|
||||
public void DefineMaps(UmbracoMapper mapper)
|
||||
{
|
||||
mapper.Define<IRelationType, RelationTypeDisplay>((source, context) => new RelationTypeDisplay(), Map);
|
||||
@@ -15,8 +26,8 @@ namespace Umbraco.Web.Models.Mapping
|
||||
}
|
||||
|
||||
// Umbraco.Code.MapAll -Icon -Trashed -AdditionalData
|
||||
// Umbraco.Code.MapAll -Relations -ParentId -Notifications
|
||||
private static void Map(IRelationType source, RelationTypeDisplay target, MapperContext context)
|
||||
// Umbraco.Code.MapAll -ParentId -Notifications
|
||||
private void Map(IRelationType source, RelationTypeDisplay target, MapperContext context)
|
||||
{
|
||||
target.ChildObjectType = source.ChildObjectType;
|
||||
target.Id = source.Id;
|
||||
@@ -28,18 +39,32 @@ namespace Umbraco.Web.Models.Mapping
|
||||
target.Udi = Udi.Create(Constants.UdiEntityType.RelationType, source.Key);
|
||||
target.Path = "-1," + source.Id;
|
||||
|
||||
// Set the "friendly" names for the parent and child object types
|
||||
target.ParentObjectTypeName = ObjectTypes.GetUmbracoObjectType(source.ParentObjectType).GetFriendlyName();
|
||||
target.ChildObjectTypeName = ObjectTypes.GetUmbracoObjectType(source.ChildObjectType).GetFriendlyName();
|
||||
// Set the "friendly" and entity names for the parent and child object types
|
||||
if (source.ParentObjectType.HasValue)
|
||||
{
|
||||
var objType = ObjectTypes.GetUmbracoObjectType(source.ParentObjectType.Value);
|
||||
target.ParentObjectTypeName = objType.GetFriendlyName();
|
||||
}
|
||||
|
||||
if (source.ChildObjectType.HasValue)
|
||||
{
|
||||
var objType = ObjectTypes.GetUmbracoObjectType(source.ChildObjectType.Value);
|
||||
target.ChildObjectTypeName = objType.GetFriendlyName();
|
||||
}
|
||||
}
|
||||
|
||||
// Umbraco.Code.MapAll -ParentName -ChildName
|
||||
private static void Map(IRelation source, RelationDisplay target, MapperContext context)
|
||||
private void Map(IRelation source, RelationDisplay target, MapperContext context)
|
||||
{
|
||||
target.ChildId = source.ChildId;
|
||||
target.Comment = source.Comment;
|
||||
target.CreateDate = source.CreateDate;
|
||||
target.ParentId = source.ParentId;
|
||||
|
||||
var entities = _relationService.GetEntitiesFromRelation(source);
|
||||
|
||||
target.ParentName = entities.Item1.Name;
|
||||
target.ChildName = entities.Item2.Name;
|
||||
}
|
||||
|
||||
// Umbraco.Code.MapAll -CreateDate -UpdateDate -DeleteDate
|
||||
|
||||
@@ -380,8 +380,8 @@ namespace Umbraco.Web.Models.Mapping
|
||||
.ToDictionary(x => x.Key, x => (IEnumerable<Permission>)x.ToArray());
|
||||
}
|
||||
|
||||
private static string MapContentTypeIcon(EntitySlim entity)
|
||||
=> entity is ContentEntitySlim contentEntity ? contentEntity.ContentTypeIcon : null;
|
||||
private static string MapContentTypeIcon(IEntitySlim entity)
|
||||
=> entity is IContentEntitySlim contentEntity ? contentEntity.ContentTypeIcon : null;
|
||||
|
||||
private IEnumerable<EntityBasic> GetStartNodes(int[] startNodeIds, UmbracoObjectTypes objectType, string localizedKey, MapperContext context)
|
||||
{
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models.Editors;
|
||||
using Umbraco.Core.PropertyEditors;
|
||||
using Umbraco.Core.Services;
|
||||
|
||||
namespace Umbraco.Web.PropertyEditors
|
||||
{
|
||||
@@ -17,13 +19,38 @@ namespace Umbraco.Web.PropertyEditors
|
||||
Group = Constants.PropertyEditors.Groups.Pickers)]
|
||||
public class ContentPickerPropertyEditor : DataEditor
|
||||
{
|
||||
public ContentPickerPropertyEditor(ILogger logger)
|
||||
private readonly IDataTypeService _dataTypeService;
|
||||
private readonly ILocalizationService _localizationService;
|
||||
|
||||
public ContentPickerPropertyEditor(IDataTypeService dataTypeService, ILocalizationService localizationService, ILogger logger)
|
||||
: base(logger)
|
||||
{ }
|
||||
{
|
||||
_dataTypeService = dataTypeService;
|
||||
_localizationService = localizationService;
|
||||
}
|
||||
|
||||
protected override IConfigurationEditor CreateConfigurationEditor()
|
||||
{
|
||||
return new ContentPickerConfigurationEditor();
|
||||
}
|
||||
|
||||
protected override IDataValueEditor CreateValueEditor() => new ContentPickerPropertyValueEditor(_dataTypeService, _localizationService, Attribute);
|
||||
|
||||
internal class ContentPickerPropertyValueEditor : DataValueEditor, IDataValueReference
|
||||
{
|
||||
public ContentPickerPropertyValueEditor(IDataTypeService dataTypeService, ILocalizationService localizationService, DataEditorAttribute attribute) : base(dataTypeService, localizationService, attribute)
|
||||
{
|
||||
}
|
||||
|
||||
public IEnumerable<UmbracoEntityReference> GetReferences(object value)
|
||||
{
|
||||
var asString = value is string str ? str : value?.ToString();
|
||||
|
||||
if (string.IsNullOrEmpty(asString)) yield break;
|
||||
|
||||
if (UdiParser.TryParse(asString, out var udi))
|
||||
yield return new UmbracoEntityReference(udi);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user