Framework: [5.1] Loading model factories from vendor packages

Created on 14 Jan 2016  路  8Comments  路  Source: laravel/framework

Yesterday I discovered a model factories but I got a problem with loading model factories from my vendor packages while running unit test implemented in base application. Is that even possible? I ended with an error which tells me that factory cannot be found "... [default]".

Most helpful comment

I'm pretty sure what @RemiCollin has there will override existing model registrations, check this out, works well for me....

https://github.com/laravel/internals/issues/311

Basically create this function in your service provider...

/**
 * Register factories.
 *
 * @param  string  $path
 * @return void
 */
protected function registerEloquentFactoriesFrom($path)
{
    $this->app->make(EloquentFactory::class)->load($path);
}

You'll need to add use use Illuminate\Database\Eloquent\Factory as EloquentFactory; before your class declaration.

Then in your register methods just do...

$this->registerEloquentFactoriesFrom(__DIR__.'/../factories');

and populate that folder as you are used to when creating factories in laravel/database/factories

All 8 comments

Sure, yeh, it's possible. You'd just need to write the code to do it.

Feel free to discuss on the forums.

I investigated that model factories are searched only in /database/factories but I want to load some from /vendor/name/package/database/factories/ but it does not work. My test is located in /tests , not in /vendor/name/package/tests and that's the problem. After analyzing L5 code I am not sure how it could even work ;)

once again... after closing ticket, please, could anybody answer? ;)

@appcia : i faced the same issue. I found the solution is to re-register the EloquentFactory class, for example in your TestCase setUp() method:

 // Override Model Factory Path
        $this->app->singleton(EloquentFactory::class, function ($app) {
            $faker = $app->make(FakerGenerator::class);
            return EloquentFactory::construct($faker, __DIR__.('/../src/database/factories'));
        });

This is far from elegant, but it's the only solution AFAIK.

I'm pretty sure what @RemiCollin has there will override existing model registrations, check this out, works well for me....

https://github.com/laravel/internals/issues/311

Basically create this function in your service provider...

/**
 * Register factories.
 *
 * @param  string  $path
 * @return void
 */
protected function registerEloquentFactoriesFrom($path)
{
    $this->app->make(EloquentFactory::class)->load($path);
}

You'll need to add use use Illuminate\Database\Eloquent\Factory as EloquentFactory; before your class declaration.

Then in your register methods just do...

$this->registerEloquentFactoriesFrom(__DIR__.'/../factories');

and populate that folder as you are used to when creating factories in laravel/database/factories

Thank you very much.

I did like you:
Modules Provider.
use Illuminate\Database\Eloquent\Factory as EloquentFactory;
//........
public function boot()
{
$this->registerEloquentFactoriesFrom(__DIR__.'/../factories');
}

protected function registerEloquentFactoriesFrom($path)
{
$this->app->make(EloquentFactory::class)->load($path);
}
And all succeed.

Lets say I created my package model factory in
package/src/database/factories/MyFactory.php

and I have my service provider in
package/src/MyServiceProvider.php

then inside MyServiceProvider.php boot() function add the code to publish MyFactory.php to the project factory folder

public function boot()
{
    $this->publishes([
        __DIR__.'/database/factories/MyFactory.php' => database_path('factories/MyFactory.php')
    ],'myfactory');
}

Then finally publish your factory using publish command
php artisan vendor:publish --tag=myfactory

Was this page helpful?
0 / 5 - 0 ratings