Skip to content

Commit b9b5aae

Browse files
mjauvinLukeTowers
andauthored
Improve support for Factories (#201)
Co-authored-by: Luke Towers <[email protected]>
1 parent 91eaa7b commit b9b5aae

File tree

3 files changed

+111
-0
lines changed

3 files changed

+111
-0
lines changed

src/Database/Factories/Factory.php

+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
<?php
2+
3+
namespace Winter\Storm\Database\Factories;
4+
5+
use Illuminate\Database\Eloquent\Factories\Factory as BaseFactory;
6+
use Illuminate\Support\Str;
7+
8+
/**
9+
* @template TModel of \Winter\Storm\Database\Model
10+
*
11+
* @method $this trashed()
12+
*/
13+
abstract class Factory extends BaseFactory
14+
{
15+
/**
16+
* Get the factory name for the given model name.
17+
*
18+
* @param class-string<\Winter\Storm\Database\Model> $modelName
19+
* @return class-string<\Winter\Storm\Database\Factories\Factory>
20+
*/
21+
public static function resolveFactoryName(string $modelName)
22+
{
23+
if (Str::contains($modelName, 'Models\\')) {
24+
$baseNamespace = trim(Str::before($modelName, 'Models'), '\\');
25+
$modelClassName = trim(Str::after($modelName, 'Models'), '\\');
26+
} else {
27+
$baseNamespace = '';
28+
$modelClassName = $modelName;
29+
}
30+
31+
return trim(implode('\\', [
32+
$baseNamespace,
33+
trim(static::$namespace, '\\'),
34+
$modelClassName.'Factory'
35+
]), '\\');
36+
}
37+
38+
/**
39+
* Get the name of the model that is generated by the factory.
40+
*
41+
* @return class-string<\Illuminate\Database\Eloquent\Model|TModel>
42+
*/
43+
public function modelName()
44+
{
45+
// @phpstan-ignore-next-line
46+
$resolver = static::$modelNameResolver ?? function (self $factory) {
47+
$baseNamespace = join("\\", array_slice(
48+
explode("\\", Str::replaceFirst(static::$namespace, '', get_class($factory))),
49+
0,
50+
-1
51+
));
52+
$factoryBasename = Str::replaceLast('Factory', '', class_basename($factory));
53+
54+
$guessedClass = $baseNamespace . '\\Models\\' . $factoryBasename;
55+
56+
return class_exists($guessedClass) ? $guessedClass : parent::modelName();
57+
};
58+
59+
// @phpstan-ignore-next-line
60+
return $this->model ?? $resolver($this);
61+
}
62+
}

src/Database/Factories/HasFactory.php

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
namespace Winter\Storm\Database\Factories;
4+
5+
trait HasFactory
6+
{
7+
/**
8+
* Get a new factory instance for the model.
9+
*/
10+
public static function factory(callable|array|int|null $count = null, callable|array $state = []): Factory
11+
{
12+
$factory = static::newFactory() ?: Factory::factoryForModel(get_called_class());
13+
14+
return $factory
15+
->count(is_numeric($count) ? $count : null)
16+
->state(is_callable($count) || is_array($count) ? $count : $state);
17+
}
18+
19+
/**
20+
* Create a new factory instance for the model.
21+
*
22+
* @return \Winter\Storm\Database\Factories\Factory<static>
23+
*/
24+
protected static function newFactory()
25+
{
26+
//
27+
}
28+
}
+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
3+
use Winter\Storm\Database\Factories\Factory;
4+
5+
class FactoryTest extends TestCase
6+
{
7+
public function testResolveFactoryName()
8+
{
9+
$factoryClass = Factory::resolveFactoryName('Module\Models\TestModel');
10+
$this->assertEquals($factoryClass, 'Module\Database\Factories\TestModelFactory');
11+
12+
$factoryClass = Factory::resolveFactoryName('Plugin\Author\Models\TestModel');
13+
$this->assertEquals($factoryClass, 'Plugin\Author\Database\Factories\TestModelFactory');
14+
15+
$factoryClass = Factory::resolveFactoryName('Models\TestModel');
16+
$this->assertEquals($factoryClass, 'Database\Factories\TestModelFactory');
17+
18+
$factoryClass = Factory::resolveFactoryName('TestModel');
19+
$this->assertEquals($factoryClass, 'Database\Factories\TestModelFactory');
20+
}
21+
}

0 commit comments

Comments
 (0)