I have InvalidArgumentException when I make database seeding - php

I'm work on Restful API , I have exception message when i want to make seeding fake data in database.
I make database fresh .
php artisan migrate:fresh
I seeding on database .
php artisan db:seed
I make model with migration and controller:
Migration: 000000_create_posts_table.php
public function up()
{
Schema::create('posts', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('title');
$table->text('content');
$table->dateTime('date_written');
$table->String('feature_image')->unllable();
$table->integer('votes_up')->unllable();
$table->integer('votes_down')->unllable();
// TelationShipe.
$table->integer('user_id');
$table->integer('category_id');
$table->timestamps();
});
Model: Post.php
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
protected $fillable = [
'title' , 'content' , 'date_written' ,
'feature_image' , 'votes_up' ,
'votes_down' , 'user_id' ,
'category_id'
];
}
Controller: PostController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class PostController extends Controller
{
//
}
Seeder: DatabaseSeeder.php
<?php
use Illuminate\Database\Seeder;
class DatabaseSeeder extends Seeder
{
/**
* Seed the application's database.
*
* #return void
*/
public function run()
{
factory(\App\Post::class , 100 )->create();
}
}
Factory: PostFactory.php
<?php
/** #var \Illuminate\Database\Eloquent\Factory $factory */
use App\User;
use Faker\Generator as Faker;
use Illuminate\Support\Str;
/*
|--------------------------------------------------------------------------
| Model Factories
|--------------------------------------------------------------------------
|
| This directory should contain each of the model factory definitions for
| your application. Factories provide a convenient way to generate new
| model instances for testing / seeding your application's database.
|
*/
$factory->define(User::class, function (Faker $faker) {
return [
'title' => $faker->title,
'content' => $faker->text(400),
'date_written' => $faker->new(),
'feature_image' => $faker->imageUrl(),
'votes_up' => $faker->numberBetween(1 , 100),
'votes_down' => $faker->numberBetween(1 , 100),
'user_id' => $faker->numberBetween(1 , 15),
'category_id' => $faker->numberBetween(1 , 15),
];
});
but the actual output console :
InvalidArgumentException : Unknown formatter "new" at
~/vendor/fzaninotto/faker/src/Faker/Generator.php:242
238|
239| return $this->formatters[$formatter];
240| }
241| }
242| throw new \InvalidArgumentException(sprintf('Unknown formatter "%s"', $formatter));
243| }
244|
245| /**
* Replaces tokens ('{{ tokenName }}') with the result
* from the token method call
*/
Exception trace:
1 Faker\Generator::getFormatter("new")
~/vendor/fzaninotto/faker/src/Faker/Generator.php:222
2 Faker\Generator::format("new", [])
~/vendor/fzaninotto/faker/src/Faker/Generator.php:279
Please use the argument -v to see more details.

Change this line
From
'date_written' => $faker->new(),
To
'date_written' => now(),
now() will return a Carbon instance of the current time which your database migration require
There's no such function on faker generator called new
Hope this helps

Related

Expand the User Model

I'm trying to expand the User Model with another Table (profile) to get a profile-picture, position, etc.
Can I override the index() function of the User Model to do that?
Current Model-Code:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;
class User extends Authenticatable
{
use HasApiTokens, HasFactory, Notifiable;
protected $fillable = [
'name',
'email',
'password',
'user_group'
];
protected $hidden = [
'password',
'remember_token',
];
protected $casts = [
'email_verified_at' => 'datetime',
];
}
What you are trying to do is setting up a relationship between the User Model and a new Profile Model. To do this you first need to create a Model Profile and it's associated Tabble profiles
php artisan make:model Profile --migration
In database\migrations there should be a file called something like that 2022_11_28_223831_create_profiles_table.php
Now you need to add a foreign key which indicates to which User this profile belongs.
public function up()
{
Schema::create('profiles', function (Blueprint $table) {
$table->id();
// $table->string('path_to_picture')
// user id
$table->foreignId('user_id')->constrained()->onDelete('cascade');
$table->timestamps();
});
}
Now in your User Model add the following function
public function profile()
{
return $this->hasOne(Profile::class);
}
And in your Profile Model
public function user()
{
return $this->belongsTo(User::class);
}
Run php artisan migrate and everything should work as expected
If you want to test if the relationship works as expected create a new TestCase with
php artisan make:test ProfileUserRelationTest
In tests\Feature\ProfileUserRelationTest.php
<?php
namespace Tests\Feature;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithFaker;
use Tests\TestCase;
use App\Models\User;
use App\Models\Profile;
use Illuminate\Support\Facades\Hash;
class ProfileUserRelationTest extends TestCase
{
use RefreshDatabase;
public function test_the_relation_between_user_and_profile_works()
{
$user = User::create([
'name' => 'John Doe',
'email' => 'jd#example.com',
'password' => Hash::make('password'),
]);
$profile = new Profile();
$profile->user_id = $user->id;
$profile->save();
$this->assertEquals($user->id, $profile->user->id);
$this->assertEquals($user->name, $profile->user->name);
$this->assertEquals($profile->id, $user->profile->id);
}
}
Now you can run php artisan test to see if everything works.
Be carefull this will refresh your database! So don't test in production.
Output should something like this
PASS Tests\Unit\ExampleTest
✓ that true is true
PASS Tests\Feature\ExampleTest
✓ the application returns a successful response
PASS Tests\Feature\ProfileUserRelationTest
✓ the relation between user and profile works
Tests: 3 passed
Time: 0.35s
Learn more about Relationships in Laravel: https://laravel.com/docs/9.x/eloquent-relationships
Learn more about migrations: https://laravel.com/docs/9.x/migrations
Alternative
$user = User::create([
'name' => 'John Doe',
'email' => 'jd#example.com',
'password' => Hash::make('password'),
]);
$user->profile()->create(...); // replace the ... with the things you want to insert you dont need to add the user_id since it will automatically added it. It will still work like the one above.

