I would like to clarify an issue regarding Laravel . These are relationships both at the migration/table level ( Foreign Keys ) and at the Model level (ORM Eloquent ).
I propose an example in which I am currently working, very simple. We have 3 tables ( Worlds, Classes, Races .
Cardinality of relations to be taken into account :
1 World has N Classes and on the other hand 1 World has N Races
Having said this, let's move on to the questions :
Let's start with migrations . I am going to put my example based on the previously mentioned tables:
World Migration
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateMundosTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('mundos', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('nombre')->unique();
$table->string('descripcion');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('mundos');
}
}
Well, the world table doesn't have a foreign key , so I just create the migration with its fields and that's it. There is no doubt or problem so far. Let
's continue... Class Migration
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateClasesTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('clases', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('nombre')->unique();
$table->string('descripcion');
$table->timestamps();
$table->bigInteger('mundo_id');
$table->foreign('mundo_id')->references('id')->on('mundos');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('clases');
}
}
Race Migration
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateRazasTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('razas', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('nombre')->unique();
$table->string('descripcion');
$table->timestamps();
$table->bigInteger('mundo_id');
$table->foreign('mundo_id')->references('id')->on('mundos');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('razas');
}
}
In the last two migrations ( Migration of Class and Migration of Race ) is where the following doubts arise:
I suppose that in terms of migration, the relationships (which in this case is from one to many , is well contemplated, I do not think it is wrong that) but this is just for the migration part . What about Eloquent ( ORM )? That is, each migration corresponds to a model .
I am going to put in this case one of the two models ( Class and Race ) because it is, after all, the same, and the same method will be applied to it, since boththey are of 1-N relationship . Let's put in the example of the Race model :
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Raza extends Model
{
//
}
If you notice, in the part of the model (ORM eloquent) I do not indicate at any time the relationship between the model, as I am doing it is at the migration level. But for the model, to my understanding as I have it , it doesn't know the relationships between the models. My doubts are:
1) Should the relationships between tables be done both at the migration level ( as I have done ) and at the model level ( in my case I have an empty model )?
2)If the answer is yes , would I have to put something like this on my models? :
public function comments()
{
return $this->hasMany('App\Comment');
}
3) Why should it be in a function and what is the meaning of the name?
4) Is it bad to make a relationship at the migration level but not at the model level? I don't understand the need to do it twice(Migration and model)
1) Should the relationships between tables be done both at the migration level (as I have done) and at the model level (in my case I have an empty model)?
The migration relationships help at the database level, don't forget that the database is very independent of what happens in php (
laravel
), for example when trying to eliminate a tuple that has dependent tuples thanks to a foreign key, the database will inform us that this tuple cannot be eliminated until it has no more dependents.Making the relationship at the model level is to be handled in laravel(php), which as I said is independent of the database and these relationships make queries with Eloquent easier to do, what's more, it is not necessary to know sql to make inquiries.
So the answer is: In neither of the two is it mandatory, in the migrations it would be so that your database remains as complete as possible and in the models so that at the time of development your life is easier. ;)
2)If the answer is yes, would I have to put something like this in my models? :
Answer: There are several methods to perform the relationships:
So I invite you to read the Laravel documentation since they are explained in detail there and I don't think I can do better than that.
3) Why should it be in a function and what is the meaning of the name?
Depending on the relationship that exists between models: If 1 World has N Classes, its inverse would be: 1 Class belongs to 1 World, Then in your models you would have something like this:
You see the simplicity of the subject.
Access and use:
4) Is it bad to make a relationship at the migration level but not at the model level? I don't understand the need to do it twice(Migration and model)
I think I've already explained everything and doing it twice isn't necessary, but if you don't want to have problems with your progress or with the system itself, I recommend that you keep doing it that way.
To begin with, you say that:
Well, in the World model you should have the relation to Classes and to Races. In the Classes model you should have the relationship with respect to World and in the Races model, with respect to World.
But, before defining these relationships in the models, you must be clear about what type of relationship it is because everything has its counterpart, whether the relationship is one to one, one to many or many to many.
Example:
Yes:
A) If a Class belongs to a single World, it would be in a one-to-many relationship.
B) If a Class belonged to many Worlds, you would be in a many-to-many relationship.
Example, if it were the case of option (A):
For a one-to-many relationship,
The Mundo model should have:
The counterpart for the Race model, in a one-to-many relationship, would be:
Note the singular or plural of the function names, that is important. Since as 1 World has many Races, the eloquent query that you will use to know the classes that correspond to the World with id = 1, would be simply:
Regarding migrations:
For this type of relationship (one to many), in this case, the breeds table must have:
The field has to be named, name of the model of its counterpart (world) concatenated with "_id".
I think it's good practice, as you've done, to define your foreign keys in migrations, although you could also specify them in model functions.