Hey there! I might be wrong but I think the factory stub should be updated with the new class format introduced in Laravel 8.0?
If this is correct, I will gladly submit a PR.
On another hand, there is also an issue related with the new factory changes. The models should implement the HasFactory trait and then Laravel will try to find the factory magically, based on the App namespace.
Is it good practice to override that magic method and add support for modules namespace? Or are we forced to use the newFactory method (fallback) on every model? Sounds kinda counter intuitive.
I can confirm that Factory has issues on the current 8.0.0 build, even with both the classic definition and the new class format introduced in Laravel 8, seeding a module does not work anymore.
the new format for seeding an entity :
\App\Models\User::factory(10)->create();
Adding the HasFactory trait to a module entity and trying to seed with the global DatabaseSeeder
class Author extends Model {
use HasFactory;
...
}
class DatabaseSeeder extends Seeder
{
/**
* Seed the application's database.
*
* @return void
*/
public function run()
{
\Modules\Author\Entities::factory(10)->create();
}
}
Running php artisan db:seed Trace
Class 'Database\Factories\Modules\Author\Entities\AuthorFactory' not found
at \vendor\laravel\framework\src\Illuminate\Database\Eloquent\Factories\Factory.php:656
652â–• public static function factoryForModel(string $modelName)
653â–• {
654â–• $factory = static::resolveFactoryName($modelName);
655â–•
➜ 656▕ return $factory::new();
657â–• }
658â–•
659â–• /**
660â–• * Specify the callback that should be invoked to guess factory names based on dynamic relationship names.
1 \vendor\laravel\framework\src\Illuminate\Database\Eloquent\Factories\HasFactory.php:15
Illuminate\Database\Eloquent\Factories\Factory::factoryForModel()
2 \database\seeders\DatabaseSeeder.php:17
Modules\Manager\Entities\Manager::factory()
Yeah, that happens because this is how Laravel resolves the factory namespace by default:
/**
* Get the factory name for the given model name.
*
* @param string $modelName
* @return string
*/
public static function resolveFactoryName(string $modelName)
{
$resolver = static::$factoryNameResolver ?: function (string $modelName) {
$modelName = Str::startsWith($modelName, 'App\\Models\\')
? Str::after($modelName, 'App\\Models\\')
: Str::after($modelName, 'App\\');
return static::$namespace.$modelName.'Factory';
};
return $resolver($modelName);
}
So, in order to support the Modules\{Module} namespace you need to put this in your model:
/**
* Create a new factory instance for the model.
*
* @return \Illuminate\Database\Eloquent\Factories\Factory
*/
protected static function newFactory()
{
return \Modules\Module\Database\Factories\ModelFactory::new();
}
However, if this package doesn't supply this by default (which currently doesn't), we need to add that in every model that has a factory, which sounds like an annoying boilerplate.
It could indeed be a could idea to add this to the generated model classes by default.
I added the corresponding method to my model Tenant, which also contains the HasFactory namespace:
use HasFactory;
// ...
protected static function newFactory()
{
return TenantFactory::new();
}
And inside the factory the model is referenced too. But I still receive errors like this when running my tests:
InvalidArgumentException: Unable to locate factory for [Modules\Tenant\Entities\Tenant].
I'm using laravel-modules v 8.2.0 with laravel framework 8.34.0
I added the corresponding method to my model Tenant, which also contains the HasFactory namespace:
use HasFactory; // ... protected static function newFactory() { return TenantFactory::new(); }And inside the factory the model is referenced too. But I still receive errors like this when running my tests:
InvalidArgumentException: Unable to locate factory for [Modules\Tenant\Entities\Tenant].I'm using laravel-modules v 8.2.0 with laravel framework 8.34.0
Make sure you import your TenantFactory class in your Model, and your Model in your TenantFactory
Maybe we can use something like this:
I added the corresponding method to my model Tenant, which also contains the HasFactory namespace:
use HasFactory; // ... protected static function newFactory() { return TenantFactory::new(); }And inside the factory the model is referenced too. But I still receive errors like this when running my tests:
InvalidArgumentException: Unable to locate factory for [Modules\Tenant\Entities\Tenant].
I'm using laravel-modules v 8.2.0 with laravel framework 8.34.0Make sure you import your
TenantFactoryclass in your Model, and your Model in yourTenantFactory
Did that. Unfortunately this is not the mistake :/
Most helpful comment
Yeah, that happens because this is how Laravel resolves the factory namespace by default:
So, in order to support the
Modules\{Module}namespace you need to put this in your model:However, if this package doesn't supply this by default (which currently doesn't), we need to add that in every model that has a factory, which sounds like an annoying boilerplate.