
Crédit: Yannick (Rêveries)
Introduction
In my Symfony 5.3 (and upwards) projects, to enable some data in my tables for raw development and for the testing, I use Hautelook/Alice Bundle. It is a great tool to load fixtures in the database. It is very easy to use and very powerful. It is a must-have for me in my projects.
Problem
One of the elements that I want to be able to fake are users. Unfortunately, I didn’t find any direct way using the bundle pre-existing features to load hashed passwords. Meaning, there is no faker function to hash any string based on the defined Symfony User Password hashing (cfr. Symfony Security Definition)
So, I could to the following:
- I could use plain passwords. I’m only in dev and test, but the issue is that during the testing, I’ll try to connect and I’ll fall against the Security wall where Symfony will try to hash my input password against the stored password and so will fail
- could define it by hand in the fixtures.yaml file of Hautelook/Alice. It could work regarding the above issue, but I would have to lok at it by hand (there is console command to do that…) and I do want to find a structural way to do it
- I could use the Custom Faker Providers functionality of Alice bundle. That’s what I’m describing below
I'll dive into the option 3 below as It’s quite easy actually, you only need to follow the following Custom Faker Provider page.
Implementation
1. Create a new Provider
So le'ts create a HashPasswordProvider.php file in the src/DataFixtures/Provider folder of your project.
1<?php
2
3<?php
4
5namespace App\DataFixtures\Providers;
6
7use App\Entity\User;
8use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
9
10class HashPasswordProvider
11{
12 /**
13 * @var UserPasswordHasherInterface
14 */
15 private $hasher;
16 public function __construct(UserPasswordHasherInterface $hasher)
17 {
18 $this->hasher = $hasher;
19 }
20
21 public function hashPassword(string $plainPassword): string
22 {
23 return $this->hasher->hashPassword(new User(), $plainPassword);
24 }
25
26}
Let’s break down the different elements:
- to be able to hash a password, you need to know which hashing algorithm is defined for the application. Fortunately, the following interface : UserPasswordHasherInterface will provide you the access to that knowledge
So, let’s inject it into our Class to benefit from it
1/**
2 * @var UserPasswordHasherInterface
3 */
4 private $hasher;
5 public function __construct(UserPasswordHasherInterface $hasher)
6 {
7 $this->hasher = $hasher;
8 }
- then, simply define a public function that will take the necessary input (here a plain password) and returns the hashed password using the UserPasswordHasher injected service
1public function hashPassword(string $plainPassword): string
2 {
3 return $this->hasher->hashPassword(new User(), $plainPassword);
4 }
2. Register the Provider as a Service
After that, you need to define your new Custom Provider as a service tagging him for the Hautelook/Alice bundle to recognize it as a Custom data Provider
1# config/services.yaml
2
3services:
4 App\DataFixtures\Providers\HashPasswordProvider:
5 tags: [{ name: nelmio_alice.faker.provider }]
3. Use the Custom Provider in the fixtures.yaml file
Eventually, you can use it in your fixtures.yaml file
1//fixtures\User.yaml
2App\Entity\User:
3 user_{1..10}:
4 email: <email()>
5 password: <hashPassword('plainPassword')>
It's as simple as that.