Validating your data fixtures with the Alice Symfony bundle
Published on 2022-10-15 • Modified on 2022-10-15
This post shows how to validate data fixtures with the Alice Symfony bundle before inserting them into the database. It's essential, as you could have invalid data otherwise in the development or test environments. Let's go! 😎
Prerequisite
I will assume you have at least a basic knowledge of Symfony and that you know how to load some fixtures with the hautelook/alice-bundle
.
Configuration
- PHP 8.3
- Symfony 6.4.12
- hautelook/alice-bundle 2.11
The hautelook/alice-bundle
composer reference, in fact, points out to https://github.com/theofidry/AliceBundle, click here to understand why.
Introduction
This is something that may not be obvious. I have used the Alice bundle for a long time, but it is something I wasn't aware of. I realized that when someone asked a question on the #alice-fixtures
channel on the Symfony dev slack. I verified, and yes, he was right; by default, fixtures are not validated. 😮
Goal
The goal is to create a simple processor that checks that each fixture item is valid before inserting it into the database. We will, of course, use the Symfony validator.
The problem
Let's check the problem. Here are the fixtures corresponding to this blog post:
article_224 (extends article):
previous_article: '@article_216'
next_article: '@article_232'
name: 'Validating your data fixtures with the Alice Symfony bundle'
date_published: <date_create('2022-10-15')>
date_modified: <date_create('2022-10-15')>
keyword: 'symfony,fixtures,alice,validation,processor,data'
time_required: 3
stackoverflow_url: https://stackoverflow.com/q/28641360/633864
icon: fad fa-box-check
This fixture item extends the article
template:
App\Entity\Article:
article (template):
#type: !php/const App\DBAL\Types\ArticleType::TYPE_BLOG_POST
type: !php/const App\Enum\ArticleType::BLOG_POST
active: true
author: <{pseudo}>
publisher: '@organization_strangebuzz'
in_language: <{locales_list}>
Now, let's add a constraint to the Author
property of the Article
entity; it's not free text anymore, but it must be an allowed value. We can use the Symfony Choice
constraint for that:
private const array ALLOWED_AUTHORS = ['COil', 'Soyuka', 'Dunglas'];
/**
* The author of this content or rating. Please note that author is special in that HTML 5 provides a special mechanism for indicating authorship via the rel tag. That is equivalent to this and may be used interchangeably.
*/
#[ORM\Column(type: 'text', nullable: false)]
#[Assert\NotBlank]
#[Assert\Choice(choices: self::ALLOWED_AUTHORS, message: '{{ value }} is an invalid value for the author! Allowed values are: {{ choices }}')]
#[Groups(groups: [Article::GROUP_DEFAULT])]
In the fixture, let's put another value than the allowed ones:
article_224 (extends article):
author: foobar
If we reload the fixtures, as expected, there is no error. In the database, we have foobar
in the author field. 😕
The solution ✨
As the bundle is extensible, we can add a processor to do some stuff before and after inserting each fixtures item in the database. Here it is:
<?php
declare(strict_types=1);
namespace App\DataFixtures\Processor;
use App\Entity\Article;
use Fidry\AliceDataFixtures\ProcessorInterface;
use Symfony\Component\Validator\ConstraintViolationList;
use Symfony\Component\Validator\Validator\ValidatorInterface;
final class ArticleProcessor implements ProcessorInterface
{
public function __construct(
private readonly ValidatorInterface $validator,
) {
}
public function preProcess(string $id, object $object): void
{
if (!$object instanceof Article) {
return;
}
/** @var ConstraintViolationList $violations */
$violations = $this->validator->validate($object);
if ($violations->count() > 0) {
$message = \sprintf("Error when validating fixture %s (Article), violation(s) detected:\n%s", $id, $violations);
throw new \DomainException($message);
}
}
public function postProcess(string $id, object $object): void
{
}
}
Thanks to Symfony, this service is auto-configured. If not, you must assign the fidry_alice_data_fixtures.processor
tag to it.
Information for Service "App\DataFixtures\Processor\ArticleProcessor"
=====================================================================
---------------- ---------------------------------------------
Option Value
---------------- ---------------------------------------------
Service ID App\DataFixtures\Processor\ArticleProcessor
Class App\DataFixtures\Processor\ArticleProcessor
Tags fidry_alice_data_fixtures.processor
Public no
Synthetic no
Lazy no
Shared yes
Abstract no
Autowired yes
Autoconfigured yes
---------------- ---------------------------------------------
Some explanations. We modify the preProcess()
function as we want to validate the data before inserting it into the database. The first argument string $id
, is the identifier of the fixture; for this blog post, it is article_224
. The second argument is the entity being processed. In this example, I trigger the validation only if it's an Article
entity, but we could do the same for all our entities. In this case, remove the instanceof
check. Now, let's try to reload the fixtures:
php bin/console doctrine:cache:clear-metadata
php bin/console doctrine:database:create --if-not-exists
php bin/console doctrine:schema:drop --force
php bin/console doctrine:schema:create
php bin/console doctrine:schema:validate
php bin/console hautelook:fixtures:load --no-interaction
In ArticleProcessor.php line 29:
Error when validating fixture article_224 (Article), violation(s) detected:
Object(App\Entity\Article).author:
"foobar" is an invalid value for the author! Allowed values are: "COil", "Soyuka", "Dunglas" (code 8e179f1b-97aa-4560-a02f-2a8b42e49df7)
hautelook:fixtures:load [-b|--bundle [BUNDLE]] [--no-bundles] [-m|--manager MANAGER] [--append] [--shard SHARD] [--purge-with-truncate]
make: *** [load-fixtures] Error 1
Victory, we finally have an error, and the process is stopped (nothing is loaded). We have a nice debug message with the fixture identifier that raises the error and the violations list to fix.
Conclusion
We saw how to validate Alice fixtures with a processor. It was fast to add, but we are sure we won't insert incorrect values in the database. This has a slight performance cost as the validator is called for each fixture, but this is insignificant regarding additional checks being made.
That's it! I hope you like it. Check out the links below to have additional information related to the post. As always, feedback, likes and retweets are welcome. (see the box below) See you! COil. 😊
Read the doc More on Stackoverflow
They gave feedback and helped me to fix errors and typos in this article; many thanks to Laurent . 👍
Call to action
Did you like this post? You can help me back in several ways: (use the Tweet on the right to comment or to contact me )
- Report any error/typo.
- Report something that could be improved.
- Like and retweet!
- Follow me on Twitter Follow me on Twitter
- Subscribe to the RSS feed.
- Click on the More on Stackoverflow buttons to make me win "Announcer" badges 🏅.
Thank you for reading! And see you soon on Strangebuzz! 😉
[🇬🇧] 5th blog post of the year: "Validating your data fixtures with the Alice Symfony bundle" https://t.co/tG9TJrxI3P Proofreading, comments, likes and retweets are welcome! 😉 Annual goal: 5/6 #symfony #alice #data #fixtures #php #validation
— COil #OnEstLaTech ✊ 🇺🇦 (@C0il) October 17, 2022