How To Set ForeignKey As PrimaryKey Using UUID Trait - laravel

I have 2 table that separate users' login info (email, username, password) and general info (full_name, address, etc).
I set users as parent table with UUID as the PrimaryKey, and profiles as child table with UUID as the PrimaryKey & ForeignKey (I don't know if this is possible, but migration runs without any error).
users_migration
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->uuid('id')->primary();
$table->string('username');
$table->string('email')->unique();
$table->string('password');
$table->rememberToken();
$table->timestamps();
});
}
user_model
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use App\Traits\UUID;
class User extends Authenticatable implements MustVerifyEmail
{
use HasFactory, Notifiable, UUID;
protected $table = "users";
public $primaryKey = "id";
public $incrementing = false;
protected $fillable =
[
'id',
'username',
'email',
'password',
];
protected $hidden = [
'password',
'remember_token',
];
public function profile()
{
return $this->hasOne(Profile::class);
}
}
profiles_migration
public function up()
{
Schema::create('profiles', function (Blueprint $table) {
$table->uuid('user_id')->primary();
$table->foreign('user_id')->references('id')->on('users')->onDelete('restrict')->onUpdate('cascade');
$table->string('full_name')->unique();
$table->longText('address')->nullable();
$table->timestamps();
});
}
profile_model
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Profile extends Model
{
use HasFactory;
protected $table = "profiles";
public $primaryKey = "user_id";
public $incrementing = false;
protected $fillable =
[
'user_id',
'full_name',
'address',
];
public function user()
{
return $this->belongsTo(User::class);
}
}
register_controller
public function Register(Request $request)
{
$newUserData = $request->validate(
[
'full_name' => ['required', 'string', 'min:5', 'max:30'],
'email' => ['required', 'unique:users', 'regex:(gmail)'],
'password' => ['required', 'min:10'],
],
[
'email.regex' => "Your email must use Gmail as its domain.",
'term.accepted' => "You must agree to Larasight's Terms and Conditions."
]
);
User::create([
'username' => Str::lower($newUserData['full_name']),
'email' => $newUserData['email'],
'password' => bcrypt($newUserData['password']),
]);
Profile::create([
'full_name' => $newUserData['full_name'],
]);
}
Error upon registrating : SQLSTATE[HY000]: General error: 1364 Field 'user_id' doesn't have a default value
Question : How to fill the user_id and full_name on profiles_table as the user registrates?

I think you are doing this in an odd way. I would recommend just have an 'id' on your profiles table and have it as the primary. Rather than 'user_id' which is a foreign key be the primary. Anyways, besides that, when you create the Profile object you have not set the primary key. So you would either have to make it nullable in your profiles migration or new up a profile instance without persisting. Lastly, I guess you could just store the User::create() to a variable and pass the id as 'user_id' in the Profile::create function.
$user = User::create([
'username' => Str::lower($newUserData['full_name']),
'email' => $newUserData['email'],
'password' => bcrypt($newUserData['password']),
]);
Profile::create([
'user_id' => $user->id,
'full_name' => $newUserData['full_name'],
]);

Related

laravel 8 admin seeder dosn't seed filed email dosn't have a default value

i am trying to insert values to admin seeder but it dosn't seed i don't know why
i wrote everything correct
and my error is
General error: 1364 Field 'email' doesn't have a default value")
and i don't want to make default value
i just want to seed the table to fill informations
here is my table admin
public function up()
{
Schema::create('admins', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('email')->unique();
$table->string('password');
$table->timestamps();
});
}
and here is my model
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Foundation\Auth\User as Authenticatable;
class Admin extends Authenticatable
{
use HasFactory;
protected $fillable = [
'name','email','password'
];
}
and here is my created AdminSedder.php
<?php
namespace Database\Seeders;
use App\Models\Admin;
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
class AdminSeeder extends Seeder
{
/**
* Run the database seeds.
*
* #return void
*/
public function run()
{
DB::table('admins')->delete();
$infos = [
['name' => 'john'],
['email' => 'john#gm.com'],
['password' => Hash::make('12345678')],
];
foreach($infos as $info){
Admin::insert($info);
}
}
}
and my DatabaseSeeder
public function run()
{
$this->call(AdminSeeder::class);
}
You are passing only the name as value for the seeder. Try this instead:
$infos = [
[
'name' => 'john',
'email' => 'john#gm.com',
'password' => Hash::make('12345678'),
],
];
And if you need more seeds, make sure that the email is unique
It looks like your infos array is invalid. In nested array all elements should be in a same array.
$infos = [
[
'name' => 'john',
'email' => 'john#gm.com',
'password' => Hash::make('12345678'),
]
];
In your AdminSeeder.php try it with the Admin model then import the two classes use App\Models\Admin; and use Faker\Factory as Faker;
public function run()
{
$faker = Faker::create();
Admin::create([
'name' => 'john',
'email' => 'john#gm.com',
'password' => Hash::make('12345678'),
]);
}

SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'user_id' cannot be null?

I got this error when try to seed database.
Laravel 7.
BlogPost Model
class BlogPost extends Model
{
protected $fillable = [
'title',
'slug',
'user_id',
'category_id',
'excerpt',
'content_raw',
'content_html',
'is_published',
'published_at',
'updated_at',
'created_at',
];
public function category()
{
return $this->belongsTo(BlogCategory::class);
}
public function user()
{
return $this->belongsTo(User::class);
}
}
User model
class User extends Authenticatable
{
use Notifiable;
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'name', 'email', 'password',
];
/**
* 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',
];
}
User migration
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('email')->unique();
$table->timestamp('email_verified_at')->nullable();
$table->string('password');
$table->rememberToken();
$table->timestamps();
});
BlogPost migration
Schema::create('blog_posts', function (Blueprint $table) {
$table->increments('id');
$table->unsignedInteger('category_id');
$table->foreignId('user_id')->constrained();
$table->string('title');
$table->string('slug')->unique();
$table->text('excerpt')->nullable();
$table->text('content_raw');
$table->text('content_html');
$table->boolean('is_published')->default(false)->index();
$table->timestamp('published_at')->nullable();
$table->foreign('category_id')->references('id')->on('blog_categories');
$table->timestamps();
});
User seeder
class UserTableSeeder extends Seeder
{
public function run()
{
$users = [
[
'name' => 'Author',
'email' => 'seriiburduja#mail.ru',
'password' => bcrypt('some1234')
],
[
'name' => 'Admin',
'email' => 'seriiburduja#gmail.com',
'password' => bcrypt('some1234')
]
];
DB::table('users')->insert($users);
}
}
BlogPost Factory
$factory->define(BlogPost::class, function (Faker $faker) {
$title = $faker->sentence(rand(3, 8), true);
$text = $faker->realText(rand(1000, 4000));
$isPublished = rand(1, 5) > 1;
$createdAt = $faker->dateTimeBetween('-6 months', '-1 day');
return [
'category_id' => rand(1, 10),
'user_id' => 1,
'title' => $title,
'slug' => Str::slug($title),
'excerpt' => $faker->text(rand(100, 400)),
'content_raw' => $text,
'content_html' => $text,
'is_published' => $isPublished,
'published_at' => $isPublished ? $faker->dateTimeBetween('-6 months', '-1day') : null,
'created_at' => $createdAt,
'updated_at' => $createdAt
];
});
DatabaseSeeder
class DatabaseSeeder extends Seeder
{
/**
* Seed the application's database.
*
* #return void
*/
public function run()
{
$this->call(UserTableSeeder::class);
$this->call(BlogCategorySeeder::class);
factory(BlogPost::class, 1)->create();
}
}
When i run php artisan migrate:fresh --seed i got this error.
Tables users and blog_categories seeds successfully, but error appear for blog_categories.
I don't understand why.
Field user_id exists in $fillable in BlogPost Model.
If i change migration for blog_posts and add a nullable for user_id, than seed work, but user_id is null. But i don't need that.
Thansk in advance.
In Blog Post Model
Change user relationship to
public function owner()
{
return $this->belongsTo(User::class);
}
In User Model
Add this relationship
public function blogposts()
{
return $this->hasMany(BlogPost::class);
}
In Database seeder don't use UserSeeder Directly create user in DatabaseSeeder
public function run()
{
$user = User::create([
'name' => "Your name",
'email' => "youremail#gmail.com",
'password' => Hash::make('YourPassword')
]);
$this->call(BlogCategorySeeder::class);
$user->blogposts()->saveMany(BlogPost::factory(1));
}
In BlogPost Factory remove user_id
return [
'category_id' => rand(1, 10),
'title' => $title,
'slug' => Str::slug($title),
'excerpt' => $faker->text(rand(100, 400)),
'content_raw' => $text,
'content_html' => $text,
'is_published' => $isPublished,
'published_at' => $isPublished ? $faker->dateTimeBetween('-6 months', '-1day') : null,
'created_at' => $createdAt,
'updated_at' => $createdAt
];
fillable is not required when you are using Seeder to insert data.
If you want to insert each and every column in database then you can use guarded property which is opposite of fillable.

