I'm looking for a strategy for destroying Eloquent aggregates, e.g. models that "contain" other models.
In Ruby on Rails's ActiveRecord, there is a dependent: :destroyoption that can be placed when defining relations, meaning that if e.g. an order is deleted, then the order_lines must go too.
Is there something similar in Laravel? Or any other alternatives besides manually cleaning up and wrapping it in a transaction?
If you use Laravel schema builder, you should use foreign key and for foreign key add for example:
$table->foreign('entry_id')
->references('id')
->on('entries')
->onDelete('CASCADE');
You can of course do the same in for example phpMyAdmin.
When using such construction, if in this case record from entries will be deleted, automatically record from this table that have entry_id the same as id from entries that is being delete will be deleted.
It's not a trigger, because trigger are much more complex structure, it's just defining relation and telling what to do if related parent record will be deleted.
Related
I have some query related to Eloquent Relationships in Laravel.
If I didn't specify a foreign key when using any relationship defined by laravel so laravel makes it work by assuming the foreign key based upon the parent model name as written in laravel 8 documentation.
So what I want to ask is that if laravel is only assuming means laravel will make the relationship work but data consistency will not be maintained by laravel as what foreign key does? Am I right?
And if I am right then the solution will be to explicitly define the foreign key in migration file when using relationships?
I guess, you're mixing two things, the database's DDL/schema and the ORM/database abstraction layer:
The database's DDL/schema defines, how the database itself is structured and works. In Laravel, this can be controlled via migrations.
The ORM/database abstraction layer normally doesn't alter the schema, it just does CRUD (which is DML not DDL). In Laravel, this can be done with either the query builder or Eloquent, which is an ORM.
That means, the former creates the foreign key constraints, the latter only assumes a column name to put in the SQL query it creates
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 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.
What is the best practice to keep database integrity while using laravel's polymorphic relations?
I'm using Model Observers to update/delete related models. So for example I delete related Documents on "deleted" event while deleting a Customer.
That means if an error occurs while deleting first document the rest will stay in the database... Or if I wrap documents deleting in a transaction all of them will stay in the database while parent object is deleted...
Unfortunately, there is no good answer for that problem. You can not keep your database integrity with foreign keys because of the polymorphic relation.
One way to try is to use database triggers. As Laravel polymorphic system keep a "type" column on the table that references the related model, you could put a "before delete" trigger on tables that can be morphed to delete all occurences that references the raw you want to delete.
For example, with the structure used in Laravel documentation :
staff
id - integer
name - string
orders
id - integer
price - integer
photos
id - integer
path - string
imageable_id - integer
imageable_type - string
You can put an "before delete" trigger on staff table that executes a query (PostgreSQL syntax here) like that :
DELETE FROM photos WHERE imageable_id = OLD.id AND imageable_type = 'staff'
That way, each time you delete a staff raw, all referenced photos will be deleted in the same transaction.
I really don't know if it's the best way to keep integrity with this kind of relation, but it seems to be an efficient one.
I have two tables, Inventory and, say, Stuff. Inventory is used to store data common to Stuff and other tables. The way the DBA envisioned this working would be with us inserting the Inventory table and then using the generated ID to insert the Stuff table.
How can I implement this scenario using Doctrine 2? I'm tempted to just add a 1:1 relationship on the model but I'm not sure I can convince the DBA to change the database.
With the workaround described here http://www.doctrine-project.org/docs/orm/2.0/en/reference/limitations-and-known-issues.html#foreign-keys-as-identifiers you should be able to get the DBAs schema working. With version 2.1 of Doctrine (or the current master) you can use the new foreign key as identifier feature to get it working.
However if you are not using Sequences of Oracle/Postgresql you need to flush operations for this (persist parent, flush, associate and persist child, flush)