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

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.

Related

How To Set ForeignKey As PrimaryKey Using UUID Trait

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'],
]);

How to remove only fields I just added with Laravel migration?

I'm adding these values to an existing table. In my down() function, how do I remove only the items I just added? truncate() will remove all the items in the table. I can use DB::table('user_account_cancel_reasons')->where('action', '==', 'cancel')->delete();, but that doesn't guarantee only removing the items in this migration. Using Laravel 7.
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AddNewFieldsToUserAccountChangeReasons extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
DB::table('user_account_change_reasons')->insert(
[
[
'reason' => 'Health Issues',
'action' => 'cancel',
'created_at' => DB::raw('CURRENT_TIMESTAMP'),
'updated_at' => DB::raw('CURRENT_TIMESTAMP')
],
[
'reason' => 'Did not use',
'action' => 'cancel',
'created_at' => DB::raw('CURRENT_TIMESTAMP'),
'updated_at' => DB::raw('CURRENT_TIMESTAMP')
],
[
'reason' => 'Other',
'action' => 'cancel',
'created_at' => DB::raw('CURRENT_TIMESTAMP'),
'updated_at' => DB::raw('CURRENT_TIMESTAMP')
],
]
);
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::table('user_account_change_reasons', function(Blueprint $table) {
DB::table('user_account_change_reasons')->truncate();
});
}
}
Try, i solved it
public function down()
{
Schema::table('user_account_change_reasons', function(Blueprint $table)
{
DB::table('user_account_change_reasons')->where('action',
'cancel')->delete();
});
}

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.

Integrity constraint violation Laravel 5.8

I have a ‘recurring_payments’ table
Schema::create('recurring_payments', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('user_id');
$table->string('card_id');
$table->string('day');
$table->integer('amount');
$table->timestamps();
});
I have a ‘card’ table
Schema::create('cards', function (Blueprint $table) {
$table->increments('id');
$table->unsignedInteger('user_id');
$table->string('token');
$table->string('last4');
$table->timestamps();
$table->softDeletes();
});
I have a ‘belongs to’ relationship between a ‘recurring_payment’ and a ‘card’
class RecurringPayment extends Model
{
protected $guarded = [];
public function card()
{
return $this->belongsTo(Card::class, 'token');
}
}
When I try to store the recurring payment
class Card extends Model
{
use SoftDeletes;
protected $fillable = [
'user_id',
'token',
'last4',
];
protected $hidden = [
'user_id',
'token',
'created_at',
'updated_at',
];
...
public function storeRecurringPayment($payment, $user)
{
$attributes = [
'user_id' => $user,
'card_id' => $payment->source['id'],
'day' => Carbon::now()->day()->addMonths(1)->format('d'),
'amount' => $payment->amount
];
// dd($attributes);
return $this->recurringPayment()->create($attributes);
}
public function recurringPayment()
{
return $this->hasOne(RecurringPayment::class);
}
...
}
it will not populate the ‘card_id’, it complains that the ‘card_id’ cannot be null, which is what I want, so far enough, but the ‘card_id’ is populated, this is the $attributes array died and dumped just before it's passed to the 'return $this->recurringPayment()->create($attributes);'
array:4 [▼
"user_id" => 3
"card_id" => "src_4zcdnrruvgxetpkgxocg6hhk5m"
"day" => "30"
"amount" => 10
]
I’m specifying in the ‘recurring_payment’ that I want to use ‘token’ as the foreign key not the default ‘card_id’ but I still get this error
SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'card_id' cannot be null (SQL: insert into 'recurring_payments' ('user_id', 'card_id', 'day', 'amount', 'updated_at', 'created_at') values (3, ?, 30, 10, 2019-07-11 13:53:08, 2019-07-11 13:53:08))
Can anyone see the mistake I've made?

How to add new column in Laravel's default Users table?

