Laravel Eloquent 模型继承

7

我是一位新手,正在尝试使用Laravel 5.5和Eloquent模型构建应用程序。

我有两个类:(1)Customer和(2)VIPCustomer,VIPCustomer继承自Customer。

您可能会立即发现VIPCustomer包含了客户具有的所有属性以及其他额外属性。

为了明确起见,一个客户可能不是VIP,而VIP必须是客户;客户可以在第一次购物时立即选择成为VIP。

因此,我正在尝试在数据库中执行以下操作:

Customer:

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

VIP客户:

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

相应地,在模型 PHP 文件中:

<?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.

1个回答

11
您当前的VIPCustomer类看起来更像是一个包含VIP数据的类,而不是一个主题(顾客)。因此,我建议将其重命名为VIPCustomerData,然后创建一个新的VIPCustomer类,让它继承Customer类。
class Customer extends Model
{
    protected $table = 'customers';
}

请确保定义表名以避免被继承猜测。然后告诉VIPCustomerVIPCustomerData建立关系。

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

现在的问题是,无论何时你尝试检索VIP客户像VIPCustomer::get(),你都会得到全部客户信息。因此,需要应用全局范围。

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');
    }
}

创建一个新的VIP客户,需要进行两个查询以进行插入。例如:

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

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

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

更新点的示例。

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

取消客户的VIP状态的示例。当然,只需从其表中删除VIPCustomerData。

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

然而,如果没有特殊的栏目来单独处理每个主题,则最好将这些主题作为一个类来维护。

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 {

    }
}

非常感谢,非常清晰。但是我如何将客户转换为VIP客户呢? - gingyan
很高兴能帮到你,如果你觉得有用的话,可以将其标记为答案。在编程中,你不应该将客户强制转换为VIP,因为通常情况下,父类不应该知道它的子类在做什么。我给了你更多的例子,只是为了创建一个属性来保存状态,以告诉它是否是VIP。 - Chay22
似乎每当我需要将一个客户变成VIP时,我都需要删除该客户并记住他的ID和信息,然后将ID明确设置为新的VIP;因为我需要不同的控制器来处理VIP和普通客户,因为有些功能仅适用于VIP客户。无论如何,谢谢。 - gingyan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接