简体   繁体   中英

Laravel Eloquent Model inheritance

I'm a new bit who is trying to build an app using Laravel 5.5, and the Eloquent model.

I have two classes: (1) Customer and (2) VIPCustomer which extends Customer.

You may immediately tell VIPCustomer contains all attributes that a customer has, and other extra attributes.

Just to be clear, a customer may not be a VIP, and a VIP must be a customer; The customer may immediately opt-in to be a VIP the first time he shops.

Therefore, I am attempting to do something like this in the database:

Customer:

+------------------------+
|id|name|gender|join_date|
+------------------------+

VIPCustomer:

+----------------------------------+
|customer_id|valid_until|type|point|
+----------------------------------+
(customer_id is a foriegn key referencing Customer.id)

And accordingly, in the model php file:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Customer extends Model
{

}

.

namespace App;

use Illuminate\Database\Eloquent\Model;

class VIPCustomer extends Customer
{
    public $incrementing = false;
}

And that's it? I saw there are others saying I should using polymorphic relationship but I don't understand what it means.

In addition, is it possible to do instantiate a new VIP Customer something like this?

$customer = new VIPCustomer;
$customer->name   = 'Alice';
$customer->gender = 'F';
$customer->type   = 'gold';
$customer->point  =  0;
$customer->save();

On top of that, say when the VIP membership ends, is it possible to preserve that person as Customer ? Because I'm afraid deleting that person will delete him from both Customer and VIPCustomer tables.

Thank you very much in advance.

Your current VIPCustomer class looks like a class that holds a VIP data, not a subject (a customer). Then so, I would rename it as VIPCustomerData here and make a new VIPCustomer to inherit Customer class instead.

class Customer extends Model
{
    protected $table = 'customers';
}

Make sure you define the table name to avoid it being guessed by inheritance. Then tell VIPCustomer to has a relation to VIPCustomerData .

class VIPCustomer extends Customer
{
    public function vipData()
    {
        return $this->hasOne(VIPCustomerData::class, 'customer_id', 'id');
    }
}

Now, the problem is whenever you're going to retrieve VIP customers like VIPCustomer::get() , you'll get whole customers instead. So, applying global scope is needed.

class VIPCustomer extends Customer
{
    protected static function boot()
    {
        parent::boot();

        static::addGlobalScope('weareviptypeofcustomer', function ($q) {
            $q->has('vipData'); // only customers with vip data
        });
    }

    public function vipData()
    {
        return $this->hasOne(VIPCustomerData::class, 'customer_id', 'id');
    }
}

To create a new Customer as VIP, of course 2 queries is needed to insert here. Example,

$vipCustomer = new VIPCustomer;
$vipCustomer->name   = 'Alice';
$vipCustomer->gender = 'F';
$vipCustomer->save();

$vipCustomerData = new VIPCustomerData;
$vipCustomerData->type   = 'gold';
$vipCustomerData->point  =  0;

$vipCustomer->vipData()->save($vipCustomerData);

Example of updating point.

$vipCustomerData = $vipCustomer->vipData; // or $vipCustomer->vipData()->first();
$vipCustomerData->point  =  10;
$vipCustomerData->save();

Example of removing VIP status from customer. Of course just delete VIPCustomerData from its table.

$vipCustomer->vipData()->delete();

However, it's better to maintain these subjects as one class if there is no special column to treat each subject differently.

class Customer extends Model
{
    protected $table = 'customers';

    protected $with = ['vipData']; // always eager load related 'vipData'

    protected $appends = ['is_vip']; // append 'is_vip' accessor

    public function vipData()
    {
        return $this->hasOne(static::class, 'customer_id', 'id');
    }

    public function getIsVipAttribute()
    {
        return (bool) $this->vipData;
    }
}

$customers = Customer::all();

foreach($customers as $customer) {
    if ($customer->is_vip) {
        // is VIP
    } else {

    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM