pbootcms网站模板|日韩1区2区|织梦模板||网站源码|日韩1区2区|jquery建站特效-html5模板网

具有 Eloquent 關(guān)系的空對象模式

Null object pattern with Eloquent relations(具有 Eloquent 關(guān)系的空對象模式)
本文介紹了具有 Eloquent 關(guān)系的空對象模式的處理方法,對大家解決問題具有一定的參考價值,需要的朋友們下面隨著小編來一起學習吧!

問題描述

經(jīng)常有這樣的情況,某個 eloquent 模型的關(guān)系未設(shè)置(即在書籍表中,author_id 為空),因此調(diào)用諸如 $model->relation 之類的東西會返回空.

There is often the case where an certain eloquent model's relation is unset (i.e. in a books table, author_id is null) and thus calling something like $model->relation returns null.

例如假設(shè) Book 模型有一個我可能想要做的 author() (hasOne) 關(guān)系

E.g. say a Book model has an author() (hasOne) relation I might want to do

$author = Book::find(1)->author->name;

如果 Book 1 沒有設(shè)置作者,它將拋出試圖獲取非對象的屬性"錯誤.有沒有辦法避免這種情況并默認為空白的 Author 所以我總是能夠在它上面調(diào)用 name,無論是否為特定設(shè)置了關(guān)系模型?

If Book 1 has no author set it will throw a "trying to get property of non object" error. Is there a way to avoid this and default to a blank Author so I'll always be able to call name on it regardless of whether the relation has been set for the specific model?

本質(zhì)上,我想避免在調(diào)用進一步的方法/屬性之前檢查 $book->author 是否是實際的 Author 的條件.如果沒有設(shè)置關(guān)系,它應(yīng)該默認為一個新的 Author 實例.

Essentially I want to avoid conditionals to check if $book->author is an actual Author before calling further methods/properties on it. It should default to a new Author instance if the relation isn't set.

我嘗試了類似的東西:

public function getAuthorAttribute($author)
{
    return $author ?: new Author;
}

然而這是行不通的;$author 被作為 null 傳入,即使它是在模型上設(shè)置的.大概是因為它是一種關(guān)系,而不是一本書的直接屬性.我需要像

however this doesn't work; $author is being passed in as null, even if it's set on the model. Presumably because it's a relation rather than a direct property of a book. I'd need something like

public function getAuthorAttribute()
{
    return $this->author()->first() ?: new Author;
}

這看起來很不雅觀,而且似乎會覆蓋任何導致性能不佳的急切加載.

which seems pretty inelegant and seems like it would override any eager loading resulting in poor performance.

推薦答案

更新

從 Laravel 5.3.23 開始,現(xiàn)在有一個內(nèi)置的方法來實現(xiàn)這一點(至少對于 HasOne 關(guān)系).withDefault() 方法已添加到 HasOne 關(guān)系中.對于您的 Book/Author 示例,您的代碼如下所示:

Update

As of Laravel 5.3.23, there is now a built in way to accomplish this (at least for HasOne relationships). A withDefault() method was added to the HasOne relationship. In the case of your Book/Author example, your code would look like:

public function author() {
    return $this->hasOne(Author::class)->withDefault();
}

如果在數(shù)據(jù)庫中找不到記錄,此關(guān)系現(xiàn)在將返回一個相當空的(設(shè)置了鍵)Author 模型.此外,如果你想用一些額外的數(shù)據(jù)填充你的空模型,你可以傳入一個屬性數(shù)組,或者你可以傳入一個閉包,它返回你想要的默認設(shè)置(沒有成為作者模型).

