Symfony2/Doctrine - validation constraint which requires access to a database - doctrine

I have an entity ArticlePattern, which has a property pattern (string). I need to access the database to check if pattern is correct. So I would like to define a method ArticlePattern::isPatternValid() and add a constraint (using Doctrine's annotation) which would check if isPatternValid is true during validation by Validator object.
From what I have read here and there it is not a good idea, to make an entity depended on service container, which mean I cannot access the doctrine service from inside ArticlePattern::isPatternValid().
So how can I make a custom validation constraint which need an access to the database? How do you deal with such situations which I think is very common seeing so many questions about accessing a service container from an entity class.
EDIT:
Ok, thanks guys, so the answer is a Custom Validation Constraint

A validator object can be:
A simple object, that has no connection to the framework environment at all.
A service (in the context of dependency injection container) which could do absolutley anything as long as it impements Symfony\Component\Validator\ConstraintValidatorInterface
So what do you have to do?
Define a simple constraint
Override validatedBy() method to return validator "name" (return 'my_validator';)
Define a simple service in DIC:
<service id="project.validator.my" class="Project\Constraints\MyValidator">
<!-- service definition here -->
<!-- the service has to be tagged -->
<tag name="validator.constraint_validator" alias="my_validator" />
</service>
EDIT
You've asked about multiple properties validation. In such a case you could create a validator that is related to the object rather to the property of the object.
In your constraint class define the target of that constraint (property / class):
class MyConstraint ... {
...
public function targets() {
return self::CLASS_CONSTRAINT;
}
}
Annotate validated class instead of property:
#Assert/MyConstraint(...)
class MyClass {
private $firstName;
private $lastName;
#Assert/Email
private $email;
...
}
The validator itself looks pretty much the same as in case of validating a property:
class MyValidator extends ConstraintValidator {
public function isValid($value, Constraint $constraint) {
// $value is an object rather a property
}
}

Your constraint should override the base validatedBy() method and return the id of the constraint validator service in your container.
public function validatedBy()
{
return 'my_pattern_validator';
}

Related

Access to Actual Class Variable from SpEL

As per spring's Event handling mechanism, we can use SpEL to select a specific handler under some circumstances. Taken from the spring doc.
public class EventXHandler {
private String handlerClassName;
#EventListener(condition = "#event.name == handlerClassName")
public void processBlockedListEvent(BlockedListEvent event) {
// notify appropriate parties via notificationAddress...
}
}
My question is; if I can access to the handler class' property in the spel.
No; you cannot do that.
If you know the bean name and add a public getter for the property, you can use
#event.name == #beanName.handlerClassName.

spring security : Why can't we access Hibernate entitiy parameters in #PreAuthorize?

I have the following interface method on which I am applying #PreAuthorize :
#PreAuthorize("doSomething(#user.id)")
void something(User user, List<User> accessList);
where User is a Hibernate entity object. It gives me an error :
org.springframework.expression.spel.SpelEvaluationException:
EL1007E:(pos 13): Field or property 'id' cannot be found on null at
org.springframework.expression.spel.ast.PropertyOrFieldReference.readProperty(PropertyOrFieldReference.java:204)
There is no way that the user parameter is null, as if I remove the annotation, and inspect the value of user in the method that implements this interface method, there is a valid User object present there. Additionally, just before calling this method, I have made sure that the user object is correctly constructed.
I really can't figure out why would the user field be considered null by the SPEL parser
You can check with the debugger what's going on in MethodSecurityEvaluationContext, inside Object lookupVariable(String name) method:
#Override
public Object lookupVariable(String name) {
Object variable = super.lookupVariable(name);
if (variable != null) {
return variable;
}
if (!argumentsAdded) {
addArgumentsAsVariables();
argumentsAdded = true;
}
and so you can see what's really going on in the addArgumentsAsVariables() method as the convertion of method arguments to SPEL variables is implemented very clearly in Spring.
Spring Security has a better answer for this problem now:
http://docs.spring.io/spring-security/site/docs/3.2.5.RELEASE/reference/htmlsingle/#access-control-using-preauthorize-and-postauthorize
Basically, you can use the #P annotation or #Param annotation if you are using < JDK 8.
You can check LazyParamAwareEvaluationContext,inside loadArgsAsVariables() method, version 3.1.0.
The same key for different Entity, because of implementing interface.
I need to add something to this as the title indicates that we cannot access hibernate properties.
There are two editions of hasPermission, the loaded object and the serialized object. Here is some code from a test case:
#PreAuthorize("isAuthenticated() and hasPermission(#organization, 'edit')")
public long protectedMethod(Organization organization)
{
return organization.getId();
}
And for the latter here we see that we can infact access the id proprty of the organization (which is a hibernate entity):
#PreAuthorize("isAuthenticated() and hasPermission(#organization.getId(), 'organization', 'edit')")
public long protectedMethodSerializableEdtion(Organization organization)
{
return organization.getId();
}

ASP.NET MVC 3: Validating model when information external to the model is required

What's a good way to validate a model when information external to the model is required in order for the validation to take place? For example, consider the following model:
public class Rating {
public string Comment { get; set; }
public int RatingLevel { get; set; }
}
The system administrator can then set the RatingLevels for which a comment is required. These settings are available through a settings service.
So, in order to fully validate the model I need information external to it, in this case the settings service.
I've considered the following so far:
Inject the service into the model. The DefaultModelBinder uses System.Activator to create the object so it doesn't go through the normal dependency resolver and I can't inject the service into the model without creating a new model binder (besides which, that doesn't feel like the correct way to go about it).
Inject the service into an annotation. I'm not yet sure this is possible but will investigate further soon. It still feels clumsy.
Use a custom model binder. Apparently I can implement OnPropertyValidating to do custom property validation. This seems the most preferable so far though I'm not yet sure how to do it.
Which method, above or not, is best suited to this type of validation problem?
Option 1 doesn't fit. The only way it would work would be to pull in the dependency via the service locator anti-pattern.
Option 2 doesn't work. Although I couldn't see how this was possible because of the C# attribute requirements, it is possible. See the following for references:
Resolving IoC Container Services for Validation Attributes in ASP.NET MVC
NInjectDataAnnotationsModelValidatorProvider
Option 3: I didn't know about this earlier, but what appears to be a very powerful way to write validators is to use the ModelValidator class and a corresponding ModelValidatorProvider.
First, you create your custom ModelValidatorProvider:
public class CustomModelValidatorProvider : ModelValidatorProvider
{
public CustomModelValidatorProvider(/* Your dependencies */) {}
public override IEnumerable<ModelValidator> GetValidators(ModelMetadata metadata, ControllerContext context)
{
if (metadata.ModelType == typeof(YourModel))
{
yield return new YourModelValidator(...);
}
}
}
ASP.NET MVC's IDependencyResolver will attempt to resolve the above provider, so as long as it's registered with your IoC container you won't need to do anything else. And then the ModelValidator:
public class EntryRatingViewModelValidatorMvcAdapter : ModelValidator
{
public EntryRatingViewModelValidatorMvcAdapter(
ModelMetadata argMetadata,
ControllerContext argContext)
: base(argMetadata, argContext)
{
_validator = validator;
}
public override IEnumerable<ModelValidationResult> Validate(object container)
{
if (/* error condition */)
{
yield return new ModelValidationResult
{
MemberName = "Model.Member",
Message = "Rating is required."
};
}
}
}
As the provider is retrieved through the IDependencyResolver and the provider has full control over the returned ModelValidators I was easily able to inject the dependencies and perform necessary validation.
You could try fluent validation. It supports asp.net mvc and DI so you can inject external services into your validators.
Assuming that you want both client and server-side validation of the model based upon the values returned from the service, I would opt for 2., Inject the service into an annotation.
I give some sample code in my response to this question about adding validators to a model. The only additional step in your case is that you will need to inject your service into your class inheriting from DataAnnotationsModelValidatorProvider.
What about just simply using IValidateableObject and in that method determine if validation is appropriate or not and setting the errors there?
How do I use IValidatableObject?

JSR-303 bean validation with Spring and iBatis

Is it possible with JSR-303 bean validation to write a custom annotation that can talk to a back end service?
We accomplished this type of validation with the "old school" Spring validators. In that case, the validator was a Spring bean and could have other services injected into it. Then that validator is injected into the controller.
An example might be an annotation (perhaps #EmailExists) to verify if an email already exists. I can only do this with a SQL query using one of our services. I would prefer to "validate" this alongside the other annotations and check it as soon as possible and not have to explicity do it in a back end service.
NOTE: We are using iBatis/MyBatis so I can't use any JPA/Hibernate tricks :-)
thanks!
That's definitely possible. Spring provides dependency injection support also within constraint validators. So you can simply inject any required services in your custom validators like this:
public class EmailExistsValidator implements ConstraintValidator<EmailExists, String> {
#Inject
private EmailValidationService service;
#Override
public void initialize(EmailExists constraintAnnotation) {}
#Override
public boolean isValid(String value, ConstraintValidatorContext context) {
if (value == null) {
return true;
}
return service.exists(value);
}
}
Depending on your concrete scenario it might be a good idea to first check "cheap" constraints such as #NotNull and only if these constraints are valid check more expensive constraints such as #EmailExists.
You can do this with help of group sequences and a redefined default group sequence for your type.

How to perform duplicate key validation using entlib (or DataAnnotations), MVC, and Repository pattern

I have a set of ASP.NET 4 projects that culminate in an MVC (3 RC2) app. The solution uses Unity and EntLib Validation for cross-cutting dependency injection and validation. Both are working great for injecting repository and service layer implementations.
However, I can't figure out how to do duplicate key validation. For example, when a user registers, we want to make sure they don't pick a UserID that someone else is already using. For this type of validation, the validating object must have a repository reference... or some other way to get an IQueryable / IEnumerable reference to check against other rows already in the DB.
What I have is a UserMetadata class that has all of the property setters and getters for a user, along with all of the appropriate DataAnnotations and EntLib Validation attributes. There is also a UserEntity class implemented using EF4 POCO Entity Generator templates. The UserEntity depends on UserMetadata, because it has a MetadataTypeAttribute. I also have a UserViewModel class that has the same exact MetadataType attribute. This way, I can apply the same validation rules, via attributes, to both the entity and viewmodel.
There are no concrete references to the Repository classes whatsoever. All repositories are injected using Unity. There is also a service layer that gets dependency injection. In the MVC project, service layer implementation classes are injected into the Controller classes (the controller classes only contain service layer interface references). Unity then injects the Repository implementations into the service layer classes (service classes also only contain interface references).
I've experimented with the DataAnnotations CustomValidationAttribute in the metadata class. The problem with this is the validation method must be static, and the method cannot instantiate a repository implementation directly. My repository interface is IRepository<T>, and I have only one single repository implementation class defined as EntityRepository<T> for all domain objects. To instantiate a repository explicitly I would need to say new EntityRepository<UserEntity>(), which would result in a circular dependency graph: UserMetadata [depends on] DuplicateUserIDValidator [depends on] UserEntity [depends on] UserMetadata.
I've also tried creating a custom EntLib Validator<T> along with a custom validation attribute. Here I don't have the same problem with a static method. I think I could get this to work if I could just figure out how to make Unity inject my EntityRepository into the validator class... which I can't. Right now, all of the validation code is in my Metadata class library, since that's where the custom validation attribute would go.
Any ideas on how to perform validations that need to check against the current repository state? Can Unity be used to inject a dependency into a lower-layer class library?
Do it in the database. That's the only solution which can be truly multi-user safe.
I found a solution, still not sure if it's the best one. Seems kind of like brute force to me.
The first thing I did was combine my Metadata classes into the same project / library as my Entity classes. Since my repository interface is IRepository<T>, the repository needed to be declared as IRepository<UserEntity>. This resolved the circular dependency I was talking about. Now I have UserEntity [depends on] UserMetadata [depends on] DuplicateUserValidationAttribute [depends on] DuplicateUserValidator [depends on] UserEntity. With all of these classes in the same library, though there is still circularity, there are no circular assembly dependencies.
The second thing I did was wrap my IUnityContainer into a singleton and moved it to my cross-cutting utilities library (before it existed only in the MVC 3 project).
Then, in my DuplicateUserValidator constructor, I could do the following:
public class DuplicateUserValidator : Micrsoft.Practices.EnterpriseLibrary.Validation.Validator<string>
{
public IRepository<UserEntity> UserRepository { get; set; }
public DuplicateUserValidator(string tag)
: base(string.Empty, tag)
{
IUnityContainer unity = UnityContainerSingleton.Get();
this.UserRepository = unity.Resolve<IRepository<UserEntity>>() as IRepository<UserEntity>;
}
}
Now I have a repository dependency injected into the custom entlib validator implementation. Wish I could get unity to automatically inject it into the constructor, maybe I'll look into that next.
Okay, I found a better solution that lets me use my previous library architecture.
I was able to keep the UserMetadata class in a separate library from UserEntity. Here is what the dependency graph looks like:
UserMetadata [depends on] DuplicateUserValidationAttribute [depends on] IDuplicateUserValidator
The actual DuplicateUserValidator implementation class is in my service layer, and looks something like this:
public class DuplicateUserValidator : Validator<string>, IDuplicateUserValidator
{
public DuplicateUserValidator()
: base(null, null)
{
}
[Dependency]
public IRepository<UserEntity> UserRepository { get; set; }
protected override string DefaultMessageTemplate
{
get { throw new NotImplementedException(); }
}
protected override void DoValidate(string stringToValidate, object currentTarget, string key, ValidationResults validationResults)
{
if (this.UserRepository == null)
throw new InvalidOperationException("This should not happen");
// actual code to perform validation...
}
}
The trick is getting the DuplicateUserValidatorAttribute to not depend on DuplicateUserValidator:
public class DuplicateUserValidatorAttribute : ValidatorAttribute
{
protected override Validator DoCreateValidator(Type targetType)
{
var validator = Unity.Container.Resolve<IDuplicateUserValidator>() as Validator;
validator.Tag = Tag;
validator.MessageTemplate = GetMessageTemplate();
return validator;
}
}
All I needed to do from there was add a mapping to the unity config. When the singleton resolves the IDuplicateUserValidator, it injects my implementation class from the service layer, honoring the [Dependency] attribute on the UserRepository property.

Resources