Set Foreign Key to 'NULL' When delete Relationship in Laravel - mysql

My question is related to Laravel, I have product model and categories. They have a relationship with category_id as a foreign key to product table, my question is, I need when I delete a category, this category_id related field be NULL, I mean, there's a Laravel way to do it? Without be in migration.
This is my Category Model:
public function products()
{
return $this->hasMany('App\Models\Product');
}
This is my Product model:
public function category()
{
return $this->belongsTo('App\Models\Category')->withDefault(function ($data) {
foreach($data->getFillable() as $dt){
$data[$dt] = __('Deleted');
}
});
}

Edit:
I mean its probably possible but I wouldn't recommend doing something that way. You could theoretically do a database query that gets all products that have the category_id of the the category you just deleted, then update them to null as long as your column accounts for null values. You would simply call this (or some variation of this) whenever you're deleting a category. This may have major performance impacts based on the size of the table you're doing this on.
ie. (using model):
Products::where('category_id', '=', $id_i_deleted)->update(['category_id' => null]);
or (using DB):
DB::table('products')->where('category_id', '=', $id_i_deleted)->update(['category_id' => null]);
But I would highly recommend just biting the bullet and altering your table structure. It'll save you infinite headaches in the long run.
Original:
Yes, it is definitely possible! Here is how you should set up your foreign key if you want it to allow for a null value:
Schema::table('products', function(Blueprint $table) {
$table->integer('category_id')->unsigned()->nullable();
$table->foreign('category_id')->references('id')->on('categories')->onDelete('set null');
});

Shorter way using a helper:
Schema::table('products', function(Blueprint $table) {
$table->foreignId('category_id')->nullable()->constrained()->on('categories')->nullOnDelete();
});

Related

how to access data of table having two foreign keys in laravel

i have a table called order_details which is having two foreign keys.
(1.) order_id
(2.) product_id
i have compacted the whole table in my view. when i access the records related to order they are working well but when i try to access the record of products which are foreign as product_id in order_detail table i am getting null.
Table of OrderDetails:
Schema::create('order_details', function (Blueprint $table) {
$table->bigIncrements('id');
$table->unsignedBigInteger('order_id');
$table->foreign('order_id')->references('id')->on('orders');
$table->unsignedBigInteger('product_id');
$table->foreign('product_id')->references('id')->on('products');
$table->integer('quantity');
$table->integer('amount');
$table->timestamps();
});
Model of OrderDetail:
public function order(){
return $this->belongsTo(Order::class);
}
public function products(){
return $this->hasMany(Product::class);
}
Model of Order:
public function orderDetails(){
return $this->hasMany(OrderDetail::class);
}
Model of Product:
public function orderDetail(){
return $this->belongsTo(OrderDetail::class);
}
i have compacted the whole table in $orderDetails on my view. when i try to access data of Order table like this:
$orderDetails[0]->Order['total_ammount']
its working fine as it is accessing the order model through order_id. but with the same way i try to get data from Product Model using product_id like this
$orderDetails[0]->Product['name']
its showing me no error but null.
Can you try be correcting these relations
OrderDetail Model
// individual row of order_details belongs to single product
public function product(){
return $this->belongsTo(Product::class);
}
Product Model to OrderDetail
I don't think this relation will be required as it hasto pass through User Model. Even though correct it as
public function orderDetails() {
return $this->hasMany(OrderDetail::class);
}

Laravel with MySQL relationship foreign key not appearing

I just want to ask if it is normal that, in Laravel, everytime I use foreign key constraint the constraint icon key is not showing inside MYSQL? Also, inside index is not showing.
Note: this is just to clarify if I am doing it the wrong way. Please help amend. Thanks.
This is the image
Schema:
public function up()
{
Schema::create('subjects', function (Blueprint $table) {
$table->increments('id');
$table->string('subject_name');
$table->integer('Level_id')->unsigned()->nullable();
$table->timestamps();
});
}
When you define a Relationship in Laravel, like this:
class Comment extends Model
{
/**
* Get the original post from where the comment is from.
*/
public function post()
{
return $this->belongsTo('App\Post');
}
}
Laravel does not define a relationship constrain in your database by default. This is not how Laravel handle relationships.
To specify one, you need to add the constrain in the migration, like the documentation states:
Schema::table('comments', function (Blueprint $table) {
$table->unsignedInteger('post_id');
// Check this part:
$table->foreign('post_id')->references('id')->on('posts');
});
Update:
I think than the actual version of the docs (L5.6) has removed this part but in the L5.0 you can see it:
Check this part:
Let's imagine that a User model might have one Phone. We can
define this relation in Eloquent:
class User extends Model {
public function phone()
{
return $this->hasOne('App\Phone');
}
}
The first argument passed to the hasOne method is the name of the
related model. Once the relationship is defined, we may retrieve it
using Eloquent's dynamic properties:
$phone = User::find(1)->phone;
The SQL performed by this statement will be as follows:
select * from users where id = 1
select * from phones where user_id = 1
Take note that Eloquent assumes the foreign key of the relationship based on the model name. In this case, Phone model is assumed to use a
user_id foreign key.
As you can see in bold, this is how Laravel manages to get the relationship information.
Also, check this answer.
From the documentation:
Laravel also provides support for creating foreign key constraints,
which are used to force referential integrity at the database level.
For example, let's define a user_id column on the posts table that
references the id column on a users table:
An example using the default users table and a new posts table, defined:
Schema::table('posts', function (Blueprint $table) {
$table->unsignedInteger('user_id');
$table->foreign('user_id')->references('id')->on('users');
});
From this, you can see that $table->unsignedInteger('user_id'); is the definition of the column in the table posts,
Then, we need define the relationship of user_id to users: $table->foreign('user_id')->references('id')->on('users'); defines the re

