I am trying to create a relationship in Laravel Migration:
User > has many > Images
User > has one > Image (image_id) <-- Avatar
Image > belongsTo > User (user_id)
If I will create the migration with references to mark the relationships, the migration will fail because image needs User, and User needs image.
How should I order migrations to prevent this from happening?
(https://laravel.com/docs/5.4/migrations)
You can create users and images tables in any order and add foreign key constrains in the second migration after creating the table. Or even in a separate migration file.
To add constrains use table() method instead of create():
Schema::table('images', function (Blueprint $table) {
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
});
Related
So, as the title says, I have two pivot tables in my Laravel project (I am still new to Laravel). My project is an Instagram clone and I have made the like function, which uses one of the two pivot tables I made and now I'm trying to make a "Save" function, similar to the actual Instagram app where people can save posts and view them at a later time. The problem is, when I check my tinker and do:
As you can see, it looks like the likes and saves are using the pivot table for likes, I have not inserted anything into the pivot table for saves yet. Here are my migrations
For likes:
Schema::create('post_user', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('user_id');
$table->unsignedBigInteger('post_id');
$table->timestamps();
});
And for saves:
Schema::create('post_user_saves', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('user_id');
$table->unsignedBigInteger('post_id');
$table->timestamps();
});
I'm aware that they are literally the same but, just like the Instagram app, a user can like a post without saving it and vice-versa and they can also like and save it at the same time. I want to insert into the post_user_saves when I click a button. Here are pics of my database as well, as you can see the post_user_saves table is empty while post_user is not, meaning that tinker is getting the pivot data from post_user
and lastly, here are the codes from my model:
public function likes()
{
return $this->belongsToMany(Post::class);
}
public function saves()
{
return $this->belongsToMany(Post::class);
}
EDIT:
here is my store method for the likes:
public function store(Post $post){
return auth()->user()->likes()->toggle($post->id);
}
I don't have the store method for my saves yet but my plan is to make it the same as the one above hence why I need to be able to store to post_user_saves.
If your relationships are correct you can use attach() to save to the pivot:
auth()->user()->likes()->attach(auth::id(), ['column' => 'value']);
The reason your save is updating the same table is because you are pretty much using the exact same relationship so eloquent doesn't know about your post_user_saves table what you would need to do is Create a model Save() then rename your migration to save_users and update your relationship accordingly.
I followed a tutorial about many-to-many relationships with Laravel (7 in my case).
The result is good, I learned a lot, but what I find strange is that I do not have physical relationships between the different tables.
I created a relationship many to many, which should link 3 tables, products, categories and products_categories
My questions :
1- Is it essential to have a physical relationship in the schema of the database?
2- How can I make these relationships appear in my diagram?
Here is a current photo of the database schema :
In this database, I have links between tables :
The Laravel relationships are not the same as your database relationships (MySQL, or others).
You don't need to have a database relationship to have your application working. it is really depending on what you are trying to achieve.
If you want to see the relationships between your tables, make sure to specify the foreign keys in your migration Schema (https://laravel.com/docs/7.x/migrations#foreign-key-constraints) such as:
Schema::table('posts', function (Blueprint $table) {
$table->unsignedBigInteger('user_id');
$table->foreign('user_id')->references('id')->on('users');
});
For pivot tables you can also use a migration Schema as follow:
Schema::table('category_product', function (Blueprint $table) {
$table->unsignedBigInteger('category_id');
$table->unsignedBigInteger('product_id');
$table->foreign('category_id')->references('id')->on('categories');
$table->foreign('product_id')->references('id')->on('products');
});
I am back adding foreign keys to some tables but this one is not working.
Schema::table('users', function(Blueprint $table){
$table->integer('account_type')->unsigned()->change();
$table->foreign('account_type')
->references('id')
->on('account_types');
});
It throws these 3 errors in terminal:
[Illuminate\Database\QueryException] SQLSTATE[HY000]: General error: 1215 Cannot add foreign key constraint (SQL: alter table `users` add constraint `users_account_type_foreign` foreign key (`account_type`) references `account_types` (`id`))
[Doctrine\DBAL\Driver\PDOException]SQLSTATE[HY000]: General error: 1215 Cannot add foreign key constraint
[PDOException] SQLSTATE[HY000]: General error: 1215 Cannot add foreign key constraint
Any idea what I need to do to fix this? I wan't to be able to click on the account_type field in my users table and be taken to the related account type in the account_types table whilst using SequelPro.
If we assume that you've already created account_types and users, then this is what you could do.
Run this command to create a new migration.
php artisan make:migration add_account_type_to_users
Then add this to your up function, what this will do is update the already existing users table, with adding a column account_type and then adding the foreign key to the account_types table.
public function up()
{
Schema::table('users', function(Blueprint $table) {
$table->integer('account_type')->unsigned();
$table->foreign('account_type')->references('id')->on('account_types');
});
}
Then add this to your down function, to allow the migration to run smoothly incase of future changes and/or a refresh.
public function down()
{
Schema::table('users', function(Blueprint $table) {
$table->dropColumn('account_type');
});
}
I am assuming your issue is with the dating of the migration files - I would advice you to go over them and make sure they get executed in the right order.
I suggest that you create a migration specifically to add the foreign key constraint. Migrations should be created in such a way that each change to your database is a NEW migration. That way if something goes wrong, you can roll it back. "Back adding" as you said you were doing is likely the root of the problem. Like some users have suggested, the order in which your migrations are created is critical to how the database is built. And you must have created both participating tables in order to create a foreign key constaint on them.
Your table 'account_type' need to be created before 'users' table.
Basically on Laravel, users table is the first created, to resolve it you can put all schema on One migration file. or you need to change the date in the name of the users file, because laravel execute migrations in name order.
I make my migration like this :
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class DatabaseContent extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
$connection = config('database.default');
Schema::connection($connection)->create('account_type', function
(Blueprint $table) {
// Own Method
}
Schema::connection($connection)->create('users', function
(Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->timestamps();
});
I have a problem with delete using laravel 5.4
I have 3 tables: Users, Posts, Vechicles
User hasMany Posts
Vehicle belognsTo Post
Post hasMany Vehicles
...anyway...when creating the schema for the vehicle table, i use 2 foreign keys:
$table->foreign('post_id')->references('id')->on('posts')->onDelete('cascade');
$table->foreign('post_user_id')->references('user_id')->on('posts');
When i want to delete a post, all the vehicles that are related to the post to be deleted....but is not working (it gives an error about constraint)
Can someone tell me what i am wrong? it is that i am using 2 foregin keys?
check this
$table->engine = "InnoDB";
Using one foreign key solve the issue:
Schema::create('vehicles', function (Blueprint $table) {
$table->increments('id');
$table->string('mark');
$table->string('model');
$table->integer('weight');
$table->string('vehicle_state');
$table->integer('post_id')->unsigned();
$table->integer('post_user_id')->unsigned();
$table->foreign('post_id')->references('id')->on('posts')->onDelete('cascade');
});
I'm trying to build some relationships in Laravel, i'm a little confused about relationships and migrations. Here is a simple example of what i'm doing:
Users -> has_many -> Cats
So my Users migration file has a relationship to Cats like so:
$table->foreign('cats_id')->references('id')->on('cats')
But when I run my migration, I get:
Error: relation cats does not exist...
Do I need to build the Cats table before the Users table?
Do I also need to specify the foreign relation between the two, or if the models contain "hasMany" and "belongsTo" wouldn't Laravel build those relationships automatically on migration?
Do I actually need migrations?
You can't reference a table that not exists. It has nothing to do with Laravel or Eloquent, it's (My)SQL thing.
First create the parent table users, then the child table cats referencing the first:
$table->foreign('user_id')->references('id')->on('users')
this is how User hasMany Cat would look like. cats table has foreign key referencing users table, not the other way around like you tried.
You need to set the foreign key to the table where the 'many' are.
$table->foreign('id')->references('cats_id')->on('Users')
You need to make sure that
Table 'Users' exists before you create table Cats (Or any other table that is referenced)
Column 'id' exists before you create the foreign key. (Or any other column that is referenced)
A quite bulletproof solution for me is to setup the tables with a first migration eg
public function up()
{
Schema::create('users', function(Blueprint $table)
{
$table->increments('id');
$table->timestamps();
$table->string('cats_id');
});
//and
Schema::create('cats', function(Blueprint $table)
{
$table->increments('id');
$table->timestamps();
$table->string('cat_name');
});
}
in one migration file and then I create another migration file that runs in the end and creates all the foreign keys for all migrations that were running before:
public function up()
{
Schema::table('cats', function(Blueprint $table)
{
$table->foreign('id')->references('cats_id')->on('users');
});
}
You can also choose what should happen to your cats table on update or delete of a user by adding eg
->onUpdate('CASCADE')->onDelete('CASCADE');
to the $table->... line
You will have to run the migration for cats table and create that table before you can associate it with users table.
Foreign key relation will be helpful when you are required to do cascade delete or update. Also an insert like the following will be easier for you with the cats relationship set.
$user = User::find(1);
$cats = array(
new Cat(array('name' => 'Kitty')),
new Cat(array('name' => 'Lily')),
);
$user->cats()->save($cats);
When specifying a relationship on User Model the Cat model also needs to exist.
In migration
Users
$table->foreign('cats_id')->references('id')->on('cats');
Cats
$table->foreign('user_id')->references('id')->on('users');
Now you force integrity on database level.
Migrate
run the migration using php artisan migrate
Next step is to add the integrity on you Model
Model
User.php
public function cats()
{
return $this->hasMany('Cats');
}
Cat.php
public function user()
{
return $this->belongsTo('User');
}