Skip to content

Commit d15de0e

Browse files
authored
feat: introduce distribute() method (#826)
1 parent d401035 commit d15de0e

7 files changed

+173
-3
lines changed

docs/index.rst

+33
Original file line numberDiff line numberDiff line change
@@ -505,6 +505,39 @@ Sequences help to create different objects in one call:
505505
]
506506
)->create();
507507

508+
Distribute values over a collection
509+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
510+
511+
If you have a collection of values that you want to distribute over a collection, you can use the ``distribute()`` method:
512+
513+
::
514+
515+
// let's say we have 2 categories...
516+
$categories = CategoryFactory::createSequence(
517+
[
518+
['name' => 'category 1'],
519+
['name' => 'category 2'],
520+
]
521+
);
522+
523+
// ...that we want to "distribute" over 2 posts
524+
$posts = PostFactory::new()
525+
->sequence(
526+
[
527+
['name' => 'post 1'],
528+
['name' => 'post 2'],
529+
]
530+
)
531+
532+
// "post 1" will have "category 1" and "post 2" will have "category 2"
533+
->distribute('category', $categories)
534+
535+
// you can even chain "distribute()" methods:
536+
// first post is published today, second post is published tomorrow
537+
->distribute('publishedAt', [new \DateTimeImmutable('today'), new \DateTimeImmutable('tomorrow')])
538+
539+
->create();
540+
508541
Faker
509542
~~~~~
510543

src/Factory.php

+12
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,18 @@ final public function sequence(iterable|callable $sequence): FactoryCollection
131131
return FactoryCollection::sequence($this, $sequence); // @phpstan-ignore return.type
132132
}
133133

134+
/**
135+
* @param list<mixed> $values
136+
*
137+
* @return FactoryCollection<T, static>
138+
*/
139+
final public function distribute(string $field, array $values): FactoryCollection
140+
{
141+
return $this->sequence(
142+
\array_map(fn($value) => [$field => $value], $values)
143+
);
144+
}
145+
134146
/**
135147
* @phpstan-param Attributes $attributes
136148
*

src/FactoryCollection.php

+23
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,29 @@ function(Factory $f) {
164164
);
165165
}
166166

167+
/**
168+
* @param list<mixed> $values
169+
*
170+
* @return self<T, TFactory>
171+
*/
172+
public function distribute(string $field, array $values): self
173+
{
174+
$factories = $this->all();
175+
176+
if (\count($factories) !== \count($values)) {
177+
throw new \InvalidArgumentException('Number of values must match number of factories.');
178+
}
179+
180+
return new self(
181+
$this->factory,
182+
static fn() => \array_map(
183+
static fn(Factory $f, $value) => $f->with([$field => $value]),
184+
$factories,
185+
$values
186+
)
187+
);
188+
}
189+
167190
public function getIterator(): \Traversable
168191
{
169192
return new \ArrayIterator($this->all());
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the zenstruck/foundry package.
5+
*
6+
* (c) Kevin Bond <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Zenstruck\Foundry\Tests\Fixture\Factories;
13+
14+
use Zenstruck\Foundry\ObjectFactory;
15+
use Zenstruck\Foundry\Tests\Fixture\SimpleObject;
16+
17+
/**
18+
* @author Nicolas PHILIPPE <[email protected]>
19+
*
20+
* @extends ObjectFactory<SimpleObject>
21+
*/
22+
final class SimpleObjectFactory extends ObjectFactory
23+
{
24+
public static function class(): string
25+
{
26+
return SimpleObject::class;
27+
}
28+
29+
public function withProps(string $prop1, ?string $prop2 = null): static
30+
{
31+
return $this->with([
32+
'prop1' => $prop1,
33+
'prop2' => $prop2,
34+
]);
35+
}
36+
37+
protected function defaults(): array
38+
{
39+
return [
40+
'prop1' => self::faker()->word(),
41+
];
42+
}
43+
}

tests/Fixture/SimpleObject.php

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the zenstruck/foundry package.
5+
*
6+
* (c) Kevin Bond <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Zenstruck\Foundry\Tests\Fixture;
13+
14+
/**
15+
* @author Nicolas PHILIPPE <[email protected]>
16+
*/
17+
final class SimpleObject
18+
{
19+
public function __construct(
20+
public string $prop1,
21+
public ?string $prop2 = null,
22+
) {
23+
}
24+
}

tests/Integration/Faker/FakerSeedSetFromLegacyConfigKernelTest.php

-3
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,6 @@ final class FakerSeedSetFromLegacyConfigKernelTest extends KernelTestCase
3131
{
3232
use Factories, FakerTestTrait, ResetDatabase;
3333

34-
/**
35-
* @test
36-
*/
3734
#[Test]
3835
#[IgnoreDeprecations]
3936
public function faker_seed_by_configuration_is_deprecated(): void

tests/Unit/ObjectFactoryTest.php

+38
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
use Zenstruck\Foundry\Test\Factories;
2020
use Zenstruck\Foundry\Tests\Fixture\Factories\Object1Factory;
2121
use Zenstruck\Foundry\Tests\Fixture\Factories\Object2Factory;
22+
use Zenstruck\Foundry\Tests\Fixture\Factories\SimpleObjectFactory;
2223
use Zenstruck\Foundry\Tests\Fixture\Object1;
2324

2425
use function Zenstruck\Foundry\factory;
@@ -434,6 +435,43 @@ public function can_use_sequence_with_associative_array(): void
434435
);
435436
}
436437

438+
/**
439+
* @test
440+
*/
441+
#[Test]
442+
public function distribute(): void
443+
{
444+
$objects = SimpleObjectFactory::new()->distribute('prop1', ['foo', 'bar'])->create();
445+
446+
self::assertCount(2, $objects);
447+
self::assertSame('foo', $objects[0]->prop1);
448+
self::assertSame('bar', $objects[1]->prop1);
449+
}
450+
451+
/**
452+
* @test
453+
*/
454+
#[Test]
455+
public function distribute_on_factory_collection(): void
456+
{
457+
$objects = SimpleObjectFactory::new()->many(2)->distribute('prop1', ['foo', 'bar'])->create();
458+
459+
self::assertCount(2, $objects);
460+
self::assertSame('foo', $objects[0]->prop1);
461+
self::assertSame('bar', $objects[1]->prop1);
462+
}
463+
464+
/**
465+
* @test
466+
*/
467+
#[Test]
468+
public function providing_invalid_values_number_to_distribute_throws(): void
469+
{
470+
$this->expectException(\InvalidArgumentException::class);
471+
472+
SimpleObjectFactory::new()->many(2)->distribute('prop1', ['foo']);
473+
}
474+
437475
/**
438476
* @test
439477
*/

0 commit comments

Comments
 (0)