This relationship will now return a fairly empty (keys are set) Author model if no record is found in the database. Additionally, you can pass in an array of attributes if you'd like to populate your empty model with some extra data, or you can pass in a Closure that returns what you'd like to have your default set to (doesn't have to be an Author model).

直到有一天它成為文檔,有關(guān)更多信息,您可以查看與更改相關(guān)的拉取請求:16198 和 16382.

Until this makes it into the documentation one day, for more information you can check out the pull requests related to the change: 16198 and 16382.

在撰寫本文時,這僅針對 HasOne 關(guān)系實施.它最終可能會遷移到 BelongsToMorphOneMorphTo 關(guān)系,但我不能肯定.

At the time of this writing, this has only been implemented for the HasOne relationship. It may eventually migrate to the BelongsTo, MorphOne, and MorphTo relationships, but I can't say for sure.

據(jù)我所知,沒有內(nèi)置的方法可以做到這一點,但有幾種解決方法.

There's no built in way that I know of to do this, but there are a couple workarounds.

正如您所發(fā)現(xiàn)的,使用訪問器的問題在于傳遞給訪問器的 $value 將始終為 null,因為它是從模型上的屬性數(shù)組.這個屬性數(shù)組不包括關(guān)系,無論它們是否已經(jīng)加載.

The problem with using an accessor, as you've found out, is that the $value passed to the accessor will always be null, since it is populated from the array of attributes on the model. This array of attributes does not include relationships, whether they're already loaded or not.

如果您想嘗試使用訪問器解決此問題,您只需忽略傳入的任何值,并自行檢查關(guān)系.

If you want to attempt to solve this with an accessor, you would just ignore whatever value is passed in, and check the relationship yourself.

public function getAuthorAttribute($value)
{
    $key = 'author';

    /**
     * If the relationship is already loaded, get the value. Otherwise, attempt
     * to load the value from the relationship method. This will also set the
     * key in $this->relations so that subsequent calls will find the key.
     */
    if (array_key_exists($key, $this->relations)) {
        $value = $this->relations[$key];
    } elseif (method_exists($this, $key)) {
        $value = $this->getRelationshipFromMethod($key);
    }

    $value = $value ?: new Author();

    /**
     * This line is optional. Do you want to set the relationship value to be
     * the new Author, or do you want to keep it null? Think of what you'd
     * want in your toArray/toJson output...
     */
    $this->setRelation($key, $value);

    return $value;
}

現(xiàn)在,在訪問器中執(zhí)行此操作的問題在于您需要為每個模型上的每個 hasOne/belongsTo 關(guān)系定義一個訪問器.

Now, the problem with doing this in the accessor is that you need to define an accessor for every hasOne/belongsTo relationship on every model.

第二個較小的問題是訪問器僅在訪問屬性時使用.因此,例如,如果您要預(yù)先加載關(guān)系,然后 dd()toArray/toJson 模型,它仍然會顯示 null 表示關(guān)系,而不是空的作者.

A second, smaller, issue is that the accessor is only used when accessing the attribute. So, for example, if you were to eager load the relationship, and then dd() or toArray/toJson the model, it would still show null for the relatioinship, instead of an empty Author.

第二個選項是覆蓋 Model 上的一些方法,而不是使用屬性訪問器.這解決了使用屬性訪問器的兩個問題.

A second option, instead of using attribute accessors, would be to override some methods on the Model. This solves both of the problems with using an attribute accessor.

您可以創(chuàng)建自己的基礎(chǔ) Model 類來擴展 Laravel Model 并覆蓋這些方法,然后所有其他模型將擴展您的基礎(chǔ) Model 類,而不是 Laravel 的 Model 類.

You can create your own base Model class that extends the Laravel Model and overrides these methods, and then all of your other models will extend your base Model class, instead of Laravel's Model class.

要處理預(yù)先加載的關(guān)系,您需要覆蓋 setRelation() 方法.如果使用 Laravel >= 5.2.30,這也將處理延遲加載關(guān)系.如果使用 Laravel <5.2.30,您還需要覆蓋延遲加載關(guān)系的 getRelationshipFromMethod() 方法.

To handle eager loaded relationships, you would need to override the setRelation() method. If using Laravel >= 5.2.30, this will also handle lazy loaded relationships. If using Laravel < 5.2.30, you will also need to override the getRelationshipFromMethod() method for lazy loaded relationships.

MyModel.php

class MyModel extends Model
{
    /**
     * Handle eager loaded relationships. Call chain:
     * Model::with() => Builder::with(): sets builder eager loads
     * Model::get() => Builder::get() => Builder::eagerLoadRelations() => Builder::loadRelation()
     *     =>Relation::initRelation() => Model::setRelation()
     *     =>Relation::match() =>Relation::matchOneOrMany() => Model::setRelation()
     */
    public function setRelation($relation, $value)
    {
        /**
         * Relationships to many records will always be a Collection, even when empty.
         * Relationships to one record will either be a Model or null. When attempting
         * to set to null, override with a new instance of the expected model.
         */
        if (is_null($value)) {
            // set the value to a new instance of the related model
            $value = $this->$relation()->getRelated()->newInstance();
        }

        $this->relations[$relation] = $value;

        return $this;
    }

    /**
     * This override is only needed in Laravel < 5.2.30. In Laravel
     * >= 5.2.30, this method calls the setRelation method, which
     * is already overridden and contains our logic above.
     *
     * Handle lazy loaded relationships. Call chain:
     * Model::__get() => Model::getAttribute() => Model::getRelationshipFromMethod();
     */
    protected function getRelationshipFromMethod($method)
    {
        $results = parent::getRelationshipFromMethod($method);

        /**
         * Relationships to many records will always be a Collection, even when empty.
         * Relationships to one record will either be a Model or null. When the
         * result is null, override with a new instance of the related model.
         */
        if (is_null($results)) {
            $results = $this->$method()->getRelated()->newInstance();
        }

        return $this->relations[$method] = $results;
    }
}

Book.php

class Book extends MyModel
{
    //
}

這篇關(guān)于具有 Eloquent 關(guān)系的空對象模式的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網(wǎng)!

【網(wǎng)站聲明】本站部分內(nèi)容來源于互聯(lián)網(wǎng),旨在幫助大家更快的解決問題,如果有圖片或者內(nèi)容侵犯了您的權(quán)益,請聯(lián)系我們刪除處理,感謝您的支持!

相關(guān)文檔推薦

Laravel Eloquent Union query(Laravel Eloquent Union 查詢)
Overwrite laravel 5 helper function(覆蓋 Laravel 5 輔助函數(shù))
laravel querybuilder how to use like in wherein function(laravel querybuilder 如何在 where 函數(shù)中使用 like)
The Response content must be a string or object implementing __toString(), quot;booleanquot; given after move to psql(響應(yīng)內(nèi)容必須是實現(xiàn) __toString()、“boolean和“boolean的字符串或?qū)ο?移動到 psql 后給出) - IT屋-程
Roles with laravel 5, how to allow only admin access to some root(Laravel 5 的角色,如何只允許管理員訪問某些根)
Laravel Auth - use md5 instead of the integrated Hash::make()(Laravel Auth - 使用 md5 而不是集成的 Hash::make())
主站蜘蛛池模板: 长沙印刷厂-包装印刷-画册印刷厂家-湖南省日大彩色印务有限公司 青州搬家公司电话_青州搬家公司哪家好「鸿喜」青州搬家 | 脑钠肽-白介素4|白介素8试剂盒-研域(上海)化学试剂有限公司 | 木材烘干机,木炭烘干机,纸管/佛香烘干设备-河南蓝天机械制造有限公司 | 脑钠肽-白介素4|白介素8试剂盒-研域(上海)化学试剂有限公司 | 焊管生产线_焊管机组_轧辊模具_焊管设备_焊管设备厂家_石家庄翔昱机械 | 玻璃钢格栅盖板|玻璃钢盖板|玻璃钢格栅板|树篦子-长沙川皖玻璃钢制品有限公司 | 广州二手电缆线回收,旧电缆回收,广州铜线回收-广东益福电缆线回收公司 | 专业生物有机肥造粒机,粉状有机肥生产线,槽式翻堆机厂家-郑州华之强重工科技有限公司 | 海鲜池-专注海鲜鱼缸、移动海鲜缸、饭店鱼缸设计定做-日晟水族厂家 | 重庆磨床过滤机,重庆纸带过滤机,机床伸缩钣金,重庆机床钣金护罩-重庆达鸿兴精密机械制造有限公司 | UV固化机_UVLED光固化机_UV干燥机生产厂家-上海冠顶公司专业生产UV固化机设备 | 软文推广发布平台_新闻稿件自助发布_媒体邀约-澜媒宝 | 防弹玻璃厂家_防爆炸玻璃_电磁屏蔽玻璃-四川大硅特玻科技有限公司 | 欧必特空气能-商用空气能热水工程,空气能热水器,超低温空气源热泵生产厂家-湖南欧必特空气能公司 | LCD3D打印机|教育|桌面|光固化|FDM3D打印机|3D打印设备-广州造维科技有限公司 | 集装袋吨袋生产厂家-噸袋廠傢-塑料编织袋-纸塑复合袋-二手吨袋-太空袋-曹县建烨包装 | 月嫂_保姆_育婴_催乳_母婴护理_产后康复_养老护理-吉祥到家家政 硫酸亚铁-聚合硫酸铁-除氟除磷剂-复合碳源-污水处理药剂厂家—长隆科技 | 混合生育酚_醋酸生育酚粉_琥珀酸生育酚-山东新元素生物科技 | 南京欧陆电气股份有限公司-风力发电机官网 | pbt头梳丝_牙刷丝_尼龙毛刷丝_PP塑料纤维合成毛丝定制厂_广州明旺 | ETFE膜结构_PTFE膜结构_空间钢结构_膜结构_张拉膜_浙江萬豪空间结构集团有限公司 | 电机修理_二手电机专家-河北豫通机电设备有限公司(原石家庄冀华高压电机维修中心) | 广州网站建设_小程序开发_番禺网站建设_佛山网站建设_粤联网络 | 美的商用净水器_美的直饮机_一级代理经销商_Midea租赁价格-厂家反渗透滤芯-直饮水批发品牌售后 | 北京森语科技有限公司-模型制作专家-展览展示-沙盘模型设计制作-多媒体模型软硬件开发-三维地理信息交互沙盘 | 齿轮减速机电机一体机_齿轮减速箱加电机一体化-德国BOSERL蜗轮蜗杆减速机电机生产厂家 | 优秀的临床医学知识库,临床知识库,医疗知识库,满足电子病历四级要求,免费试用 | 阻燃剂-氢氧化镁-氢氧化铝-沥青阻燃剂-合肥皖燃新材料 | 哈尔滨治「失眠/抑郁/焦虑症/精神心理」专科医院排行榜-京科脑康免费咨询 一对一诊疗 | 流量卡中心-流量卡套餐查询系统_移动电信联通流量卡套餐大全 | 校车_校车价格_19座幼儿园校车_幼儿园校车_大鼻子校车 | 搬运设备、起重设备、吊装设备—『龙海起重成套设备』 | 【甲方装饰】合肥工装公司-合肥装修设计公司,专业从事安徽办公室、店面、售楼部、餐饮店、厂房装修设计服务 | 泰兴市热钻机械有限公司-热熔钻孔机-数控热熔钻-热熔钻孔攻牙一体机 | 硅胶制品-硅橡胶制品-东莞硅胶制品厂家-广东帝博科技有限公司 | 在线悬浮物浓度计-多参数水质在线检测仪-上海沃懋仪表科技有限公司 | 二手电脑回收_二手打印机回收_二手复印机回_硒鼓墨盒回收-广州益美二手电脑回收公司 | 臻知网大型互动问答社区-你的问题将在这里得到解答!-无锡据风网络科技有限公司 | 低粘度纤维素|混凝土灌浆料|有机硅憎水粉|聚羧酸减水剂-南京斯泰宝 | 广州网站建设_小程序开发_番禺网站建设_佛山网站建设_粤联网络 | 电采暖锅炉_超低温空气源热泵_空气源热水器-鑫鲁禹电锅炉空气能热泵厂家 |