Chapters
48 Chapters
|
5:13:28
|
Login to bookmark this video
-
Course Code
Subscribe to download the code!
Subscribe to download the code!
-
This Video
Subscribe to download the video!
Subscribe to download the video!
-
Subtitles
Subscribe to download the subtitles!
Subscribe to download the subtitles!
-
Course Script
Subscribe to download the script!
Subscribe to download the script!
07.
Validating Who/When Can Publish
Scroll down to the script below, click on any sentence (including terminal blocks) to jump to that spot in the video!
Subscribe to jump to this part in the video!
Keep on Learning!
If you liked what you've learned so far, dive in! Subscribe to get access to this tutorial plus video, code and script downloads.
This tutorial also works great with API Platform 2.6.
What PHP libraries does this tutorial use?
// composer.json
{
"require": {
"php": ">=8.2",
"ext-ctype": "*",
"ext-iconv": "*",
"api-platform/core": "^2.1", // v2.5.10
"composer/package-versions-deprecated": "^1.11", // 1.11.99
"doctrine/annotations": "^1.0", // 1.12.1
"doctrine/doctrine-bundle": "^2.0", // 2.1.2
"doctrine/doctrine-migrations-bundle": "^3.0", // 3.0.2
"doctrine/orm": "^2.4.5", // 2.8.2
"nelmio/cors-bundle": "^2.1", // 2.1.0
"nesbot/carbon": "^2.17", // 2.39.1
"phpdocumentor/reflection-docblock": "^3.0 || ^4.0 || ^5.0", // 5.2.2
"ramsey/uuid-doctrine": "^1.6", // 1.6.0
"symfony/asset": "5.1.*", // v5.1.5
"symfony/console": "5.1.*", // v5.1.5
"symfony/debug-bundle": "5.1.*", // v5.1.5
"symfony/dotenv": "5.1.*", // v5.1.5
"symfony/expression-language": "5.1.*", // v5.1.5
"symfony/flex": "^1.1", // v1.21.6
"symfony/framework-bundle": "5.1.*", // v5.1.5
"symfony/http-client": "5.1.*", // v5.1.5
"symfony/monolog-bundle": "^3.4", // v3.5.0
"symfony/security-bundle": "5.1.*", // v5.1.5
"symfony/twig-bundle": "5.1.*", // v5.1.5
"symfony/validator": "5.1.*", // v5.1.5
"symfony/webpack-encore-bundle": "^1.6", // v1.8.0
"symfony/yaml": "5.1.*" // v5.1.5
},
"require-dev": {
"doctrine/doctrine-fixtures-bundle": "^3.3", // 3.3.2
"symfony/browser-kit": "5.1.*", // v5.1.5
"symfony/css-selector": "5.1.*", // v5.1.5
"symfony/maker-bundle": "^1.11", // v1.23.0
"symfony/phpunit-bridge": "5.1.*", // v5.1.5
"symfony/stopwatch": "5.1.*", // v5.1.5
"symfony/twig-bundle": "5.1.*", // v5.1.5
"symfony/web-profiler-bundle": "5.1.*", // v5.1.5
"zenstruck/foundry": "^1.1" // v1.8.0
}
}
7 Comments
How can I add a custom ConstraintValidatorFactory or replace the default ConstraintValidatorFactory?
I have ConstraintValidator which needs a Service injected.
But this works not with the default implementation of ConstraintValidatorFactory
Hey M_Holstein!
Sorry for the slow reply. The "constraint validation" classes are services, so you should be able to add a constructor and autowire services into it like normal. If you're seeing something different, then something isn't quite right...
Cheers!
Thanks for the reply.
Yes, our Code works with a new instance of ValidatorBuilder what I've seen later.
<br />$validatorBuilder = new ValidatorBuilder();<br />This was why the classes not worked as expected.
But we have now a own Factory to be more flexible and set them to the ValidatorBuilder
`
public function initValidator(ObjectMetadataFactory $metadataFactory, ConstraintValidatorFactory $constraintValidatorFactory)
{
}
`
We need custom Validators for different properties and special logic to get the instance of the ConstraintValidator that's why we need custom getInstance() method of the factory.
Regards
Mark
Hey M_Holstein!
> $validatorBuilder = new ValidatorBuilder();
Hmm, you have this code? Are you using the the Symfony Framework or API Platform in a custom application (with no framework)? I'm asking because, in the Symfony Framework, you are not responsible for instantiating the ValidatorBuilder: it's already a service in the container and it's passed a ConstraintValidatorFactory instance that's able to load custom ConstraintValidators from the service container. So, are you outside of Symfony? If not, what's the reason for instantiating the validator builder manually?
Cheers!
weaverryan , yes we have this in a Symfony bundle.
We need to set Metadatafactory and ConstraintValidatorFactory . If we do this in the ValidatorBuilder Service, we became errors like this
<br />Symfony\Component\Validator\Exception\ValidatorException : You cannot enable annotation mapping after setting a custom metadata factory. Configure your metadata factory instead.<br />If the metadata factory was once set in the ValidatorBuilder object, no other setter of the object can be used.
I didn't understand the message <b>Configure your metadata factory instead.</b> fully.
How and where could I do this?
We also can not used annotations for the constraints, because we only know after instantiating the object what kind of validation we need. For example: Assert\Count it can be 1 or 3 or 5.
I have no way found how to change this on a Object. Only on classes.
You have to know, that we have have a entity that can be everything.
A Car, a bike, a plane, picture data. Everything. :-)
These are made by dynamic amount of attributes via a attributes entity.
So that`s why we like to have a service that can check this object against Constraint dynamic.
Regards
Mark
Hey M_Holstein!
Ah... I understand much better now! In general, if you're going to try to create the validator manually, you're probably going to run into limitations. So the "ideal" answer is to try to extend the existing service, without totally replacing it.
You mentioned you're doing this because you need to set a custom MetadataFactory and a custom ConstraintValidationFactory. I've never had to do either of these, but let's see what we can discover:
<b>MetadataFactory</b>
This class is created inside the normal ValidatorBuilder service automatically. Basically, if someone calls getValidator() and the setMetadataFactory() has not been called yet (and I'm 95% sure that it is NOT called by default in Symfony_, then it will be created automatically.
However, I'm not sure that you really need to REPLACE the metadata factory. There is already a mechanism in the ValidatorBuilder to extend the metadata factory: by creating a "loader" class and calling ->addLoader() on the ValidatorBuilder.
I don't think there is a built-in way to do this. So the process would be:
A) Create a class that loads your custom metadata and make it implement LoaderInterface (here is an example: https://github.com/symfony/symfony/blob/6821b55341c6444b45bf3eeebdffe9a0669daa66/src/Symfony/Component/Validator/Mapping/Loader/StaticMethodLoader.php#L22 ).
B) Create a compiler pass - https://symfony.com/doc/current/service_container/compiler_passes.html - where you fetch the
validator.builderservice definition and then add a "call" to it to call setLoader() and pass in your new service. The logic would look something like:<b>ConstraintValidationFactory</b>
The default ConstraintValidationFactory is the
validator.validator_factory. Instead of replacing this, I would decorate it using service decoration - https://symfony.com/doc/current/service_container/service_decoration.htmlSo, you would create a new class that implements
ConstraintValidatorFactoryInterface, add your custom logic, and call the "inner" constraint validation factory for the "normal" functionality. Then wire the service decoration in services.yaml. The result will be that Symfony will start using YOUR custom ConstraintValidatorFactoryInterface service, and will pass you the normal, core one.I hope this helps!
weaverryan thank you very much for this.
I think this will improve our code a lot. :)
I will definitely try this.
Validator and constraints and the customization of this are a very complicated topic. ;)
Thx again.
Regards
Mark
"Houston: no signs of life"
Start the conversation!