Skip to content

Commit

Permalink
feat: improve Factory generics (#52005)
Browse files Browse the repository at this point in the history
  • Loading branch information
calebdw authored Jul 8, 2024
1 parent d99a857 commit 2f1f330
Show file tree
Hide file tree
Showing 6 changed files with 125 additions and 145 deletions.
58 changes: 32 additions & 26 deletions src/Illuminate/Database/Eloquent/Factories/Factory.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ abstract class Factory
/**
* The name of the factory's corresponding model.
*
* @var class-string<\Illuminate\Database\Eloquent\Model|TModel>
* @var class-string<TModel>
*/
protected $model;

Expand Down Expand Up @@ -109,7 +109,7 @@ abstract class Factory
/**
* The default model name resolver.
*
* @var callable
* @var callable(self): class-string<TModel>
*/
protected static $modelNameResolver;

Expand Down Expand Up @@ -214,7 +214,7 @@ public function raw($attributes = [], ?Model $parent = null)
* Create a single model and persist it to the database.
*
* @param (callable(array<string, mixed>): array<string, mixed>)|array<string, mixed> $attributes
* @return \Illuminate\Database\Eloquent\Model|TModel
* @return TModel
*/
public function createOne($attributes = [])
{
Expand All @@ -225,7 +225,7 @@ public function createOne($attributes = [])
* Create a single model and persist it to the database without dispatching any model events.
*
* @param (callable(array<string, mixed>): array<string, mixed>)|array<string, mixed> $attributes
* @return \Illuminate\Database\Eloquent\Model|TModel
* @return TModel
*/
public function createOneQuietly($attributes = [])
{
Expand All @@ -236,7 +236,7 @@ public function createOneQuietly($attributes = [])
* Create a collection of models and persist them to the database.
*
* @param int|null|iterable<int, array<string, mixed>> $records
* @return \Illuminate\Database\Eloquent\Collection<int, \Illuminate\Database\Eloquent\Model|TModel>
* @return \Illuminate\Database\Eloquent\Collection<int, TModel>
*/
public function createMany(int|iterable|null $records = null)
{
Expand All @@ -259,7 +259,7 @@ public function createMany(int|iterable|null $records = null)
* Create a collection of models and persist them to the database without dispatching any model events.
*
* @param int|null|iterable<int, array<string, mixed>> $records
* @return \Illuminate\Database\Eloquent\Collection<int, \Illuminate\Database\Eloquent\Model|TModel>
* @return \Illuminate\Database\Eloquent\Collection<int, TModel>
*/
public function createManyQuietly(int|iterable|null $records = null)
{
Expand All @@ -273,7 +273,7 @@ public function createManyQuietly(int|iterable|null $records = null)
*
* @param (callable(array<string, mixed>): array<string, mixed>)|array<string, mixed> $attributes
* @param \Illuminate\Database\Eloquent\Model|null $parent
* @return \Illuminate\Database\Eloquent\Collection<int, \Illuminate\Database\Eloquent\Model|TModel>|\Illuminate\Database\Eloquent\Model|TModel
* @return \Illuminate\Database\Eloquent\Collection<int, TModel>|TModel
*/
public function create($attributes = [], ?Model $parent = null)
{
Expand Down Expand Up @@ -301,7 +301,7 @@ public function create($attributes = [], ?Model $parent = null)
*
* @param (callable(array<string, mixed>): array<string, mixed>)|array<string, mixed> $attributes
* @param \Illuminate\Database\Eloquent\Model|null $parent
* @return \Illuminate\Database\Eloquent\Collection<int, \Illuminate\Database\Eloquent\Model|TModel>|\Illuminate\Database\Eloquent\Model|TModel
* @return \Illuminate\Database\Eloquent\Collection<int, TModel>|TModel
*/
public function createQuietly($attributes = [], ?Model $parent = null)
{
Expand All @@ -315,7 +315,7 @@ public function createQuietly($attributes = [], ?Model $parent = null)
*
* @param array<string, mixed> $attributes
* @param \Illuminate\Database\Eloquent\Model|null $parent
* @return \Closure(): (\Illuminate\Database\Eloquent\Collection<int, \Illuminate\Database\Eloquent\Model|TModel>|\Illuminate\Database\Eloquent\Model|TModel)
* @return \Closure(): (\Illuminate\Database\Eloquent\Collection<int, TModel>|TModel)
*/
public function lazy(array $attributes = [], ?Model $parent = null)
{
Expand All @@ -325,7 +325,7 @@ public function lazy(array $attributes = [], ?Model $parent = null)
/**
* Set the connection name on the results and store them.
*
* @param \Illuminate\Support\Collection $results
* @param \Illuminate\Support\Collection<int, \Illuminate\Database\Eloquent\Model> $results
* @return void
*/
protected function store(Collection $results)
Expand Down Expand Up @@ -366,7 +366,7 @@ protected function createChildren(Model $model)
* Make a single instance of the model.
*
* @param (callable(array<string, mixed>): array<string, mixed>)|array<string, mixed> $attributes
* @return \Illuminate\Database\Eloquent\Model|TModel
* @return TModel
*/
public function makeOne($attributes = [])
{
Expand All @@ -378,7 +378,7 @@ public function makeOne($attributes = [])
*
* @param (callable(array<string, mixed>): array<string, mixed>)|array<string, mixed> $attributes
* @param \Illuminate\Database\Eloquent\Model|null $parent
* @return \Illuminate\Database\Eloquent\Collection<int, \Illuminate\Database\Eloquent\Model|TModel>|\Illuminate\Database\Eloquent\Model|TModel
* @return \Illuminate\Database\Eloquent\Collection<int, TModel>|TModel
*/
public function make($attributes = [], ?Model $parent = null)
{
Expand Down Expand Up @@ -504,7 +504,7 @@ protected function expandAttributes(array $definition)
/**
* Add a new state transformation to the model definition.
*
* @param (callable(array<string, mixed>, \Illuminate\Database\Eloquent\Model|null): array<string, mixed>)|array<string, mixed> $state
* @param (callable(array<string, mixed>, TModel|null): array<string, mixed>)|array<string, mixed> $state
* @return static
*/
public function state($state)
Expand Down Expand Up @@ -654,8 +654,10 @@ public function recycle($model)
/**
* Retrieve a random model of a given type from previously provided models to recycle.
*
* @param string $modelClassName
* @return \Illuminate\Database\Eloquent\Model|null
* @template TClass of \Illuminate\Database\Eloquent\Model
*
* @param class-string<TClass> $modelClassName
* @return TClass|null
*/
public function getRandomRecycledModel($modelClassName)
{
Expand All @@ -665,7 +667,7 @@ public function getRandomRecycledModel($modelClassName)
/**
* Add a new "after making" callback to the model definition.
*
* @param \Closure(\Illuminate\Database\Eloquent\Model|TModel): mixed $callback
* @param \Closure(TModel): mixed $callback
* @return static
*/
public function afterMaking(Closure $callback)
Expand All @@ -676,7 +678,7 @@ public function afterMaking(Closure $callback)
/**
* Add a new "after creating" callback to the model definition.
*
* @param \Closure(\Illuminate\Database\Eloquent\Model|TModel): mixed $callback
* @param \Closure(TModel): mixed $callback
* @return static
*/
public function afterCreating(Closure $callback)
Expand Down Expand Up @@ -761,7 +763,7 @@ protected function newInstance(array $arguments = [])
* Get a new model instance.
*
* @param array<string, mixed> $attributes
* @return \Illuminate\Database\Eloquent\Model|TModel
* @return TModel
*/
public function newModel(array $attributes = [])
{
Expand All @@ -773,7 +775,7 @@ public function newModel(array $attributes = [])
/**
* Get the name of the model that is generated by the factory.
*
* @return class-string<\Illuminate\Database\Eloquent\Model|TModel>
* @return class-string<TModel>
*/
public function modelName()
{
Expand All @@ -797,7 +799,7 @@ public function modelName()
/**
* Specify the callback that should be invoked to guess model names based on factory names.
*
* @param callable(self): class-string<\Illuminate\Database\Eloquent\Model|TModel> $callback
* @param callable(self): class-string<TModel> $callback
* @return void
*/
public static function guessModelNamesUsing(callable $callback)
Expand All @@ -819,8 +821,10 @@ public static function useNamespace(string $namespace)
/**
* Get a new factory instance for the given model name.
*
* @param class-string<\Illuminate\Database\Eloquent\Model> $modelName
* @return \Illuminate\Database\Eloquent\Factories\Factory
* @template TClass of \Illuminate\Database\Eloquent\Model
*
* @param class-string<TClass> $modelName
* @return \Illuminate\Database\Eloquent\Factories\Factory<TClass>
*/
public static function factoryForModel(string $modelName)
{
Expand Down Expand Up @@ -853,8 +857,10 @@ protected function withFaker()
/**
* Get the factory name for the given model name.
*
* @param class-string<\Illuminate\Database\Eloquent\Model> $modelName
* @return class-string<\Illuminate\Database\Eloquent\Factories\Factory>
* @template TClass of \Illuminate\Database\Eloquent\Model
*
* @param class-string<TClass> $modelName
* @return class-string<\Illuminate\Database\Eloquent\Factories\Factory<TClass>>
*/
public static function resolveFactoryName(string $modelName)
{
Expand All @@ -880,8 +886,8 @@ protected static function appNamespace()
{
try {
return Container::getInstance()
->make(Application::class)
->getNamespace();
->make(Application::class)
->getNamespace();
} catch (Throwable) {
return 'App\\';
}
Expand Down
19 changes: 13 additions & 6 deletions src/Illuminate/Database/Eloquent/Factories/HasFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,21 @@

namespace Illuminate\Database\Eloquent\Factories;

/**
* @template TFactory of \Illuminate\Database\Eloquent\Factories\Factory
*/
trait HasFactory
{
/**
* Get a new factory instance for the model.
*
* @param callable|array|int|null $count
* @param callable|array $state
* @return \Illuminate\Database\Eloquent\Factories\Factory<static>
* @param (callable(array<string, mixed>, static|null): array<string, mixed>)|array<string, mixed>|int|null $count
* @param (callable(array<string, mixed>, static|null): array<string, mixed>)|array<string, mixed> $state
* @return TFactory
*/
public static function factory($count = null, $state = [])
{
$factory = static::newFactory() ?: Factory::factoryForModel(get_called_class());
$factory = static::newFactory() ?? Factory::factoryForModel(get_called_class());

return $factory
->count(is_numeric($count) ? $count : null)
Expand All @@ -23,10 +26,14 @@ public static function factory($count = null, $state = [])
/**
* Create a new factory instance for the model.
*
* @return \Illuminate\Database\Eloquent\Factories\Factory<static>
* @return TFactory|null
*/
protected static function newFactory()
{
//
if (isset(static::$factory)) {
return static::$factory::new();
}

return null;
}
}
6 changes: 2 additions & 4 deletions tests/Database/Fixtures/Models/Money/Price.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,10 @@

class Price extends Model
{
/** @use HasFactory<PriceFactory> */
use HasFactory;

protected $table = 'prices';

public static function factory()
{
return PriceFactory::new();
}
protected static string $factory = PriceFactory::class;
}
20 changes: 20 additions & 0 deletions types/Autoload.php
Original file line number Diff line number Diff line change
@@ -1,17 +1,37 @@
<?php

use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\MassPrunable;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\HasDatabaseNotifications;

class User extends Authenticatable
{
use HasDatabaseNotifications;
/** @use HasFactory<UserFactory> */
use HasFactory;
use MassPrunable;
use SoftDeletes;

protected static string $factory = UserFactory::class;
}

/** @extends Factory<User> */
class UserFactory extends Factory
{
protected $model = User::class;

public function definition(): array
{
return [];
}
}

class Post extends Model
{
}

enum UserType
Expand Down
Loading

0 comments on commit 2f1f330

Please sign in to comment.