I'm trying to create a login/register system for a project using laravel, and since it's my first time, I've been running into a lot of troubles, so I'd ask to please forgive me for any extremely dumb mistakes I've made.
I've already succesfully added a new custom field to the default registration screen, but in my modified users table, I also have two foreign keys referencing other tables ('gameInfo_id' refers to the 'gameInfo' table, and 'role_id' refers to the 'roles' table)
This is the error I'm getting:
Does this mean I have to find a way for the foreign key to be filled in automatically? If so, how would I go about doing this?
I've done some googling and found that this usually seems to be issue, but I've never found a clear solution.
Thank you!
Here's my migrations in the users table:
Schema::create('users', function (Blueprint $table) {
$table->increments('id');
$table->string('firstName');
$table->string('lastName');
$table->string('email')->unique;
$table->string('password');
$table->integer('gameInfo_id')->unsigned();
$table->integer('role_id')->unsigned();
$table->timestamps();
});
Schema::table('users', function($table) {
$table->foreign('gameInfo_id')->references('id')->on('gameInfo');
$table->foreign('role_id')->references('id')->on('roles');
});
gameInfo is a table of scores that the user would achieve in a game we're also making. What I'm trying to make happen is, when a new user registers an account, it creates a new row in gameInfo, to which the gameInfo_id foreign key would refer. The columns of this newly created row could be set to 0 by default if it helps
I would do it the other way around.
I would reference the user on the gameInfo table with a user_id column.
that way, the user hasMany gameInfo, and a gameInfo belongs to a user. Since the Game info isn't created before the user is created, and has played a game.
Does that make sense?
If the users table already contains datasets, where some of them don't have existing gameInfo_id or role_id, you can't add an foreign key constraint to the table.
The table must be in an valid state, before you add an foreign key constraint.
That means: Adding an new foreign key constraint to an existing field is not the best idea. Doing it anyway, you have to fix the integrity before.
If your still on an development environment, the best way to fix this would be to start all over again with migrate:refresh.
If the system runs in production with users, you have to fix all users with invalid or unset gameInfo_id and role_id. If you have just a few users, you could do this by hand. If you have many users, you could do some magic inside the migration script (iterate over all users and add missing references, before you add fk constraints).
Since the ->nullable() didn't seem te be recognized by laravel, I instead decided to give each column in gameInfo a default value of 0, which works just fine for me as well.
On the other hand, reversing the FK relationship between users and gameInfo also worked, so my problem's been resolved!
Thank you all very much for your answers, every contribution is appreciated greatly!
Related
I was using the Entrust roles and permission library for Laravel and Lumen. Although I had a reason to use it differently from the way it was supposed to be used because of my unique case. I needed to have multiple instances of of a user with the same role differentiated by a certain foreign key.
Lets assume I wanted a user to have same role for different jobs or different roles for different jobs so I added a job_id to the role_users table to help me filter the roles a user has for for a particular job..
This just means a user can be an admin for job1 and an admin for job2.. This posed a problem because Entrust some how made primary keys of both role_id and user_id on the role_users table..
First I didn't think that was possible, plus I don't understand why.. This also means that I couldn't have multiple instances of the same role_id and user_id which i wanted. I did a little research and found out I could drop a primary key using $table->dropPrimary() method.
I did this in my up() method, although the action needs to be replicated in my down method. I couldnt' create a primary key there because if multiple instances already exist it would thrown a fatal exception.
Basically I need a way to drop the primary key on condition that it exists so I don't have to recreate it in the down method.
You don't need to put anything in down() in this case.
My usual rule for putting something in down() is when the up() contains something that will prevent my migration to rollback successfully.
In your case dropping a primary key won't affect the rollback in any way.
If you really need to have this rollback. You could add some script that handles duplicates in your table and apply the primary key again
I have created two migrations with the Jeffrey Way generators for Laravel 5. Namely: php artisan make:migrate:schema create_roles_table --schema='name:string, description:text' and php artisan make:migrate:pivot user role.
Now, my MySQL database is defaulted to InnoDB, which I've read should be. I also moved the foreign key setup to Schema::table() instead of Schema::create('role_user'). There shouldn't be anything wrong with my migrations, yet they error out with: General error: 1215 Cannot add foreign key constraint (SQL: alter table role_user add constraint role_user_user_id_foreign foreign key (user_id) references user (id) on delete cascade).
Schema::create('role_user', function (Blueprint $table) {
$table->engine = 'InnoDB';
$table->integer('role_id')->unsigned()->index();
$table->integer('user_id')->unsigned()->index();
$table->primary(['role_id', 'user_id']);
});
Schema::table('role_user', function(Blueprint $table){
$table->foreign('user_id')->references('id')->on('user')->onDelete('cascade');
$table->foreign('role_id')->references('id')->on('role')->onDelete('cascade');
});
I have called $table->engine = 'InnoDB'; in every migration. Also have I set all id columns to unsigned, even though they were like that already. I am clueless, who helps me out..
Check to see if you have already migrated the tables users and roles. Otherwise you will not be able to create a foreign key. Check your migration order as well. If you are migrating this one before the users and roles it will fail.
Well, apparently this was a huge typo. user instead of users, for example. I had hoped Laravel would get that right, but unfortunately Laravel and I as well didn't.
This might be related to your SQL engine, check your engine (mariadb, mysql, ...)
And then read the documentation from your engine regarding foreign keys.
Quick solution
Remove the onDelete('cascade') and run the migration.
You can add it manually from phpMyAdmin later on
I am building something that allows users to upload their graphical work and other users can comments on the projects and like other projects.
Now when a user wants to delete their own project it works but as soon as the project has comments or likes I get this error:
Integrity constraint violation: 1451
Cannot delete or update a parent row: a foreign key constraint fails
(`scotchbox`.`comments`, CONSTRAINT `comments_on_projects_foreign` FOREIGN KEY (`on_projects`)
REFERENCES `projects` (`id`)) (SQL: delete from `projects`
where `id` = 31 and `user_id` = 32)
I assume this can be resolved by deleting the comments from the comments table and the likes from the likes table aswell? but I honestly have no idea how to fix this issue with the foreign keys.
I think I need a way to delete the comments and likes of the project before deleting the project itself. Is this possible from the destroy function of my ProjectsController?
This is my destroy function for deleting the projects:
public function destroy($id)
{
$input = Request::all();
Project::whereId($id)->whereUserId(Auth::user()->id)->delete();
return redirect('projects/');
}
When you have a foreign key, you can choose the behavior of deletion.
You have: Users, Projects
User has many Projects
so that means in the Projects schema you will have something similar to this
Schema::create('projects', function(Blueprint $table){
// table fields
$table->integer('user_id')->unsigned();
$table->foreign('user_id')->references('id')->on('users');
});
In this case, you have established a relation without saying "how to behave" if a deletion occurs on the parent (User), that means if you attempt to delete the user, the query exception will be thrown to protect you.
So, if this is the case, you will have to find all the children (Projects) of that parent (User), and delete them before you are able to delete the Parent.
the 2nd solution would be adding onDelete() behavior:
Schema::create('projects', function(Blueprint $table){
// table fields
$table->integer('user_id')->unsigned();
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
});
This means, if you delete the Parent (User) it will automatically find all of the children (Projects) and delete them one by one for you.
Finally, please note that i am using Parent Children analogy in order to clarify the situation, where this analogy only fits in the One to Many relations.
Please avoid using the analogy when you are surrounded by Databasists to protect yourself from further consequences.
The user you try to delete commented on a project. Delete his comments before deleting the user. Or there is a comment on the project you try to delete.
Fixed it by adding onDelete('cascade') to my migrations like this:
Comments migration:
$table->foreign('on_projects')->references('id')->on('projects')->onDelete('cascade');
Likes migration:
$table->foreign('project_id')->references('id')->on('projects')->onDelete('cascade');
I am new to Laravel, so a bit new to this framework's best practices. I am trying to understand the best way to approach creating a database using migrations.
The few examples I found on the web, including the Laravel documentation here and here, seem to refer to migration scripts that handle only one table. I am creating an application with around 10 tables, all interrelated with foreign keys between them, some with many-to-many relationships.
Is the recommended approach to have one migration file per table? If so why? (What are the disadvantages of putting all table creation scripts in one file, if any?)
What about foreign keys and relationships? How does one enforce these relationships, and the order in which migrations are executed such that if table1 references a column in table2, table2 is created before table1?
What about many-to-many relationships? Does the relationship (pivot) table need to be created manually too through a separate migration script? If yes what ensures that it is created after the 2 related tables?
During development of your application I don't think you should care too much having only one table per migration, sometimes it's just easier to have some tables togheter in a single migration, but as soon as your system go to production, you will not be able to keep working like that, because you will only migrate in production and probably never rollback, so your migrations will be really small, sometimes you'll have a migration for a single column creation.
The advantages of putting tables in different migrations is the same of having a thin class, the less information you have in one file, the easier is to manage and make changes on it. So if you put all tables in a single migration, it gets harder to maintain, but that's really up to you.
Foreign keys are a good example of why you should create one migration per table and even per foreign key: every time you rollback a table related to foreign keys, you must first delete all foreign dependencies, that's why Laravel creates a migrates them all in the same order, it helps you never screw a table drop. So, create your tables migrations first, then you create your foreign keys migrations, so when you rollback it will first rollback the constraints and then the tables.
I create foreign keys for a table in the same migration of that table, unless I have too much cross foreign keys. But I always create a foreign key in a separate Schema::table() command, because some databases need you to have the column before attaching the constraint to it:
public function up()
{
Schema::create('statuses', function(Blueprint $table)
{
$table->string('id', 64)->primary();
$table->string('user_id', 64)->index();
$table->text('body');
$table->timestamps();
});
Schema::table('statuses', function(Blueprint $table)
{
$table->foreign('user_id')
->references('id')
->on('users')
->onUpdate('cascade')
->onDelete('cascade');
});
}
About many to many, if you create the table and foreign keys togheter, you should first create the master and then the pivot tables, but if you are creating your foreign keys in separate migrations, first create the tables (order will not matter much, but it's also better to be organized in those cases) and then the migrations for the foreign keys.
During development I do a lot of changes in my tables, so I'm always coming back to them, so this is what I use to do, when I'm altering a migration:
1) php artisan migrate:reset many times
2) Alter migration
3) php artisan migrate
If I'm just creating a new one, usually I won't have any problems, because migrations are usually idepotent.
Your last question was already answered, but I'll say it again: Laravel name the migrations files using timestamps, the way you will never have a migration being ran before another one created before it:
2014_07_16_190821_create_statuses_table
And the name of the migration matter, because this one above will create this class:
CreateStatusesTable
So one thing you must do is to create every migration with a different name, otherwise you will end up with two classes with the same name and, not Laravel, but PHP will complaint about it.
I am very new in laravel.I am doing a project where user first of all sign up and his information will store in a User table.then he or she sign in to the website and the user will provide another form for registration as a Blood donner. This imformation will store another table namely blooddonners table.so i want to make a foreign key in blooddonner table.The foreingn key will be the id from the user table.Thats why i have created a migration for blooddonner table like that,
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateBlooddonnerTable extends Migration {
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('blooddonners', function(Blueprint $table)
{
$table->increments('id');
$table->unsignedInteger('donner_id');
$table->foreign('donner_id')->references('id')->on('users')->onDelete('cascade')->onUpdate('cascade');
$table->string('donner_name');
$table->string('email')->unique();
$table->string('blood_group');
$table->string('phone_number')->unique();
$table->string('location');
$table->date('date_of_birth');
$table->date('last_date_of_donation');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::drop('blooddonners');
}
}
but after submitting the the form,i am facing the following error,
Illuminate \ Database \ QueryException
SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or update a child row: a foreign key constraint fails (`needa`.`blooddonners`, CONSTRAINT `blooddonners_donner_id_foreign` FOREIGN KEY (`donner_id`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE) (SQL: insert into `blooddonners` (`date_of_birth`, `blood_group`, `location`, `email`, `phone_number`, `last_date_of_donation`, `updated_at`, `created_at`) values (2014-08-06, A-, SHERPUR, raihn_cse#yahoo.com, 01796580404, 2014-08- 20, 2014-08-10 19:42:38, 2014-08-10 19:42:38))
though i am very new in Laravel,so i have question that,the way i have set foreign in my migration file ,is it the rigth way to set foreign key ?, cause the error is related to that foreign key.
There's nothing wrong with the way you're setting up foreign keys. Proof of that is that MySQL is actually stopping you from inserting an entry which violates the foreign key you've told it to enforce. The problem is that you're trying to add a blood donor entry without specifying which user it is related to. You have two options, then:
In the query you are using to add the new blood donor, specify the related user's id;
Even though donor_id is the foreign key, it can be nullable if that's what you want, though you need to tell Laravel / MySQL that.
Here's how to define a nullable column:
$table->unsignedInteger('donor_id')->nullable();
I've taken the liberty of correcting your spelling: blood donner > blood donor. Proper spelling helps code readability, too ;)
Edit
If you want a suggestion on how you can improve your database design in order to make good use of foreign keys, here's how I'd approach it:
First thing: I'd only have a secondary blood_donors table if not every user was a blood donor. If 100% of your users are blood donors, don't over-complicate things: use only one table and add more columns. Otherwise, read on.
My users table would probably have all columns that relate to general personal information:
name
email
phone number (unique on users)
location
date of birth
After that I can just "link" the users table and the blood_donors table via foreign keys so I don't have to repeat myself. All I need to know is which user corresponds to which blood donor, and all I need to accomplish that is an id. That way, when I do a query on the database, whether it's on the blood_donors or users table originally, I can easily join both tables together and have all the data at once, without having it repeated in two different places.
So, going back to your migration, this would now suffice:
Schema::create('blooddonners', function(Blueprint $table)
{
$table->increments('id');
$table->unsignedInteger('user_id');
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade')->onUpdate('cascade');
$table->string('blood_group');
$table->date('last_date_of_donation');
$table->timestamps();
});
i.e. you don't need a "donor name" in your blood_donors table, because you already have it recorded on your users table, and they are the same person after all. You should have columns which are pertinent only in the context of donating blood.
You can then access all this data with a query like this (assuming you already have your models set up):
User::join('blood_donors', 'users.id', '=', 'blood_donors.user_id')->get();
And you'd have an object with both tables' columns at once. Just be mindful that columns with the exact same name will override each other in your final object, so if you want to reliably access both ids within that object, you'd better specify aliases on the select portion of the query. You can even change the column names if you have to. In Laravel you can do it like this:
User::select('users.*', 'users.name as donor_name', 'blood_donors.id as donor_id')
->join('blood_donors', 'users.id', '=', 'blood_donors.user_id')
->get();
Take a look at the Eloquent documentation on relationships to see how you can take your database designs further and still maintain clean, readable code.