Use a column value in an other table with laravel query builder

I have two table witch named users & Inbox
In the Inbox table I have a column named sender_id that have the user_id of the sender
I want to show this message in the view. I need a query to get the sender_id from the inbox table and use that to select a certain user from the users table
I need to do this with all messages and all users.
Laravel is basicly straith foward when you use eloquent. You can always customise it.
First, almost all the time, I create a model and a migration at the same time using this : php artisan make:model Something --migration
I know you already make some models and/or migrations, but I'll go step by step to help you understand it.
So, in your case, it'll be php artisan make:model User --migration and php artisan make:model Inbox --migration. Doing this, you get two model named User and Inbox and two migration named date_create_users_table.php and date_create_inboxs_table.php. Maybe you already did the default user table with php artisan make:auth. If it's the case, don't remake one.
I'm not sure about how laravel will name the Inbox model migration... Since, I think, Laravel 5.3, the plurialisation changed and don't always just add an "S" at the end.
Then, now you got your models and migrations, let's add some line into your migration files. Since you want to do a one to many relationship. You don't need to touch the user one. Only the Inbox migration. Each Inbox is related to one User and Users can have many Inboxs. Add something like this in your migration:
public function up()
{
Schema::create('inboxs', function (Blueprint $table) {
$table->increments('id');
$table->integer('user_id');
$table->foreign('user_id')->references('id')->on('users');
all other columns...
});
}
There, you can change the column's name if you need to have a sender, a recipient, etc... Do this instead :
public function up()
{
Schema::create('inboxs', function (Blueprint $table) {
$table->increments('id');
$table->integer('sender_id');
$table->foreign('sender_id')->references('id')->on('users');
$table->integer('recipient_id');
$table->foreign('recipient_id')->references('id')->on('users');
all other columns...
});
}
What we just did, it's creating the Foreign key that Laravel will use to build the query. There is one last part before the fun one. We need to create the relation in our Model. Begin with the user one:
App/User.php
public function inboxs() {
return $this->hasMany(Inbox::class);
}
And now into the App/Inbox.php model:
public function user() {
return $this->belongsTo(User::class);
}
If you need to have a Sender/Recipient/etc... go this way instead:
public function sender() {
return $this->belongsTo(User::class);
}
public function recipient() {
return $this->belongsTo(User::class);
}
Note that each of your function need to be writen in the same way it's into your migration. sender_id need a relation named sender().
Now, that our relations are done, we can simply call everything using eloquent.
$inboxs = Inbox::with('sender')->get();
This will return an array of all your Inbox into the inboxs table. You can access the sender this way: $inboxs[0]->sender();
You need the id, do this: $sender_id = $inboxs[0]->sender_id;
The sender name : $sender_name = $inboxs[0]->sender->name;
If you want to get one Inbox and you have the id, just do this $inbox = Inbox::with('sender')->find($id);
This way you don't get an array, only one result and can access the sender directly using $sender_name = $inbox->sender->name; instead of having to add [0] or using a foreach loop.
You can get all messages sended by a user using something like this:
$inboxs = Inbox::where('sender_id', $sender_id)->get();
Finally, you can pass your data to the view using:
return view('path.to.view')->with('inbox',$inbox);
Into the view you do this to show the sender's name:
//If view.blade.php
{{$inbox['sender']['name']}} //work a 100%
{{$inbox->sender->name}} //I'm not sure about this one
//If not using blade
<?php echo $inbox['sender']['name']; ?>
There is a lot of thing you can do using Eloquent and you can add as much condition you want. The only thing I suggest you to really do if you want to use Eloquent, be aware about the n+1 problem. There is a link where I explain it. Look for the EDIT section of my answer.
If you need some documentation:
Laravel 5.3 Relationships
Laravel 5.3 Migrations
Laravel 5.3 Eloquent
I think you should update your code like:
$user_messages = DB::table('messages')
->select('messages.id as msgId','messages.message as message','users.id as userId','users.user_name as user_name')
->join('messages','messages.user_id','=','users.id')
->where('messages.user_id',$user_id)
->get();
return view("view.path")
->with('messages',$user_messages);
Hope this work for you!
In Model :
namespace App;
use Illuminate\Database\Eloquent\Model;
class Messages extends Model
{
protected $table = 'table_name';
public function sender()
{
return $this->belongsTo('App\User', 'sender_id', 'id');
}
}
In Controller :
public function functionName($user_id){
$messages = Messages::where('sender_id', $user_id)->get();
return view("view.path")
->with('messages',$messages);
}
In view, you can access seder details like this $message->sender->name for name for id $message->sender->id

