-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathProductLinkedOnceRule.cs
More file actions
95 lines (72 loc) · 3.84 KB
/
Copy pathProductLinkedOnceRule.cs
File metadata and controls
95 lines (72 loc) · 3.84 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using CMS.ContentEngine;
using CMS.Core;
using DancingGoat.AdminComponents.UIPages;
using DancingGoat.Models;
using Kentico.Xperience.Admin.Base.Forms;
[assembly: RegisterFormValidationRule(ProductLinkedOnceRule.IDENTIFIER, typeof(ProductLinkedOnceRule), "{$dancinggoat.formvalidationrule.productlinkedonce.name$}", "{$dancinggoat.formvalidationrule.productlinkedonce.description$}")]
namespace DancingGoat.AdminComponents.UIPages;
/// <summary>
/// Validates whether value for the field was set.
/// </summary>
/// <remarks>
/// The rule considers <see langword="null"/> value, empty string or empty collection as invalid values.
/// </remarks>
public sealed class ProductLinkedOnceRule : ValidationRule<ProductLinkedOnceRuleProperties, IEnumerable<ContentItemReference>>
{
internal const string IDENTIFIER = "DancingGoat.ProductLinkedOnce";
private readonly ILocalizationService localizationService;
private readonly IContentQueryExecutor executor;
/// <inheritdoc/>
protected override string DefaultErrorMessage => localizationService.GetString("Product already linked once and can not be linked again.");
/// <summary>
/// Creates a new instance of <see cref="ProductLinkedOnceRule"/> class.
/// </summary>
public ProductLinkedOnceRule(ILocalizationService localizationService, IContentQueryExecutor executor)
{
this.localizationService = localizationService;
this.executor = executor;
}
/// <summary>
/// Validates whether product is linked only once.
/// </summary>
/// <param name="value">Value to be validated.</param>
/// <param name="formFieldValueProvider">Provider of values of other form fields for contextual validation.</param>
/// <returns>Returns the validation result.</returns>
public override async Task<ValidationResult> Validate(IEnumerable<ContentItemReference> value, IFormFieldValueProvider formFieldValueProvider)
{
if (FormContext is not IContentItemFormContextBase contentItemFormContext)
{
throw new InvalidOperationException("The validation rule can only be used in a content item form context.");
}
if (!(value?.Any() ?? false))
{
return await ValidationResult.FailResult();
}
var contentItemId = contentItemFormContext.ItemId;
var identifier = value.First().Identifier;
var contentQueryBuilder = new ContentItemQueryBuilder()
.ForContentTypes(a => a.OfReusableSchema(IProductFields.REUSABLE_FIELD_SCHEMA_NAME))
.Parameters(p => p.Where(x => x.WhereEquals(nameof(IContentItemFieldsSource.SystemFields.ContentItemGUID), identifier))
.Columns(nameof(IContentItemFieldsSource.SystemFields.ContentItemID)));
var contentItem = (await executor.GetMappedResult<IContentItemFieldsSource>(contentQueryBuilder, new ContentQueryExecutionOptions { ForPreview = true, IncludeSecuredItems = true })).FirstOrDefault();
if (contentItem == null)
{
return await ValidationResult.FailResult();
}
var queryBuilder = new ContentItemQueryBuilder()
.ForContentType(ProductPage.CONTENT_TYPE_NAME, config => config.WithLinkedItems(1)
.Linking(nameof(ProductPage.ProductPageProduct), [contentItem.SystemFields.ContentItemID])
.Where(x => x.WhereNotEquals(nameof(IContentItemFieldsSource.SystemFields.ContentItemID), contentItemId))
);
var duplicateRecords = await executor.GetMappedResult<object>(queryBuilder, new ContentQueryExecutionOptions { ForPreview = true, IncludeSecuredItems = true });
if (duplicateRecords.Any())
{
return await ValidationResult.FailResult();
}
return await ValidationResult.SuccessResult();
}
}