How to convert the image title to a slug and save it to the Database? Laravel

A user can upload an image and I want to catch the provided $request image title and convert it to a slug and save it to the Database
UploadScreenShotController#upload:
public function upload(Request $request)
{
if (!auth()->check()) return $this->with('error', 'Session has ended. Please refresh the page and try again.');
$request->validate([
'image' => 'required|image|mimes:jpeg,png,jpg,gif,svg|max:2048',
]);
$image = $request->image;
$filename = $image->getClientOriginalName();
$request->image->move(public_path('images/tcpa/screenshots'), $filename);
return back()
->with('success', 'You have successfully uploaded an image.')
->with('image', $filename);
}
My form:
{!! Form::open(['method' => 'POST', 'files' => 'true', 'route' => ['admin.sms.tcpa-upload-screenshot']])!!}
{!! Form::file('image') !!}
{!! Form::submit('Upload File') !!}
{!! Form::close() !!}
This function gets the image name, but it doesn't convert it to a slug and it doesn't save in the Database.
How to convert the image title to a slug and save it to the Database?
put 'enctype'=>'multipart/form-data'
{!! Form::open(['method' => 'POST', 'files' => 'true','enctype'=>'multipart/form-data', 'route' => ['admin.sms.tcpa-upload-screenshot']])!!}
You can use Sluggable package to create slug in your project. This package provides a trait that will generate a unique slug when saving any Eloquent model.
Installation
You can install the package via composer:
`composer require spatie/laravel-sluggable`
Here's an example of how to implement the trait:
namespace App;
use Spatie\Sluggable\HasSlug;
use Spatie\Sluggable\SlugOptions;
use Illuminate\Database\Eloquent\Model;
class YourEloquentModel extends Model
{
use HasSlug;
/**
* Get the options for generating the slug.
*/
public function getSlugOptions() : SlugOptions
{
return SlugOptions::create()
->generateSlugsFrom('name')
->saveSlugsTo('slug');
}
}
And also remember to add a slug field into you database table. Use Laravel Migration to edit your current Table.
Example ::
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateYourEloquentModelTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('your_eloquent_models', function (Blueprint $table) {
$table->increments('id');
$table->string('slug'); // Field name same as your `saveSlugsTo`
$table->string('name');
$table->timestamps();
});
}
}
And then if you want to use this slug as route name, remember to use Laravel's implicit route model binding in your model file:
/**
* Get the route key for the model.
*
* #return string
*/
public function getRouteKeyName()
{
return 'slug';
}
I think it will help you
If you can do it using the boot method in your model.
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Str;
class YourEloquentModel extends Model
{
protected static function boot()
{
parent::boot();
self::creating(function ($model) {
$model->slug = Str::slug($model->name, '-');
});
}
}
The rest of the things you can follow as #NIVED KRISHNA showed his answer; Like: migration, route model binding.

Can we execute seeder without truncating table or is there any way to achieve this

