mikelplhts
mikelplhts

Reputation: 1221

Custom Factory class not found on my Laravel package

I'm creating a package that will serve as a base for projects, and I'm stuck on the creation of factories. For the package, I use the namespace Gad\Base.

I created a model MyModel in src/:

namespace Gad\Base;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class MyModel extends Model
{
    use HasFactory;

    protected $guarded = [];
}

and the corresponding factory MyModelFactory in database/factories/:

namespace Database\Factories;

use Gad\Base\MyModel;
use Illuminate\Database\Eloquent\Factories\Factory;

class MyModelFactory extends Factory
{
    protected $model = MyModel::class;

    public function definition()
    {
        return [
            'something' => $this->faker->text(100),
        ];
    }
}

But when I try to use the factory (in a test, for example)

MyModel::factory()->create()

I get the following error:

Error: Class "Database\Factories\Gad\Base\MyModelFactory" not found

I am not sure why looks for Database\Factories\Gad\Base\MyModelFactory and not for Database\Factories\MyModelFactory.

This is how I defined my autoload in composer.json:

"autoload": {
    "psr-4": {
        "Gad\\Base\\": "src/"
    }
},
"autoload-dev": {
    "psr-4": {
        "Gad\\Base\\Tests\\": "tests/",
        "Database\\Factories\\": "database/factories/"
    }
}

If in MyModel I override the static function newFactory() like this:

protected static function newFactory()
{
    return new MyModelFactory();
}

Everything works fine. Anyone knows what I did wrong?

Upvotes: 0

Views: 1030

Answers (1)

N69S
N69S

Reputation: 17216

The answer is in the resolver for factory name Illuminate/Database/Eloquent/Factories/Factory.php@798

    /**
     * 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>
     */
    public static function resolveFactoryName(string $modelName)
    {
        $resolver = static::$factoryNameResolver ?? function (string $modelName) {
            $appNamespace = static::appNamespace();

            $modelName = Str::startsWith($modelName, $appNamespace.'Models\\')
                ? Str::after($modelName, $appNamespace.'Models\\')
                : Str::after($modelName, $appNamespace);

            return static::$namespace.$modelName.'Factory';
        };

        return $resolver($modelName);
    }

It checks if the model is in the namespace \App\Models\ (or more precisely \$appNamespace\Models\) like standard models of the app, if not it apprends the namespace of the model and add the suffix Factory to it.

Upvotes: 0

Related Questions