@@ -35,8 +35,9 @@ to load fixtures or inside your tests, [where it has even more features](#using-
3535 8 . [ Instantiation] ( #instantiation )
3636 9 . [ Immutable] ( #immutable )
3737 10 . [ Doctrine Relationships] ( #doctrine-relationships )
38- 11 . [ Anonymous Factories] ( #anonymous-factories )
39- 12 . [ Without Persisting] ( #without-persisting )
38+ 11 . [ Factories as Services] ( #factories-as-services )
39+ 12 . [ Anonymous Factories] ( #anonymous-factories )
40+ 13 . [ Without Persisting] ( #without-persisting )
40414 . [ Using with DoctrineFixturesBundle] ( #using-with-doctrinefixturesbundle )
41425 . [ Using in your Tests] ( #using-in-your-tests )
4243 1 . [ Enable Foundry in your TestCase] ( #enable-foundry-in-your-testcase )
@@ -199,6 +200,13 @@ use Zenstruck\Foundry\Proxy;
199200 */
200201final class PostFactory extends ModelFactory
201202{
203+ public function __construct()
204+ {
205+ parent::__construct();
206+
207+ // TODO inject services if required (https://github.com/zenstruck/foundry#factories-as-services)
208+ }
209+
202210 protected function getDefaults(): array
203211 {
204212 return [
@@ -277,6 +285,9 @@ $posts = PostFactory::randomSet(4); // array containing 4 "Post|Proxy" objects
277285$posts = PostFactory::randomRange(0, 5); // array containing 0-5 "Post|Proxy" objects
278286```
279287
288+ ** WARNING** : Never instantiate your ` ModelFactory ` with the constructor (ie ` new PostFactory() ` ). This will
289+ cause the factory to not be instantiated properly. Always instantiate with ` PostFactory::new() ` .
290+
280291### Reusable Model Factory "States"
281292
282293You can add any methods you want to your model factories (ie static methods that create an object in a certain way) but
@@ -680,6 +691,71 @@ PostFactory::new()->many(3)->create(['tags' => TagFactory::new()->many(3)]);
680691PostFactory::new()->many(3)->create(['tags' => TagFactory::new()->many(0, 3)]);
681692```
682693
694+ ### Factories as Services
695+
696+ If your factories require dependencies, you can define them as a service. The following example demonstrates a very
697+ common use-case: encoding a password with the ` UserPasswordEncoderInterface ` service.
698+
699+ ``` php
700+ // src/Factory/UserFactory.php
701+
702+ namespace App\Story;
703+
704+ use App\Entity\User;
705+ use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
706+ use Zenstruck\Foundry\ModelFactory;
707+
708+ final class UserFactory extends ModelFactory
709+ {
710+ private $passwordEncoder;
711+
712+ public function __construct(UserPasswordEncoderInterface $passwordEncoder)
713+ {
714+ parent::__construct();
715+
716+ $this->passwordEncoder = $passwordEncoder;
717+ }
718+
719+ protected function getDefaults(): array
720+ {
721+ return [
722+ 'email' => self::faker()->unique()->safeEmail,
723+ 'password' => '1234',
724+ ];
725+ }
726+
727+ protected function initialize(): self
728+ {
729+ return $this
730+ ->afterInstantiate(function(User $user) {
731+ $user->setPassword($this->passwordEncoder->encodePassword($user, $user->getPassword()));
732+ })
733+ ;
734+ }
735+
736+ protected static function getClass(): string
737+ {
738+ return User::class;
739+ }
740+ }
741+ ```
742+
743+ If using a standard Symfony Flex app, this will be autowired/autoconfigured. If not, register the service and tag
744+ with ` foundry.factory ` .
745+
746+ Use the factory as normal:
747+
748+ ``` php
749+ UserFactory::new()->create(['password' => 'mypass'])->getPassword(); // "mypass" encoded
750+ UserFactory::new()->create()->getPassword(); // "1234" encoded (because "1234" is set as the default password)
751+ ```
752+
753+ ** NOTES** :
754+ 1 . The provided bundle is required for factories as services.
755+ 2 . If using ` make:factory --test ` , factories will be created in the ` tests/Factory ` directory which is not
756+ autowired/autoconfigured in a standard Symfony Flex app. You will have to manually register these as
757+ services.
758+
683759### Anonymous Factories
684760
685761Foundry can be used to create factories for entities that you don't have model factories for:
@@ -1172,6 +1248,27 @@ these tests to be unnecessarily slow. You can improve the speed by reducing the
11721248 memory_cost: 10 # Lowest possible value for argon
11731249 ```
11741250
1251+ 3 . Pre-encode user passwords with a known value via ` bin/console security:encode-password ` and set this in
1252+ ` ModelFactory::getDefaults() ` . Add the known value as a ` const ` on your factory:
1253+
1254+ ```php
1255+ class UserFactory extends ModelFactory
1256+ {
1257+ public const DEFAULT_PASSWORD = '1234'; // the password used to create the pre-encoded version below
1258+
1259+ protected function getDefaults(): array
1260+ {
1261+ return [
1262+ // ...
1263+ 'password' => '$argon2id$v=19$m=65536,t=4,p=1$pLFF3D2gnvDmxMuuqH4BrA$3vKfv0cw+6EaNspq9btVAYc+jCOqrmWRstInB2fRPeQ',
1264+ ];
1265+ }
1266+ }
1267+ ```
1268+
1269+ Now, in your tests, when you need access to the unencoded password for a user created with `UserFactory`, use
1270+ `UserFactory::DEFAULT_PASSWORD`.
1271+
11751272### Using without the Bundle
11761273
11771274The provided bundle is not strictly required to use Foundry for tests. You can have all your factories, stories, and
@@ -1262,7 +1359,7 @@ PostStory::load(); // does nothing - already loaded
12621359
12631360### Stories as Services
12641361
1265- If you stories require dependencies, you can define them as a service:
1362+ If your stories require dependencies, you can define them as a service:
12661363
12671364``` php
12681365// src/Story/PostStory.php
0 commit comments