Passed
Pull Request — master (#111)
by Wouter
02:00
created

ModelFactory   A

Complexity

Total Complexity 21

Size/Duplication

Total Lines 151
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 21
eloc 36
c 1
b 0
f 0
dl 0
loc 151
rs 10
ccs 33
cts 33
cp 1

12 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 3 1
A initialize() 0 3 1
A randomRange() 0 3 1
A findOrCreate() 0 7 3
A addState() 0 3 1
A random() 0 3 1
A repository() 0 3 1
A randomOrCreate() 0 6 2
A randomSet() 0 3 1
A createOne() 0 3 1
A __callStatic() 0 7 2
A new() 0 28 6
1
<?php
2
3
namespace Zenstruck\Foundry;
4
5
/**
6
 * @template TModel of object
7
 * @template-extends Factory<TModel>
8
 *
9
 * @method static Proxy[]|object[] createMany(int $number, array|callable $attributes = [])
10
 * @psalm-method static list<Proxy<TModel>> createMany(int $number, array|callable $attributes = [])
11
 *
12
 * @author Kevin Bond <[email protected]>
13 604
 */
14
abstract class ModelFactory extends Factory
15 604
{
16 604
    public function __construct()
17
    {
18
        parent::__construct(static::getClass());
19
    }
20
21
    public static function __callStatic(string $name, array $arguments)
22
    {
23
        if ('createMany' !== $name) {
24 611
            throw new \BadMethodCallException(\sprintf('Call to undefined static method "%s::%s".', static::class, __METHOD__));
25
        }
26 611
27 10
        return static::new()->many($arguments[0])->create($arguments[1] ?? []);
28 10
    }
29
30
    /**
31
     * @param array|callable|string $defaultAttributes If string, assumes state
32 611
     * @param string                ...$states         Optionally pass default states (these must be methods on your ObjectFactory with no arguments)
33 16
     *
34 10
     * @return static
35
     */
36
    final public static function new($defaultAttributes = [], string ...$states): self
37
    {
38 604
        if (\is_string($defaultAttributes)) {
39 604
            $states = \array_merge([$defaultAttributes], $states);
40 604
            $defaultAttributes = [];
41
        }
42
43 604
        try {
44 20
            $factory = self::isBooted() ? self::configuration()->factories()->create(static::class) : new static();
45
        } catch (\ArgumentCountError $e) {
46
            throw new \RuntimeException('Model Factories with dependencies (Model Factory services) cannot be created before foundry is booted.', 0, $e);
47 600
        }
48 10
49
        $factory = $factory
50
            ->withAttributes([$factory, 'getDefaults'])
51 600
            ->withAttributes($defaultAttributes)
52
            ->initialize()
53
        ;
54
55
        if (!$factory instanceof static) {
0 ignored issues
show
introduced by
$factory is always a sub-type of static.
Loading history...
56
            throw new \TypeError(\sprintf('"%1$s::initialize()" must return an instance of "%1$s".', static::class));
57
        }
58
59
        foreach ($states as $state) {
60
            $factory = $factory->{$state}();
61
        }
62 10
63
        return $factory;
64 10
    }
65 10
66
    /**
67
     * A shortcut to create a single model without states.
68 10
     *
69
     * @return Proxy|object
70
     *
71
     * @psalm-return Proxy<TModel>
72
     */
73
    final public static function createOne(array $attributes = []): Proxy
74 20
    {
75
        return static::new()->create($attributes);
76 20
    }
77
78
    /**
79
     * Try and find existing object for the given $attributes. If not found,
80
     * instantiate and persist.
81
     *
82 10
     * @return Proxy|object
83
     *
84 10
     * @psalm-return Proxy<TModel>
85
     */
86
    final public static function findOrCreate(array $attributes): Proxy
87
    {
88
        if ($found = static::repository()->find($attributes)) {
89
            return \is_array($found) ? $found[0] : $found;
0 ignored issues
show
introduced by
The condition is_array($found) is always false.
Loading history...
90 10
        }
91
92 10
        return static::new()->create($attributes);
93
    }
94
95
    /**
96 210
     * @see RepositoryProxy::random()
97
     */
98 210
    final public static function random(): Proxy
99
    {
100
        return static::repository()->random();
101
    }
102
103
    /**
104
     * Fetch one random object and create a new object if none exists.
105
     *
106 600
     * @return Proxy|object
107
     *
108 600
     * @psalm-return Proxy<TModel>
109
     */
110
    final public static function randomOrCreate(): Proxy
111
    {
112
        try {
113
            return static::repository()->random();
114
        } catch (\RuntimeException $e) {
115
            return static::new()->create();
116 30
        }
117
    }
118 30
119
    /**
120
     * @see RepositoryProxy::randomSet()
121
     */
122
    final public static function randomSet(int $number): array
123
    {
124
        return static::repository()->randomSet($number);
125
    }
126
127
    /**
128
     * @see RepositoryProxy::randomRange()
129
     */
130
    final public static function randomRange(int $min, int $max): array
131
    {
132
        return static::repository()->randomRange($min, $max);
133
    }
134
135
    /** @psalm-return RepositoryProxy<TModel> */
136
    final public static function repository(): RepositoryProxy
137
    {
138
        return static::configuration()->repositoryFor(static::getClass());
139
    }
140
141
    /**
142
     * Override to add default instantiator and default afterInstantiate/afterPersist events.
143
     *
144
     * @return static
145
     */
146
    protected function initialize()
147
    {
148
        return $this;
149
    }
150
151
    /**
152
     * @param array|callable $attributes
153
     *
154
     * @return static
155
     */
156
    final protected function addState($attributes = []): self
157
    {
158
        return $this->withAttributes($attributes);
159
    }
160
161
    /** @psalm-return class-string<TModel> */
162
    abstract protected static function getClass(): string;
163
164
    abstract protected function getDefaults(): array;
165
}
166