I'm using [Nwidart][1] module package and I'm trying to create a seeder using a factory. But when I try to run php artisan db:seed I get this error
Call to undefined function Modules\Products\Database\Seeders\factory()
Here is my ProductsDatabaseSeeder.php
<?php
namespace Modules\Products\Database\Seeders;
use Illuminate\Database\Seeder;
use Illuminate\Database\Eloquent\Model;
use Modules\Products\Models\Product;
class ProductsDatabaseSeeder extends Seeder
{
/**
* Run the database seeds.
*
* #return void
*/
public function run()
{
Model::unguard();
factory(Product::class, 10)->create();
}
}
My ProductFactory
<?php
/** #var \Illuminate\Database\Eloquent\Factory $factory */
use Faker\Generator as Faker;
use Modules\Products\Models\Product;
$factory->define(Product::class, function (Faker $faker) {
return [
'title' => $this->faker->title,
'price' => $this->faker->randomNumber(3),
];
});
My Product.php
<?php
namespace Modules\Products\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Product extends Model
{
use HasFactory;
protected $fillable = [];
}
Full error
Call to undefined function Modules\Products\Database\Seeders\factory()
at Modules/Products/Database/Seeders/ProductsDatabaseSeeder.php:25
21▕
22▕
23▕
24▕
➜ 25▕ $product = factory(Product::class, 10)->create();
26▕
27▕
28▕ }
29▕ }
+8 vendor frames
9 database/seeders/DatabaseSeeder.php:20
Illuminate\Database\Seeder::call()
+24 vendor frames
34 artisan:37
Illuminate\Foundation\Console\Kernel::handle()
This is what I get after changing
factory(Product::class, 10)->create();
to
Product::factory()->count(10)->create();
Class 'Database\Factories\Modules\Products\Models\ProductFactory' 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 frames
2 Modules/Products/Database/Seeders/ProductsDatabaseSeeder.php:25
Modules\Products\Models\Product::factory()
+8 vendor frames
11 database/seeders/DatabaseSeeder.php:21
Illuminate\Database\Seeder::call()
[1]: https://nwidart.com/laravel-modules/v6/introduction
As of Laravel 8 which is what you probably use - as you are using the HasFactory trait - you will need to call
Product::factory()->create()
In order to run the factory
https://laracasts.com/discuss/channels/code-review/please-help-call-to-undefined-function-factory?signup
Apart from adding the HasFactory trait to your model, 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();
}
So, in your model Product.php
<?php
namespace Modules\Products\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Product extends Model
{
use HasFactory;
/**
* Create a new factory instance for the model.
*
* #return \Illuminate\Database\Eloquent\Factories\Factory
*/
protected static function newFactory()
{
return \Modules\Products\Database\Factories\ProductFactory::new();
}
protected $fillable = [];
}
Also, since laravel 8 the conventions of using a factory has changed.
So, in your
ProductsDatabaseSeeder.php
<?php
namespace Modules\Products\Database\Seeders;
use Illuminate\Database\Seeder;
use Illuminate\Database\Eloquent\Model;
use Modules\Products\Models\Product;
class ProductsDatabaseSeeder extends Seeder
{
/**
* Run the database seeds.
*
* #return void
*/
public function run()
{
Model::unguard();
Product::factory()->count(50)->create();
}
}
And, finally the factory class ProductFactory.php like
<?php
namespace Modules\Products\Database\Factories;
use Illuminate\Database\Eloquent\Factories\Factory;
use Modules\Products\Models\Product;
class ProductFactory extends Factory
{
protected $model = Product::class;
public function definition()
{
return [
'title' => $this->faker->title,
'price' => $this->faker->randomNumber(3),
];
}
}
Related
I am new to laravel , I receive error while trying to seed data, I have done it successfully in two different tables but I am stuck at this one :
Model
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Project extends Model
{
use HasFactory;
public $timestamps = false;
protected $fillable = [
'Pmid',
'Ministry',
'P_name',
'Budget',
];
protected $casts = [
'Registered_at' => 'datetime',
];
}
Factory
<?php
namespace Database\Factories;
use App\Models\Project;
use Illuminate\Database\Eloquent\Factories\Factory;
class ProjectFactory extends Factory
{
protected $model = Project::class;
/**
* Define the model's default state.
*
* #return array
*/
public function definition()
{
return [
'Pmid' => $this->faker->unique()->name(),
'Ministry' => $this->faker->name(),
'P_name' => $this->faker->name(),
'Budget' => $this->faker->name(),
'Registered_at' => now(),
];
}
}
Seeder
<?php
namespace Database\Seeders;
use App\Models\Project;
use Illuminate\Database\Seeder;
class ProjectTableSeeder extends Seeder
{
/**
* Run the database seeds.
*
* #return void
*/
public function run()
{
Project::factory()->count(20)->create();
}
}
Migration
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateProjectsTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('projects', function (Blueprint $table) {
$table->increments('id');
$table->string('Pmid')->unique();
$table->string('Ministry');
$table->string('P_name');
$table->integer('Budget');
$table->timestamp('Registered_at');
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('projects');
}
}
error
Illuminate\Database\QueryException
SQLSTATE[22007]: Invalid datetime format: 1366 Incorrect integer value: 'Mathias Kuhlman' for column laravel.projects.Budget at row 1 (SQL: insert into projects (Pmid, Ministry, P_name, Budget, Registered_at) values (Nicholas Mayer, Ms. Donna Strosin, Hermann Bins, Mathias Kuhlman, 2021-12-05 08:36:39))
You're using
'Budget' => $this->faker->name(),
to create the data, but your migration shows that that column should be an integer :
$table->integer('Budget');
I suspect you've just copied and pasted the faker rows without changing the type of value being faked.
I am facing a weird error right now
In my controller, when I import the class user like this
use Illuminate\Foundation\Auth\User;
It works when I use eloquent like
public function index()
{
$farms = User::where('role_id', 3)->get();
$user = Auth::user();
$animal = Animal::all();
return view('clinic.index', compact('user', 'animal', 'farms'));
}
But refuses to work when it comes to table relationships like
public function show($id)
{
$farms = User::with(['animals'])->findOrFail($id);
return view('clinic.show',compact('farms'));
}
showing me this error
"Call to undefined relationship [animals] on model [Illuminate\Foundation\Auth\User]"
But whenever I import the user class as App\User in my controller,
It works in the relationship but refuses to work with the eloquent showing this error
"Call to a member function get() on null"
Now I am kinda confused. Any help will be welcomed
App\User
<?php
namespace App;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Illuminate\Database\Eloquent\Model;
class User extends Authenticatable
{
use Notifiable;
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $guarded = [];
public static function where(string $string, int $int)
{
}
public static function select(array $array)
{
}
public function role(){
return $this->belongsTo(Role::class);
}
public function animals(){
return $this->hasMany(Animal::class);
}
public function clinics(){
return $this->hasMany(Clinic::class);
}
public function slaughter(){
return $this->hasMany(Slaughter::class);
}
public function address(){
return $this->belongsTo(Address::class);
}
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
'password', 'remember_token',
];
/**
* The attributes that should be cast to native types.
*
* #var array
*/
protected $casts = [
'email_verified_at' => 'datetime',
];
}
The Illuminate\Foundation\Auth\User class is the parent of the App\User class and animals relation set in the App\Userclass. So you can't call animals relation from Illuminate\Foundation\Auth\User class.
You should remove these functions from the App\User Model:
public static function where(string $string, int $int)
{
}
public static function select(array $array)
{
}
I am working on Order-Ticket functionality. Many tickets should ideally be generated for a single order.
Earlier, the responsibility of creating tickets was written inside Order Model and that time it worked fine but now that I am trying to move that responsibility to Ticket model itself, it is not working.
I'll start with the Test file 'TicketTest.php'
<?php
use Illuminate\Foundation\Testing\WithoutMiddleware;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use App\Concert;
use Carbon\Carbon;
use App\Order;
class TicketTest extends TestCase
{
use DatabaseMigrations;
/** #test */
function can_create_multiple_tickets_for_order(){
$numberOfTickets = 2;
// Arrange - Create Concert and Order
$concert = factory(Concert::class)->create(
[
'date' => Carbon::parse('December 1, 2016 8:00pm'),
]
);
$order = $concert->orders()->create([
'email' => 'abc#gmail.com'
]);
// Act - Create Tickets
$order->tickets()->createTickets($numberOfTickets); // This line throws call to undefined method.
// Assert
$this->assertEquals($numberOfTickets, $order->tickets()->count());
}
}
'Order.php' Model
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Order extends Model
{
protected $guarded = [];
public function tickets()
{
return $this->hasMany(Ticket::class);
}
}
'Ticket.php' Model
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Ticket extends Model
{
public function createTickets($ticketQuantity){
foreach(range(1, $ticketQuantity) as $i) {
$this->create([]);
}
}
public function order(){
return $this->belongsTo(Order::class);
}
}
Before Laravel 5.4, I solved this problem by creating a new Relation and using that relation to Map Order to Ticket. Created a file 'app/Relation/TicketOrderRelation.php' and added following code in it
<?php
namespace App\Relation;
use Illuminate\Database\Eloquent\Relations\HasMany;
class TicketOrderRelation extends HasMany {
/**
* Create a Collection of new tickets
*
* #param int $ticketQuantity Number of Tickets to be created
* #return \Illuminate\Database\Eloquent\Collection
*/
public function createTickets($ticketQuantity){
$instances = [];
foreach(range(1, $ticketQuantity) as $i) {
$instances[] = $this->create([]);
}
return collect($instances);
}
}
New 'Order.php' file
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use App\Relation\TicketOrderRelation;
class Order extends Model
{
protected $guarded = [];
/**
* Define a one-to-many relationship. One Order can have many tickets.
*
* This method is duplicate of hasMany method. The only difference is it
* returns object of TicketOrderRelation class at the bottom instead of
* object of HasMany class.
*
* #param string $related
* #param string $foreignKey
* #param string $localKey
* #return \App\Relation\TicketOrderRelation
*/
public function ticketOrderRelation($related, $foreignKey = null, $localKey = null)
{
$foreignKey = $foreignKey ?: $this->getForeignKey();
$instance = new $related;
$localKey = $localKey ?: $this->getKeyName();
return new TicketOrderRelation($instance->newQuery(), $this, $instance->getTable().'.'.$foreignKey, $localKey);
}
public function tickets()
{
return $this->ticketOrderRelation(Ticket::class);
}
}
New 'Ticket.php' file
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Ticket extends Model
{
protected $guarded = [];
public function order()
{
return $this->belongsTo(Order::class);
}
}
After Laravel 5.4, Eloquent builder started supporting create method which makes creation easy.
This answer shows how to create a custom Builder. I have not yet tried if custom builder solves this problem on Laravel 5.4 or not but if it does, then I would prefer that.
I'm new in Laravel. I have 2 tables Productions and Products. Also, I have 2 factories ProductionFactory and ProductFactory. I want to test them via phpunit. Their connection is via production_id.
Error is ErrorException: Undefined variable: production.
I don't get it.
Thanks in advance.
This is a code.
ProductionFactory.php
$factory->define(App\Production::class, function (Faker $faker) {
return [
'name' =>$faker->name,
];
});
ProductFactory.php
$factory->define(App\Product::class, function (Faker $faker) {
$production_id = App\Production::pluck('id');
if(!$production_id->isEmpty()){
$production = $production_id->random();
}
return [
'id' =>$faker->uuid,
'name' =>$faker->name,
'price' => $faker->numberBetween($min = 100, $max = 900),
'description' =>Str::random(10),
'production_id'=> $production,
];
ProductionTest.php
class ProductionTest extends TestCase
{
use RefreshDatabase;
/**
* A basic unit test example.
* #test
* #return void
*/
public function production()
{
factory(Production::class)->make();
$this->assertTrue(true);
}
}
ProductTest.php
class ProductTest extends TestCase
{
use RefreshDatabase;
/**
* A basic unit test example.
* #test
* #return void
*/
public function product()
{
factory(Product::class)->make();
$this->assertTrue(true);
}
}
Model Production
use Illuminate\Database\Eloquent\SoftDeletes;
class Production extends Model
{
use SoftDeletes;
protected $fillable = [
'name',
];
public function products()
{
return $this->hasMany('App\Product');
}
Model Product
class Product extends Model
{
use SoftDeletes;
protected $fillable = [
'id','name','price','description','production_id'
];
public function production()
{
return $this->belongsTo('App\Production');
}
SQLSTATE[HY000]: General error: 1364 Field 'production_id' doesn't have a default value
It depends on what functionality should be tested.
A basic test to check the model relationship is set correctly?
I pushed a working demo to GitHub (https://github.com/.../laravel-basic-relationship-tests).
App/Product.php
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Product extends Model
{
public function production()
{
return $this->belongsTo(Production::class);
}
}
App/Production.php
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Production extends Model
{
public function products()
{
return $this->belongsTo(Product::class);
}
}
Product Factory
<?php
/* #var $factory \Illuminate\Database\Eloquent\Factory */
use App\Product as Model;
use Faker\Generator as Faker;
$factory->define(Model::class, function (Faker $faker) {
$production = factory(\App\Production::class)->make();
$production->save();
return [
'name' => $faker->name,
'price' => $faker->numberBetween($min = 100, $max = 900),
'description' => $faker->text,
'production_id' => $production->id
];
});
Production Factory
<?php
/* #var $factory \Illuminate\Database\Eloquent\Factory */
use App\Production as Model;
use Faker\Generator as Faker;
$factory->define(Model::class, function (Faker $faker) {
return [
'name' => $faker->name
];
});
$factory->afterCreatingState(Model::class, 'seed', function ($production, $faker) {
$product = factory(\App\Product::class)->make();
$production->products()->associate($product);
});
Product Test
<?php
namespace Tests\Feature;
use Tests\TestCase;
use Illuminate\Foundation\Testing\WithFaker;
use Illuminate\Foundation\Testing\RefreshDatabase;
class ProductTest extends TestCase
{
/**
* #return void
*/
public function testProductHasWorkingProductionRelationship()
{
$product = factory(\App\Product::class)->create();
$this->assertNotEmpty($product->production);
}
}
Production Test
<?php
namespace Tests\Feature;
use Tests\TestCase;
use Illuminate\Foundation\Testing\WithFaker;
use Illuminate\Foundation\Testing\RefreshDatabase;
class ProductionTest extends TestCase
{
/**
* #return void
*/
public function testProductionHasWorkingProductRelationship()
{
$production = factory(\App\Production::class)->state('seed')->create();
$this->assertNotEmpty($production->products);
}
}
Hope this is a great starting point for any further tests.
I am using laravel 5.6 version, here is my Test model file
<?php
namespace App\Model\data\Models;
use Illuminate\database\Eloquent\Model;
class Test extends Model
{
protected $guarded = ['id'];
protected $table = 'tests';
/*
* Test - TestTranslation relation
* Test has many translations
*/
public function translations()
{
return $this->hasMany('App\Model\Data\Models\TestTranslation');
}
/*
* Test - Image relation
* Test can have an thumbnail
*/
public function thumbnails()
{
return $this->morphMany('App\Model\Data\Models\Image', 'type');
}
}
Here is my Image model
<?php
namespace App\Model\Data\Models;
use Illuminate\Database\Eloquent\Model;
class Image extends Model
{
protected $guarded = ['id'];
protected $table = 'images';
/*
* Image belongs to Post, Account, Comment
*/
public function type()
{
return $this->morphTo();
}
}
Here is my Database scheme for Images table:
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateImagesTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('images', function (Blueprint $table) {
$table->increments('id');
$table->string('path');
$table->enum('type', ['avatar', 'thumbnail', 'generic'])->default('generic');
$table->integer('type_id')->unsigned()->nullable();
$table->enum('type_type',[
"Account",
"Comment",
"Post",
"Skill",
"Test"
])->nullable();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('images');
}
}
In AppServiceProvider I linked 'Test' to my model file:
<?php
namespace App\Providers;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\ServiceProvider;
use Laravel\Dusk\DuskServiceProvider;
use Illuminate\Database\Eloquent\Relations\Relation;
use App\Model\Data\Models\Account;
use App\Model\Data\Models\EmailChangeConfirmation;
use App\Model\Observers\Common\AccountObserver;
use App\Model\Observers\Common\EmailChangeConfirmationObserver;
class AppServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot()
{
Schema::defaultStringLength(191);
Relation::morphMap([
'Account' => 'App\Model\Data\Models\Account',
'Comment' => 'App\Model\Data\Models\Comment',
'Post' => 'App\Model\Data\Models\Post',
'Skill' => 'App\Model\Data\Models\Skill',
'Test' => 'App\Model\Data\Models\Test'
]);
if(env('APP_ENV') != 'testing') {
Account::observe(AccountObserver::class);
EmailChangeConfirmation::observe(EmailChangeConfirmationObserver::class);
}
}
/**
* Register any application services.
*
* #return void
*/
public function register()
{
if ($this->app->environment('local', 'testing')) {
$this->app->register(DuskServiceProvider::class);
}
}
}
As you can see, I have more morhpMany types, and all of them works fine. But for some reason, this Test relation that I added recently always returns an empty collection, even tough I am sure that test has thumbnails. Cause:
in this screenshot, I have records in database that each test has two images. Their ID matches ids of created tests and type is "Test". I tried to clear all caches, run composer dump-autoload but none of them helped.
Maybe someone can help identify what is wrong here? Because as I said before other types as Post, Account works fine.