Herramientas de usuario

Herramientas del sitio


informatica:programacion:php:frameworks:laravel:relaciones_entre_modelos

¡Esta es una revisión vieja del documento!


Relaciones entre modelos

Relaciones uno a uno

Por ejemplo, un pago pertenece a una orden y una orden tiene un único pago.

Para estas relaciones se necesitan claves foráneas.

El modelo que pertenece a otro es el que lleva la clave foránea. Para el ejemplo, anterior, un pago pertenece a una orden, así que será el pago quien lleve la clave foránea de la orden.

Por consistencia, se recomienda que la clave foránea se llame igual que el modelo relacionado seguido de _id.

Vamos la migración donde se crea un orden:

// code
 
class createPaymentsTable extends Migration 
{
    public function up()
    {
        Schema::create("orders", function (Blueprint $table) {
            $table->id();
            $table->float("amount")->unsigned();
            $table->timestamp("payed_at")->nullable();
            $table->bigInteger("order_id")->unsigned();
            $table->timestamps();
 
            // Establecemos la relación de la clave foránea con la clave
            // primaria de la tabla padre
            $table->foreign("order_id")->references("id")->on("orders");
        });
    }
    // code
}

Ahora tenemos que relacionar a nivel de modelo las órdenes y los pagos. Vamos al model Order.php:

namespace App;
 
use App\Model\Payment;
use Illuminate\Database\Eloquent\Model;
 
class Order extends Model {
 
    protected $fillable = ["status"];
 
 
    public function payment() 
    {
        // Una orden tiene un pago
        return $this->hasOne(Payment::class);
 
    }
 
}
 

Ahora tenemos que ir al modelo Payment.php para poder decir que pertenece a una orden:

namespace App;
 
use App\Models\Order;
 
// code
 
    protected $fillable = [
        "amount",
        "payed_at",
        "order_id"
    ];
 
    public function order() 
    {
        return $this->belongsTo(Order::class);
    }

Para hacer pruebas:

php artisan tinker

Creamos una orden:

$order = App\Models\Order->factory->create();

Creamos un pago asociado a la orden anterior:

$payment = App\Models\Order::factory->create(["order_id" => $order->id]);

Está estblaceida una relación, de tal manera que podemos acceder al pago desde la orden:

$order->payment;

Y desde el pago a la orden a la que pertenece:

$payment->order;

Si hubiéramos puesto los paréntesis en payment u order, obtendríamos un query builder que nos permitiría afinar más la consulta encadenando métodos ($payment→order()→where(…))

Relaciones uno a muchos

Por ejemplo, un usuario puede tener múltiples órdenes. Sin embargo, una orden pertenece a un único usuario.

Para estas relaciones se necesitan claves foráneas.

El modelo que pertenece a otro es el que lleva la clave foránea. Para el ejemplo, anterior, una orden pertenece al usuario, así que será la orden quien lleve la clave foránea del usuario.

Vamos la migración donde se crea una orden:

// code
 
class createOrdersTable extends Migration 
{
    public function up()
    {
        Schema::create("orders", function (Blueprint $table) {
            $table->id();
            $table->string("status")->default("pending");
            // Clave foránea:
            $table->bigInteger("customer_id")->unsigned();
            $table->timestamps();
 
            // Establecemos la relación de la clave foránea con la clave
            // primaria de la tabla padre
            $table->foreign("customer_id")->references("id")->on("users");
        });
    }
    // code
}

Ahora tenemos que relacionar a nivel de modelo las órdenes y los pagos. Vamos al model Order.php:

namespace App;
 
use App\Model\User;
use Illuminate\Database\Eloquent\Model;
 
class Order extends Model {
 
    protected $fillable = [
        "status",
        "customer_id"
    ];
 
    // code
 
    public function user() 
    {
        // Una orden tiene un pago
        return $this->belongsTo(User::class);
 
    }
 
}
 

Laravel, cuando indicamos relaciones (por ejemplo, belongsTo), supone que la clave foránea tendrá el nombre del modelo + _id. Por tanto, en el código anterior, Laravel espera que exista en la tabla orders un campo llamado user_id. Si queremos indicar explícitamente el nombre de la clave foránea a utilizar:

    public function user() 
    {
        // Una orden tiene un pago
        return $this->belongsTo(User::class, "customer_id");
 
    }

Ahora tenemos que ir al modelo User.php para poder decir que puede tener muchas instancias de orden:

namespace App;
 
use App\Models\Order;
 
// code
 
    protected $fillable = [
        "amount",
        "payed_at",
        "order_id"
    ];
 
    // Un usuario puede tener muchas órdenes
    public function orders() 
    {
        return $this->hasMany(Order::class);
    }

Si queremos indicar explícitamente el nombre de la clave foránea a utilizar:

    // Un usuario puede tener muchas órdenes
    public function orders() 
    {
        return $this->hasMany(Order::class, "customer_id");
    }

Para hacer pruebas:

php artisan tinker

Creamos una instancia de usuario:

$user= App\Models\Order->factory->create();

Creamos una orden asociada al usuario anterior

$order = App\Models\Order::factory->create(["customer_id" => $user->id]);

Está establecida una relación, de tal manera que podemos acceder a la lista de órdenes del usuario:

$user->orders;

Y desde la orden a la que pertenece:

$payment->order;
informatica/programacion/php/frameworks/laravel/relaciones_entre_modelos.1686815840.txt.gz · Última modificación: por tempwin