we are working on a project where I would like to insert one row to database using seeder but when I have executed that seeder it truncates table and insert seeds record. What I want is it should insert a new record only without truncating existing data.
Can anyone help to get this?
This seeder feature is available in mostly all MVC like Laravel and Yii2 that we are using.
use yii\db\Migration;
class m200118_113041_create_table_admin_master extends Migration
{
public function Safeup()
{
$seeder = new \tebazil\yii2seeder\Seeder();
$generator = $seeder->getGeneratorConfigurator();
$faker = $generator->getFakerConfigurator();
$seeder->table('admin_master')->columns([
'email'=>$faker->email,
'password'=>rand(1, 999999),
'created_date'=> date('Y-m-d H:i:s'),
])->rowQuantity(30);
$seeder->refill();
}
public function Safedown()
{
// $this->dropTable('{{%admin_master}}');
}
}
Here above is the example of my migration in Yii2
you can create a new migration file and put insert query in that easily
php artisan make:migration insert_somename_table
than inside migration file
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
use DB;
class InsertSomenameTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
DB::('somename')->insert(array('key1' => 'value1', 'key2' => 'value2'));
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
DB::('somename')->where('key1', '=', 'value1')->delete();
}
}
and execute
php artisan migrate
You can do this in two ways
1.Update your seeder
Consider your table name is 'categories' and you already have 12 categories.
You should start your new category id from 13 in the seeder array.
Your seeder look like this
public function run()
{
$data = array(
['id' => 13, 'category' => 'Category1', 'status' => 1],
['id' => 24, 'category' => 'category2', 'status' => 1]
);
DB::table('categories')->insert($data);
}
2. Execute queries
Write one method and execute insert queries

Laravel Factories how to call them from your database seeder file

How to call the factorie files from the database seeder I looked at the laravel docs and was trying around whit this code
https://laravel.com/docs/5.7/seeding
factory(App\User::class, 50)->create()->each(function ($user) {
$user->posts()->save(factory(App\Post::class)->make());
});
But it didnt work so mine question is how do i call mine factorie from mine database seeder file so i can execute them from the command line?
databaseseeder
<?php
use Illuminate\Database\Seeder;
class DatabaseSeeder extends Seeder
{
/**
* Seed the application's database.
*
* #return void
*/
public function run()
{
Eloquent::unguard();
$this->call(UserFactory::class);
$this->call(PostFacory::class);
$this->call(ProfileFacory::class);
$this->command->info("Database seeded.");
Eloquent::reguard();
}
}
user factorie
<?php
use Faker\Generator as Faker;
$factory->define(App\User::class, function (Faker $faker) {
return [
'name' => $faker->name,
'email' => $faker->unique()->safeEmail,
'email_verified_at' => now(),
'password' => bcrypt('password'),
'remember_token' => str_random(10),
];
});
Database seeding is
php artisan db:seed
In the laravel path... also if you have already seeded you have to clean ( sure if do not have inportant data )
php artisan migrate:refresh
Carefully here :)

How to seed multiple relationships in Laravel with Faker

I have a database with two columns, brands and shops. Each brand can owe several shops, and I want to seed my database via Fakers using Laravel.
So after setting up the migrations and the relationships in the models
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Brand extends Model
{
/**
* Get the shops for the brand.
*/
public function shops()
{
return $this->hasMany('App\Shop','sh_brand_id');
}
}
And:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Shop extends Model
{
public function user() {
return $this->belongsTo('App\Brand','sh_brand_id');
}
}
I want to use a Factory to seed the database.
<?php
use Faker\Generator as Faker;
$factory->define(App\Shop::class, function (Faker $faker) {
return [
'name' => $faker->company,
'address' => $faker->address,
];
});
And
use Faker\Generator as Faker;
$factory->define(App\Brand::class, function (Faker $faker) {
return [
'name' => $faker->company,
'logo_url' => $faker->imageUrl(640, 480),
'website' => $faker->url,
'description' => $faker->text(500),
'telephone_number' =>'31'. $faker->randomNumber(8),
'principal_address' => $faker->address,
'email' => $faker->unique()->safeEmail,
];
});
And finally I need to seed the database using those Factories. There are documentation in the website and many examples for do it, but each solution I've found let me generate only one shop for each brand, and I want to generate many shops for each brands.
What is the best way to do this?
Put it directly in your factory. I use a helper method getInstanceOf to pick a random instance of another model.
use Faker\Generator as Faker;
use App\Brand;
use App\Shop;
function getInstanceOf($class, $returnIdOnly = true) {
$instance = $class::inRandomOrder()->first() ?? factory($class)->create();
return $returnIdOnly ? $instance->id : $instance;
}
$factory->define(Shop::class, function (Faker $faker) {
return [
'name' => $faker->company,
'address' => $faker->address,
'sh_brand_id' => getInstanceOf(Brand::class)
];
});
Then when seeding,
factory(App\Brand::class, 10);
factory(App\Shop::class, 50);
I've found this workaround that works for me:
<?php
use Illuminate\Database\Seeder;
class DatabaseSeeder extends Seeder {
/**
* Run the database seeds.
*
* #return void
*/
public function run() {
factory(App\Brand::class, 50)->create()
->each(
function ($br) {
factory(App\Shop::class, 10)->create()
->each(
function($sh) use (&$br) {
$br->shops()->save($sh)->make();
}
);
}
);
}
}

Categories