Save data with 3 relations eloquent

I am trying to save data with eloquent relationship.
I have following three tables: User Table, Category Table and Post Table.
Post Table
Schema::create('posts', function (Blueprint $table) {
$table->increments('id');
$table->integer('category_id')->unsigned();
$table->integer('user_id')->unsigned();
$table->string('heading');
$table->timestamps();
$table->foreign('category_id')->references('id')->on('categories');
$table->foreign('user_id')->references('id')->on('users');
});
Relations:
Category:
public function posts() {
return $this->hasMany('App\Post');
}
Post:
public function user() {
return $this->belongsTo('App\User');
}
public function category() {
return $this->belongsTo('App\Category');
}
User:
public function posts($category) {
return $this->hasMany('App\Post');
}
My Problem is that, how can I save post just by passing the Heading in create function. I want to use the relationship. As an example I want to use this kind of code:
$data = ['heading' => $heading];
$user->posts()->category()->create($data);
Is this possible to do this kind of stuff ?
Or any another simple way to achieve this.
EDIT
I need to create post by using this kind of relationship.
As per the process:
user will fill up the form from which I will get the data along with
the category id.
Now I need to create data for that user related with the given category id.
It's because after you call posts() method you won't get to the model's relation (only the query builder) so you will not access category() relation method. It's because posts are one-to-many relation and you don';t know exacly which record you refer to create data.
EDIT
If you want to create new post entry the the best way to sole this is:
$data = ['heading' => $heading, 'category_id' => $putHereCategoryId];
$user->posts()->create($data);
You'll need to obtain somehow the id of the desire category for the new post's entry.

Laravel 5 migration - foreign key constraint fails

I'm having problems with running my migration. I have a mysql database with some tables. The specific table is product_blender. Some fields in the table are like this:
id (PK)
area_id (FK)
inhabitants (varchar)
heating_type_id (FK)
...
Now I would like to create another table called installateur_types. The table needs to contain a PK and a varchar field. I would also like to create a FK in product_blender table to the id of my newly created tabel.
This is what I've done:
Created migration to create a table:
public function up()
{
Schema::create('installateur_types', function(Blueprint $table)
{
$table->increments('id');
$table->string('type');
});
}
public function down()
{
Schema::drop('installateur_types');
}
Run the migration, this was successful. Table was created with correct fields.
Then I've created the migration to add a FK field to the product_blender table.
public function up()
{
Schema::table('product_blenders', function ($table) {
$table->integer('installateurtype_id')->unsigned();
$table->foreign('installateurtype_id')->references('id')->on('installateur_types')->onDelete('cascade');
});
}
public function down()
{
//
}
When I now run the migration I get the following error:
What am I doing wrong?
If your products_blender table is not empty, then when you add a new column which is not null (which is the default for eloquent), it will be assuming some default value on its own. This value may not be available in the table this new column is referring to, causing the foreign key constraint to fail.
One of the way to get around this is to give a default value to the new column or just make it nullable.
$table->integer('installateurtype_id')->unsigned()->nullable();
$table->foreign('installateurtype_id')->references('id')->on('installateur_types')->onDelete('cascade');
There is one other solution, which turns off this checks, which can be done using DB::statement('SET FOREIGN_KEY_CHECKS=0;'). Then again turn that one for future with DB::statement('SET FOREIGN_KEY_CHECKS=1;'). In you code you can do something like
DB::statement('SET FOREIGN_KEY_CHECKS=0;');
$table->integer('installateurtype_id')->unsigned();
$table->foreign('installateurtype_id')->references('id')->on('installateur_types')->onDelete('cascade');
DB::statement('SET FOREIGN_KEY_CHECKS=1;');