如何重构实现相同方法的两个模型 类

How to refactor two Model classes implementing same method

给定两个 class 扩展模型的模型,它是 Eloquent\Model 的扩展,具有完全相同的复制粘贴方法。提取此重复方法的推荐方法是什么?一个抽象 class 和扩展模型的方法,然后两个 classes 都可以扩展,或者一个 Trait 来散布在功能中?两个 classes 的名称非常相似,但在我们系统中的用途不同。命名建议也很受欢迎。

下面是 classes 但只粘贴了相似之处。 SQL 视图 class 使用 SQL 视图来消除对属性的需要,它允许它与系统的其他部分一起使用。

getExpirationMessageAttribute

<?php
class SupplierDocument extends Model {
    use HasFactory, Taskable;

    protected $appends = ['days_till_expiry', 'expiration_status', 'expiration_message'];

    public function owner() {
        return $this->belongsTo(User::class, 'owner_id');
    }

    public function facilities() {
        return $this->belongsToMany(Facility::class, 'supplier_document_facilities');
    }



    /**
     * Document expiration status.
     *
     * @return string
     */
    public function getExpirationStatusAttribute() {
        if (! $this->load('type')->type->is_expirable) {
            return DocumentStatusEnum::NotExpirable;
        }

        if (Carbon::parse($this->expires_at)->isPast()) {
            return DocumentStatusEnum::Expired;
        }

        if (Carbon::parse($this->expires_at)->diffInDays(now()) <= $this->type->expiration_window) {
            return DocumentStatusEnum::ExpiringSoon;
        }

        return DocumentStatusEnum::Active;
    }

    /**
     * Document days till expiration.
     *
     * @return string
     */
    public function getDaysTillExpiryAttribute() {
        if ($this->expires_at) {
            return Carbon::parse($this->expires_at)->diffInDays(Carbon::now()->toDateString());
        }
    }

    /**
     * Document expiration message.
     *
     * @return string
     */
    public function getExpirationMessageAttribute() {
        if ($this->expiration_status === DocumentStatusEnum::ExpiringSoon) {
            if ($this->days_till_expiry > 1) {
                return "Expiring in $this->days_till_expiry days";
            } elseif ($this->days_till_expiry === 1) {
                return 'Expiring in 1 day';
            } else {
                return 'Expires today';
            }
        }

        if ($this->expiration_status === DocumentStatusEnum::Expired) {
            return "Expired $this->days_till_expiry days ago";
        } elseif ($this->expiration_status === DocumentStatusEnum::NotExpirable) {
            return DocumentStatusEnum::NotExpirable;
        }
        return DocumentStatusEnum::Active;
    }
}
<?php
class SupplierDocumentView extends Model {
    protected $appends = ['expiration_message'];
    protected $table = 'supplier_documents_view';

    public function owner() {
        return $this->belongsTo(User::class, 'owner_id');
    }

    public function facilities() {
        return $this->belongsToMany(Facility::class, 'supplier_document_facilities', 'supplier_document_id');
    }

    /**
     * Document expiration message.
     *
     * @return string
     */
    public function getExpirationMessageAttribute() {
        if ($this->expiration_status === DocumentStatusEnum::ExpiringSoon) {
            if ($this->days_till_expiry > 1) {
                return "Expiring in $this->days_till_expiry days";
            } elseif ($this->days_till_expiry === 1) {
                return 'Expiring in 1 day';
            } else {
                return 'Expires today';
            }
        }

        if ($this->expiration_status === DocumentStatusEnum::Expired) {
            return "Expired $this->days_till_expiry days ago";
        } elseif ($this->expiration_status === DocumentStatusEnum::NotExpirable) {
            return DocumentStatusEnum::NotExpirable;
        }
        return DocumentStatusEnum::Active;
    }
}

只需将其移至特征:

trait ExpirationAwareTrait
{
    public abstract function getExpirationStatusAttribute(): string;
    
    public function getExpirationMessageAttribute()
    {
        if ($this->expiration_status === DocumentStatusEnum::ExpiringSoon) {
            if ($this->days_till_expiry > 1) {
                return "Expiring in $this->days_till_expiry days";
            } elseif ($this->days_till_expiry === 1) {
                return 'Expiring in 1 day';
            } else {
                return 'Expires today';
            }
        }

        if ($this->expiration_status === DocumentStatusEnum::Expired) {
            return "Expired $this->days_till_expiry days ago";
        } elseif ($this->expiration_status === DocumentStatusEnum::NotExpirable) {
            return DocumentStatusEnum::NotExpirable;
        }

        return DocumentStatusEnum::Active;
    }
}

当您使用此特征时 - 您将必须实现getExpirationStatusAttribute方法。