Smiffy's avatar

Set return type on Factory

Is it possible to expclitly define the return type of a factory? I am refactoring some code and have deprecated a class method. Turns out that some of these are not picked out by PHPStorm since it returns Model so it isn't aware that the method called is deprecated. Code for clarity:

//In MyModel.php...

/** @deprecated */
public function myMethod()
{
   //whatever
}

//In a test
$myModel = MyModel::factory()->create(); //returns Model

$myModel->myMethod(); //should be flagged as deprecated

I can get around this by flagging the created objects explicitly:

/** @var \App\Models\MyModel $myModel */
$myModel = MyModel::factory()->create();

$myModel->myMethod(); //this is now picked up correctly

However it means going through and manually picking these out which kind of defeats the purpose.

0 likes
3 replies
LaryAI's avatar
Level 58

Yes, it is possible to explicitly define the return type of a factory in Laravel. You can achieve this by using PHPDoc annotations.

In your case, you can add a PHPDoc annotation to the factory method in your model class to specify the return type. Here's an example:

/**
 * @method static \Illuminate\Database\Eloquent\Factories\Factory|\App\Models\MyModel factory(...$parameters)
 */
public static function newFactory()
{
    return \App\Database\Factories\MyModelFactory::new();
}

Make sure to replace \App\Models\MyModel with the actual namespace and class name of your model, and \App\Database\Factories\MyModelFactory with the actual namespace and class name of your model's factory.

By adding this PHPDoc annotation, you are explicitly defining the return type of the factory method, which will help PHPStorm and other IDEs to correctly infer the return type and provide proper code completion and deprecation warnings.

Hope this helps! Let me know if you have any further questions.

Smiffy's avatar

LarryAIs answer got me part of the way there. My model had to be marked up as follows:

/**
 * @method static MyModelFactory|MyModel factory(...$parameters)
 */
class MyModel extends Model
{
    use HasFactory;

    protected static function newFactory()
    {
        return MyModelFactory::new();
    }
}
Tray2's avatar

Why are you complicating things?

This is a factory

<?php

namespace Database\Factories;

use App\Models\Actor;
use Illuminate\Database\Eloquent\Factories\Factory;

class ActorFactory extends Factory
{
    protected $model = Actor::class;

    public function definition(): array
    {
        return [
            'first_name' => $this->faker->firstName(),
            'last_name' => $this->faker->lastName(),
        ];
    }
}

This is the model

class Actor extends Model
{
    use HasFactory;

    protected $guarded = [];
}

And this in the test

//Create the actor in the database
$this->actor = Actor::factory()->create();


//Create the actor in memory
$this->actor = Actor::factory()->make();

Please or to participate in this conversation.