Passed
Push — master ( 6001e7...112d57 )
by Kevin
02:54
created

ModelFactory::getEntityClass()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
eloc 1
c 0
b 0
f 0
dl 0
loc 3
ccs 0
cts 0
cp 0
rs 10
cc 1
nc 1
nop 0
crap 2
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, $name));
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::first()
97
     *
98 210
     * @throws \RuntimeException If no entities exist
99
     */
100
    final public static function first(string $sortedField = 'id'): Proxy
101
    {
102
        if (null === $proxy = static::repository()->first($sortedField)) {
103
            throw new \RuntimeException(\sprintf('No "%s" objects persisted.', static::getClass()));
104
        }
105
106 600
        return $proxy;
107
    }
108 600
109
    /**
110
     * @see RepositoryProxy::last()
111
     *
112
     * @throws \RuntimeException If no entities exist
113
     */
114
    final public static function last(string $sortedField = 'id'): Proxy
115
    {
116 30
        if (null === $proxy = static::repository()->last($sortedField)) {
117
            throw new \RuntimeException(\sprintf('No "%s" objects persisted.', static::getClass()));
118 30
        }
119
120
        return $proxy;
121
    }
122
123
    /**
124
     * @see RepositoryProxy::random()
125
     */
126
    final public static function random(array $attributes = []): Proxy
127
    {
128
        return static::repository()->random($attributes);
129
    }
130
131
    /**
132
     * Fetch one random object and create a new object if none exists.
133
     *
134
     * @return Proxy|object
135
     *
136
     * @psalm-return Proxy<TModel>
137
     */
138
    final public static function randomOrCreate(array $attributes = []): Proxy
139
    {
140
        try {
141
            return static::repository()->random($attributes);
142
        } catch (\RuntimeException $e) {
143
            return static::new()->create($attributes);
144
        }
145
    }
146
147
    /**
148
     * @see RepositoryProxy::randomSet()
149
     */
150
    final public static function randomSet(int $number, array $attributes = []): array
151
    {
152
        return static::repository()->randomSet($number, $attributes);
153
    }
154
155
    /**
156
     * @see RepositoryProxy::randomRange()
157
     */
158
    final public static function randomRange(int $min, int $max, array $attributes = []): array
159
    {
160
        return static::repository()->randomRange($min, $max, $attributes);
161
    }
162
163
    /**
164
     * @see RepositoryProxy::count()
165
     */
166
    final public static function count(): int
167
    {
168
        return static::repository()->count();
169
    }
170
171
    /**
172
     * @see RepositoryProxy::truncate()
173
     */
174
    final public static function truncate(): void
175
    {
176
        static::repository()->truncate();
177
    }
178
179
    /**
180
     * @see RepositoryProxy::findAll()
181
     */
182
    final public static function all(): array
183
    {
184
        return static::repository()->findAll();
185
    }
186
187
    /**
188
     * @see RepositoryProxy::find()
189
     *
190
     * @throws \RuntimeException If no entity found
191
     */
192
    final public static function find($criteria): Proxy
193
    {
194
        if (null === $proxy = static::repository()->find($criteria)) {
195
            throw new \RuntimeException(\sprintf('Could not find "%s" object.', static::getClass()));
196
        }
197
198
        return $proxy;
199
    }
200
201
    /**
202
     * @see RepositoryProxy::findBy()
203
     */
204
    final public static function findBy(array $attributes): array
205
    {
206
        return static::repository()->findBy($attributes);
207
    }
208
209
    final public static function assert(): RepositoryAssertions
210
    {
211
        return static::repository()->assert();
212
    }
213
214
    /**
215
     * @psalm-return RepositoryProxy<TModel>
216
     */
217
    final public static function repository(): RepositoryProxy
218
    {
219
        return static::configuration()->repositoryFor(static::getClass());
220
    }
221
222
    /**
223
     * @internal
224
     * @psalm-return class-string<TModel>
225
     */
226
    final public static function getEntityClass(): string
227
    {
228
        return static::getClass();
229
    }
230
231
    /** @psalm-return class-string<TModel> */
232
    abstract protected static function getClass(): string;
233
234
    /**
235
     * Override to add default instantiator and default afterInstantiate/afterPersist events.
236
     *
237
     * @return static
238
     */
239
    protected function initialize()
240
    {
241
        return $this;
242
    }
243
244
    /**
245
     * @param array|callable $attributes
246
     *
247
     * @return static
248
     */
249
    final protected function addState($attributes = []): self
250
    {
251
        return $this->withAttributes($attributes);
252
    }
253
254
    abstract protected function getDefaults(): array;
255
}
256