In my Laravel 9 application with a MySQL database, I am trying to add a comment to a unique contraint with a migration file. According to the Laravel documentation adding comments is only allowed on column modifiers (thus no support for the unique constraint). However, when I look at the MySQL documentation I see MySQL does support it.
My following code will silently ignore the comment on the unique constraint:
Schema::create('customer_order', function (Blueprint $table) {
$table->id();
$table->unsignedInteger('customer_id');
$table->unsignedInteger('order_id');
$table->foreign('customer_id')->references('id')->on('customer');
$table->foreign('order_id')->references('id')->on('orders');
$table->unique(['customer_id'])->comment('To enforce this is table is used as a one to many relationship.');
$table->unique(['customer_id', 'order_id']);
}
Since it appears that Laravel does not support adding comments on indexes (like a unique constraint), is there a workaround?
p.s. I am aware I strictly do not need a pivot table in this situation. Please just assume I need the pivot table setup for some historical or technical reason.
Related
In Laravel, pivot tables are used to define many-to-many relationships between two models. When creating a pivot table, one has the option of defining an auto-incrementing id field as the primary key or using a UUID instead.
For example, consider the following pivot table that links a benefits table with a units table:
Schema::create('benefit_unit', function (Blueprint $table) {
$table->uuid('id')->primary();
$table->uuid('benefit_id');
$table->uuid('unit_id');
$table->timestamps();
$table->foreign('benefit_id')->references('id')->on('benefits');
$table->foreign('unit_id')->references('id')->on('units');
});
As you can see, this pivot table uses UUIDs as primary keys instead of auto-incrementing IDs.
My question is: does it make any sense to use UUIDs for pivot tables, or is it better to use auto-incrementing IDs like the default behavior in Laravel? Are there any potential security advantages to using UUIDs for pivot tables, or are there any downsides to using them?
I readed an amazing post about this recently. The conclusion of the article is this:
But based on our experience, 95% of the time, the default choice should ? always be Auto Increment Integer. Why?
Readability, and readability leads simplicity. Number is easy to write, easy to remember and easy to communicate. The primary key is not only used by the system, it's also exposed to the end user (e.g. order #), inspected by the operation engineer, customer suppport etc...
If you want more details about that, this is the post: https://www.bytebase.com/blog/choose-primary-key-uuid-or-auto-increment
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'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!
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 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.