【问题标题】:Laravel Eloquent Model inheritanceLaravel Eloquent 模型继承
【发布时间】:2018-06-16 01:50:11
【问题描述】:

我是一个尝试使用 Laravel 5.5 和 Eloquent 模型构建应用程序的新手。

我有两个课程:(1) 客户 (2) VIPCustomer 扩展了 Customer。

您可以立即告诉 VIPCustomer 包含客户拥有的所有属性以及其他额外属性。

需要说明的是,客户可能不是 VIP,VIP 必须是客户;客户在第一次购物时可以立即选择成为 VIP。

因此,我试图在数据库中做这样的事情:

客户:

+------------------------+
|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;
}

就这样吗?我看到有人说我应该使用多态关系,但我不明白这是什么意思。

此外,是否可以像这样实例化一个新的 VIP 客户?

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

除此之外,比如当 VIP 会员资格结束时,是否可以保留该人作为客户?因为我担心删除那个人会将他从 Customer 和 VIPCustomer 表中删除。

非常感谢您。

【问题讨论】:

    标签: php laravel inheritance model eloquent


    【解决方案1】:

    您当前的VIPCustomer 类看起来像一个包含 VIP 数据的类,而不是一个主题(客户)。那么,我在这里将其重命名为VIPCustomerData,并创建一个新的VIPCustomer 来继承Customer 类。

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

    确保定义表名以避免被继承猜到。然后告诉VIPCustomer 与VIPCustomerData 有关系。

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

    现在,问题是每当您要检索像 VIPCustomer::get() 这样的 VIP 客户时,您将获得全部客户。因此,需要应用全局范围。

    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,当然需要在此处插入 2 个查询。例如,

    $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 {
    
        }
    }
    

    【讨论】:

    • 非常感谢,已经很清楚了。但是我如何将客户投射到 VIPCustomer 呢?
    • 很高兴它有帮助,如果您觉得可以,可以将其标记为答案。您不应该将客户投射到 VIP,因为大多数情况下在编程中,父类永远不应该知道它的子类。他们做什么、做什么、是什么等等。我给你举了更多例子,只是让一个属性持有一个状态来判断它是否是 VIP。
    • 似乎每当我需要将客户更改为VIP时,我都需要删除该客户并记住他的ID和信息,并将ID显式设置为新的VIP;因为我需要为 VIP 和普通客户使用不同的控制器,因为只有 VIP 客户才有的功能。还是谢谢你。
    猜你喜欢
    • 2014-04-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-21
    • 2019-03-28
    • 1970-01-01
    • 2014-02-05
    • 1970-01-01
    相关资源
    最近更新 更多