Laravel Eloquent Many to Many to One relationship

I'm creating a laravel application where the user logins in and can create clients and fill out an applicant form that is linked to the client.
I'm trying to make a relationship with many users that each have many clients, which have one applicant. But I get the following error:
Error
I'm confused with whats wrong and with naming the functions.
ClientContoller:
public function createApplicant(){
$data = request()->validate([
'name' => 'required',
'dob' => 'required',
'age' => 'required',
'gender' => 'required',
'ethnicity' => 'required',
'country' => 'required',
'interpreter' => '',
'language' => 'required',
'homeAddress' => 'required',
'job' => 'required',
'workAddress' => 'required',
'email' => 'required',
'phone' => 'required',
'contact' => 'required',
'extra' => 'required',
]);
auth()->user()->clients()->applicant()->create([
'name'=>$data['name'],
'dob'=>$data['dob'],
'age'=>$data['age'],
'gender'=>$data['gender'],
'ethnicity'=>$data['ethnicity'],
'country'=>$data['country'],
'interpreter'=>$data['interpreter'],
'language'=>$data['language'],
'homeAddress'=>$data['homeAddress'],
'job'=>$data['job'],
'workAddress'=>$data['workAddress'],
'email'=>$data['email'],
'phone'=>$data['phone'],
'contact'=>$data['contact'],
'extra'=>$data['extra'],
]);
dd($data);
}
User Model:
<?php
namespace App\Models;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
class User extends Authenticatable
{
use HasFactory, Notifiable;
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'name',
'email',
'password',
];
/**
* 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',
];
public function clients(){
return $this->hasMany(Client::class);
}
}
Client Model
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Client extends Model
{
use HasFactory;
public $timestamps = false;
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'name',
'email'
];
public function applicant(){
return $this->hasOne(Applicant::class);
}
}
Applicant Model:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Applicant extends Model
{
use HasFactory;
protected $fillable = [
'fullName',
'date_of_birth',
'age',
'gender',
'ethnicity',
'country',
'interpreter',
'language',
'homeAddress',
'job',
'workAddress',
'email',
'phone',
'contact',
'extra'
];
}
applicants table
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class Applicants extends Migration
{
public function up()
{
Schema::create('applicants', function (Blueprint $table) {
$table->id();
$table->string('fullName');
$table->date('date_of_birth');
$table->string('age');
$table->string('gender');
$table->string('ethnicity');
$table->string('country');
$table->boolean('interpreter');
$table->string('language');
$table->string('homeAddress');
$table->string('job');
$table->string('workAddress');
$table->string('email')->unique();
$table->string('phone');
$table->string('contact');
$table->string('extra');
$table->rememberToken();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('applicants');
}
}
clients table
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class Clients extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('clients', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('email')->unique();
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('clients');
}
}
Any help would be greatly appreciated.
Thank you!
As Maksim mentioned, Laravel is confused which client it should create an applicant for. So, you need to specify it somehow. My suggestion is:
public function createApplicant(Request $request){
$data = request()->validate([
'name' => 'required',
'dob' => 'required',
'age' => 'required',
'gender' => 'required',
'ethnicity' => 'required',
'country' => 'required',
'interpreter' => '',
'language' => 'required',
'homeAddress' => 'required',
'job' => 'required',
'workAddress' => 'required',
'email' => 'required',
'phone' => 'required',
'contact' => 'required',
'extra' => 'required',
]);
$client = Client::find($request->id);
$client->applicant()->create([
'name'=>$data['name'],
'dob'=>$data['dob'],
'age'=>$data['age'],
'gender'=>$data['gender'],
'ethnicity'=>$data['ethnicity'],
'country'=>$data['country'],
'interpreter'=>$data['interpreter'],
'language'=>$data['language'],
'homeAddress'=>$data['homeAddress'],
'job'=>$data['job'],
'workAddress'=>$data['workAddress'],
'email'=>$data['email'],
'phone'=>$data['phone'],
'contact'=>$data['contact'],
'extra'=>$data['extra'],
]);
dd($data);
}
So, you need to form a request before sending data to controller, with an id field, where you specify, which exact client you want to create applicant for.
Alternatively, if you call it like
Route::post('/add_applicant/{id}', 'ClientController#createApplicant');
you could replace Request $request and $request->id with just $id. The main idea is just to pass an id parameter somehow.
However, you still can find a more elegant approach.

How to seed 2 tables that are related to each other in Laravel 8

So I have 2 tables one is the User table and the other is the related UserProfile table. I wanted to fill them with dummy data but I cant get it to work that when I run the seeder it will fill both tables. For now it will fill the User table with dummy data only.
Solution found(any sugestions are welcome)
User.php
<?php
namespace App\Models;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;
use App\Models\UserProfile;
class User extends Authenticatable implements MustVerifyEmail
{
use HasFactory, Notifiable, HasApiTokens;
protected $table = 'user';
protected $fillable = [
'name',
'email',
'password',
];
protected $hidden = [
'password',
'remember_token',
];
public function profile()
{
return $this->hasOne(UserProfile::class, 'user_id');
}
}
UserProfile.php
namespace App\Models;
use App\Models\User;
class UserProfile
{
protected $table = 'user_profile';
protected $fillable = [
'user_id',
'firstname',
'lastname',
];
public function user()
{
return $this->belongsTo(User::class, 'id');
}
}
UserFactory.php
namespace Database\Factories;
use App\Models\User;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Str;
class UserFactory extends Factory
{
protected $model = User::class;
public function definition()
{
return [
'name' => $this->faker->firstName,
'email' => $this->faker->unique()->safeEmail,
'active' => mt_rand(0,1),
'role' => mt_rand(0,5),
'email_verified_at' => now(),
'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi',
'remember_token' => Str::random(10),
];
}
}
UserProfileFactory.php
namespace Database\Factories;
use App\Models\UserProfile;
use Illuminate\Database\Eloquent\Factories\Factory;
class UserProfileFactory extends Factory
{
protected $model = UserProfile::class;
public function definition()
{
return [
'user_id' => User::Factory(),
'firstname' => $this->faker->firstName,
'lastname' => $this->faker->lastName,
'default_language' => 'en',
];
}
}
DatabaseSeeder.php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
use App\Models\User;
class DatabaseSeeder extends Seeder
{
/**
* Seed the application's database.
*
* #return void
*/
public function run()
{
//solution
User::factory(100)->hasProfile(1, function (array $attributes, User $user) {
return ['firstname' => $user->name];
})->create();
}
}
Could you give this a try:
public function definition()
{
$user = [
'name' => $this->faker->firstName,
'email' => $this->faker->unique()->safeEmail,
'active' => mt_rand(0, 1),
'role' => mt_rand(0, 5),
'email_verified_at' => now(),
'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi',
'remember_token' => Str::random(10),
];
UserProfile::create([
'user_id' => $user->id
//any other extra data you have in the user_profiles table
]);
return $user;
}
You need to use for method, Belongs To Relationships
UserProfile::factory()
->for(User::factory()->state([
'name' => 'name', // optional
...
]), 'profile')->state([
'firstname' => 'firstname', // optional
...
])->create();
or
$users = User::factory()->count(100)->create();
foreach ($users as $key => $user) {
UserProfile::factory()
->for($user, 'profile')
->create();
}

Call to a member function details() on null?

My code is:
$user = User::create([
'email' => $request->email,
'password' => Hash::make($request->password),
]);
$user_details = [
'name' => $request->name,
'address' => $request->address,
'lastname' => $request->lastname,
'secondname' => $request->secondname,
'inn' => $request->inn,
'fincode' => $request->fincode,
];
$user->details()->create($user_details);
Model User is:
class User extends Authenticatable implements JWTSubject
{
use Notifiable;
public function details()
{
return $this->hasOne(UserDetails::class, 'user_id', 'id');
}
}
UserDetails model is:
namespace App;
use Illuminate\Database\Eloquent\Model;
class UserDetails extends Model
{
protected $table = 'enterprise';
protected $fillable = ['name', 'lastname', 'secondname', 'address', 'inn', 'fincode'];
}
I believe that your $user has not been persisted, hence having the error, in your case $user is null, that's why you cannot call details on null object. Make sure that you use all the required fields on your user.
You might be missing the fillable array in the User model if the one that you shared is the full content, then add this:
protected $fillable = [ 'email', 'password'];

Resources