I'm trying to build a custom validator running as a service (mainly for getting the entity manager).
I followed the doc and some blog posts but can't make it working. I have this error
Catchable Fatal Error: Argument 1 passed to
D\AjaxBundle\Validator\Constraints\SelectTypeValidator::__construct() must implement
interface Doctrine\Common\Persistence\ObjectManager, none given, called in
/AJAX/vendor/symfony/symfony/src/Symfony/Bundle/FrameworkBundle/Validator/ConstraintValidatorFactory.php on line 67 and defined in
/AJAX/src/D/AjaxBundle/Validator/Constraints/SelectTypeValidator.php line 14
services.yml
validator.selectType:
class: D\AjaxBundle\Validator\Constraints\SeletTypeValidator
arguments: ["#doctrine.orm.entity_manager"]
tags:
- { name: validator.selectType, alias: selectType }
SelectTypeValidator:
namespace D\AjaxBundle\Validator\Constraints;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
use Doctrine\Common\Persistence\ObjectManager;
class SelectTypeValidator extends ConstraintValidator
{
private $om;
public function __construct(ObjectManager $om)
{
$this->om = $om;
}
public function validate($value, Constraint $constraint)
{
$fieldOne = $this->om->getRepository('DAjaxBundle:City')->findOneBy(array('id' =>
$value->getId()));
if ($fieldOne == null) {
$this->context->addViolation($constraint->message, array('%string%' => $value->
getId()));
}
}
}
SelectType
namespace D\AjaxBundle\Validator\Constraints;
use Symfony\Component\Validator\Constraint;
class SelectType extends Constraint
{
public $message ='jakis text';
public function validateBy()
{
return 'selectType';
}
}
The service tag name should be validator.constraint_validator instead of validator.selectType
I'm not sure if this'll make a difference but it's worth a try...I never wrap service arguments with quotes:
arguments: [#doctrine.orm.entity_manager]
Related
I want to validate an object with constraint annotations, and use dependencies (entityManager) at the validator.
The validator does not work, if it has dependencies (eg. entityManager) in the constructor.
I followed the docs, but it does not work:
https://symfony.com/doc/current/validation/custom_constraint.html#constraint-validators-with-dependencies
"ClassNotFoundException
Attempted to load class "validator_question_exists" from the global namespace.
Did you forget a "use" statement?"
I try to validate the 'Question' object like this (maybe here is the problem):
$validator = Validation::createValidatorBuilder()
->enableAnnotationMapping()
->getValidator()
;
$question = new Question();
$errors = $validator->validate($question);
Question (the object to validate)
/** #App\Validator\Constraint\Question\QuestionExists() */
class QuestionReadInput{
....
}
services.yaml
services:
validator.unique.question_exists:
class: App\Validator\Constraint\Question\QuestionExistsValidator
tags:
- { name: validator.constraint_validator, alias: validator_question_exists}
Constraint
namespace App\Validator\Constraint\Question;
use Symfony\Component\Validator\Constraint;
/**
* #Annotation
*/
class QuestionExists extends Constraint
{
public $message;
public function getTargets()
{
return self::CLASS_CONSTRAINT;
}
public function validatedBy()
{
//if i delete this function, symfony cant autowire the entitymanager to the validator
//this throws an error, wants to make a new validator_question_exists(), which not exists, because its a service alias, the docs said it should be okay
return 'validator_question_exists';
}
}
Validator
class QuestionExistsValidator extends ConstraintValidator
{
private $entityManager;
public function __construct(EntityManagerInterface $entityManager)
{
$this->entityManager = $entityManager;
}
public function validate($value, Constraint $constraint)
{
die('I dont see this message...');
}
debug:container
Information for Service "validator.unique.question_exists"
---------------- -------------------------------------------------------------------
Option Value
---------------- -------------------------------------------------------------------
Service ID validator.unique.question_exists
Class App\Validator\Constraint\Question\QuestionExistsValidator
Tags validator.constraint_validator (alias: validator_question_exists)
validator.constraint_validator
Public no
Synthetic no
Lazy no
Shared yes
Abstract no
Autowired yes
Autoconfigured yes
If you are declaring the service yourself, then you should also be adding it's arguments:
services:
validator.unique.question_exists:
class: App\Validator\Constraint\Question\QuestionExistsValidator
arguments: ['#doctrine.orm.entity_manager']
tags:
- { name: validator.constraint_validator }
Other than that it should work without any tag aliases or validatedBy method.
Sidenote: for quite a while now in Symfony it's recommended to name (id) your services by the class names, that way auto-wiring could handle your service, and you wouldn't need the class parameter, i.e.:
services:
App\Validator\Constraint\Question\QuestionExistsValidator:
arguments: ['#doctrine.orm.entity_manager']
tags:
- { name: validator.constraint_validator }
I just used the default symfony Validator, as #xabbuh mentioned, and it worked.
__construct(ValidatorInterface $validator){
$question = new Question();
$errors = $validator->validate($question);
}
I should have not create my own validator with Validaton::createValidatorBuilder.
It does not matter if you use this config:
App\Validator\Constraint\Question\QuestionExistsValidator:
tags: ['validator.constraint_validator']
with no validatedBy()
or that:
validator.unique.question_exists:
class: App\Validator\Constraint\Question\QuestionExistsValidator
tags:
- { name: validator.constraint_validator, alias: validator_question_exists}
with:
public function validatedBy() {
return 'validator_question_exists';
}
I'm getting an error with using the Symfony service container. This is the error I'm getting:
Catchable Fatal Error: Argument 3 passed to housesBundle\Model\PropertyDetailsModel::__construct() must be an instance of
housesBundle\Model\AuditModel, instance of sharedBundle\Model\AuditModel given,
called in /var/www/anildave/symfony/app/cache/dev/appDevDebugProjectContainer.php
on line 1876 and defined
500 Internal Server Error - ContextErrorException
services.yml
audit_model_service:
class: sharedBundle\Model\AuditModel
arguments: [#doctrine.dbal.default_connection]
property_details_model_service:
class: housesBundle\Model\PropertyDetailsModel
arguments: [#doctrine.dbal.default_connection,#request_stack,#audit_model_service]
calls:
- [ setContainer, [ #service_container ]]
PropertyDetailsModel.php
namespace housesBundle\Model;
use Doctrine\DBAL\Connection;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use sharedBundle\Model;
use sharedBundle\Helper;
class PropertyDetailsModel extends Controller
{
private $connection;
private $requestStack;
private $auditModel;
public function __construct(Connection $connection, RequestStack $requestStack, AuditModel $auditModel)
{
$this->connection = $connection;
$this->requestStack = $requestStack;
$this->auditModel = $auditModel;
}
I'm not sure what I'm doing wrong.
Thanks
Look at your uses :
use Doctrine\DBAL\Connection;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use sharedBundle\Model;
use sharedBundle\Helper;
use sharedBundle\Model\AuditModel; // <---- Look here, add this
Symfony version: 2.5
Error
"Catchable Fatal Error: Argument 1 passed to Intermedius\UserBundle\Validator\Constraints\RegisteredEmailValidator::__construct() must implement interface Symfony\Component\DependencyInjection\ContainerInterface, none given, called in D:\Projektek\pricing_tool\backend\vendor\symfony\symfony\src\Symfony\Bundle\FrameworkBundle\Validator\ConstraintValidatorFactory.php on line 71 and defined in D:\Projektek\pricing_tool\backend\src\Intermedius\UserBundle\Validator\Constraints\RegisteredEmailValidator.php line 22"
RegisteredEmail.php
class RegisteredEmail extends Constraint
{
public $message = "MSG";
}
RegistereEmailValidator.php
class RegisteredEmailValidator extends ConstraintValidator{
public $containerInterface;
function __construct(ContainerInterface $containerInterface)
{
$this->containerInterface = $containerInterface;
}
public function validate($value, Constraint $constraint)
{
if (!$constraint instanceof RegisteredEmail) {
throw new UnexpectedTypeException($constraint, __NAMESPACE__ . '\RegisteredEmail');
}
}
public function validateBy()
{
return "registered_email";
}
}
services.yml
services:
intermedius.user.validator.registered_email:
class: Intermedius\UserBundle\Validator\Constraints\RegisteredEmail
arguments: [ #service_container ]
tags:
- { name: validator.constraint_validator, alias: registered_email }
The class of your validator service definition should be set to the validator class, not the constraint.
class: Intermedius\UserBundle\Validator\Constraints\RegisteredEmailValidator
You should not inject the service_container in your services. In your example you should rather inject only the services you need instead. See for example the "Avoiding your Code Becoming Dependent on the Container" section of http://symfony.com/doc/current/components/dependency_injection.html.
I'm trying to create a custom validation constraint, this is the relevant code:
ValidCoupon.php
<?php
namespace Bcg\UtilsBundle\Validator\Constraints;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
/**
* #Annotation
*/
class ValidCoupon extends Constraint
{
public function validatedBy()
{
return 'valid_coupon';
}
public $message = 'The coupon is not valid.';
}
class ValidCouponValidator extends ConstraintValidator
{
public function validate($value, Constraint $constraint)
{
var_dump($value);
if (true) {
$this->context->addViolation(
$constraint->message,
array()
);
}
}
}
I call the service in the config.yml like this:
services:
validator.unique.valid_coupon:
class: Bcg\UtilsBundle\Validator\Constraints\ValidCoupon
tags:
- { name: validator.constraint_validator, alias: valid_coupon }
The validation.yml looks like this:
Bcg\UtilsBundle\Entity\Order:
properties:
coupon:
- Bcg\UtilsBundle\Validator\Constraints\ValidCoupon: ~
And the error I get is the following:
Expected argument of type
"Symfony\Component\Validator\ConstraintValidatorInterface",
"Bcg\UtilsBundle\Validator\Constraints\ValidCoupon" given 500 Internal
Server Error - UnexpectedTypeException
Full stack trace here.
I'm pretty stuck, it doesn't seem to find ValidCouponValidator I don't really know how to continue from here, I know that the public function validateBy() is executed, so it should be correctly overridden but it doesn't seem so...
Seems like you have a type in your validator service configuration :
You declare your ValidCoupon class as a validator instead of your ValidCouponValidator (which indeed implements the ConstraintValidatorInterface as the error complains about).
Try this:
services:
validator.unique.valid_coupon:
class: Bcg\UtilsBundle\Validator\Constraints\ValidCouponValidator
tags:
- { name: validator.constraint_validator, alias: valid_coupon }
I am trying to use dependancy injection for a custom validator, in order to be able to use the entityManager.
I followed the Symfony Example: Dependency Injection, but I am allways getting this error message:
FatalErrorException: Error: Class 'isdoi' not found in
/home/milos/workspace/merrin3/vendor/symfony/symfony/src/Symfony/Bundle/FrameworkBundle/Validator/ConstraintValidatorFactory.php
line 68
Here are my classes:
1. The IsDOI class:
<?php
namespace Merrin\MainBundle\Validator\Constraints;
use Symfony\Component\Validator\Constraint;
/**
* #Annotation
*/
class IsDOI extends Constraint
{
public $message_publisher_DOI = 'The Publisher DOI abbreviation does not correspond to the DOI you filled in !';
public $message_journal_DOI = 'No journal found with the DOI you filled in !';
public $journal;
public $doiAbbreviation;
public function validatedBy() {
return "isdoi";
}
public function getTargets()
{
return self::CLASS_CONSTRAINT;
}
}
2. The IsDOIValidator class:
<?php
namespace Merrin\MainBundle\Validator\Constraints;
use Doctrine\ORM\EntityManager;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
class IsDOIValidator extends ConstraintValidator
{
private $entityManager;
public function __construct(EntityManager $entityManager)
{
$this->entityManager = $entityManager;
}
public function validate($value, Constraint $constraint)
{
$em_mdpipub = $this->entityManager('mdpipub');
//Do some tests here...
}
}
3. Service:
merrin.main.validator.isdoi:
class: Merrin\MainBundle\Validator\Constraints\IsDOIValidator
arguments:
entityManager: "#doctrine.orm.entity_manager"
Where am I wrong? Thank you for your help.
You have wrong service file, when You add tags and alias you could use "isdoi" name
merrin.main.validator.isdoi:
class: Merrin\MainBundle\Validator\Constraints\IsDOIValidator
arguments:
entityManager: "#doctrine.orm.entity_manager"
tags:
- { name: validator.constraint_validator, alias: isdoi }
You're telling Symfony2 that the validator class for your constraint is isdoi (validateBy method). However, your validator is IsDOIValidator.
You must use :
public function validateBy()
{
return "IsDOIValidator";
}
However, if your Constraint class name is IsDOI, Symfony will automatically look for IsDOIValidator as a ConstraintValidator. The default behavior for validateBy is to append "Validator" to the constraint name, and look for the class with this name. So if you do not overload validateBy, Symfony2 will automatically search for IsDOIValidator.