I modified the default laravel's user table and I did that by creating my own migration.
Here's my migration sample:
public function up()
{
Schema::table('users', function (Blueprint $table) {
$table->string('username', 15)->unique()->after('id');
$table->string('lastname', 15)->unique()->after('username');
$table->string('firstname', 15)->unique()->after('lastname');
$table->string('contact')->nullable()->after('email');
$table->date('birthday')->after('contact');
$table->tinyInteger('status')->default(1)->after('birthday');
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::table('users', function (Blueprint $table) {
$table->dropColumn('username');
$table->dropColumn('lastname');
$table->dropColumn('firstname');
$table->dropColumn('contact');
$table->dropColumn('birthday');
$table->dropColumn('status');
});
}
And I removed the column name in the default laravel table so it looks like this:
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->increments('id');
$table->string('email')->unique();
$table->string('password', 60);
$table->rememberToken();
$table->timestamps();
});
}
I checked the values from my form in the AuthController and I dont have an issue in getting the values. Here's what I added in the AuthController
protected $username = 'username'; //choose username instead of email
protected $redirectPath = '/dashboard'; //if successful login
protected $loginPath = 'auth/login'; //if not login
protected $redirectAfterLogout = 'auth/login'; //redirect after login
/**
* Create a new authentication controller instance.
*
* #return void
*/
public function __construct()
{
$this->middleware('guest', ['except' => 'getLogout']);
}
/**
* Get a validator for an incoming registration request.
*
* #param array $data
* #return \Illuminate\Contracts\Validation\Validator
*/
protected function validator(array $data)
{
return Validator::make($data, [
'username' => 'required|min:8|max:16|unique:users',
'lastname' => 'required',
'firstname' => 'required',
'contact' => 'required',
'birthday' => 'date_format: Y-m-d',
'email' => 'required|email|max:255|unique:users',
'password' => 'required|confirmed|min:6',
]);
}
/**
* Create a new user instance after a valid registration.
*
* #param array $data
* #return User
*/
protected function create(array $data)
{
//dd($data); -- I can get all the values here
// I added my own column in this part to save. Is it correct?
return User::create([
'username' => $data['username'],
'lastname' => $data['lastname'],
'firstname' => $data['firstname'],
'birthday' => $data['birthday'],
'contact' => $data['contact'],
'email' => $data['email'],
'status' => 1,
'password' => bcrypt($data['password']),
]);
}
And when I try to save the data I can only save these columns
mysql> select * from users \G;
*************************** 1. row ***************************
id: 1
username:
lastname:
firstname:
email: myemail#gmail.com
contact: NULL
birthday: 0000-00-00
status: 1
password: $2y$10$3NkmqZaje4MKzheqPZKbhOIGD7ZlqYRfIP6DJZz4zb4gXVNvFsv2W
remember_token: PCYczF2Y9ts97TvbDOLsiXO5hxkekkxysmMYuIdN5MsaIY8TnroEof6d2jVM
created_at: 2015-09-17 06:56:43
updated_at: 2015-09-17 07:00:35
1 row in set (0.00 sec)
ERROR:
No query specified
How can I add my new column in the database?
Ok that's all I hope you can help me.
You can not edit the users table with this way
first, go to the terminal and write this command :
php artisan make:migration add_new_fields_to_users_table
and click enter.
After that, go to the migration file and in the add_new_fields_to_users_table.php
and write your new columns
$table->string('username', 15)->unique()->after('id');
$table->string('lastname', 15)->after('username');
$table->string('firstname', 15)->after('lastname');
$table->string('contact')->nullable()->after('email');
$table->date('birthday')->after('contact');
$table->tinyInteger('status')->default(1)->after('birthday');
Then , go to the terminal and do this:
php artisan migrate
and finally go to the User model and add the name's of your new table to the fillable variable
protected $fillable = [
'name', 'email', 'password','username',
'lastname','firstname','contact','birthday','status'
];
I hope this will help you
Ok I found the answer.
I need to put my own custom column in the fillable content:
protected $fillable = ['username', 'lastname', 'firstname', 'contact', 'email', 'birthday', 'status', 'password'];
Three files you need no adjust when you are adding new fields to the default users table or modifying to the default users table:
Users model found in Controllers\User.php or Controllers\Models\User.php
Update:
protected $fillable = [
'name',
'email',
'password',
];
Register blade in view located in views\auth\register.blade.php
Add new text-field for your new fields
Register Controller located at Controllers\Auth\RegisterController.php
Update:
Validator function and create function
protected function validator(array $data)
{
return Validator::make($data, [
'name' => ['required', 'string', 'max:255'],
'email' => ['required', 'string', 'email', 'max:255', 'unique:users'],
'password' => ['required', 'string', 'min:8', 'confirmed'],
]);
}
protected function create(array $data)
{
return User::create([
'username' => $data['username'],
'email' => $data['email'],
'phone' => $data['phone'],
'password' => Hash::make($data['password']),
]);
}
Users table found in database\migrations\create_users_table.php
Add/Modify your schema
In the start I was able to add a role column to the users table like this.
public function up()
{
Schema::create('users', function (Blueprint $table) {
...
$table->string("role")->default("user");
...
});
}
I ran migrate and rollback commands several times while I was testing the application with different data. Later I needed two more columns in the user table.
Did as I had done before but failed.
Solved my problem with this artisan command and I was able to add more columns just by defining them in the user table schema as above.
Warning:
This rolls back all the migrations and you will lose all the data in your database. Make sure that you intentionally wanna happen this to the data.
php artisan migrate:reset

Resources