Skip to content

Commit

Permalink
Implement DateDependencyValidator
Browse files Browse the repository at this point in the history
  • Loading branch information
eschleb committed Apr 4, 2024
1 parent b68883e commit 1c291e5
Show file tree
Hide file tree
Showing 6 changed files with 232 additions and 0 deletions.
1 change: 1 addition & 0 deletions custom-definitions/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
- MimeType
- NodeType
- Template
- [DateDependency](src/main/java/com/merkle/oss/magnolia/definition/custom/validator/datedependency/README.md)

## Configuration

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package com.merkle.oss.magnolia.definition.custom.validator.datedependency;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.temporal.Temporal;

import com.vaadin.data.ValidationResult;
import com.vaadin.data.ValueContext;
import com.vaadin.data.validator.AbstractValidator;

public class DateDependencyValidator extends AbstractValidator<Temporal> {
private final DateDependencyValidatorDefinition definition;

public DateDependencyValidator(
final DateDependencyValidatorDefinition definition,
final String errorMessage
) {
super(errorMessage);
this.definition = definition;
}

@Override
public ValidationResult apply(final Temporal value, final ValueContext context) {
return toResult(value, isValid(value));
}

private boolean isValid(final Temporal value) {
definition.getState().update(definition.getPropertyName(), convert(value));
return definition.getValidator().test(definition.getState());
}

private LocalDateTime convert(final Temporal value) {
if(value instanceof LocalDate) {
return ((LocalDate)value).atStartOfDay();
}
return LocalDateTime.from(value);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package com.merkle.oss.magnolia.definition.custom.validator.datedependency;

import info.magnolia.i18nsystem.I18nable;
import info.magnolia.ui.field.ConfiguredFieldValidatorDefinition;
import info.magnolia.ui.field.FieldValidatorFactory;
import info.magnolia.ui.field.ValidatorType;

import java.time.LocalDateTime;
import java.time.temporal.Temporal;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.function.Predicate;

import javax.annotation.Nullable;

import com.merkle.oss.magnolia.definition.key.generator.FieldValidatorDefinitionKeyGenerator;

@I18nable(keyGenerator = FieldValidatorDefinitionKeyGenerator.class)
@ValidatorType("dateDependency")
public class DateDependencyValidatorDefinition extends ConfiguredFieldValidatorDefinition {
private final State state;
private final String propertyName;
private final Predicate<State> validator;

DateDependencyValidatorDefinition(final State state, final String propertyName, final boolean i18n, final Predicate<State> validator) {
this.state = state;
this.propertyName = propertyName;
this.validator = validator;
state.propertyNameI18nMapping.put(propertyName, i18n);
}

@Override
public Class<? extends FieldValidatorFactory<Temporal>> getFactoryClass() {
return DateDependencyValidatorFactory.class;
}

public State getState() {
return state;
}

public String getPropertyName() {
return propertyName;
}

public Predicate<State> getValidator() {
return validator;
}

public static class State {
private final Map<String, Boolean> propertyNameI18nMapping = new HashMap<>();
private final Map<String, LocalDateTime> dates = new HashMap<>();

void update(final String propertyName, @Nullable final LocalDateTime LocalDateTime) {
dates.put(propertyName, LocalDateTime);
}

Map<String, Boolean> getPropertyNameI18nMapping() {
return propertyNameI18nMapping;
}

public Optional<LocalDateTime> get(final String propertyName) {
return Optional.ofNullable(dates.get(propertyName));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package com.merkle.oss.magnolia.definition.custom.validator.datedependency;

import info.magnolia.ui.field.DateFieldDefinition;

import java.util.function.Predicate;

import com.merkle.oss.magnolia.definition.builder.validator.AbstractConfiguredFieldValidatorDefinitionBuilder;
import com.merkle.oss.magnolia.definition.custom.validator.datedependency.DateDependencyValidatorDefinition.State;

public class DateDependencyValidatorDefinitionBuilder extends AbstractConfiguredFieldValidatorDefinitionBuilder<DateDependencyValidatorDefinition, DateDependencyValidatorDefinitionBuilder> {
private final Predicate<State> validator;
private final State state = new State();

public DateDependencyValidatorDefinitionBuilder(final Predicate<State> validator) {
this.validator = validator;
}

public DateDependencyValidatorDefinition build(final String propertyName) {
return build(propertyName, false);
}
public DateDependencyValidatorDefinition build(final String propertyName, final boolean i18n) {
return build("dateDependencyValidator", propertyName, i18n);
}
public DateDependencyValidatorDefinition build(final String name, final String propertyName) {
return build(name, propertyName, false);
}
public DateDependencyValidatorDefinition build(final String name, final String propertyName, final boolean i18n) {
final DateDependencyValidatorDefinition definition = new DateDependencyValidatorDefinition(state, propertyName, i18n, validator);
super.populate(definition, name);
return definition;
}

public DateFieldDefinition buildAndAdd(final DateFieldDefinition dateField) {
final DateDependencyValidatorDefinition validator = build(dateField.getName(), dateField.isI18n());
dateField.getValidators().add(validator);
return dateField;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package com.merkle.oss.magnolia.definition.custom.validator.datedependency;

import info.magnolia.ui.ValueContext;
import info.magnolia.ui.editor.LocaleContext;
import info.magnolia.ui.field.AbstractFieldValidatorFactory;

import java.time.LocalDateTime;
import java.time.temporal.Temporal;
import java.util.Optional;

import javax.inject.Inject;
import javax.jcr.Item;
import javax.jcr.Node;

import com.merkle.oss.magnolia.powernode.PowerNode;
import com.merkle.oss.magnolia.powernode.PowerNodeService;
import com.merkle.oss.magnolia.powernode.ValueConverter;
import com.vaadin.data.Validator;

public class DateDependencyValidatorFactory extends AbstractFieldValidatorFactory<DateDependencyValidatorDefinition, Temporal> {
private final PowerNodeService powerNodeService;
private final ValueContext<Item> valueContext;
private final LocaleContext localeContext;

@Inject
public DateDependencyValidatorFactory(
final PowerNodeService powerNodeService,
final ValueContext<Item> valueContext,
final LocaleContext localeContext,
final DateDependencyValidatorDefinition definition
) {
super(definition);
this.powerNodeService = powerNodeService;
this.valueContext = valueContext;
this.localeContext = localeContext;
}

@Override
public Validator<Temporal> createValidator() {
valueContext.getSingle()
.filter(Item::isNode)
.map(Node.class::cast)
.map(powerNodeService::convertToPowerNode)
.ifPresent(this::updateState);
return new DateDependencyValidator(definition, getI18nErrorMessage());
}

private void updateState(final PowerNode item) {
definition.getState().getPropertyNameI18nMapping().forEach((propertyName, i18n) ->
definition.getState().update(propertyName, get(item, propertyName, i18n).orElse(null))
);
}

private Optional<LocalDateTime> get(final PowerNode item, final String propertyName, final boolean i18n) {
if(i18n) {
return item.getProperty(propertyName, localeContext.getCurrent(), ValueConverter::getLocalDateTime);
}
return item.getProperty(propertyName, ValueConverter::getLocalDateTime);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# DateDependency Validator
Validator to define dependencies between multiple date fields. E.g. endDate must be after startDate.

## Usage
### Dialog
```java
import info.magnolia.ui.field.EditorPropertyDefinition;
import info.magnolia.module.blossom.annotation.TabFactory;
import com.merkle.oss.magnolia.definition.builder.simple.DateFieldDefinitionBuilder;
import com.merkle.oss.magnolia.definition.custom.validator.datedependency.DateDependencyValidatorDefinitionBuilder;

@TabFactory("someTab")
public List<EditorPropertyDefinition> someTab() {
final DateDependencyValidatorDefinitionBuilder dateDependencyValidatorBuilder = new DateDependencyValidatorDefinitionBuilder(state ->
state.get("startDate").flatMap(startDate ->
state.get("endDate").map(startDate::isBefore)
).orElse(true)
);
return List.of(
//Option1 specifying dateField name & i18n
new DateFieldDefinitionBuilder().validator(dateDependencyValidatorBuilder.build("startDate")).build("startDate"),
new DateFieldDefinitionBuilder().i18n().validator(dateDependencyValidatorBuilder.build("endDate", true)).build("endDate")

//Option2 Taking name & i18n from DateFieldDefinition
// dateDependencyValidatorBuilder.buildAndAdd(new DateFieldDefinitionBuilder().build("startDate")),
// dateDependencyValidatorBuilder.buildAndAdd(new DateFieldDefinitionBuilder().i18n().build("endDate"))
);
}
```

0 comments on commit 1c291e5

Please sign in to comment.