久久久久久久av_日韩在线中文_看一级毛片视频_日本精品二区_成人深夜福利视频_武道仙尊动漫在线观看

具有 Eloquent 關系的空對象模式

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

問題描述

經(jīng)常有這樣的情況,某個 eloquent 模型的關系未設置(即在書籍表中,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.

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

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

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

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

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 的條件.如果沒有設置關系,它應該默認為一個新的 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 傳入,即使它是在模型上設置的.大概是因為它是一種關系,而不是一本書的直接屬性.我需要像

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 關系).withDefault() 方法已添加到 HasOne 關系中.對于您的 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ù)庫中找不到記錄,此關系現(xiàn)在將返回一個相當空的(設置了鍵)Author 模型.此外,如果你想用一些額外的數(shù)據(jù)填充你的空模型,你可以傳入一個屬性數(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).

直到有一天它成為文檔,有關更多信息,您可以查看與更改相關的拉取請求: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 關系實施.它最終可能會遷移到 BelongsTo、MorphOneMorphTo 關系,但我不能肯定.

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ù)組不包括關系,無論它們是否已經(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.

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

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 關系定義一個訪問器.

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.

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

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)建自己的基礎 Model 類來擴展 Laravel Model 并覆蓋這些方法,然后所有其他模型將擴展您的基礎 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.

要處理預先加載的關系,您需要覆蓋 setRelation() 方法.如果使用 Laravel >= 5.2.30,這也將處理延遲加載關系.如果使用 Laravel <5.2.30,您還需要覆蓋延遲加載關系的 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
{
    //
}

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

【網(wǎng)站聲明】本站部分內(nèi)容來源于互聯(lián)網(wǎng),旨在幫助大家更快的解決問題,如果有圖片或者內(nèi)容侵犯了您的權益,請聯(liá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(響應內(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())
主站蜘蛛池模板: 欧美精品二区 | 黄片毛片| 精品一区二区三区在线观看国产 | 精品一区二区三区免费视频 | 成人亚洲精品久久久久软件 | 色婷婷精品久久二区二区蜜臂av | 日韩综合网 | 国产精品久久一区二区三区 | 国产欧美一区二区精品久导航 | caoporn国产| 成人亚洲视频 | 日一区二区 | 欧美又大粗又爽又黄大片视频 | 日韩插插| 亚洲视频一区 | 97人人澡人人爽91综合色 | 视频三区 | 国产美女一区 | 99久久婷婷国产亚洲终合精品 | 欧美日韩精品综合 | 国产精品成人一区二区三区夜夜夜 | 亚洲a网| 综合五月| 中文字幕国产高清 | 成人精品福利 | 国产盗摄视频 | 久久国产婷婷国产香蕉 | 人人干人人艹 | 中文字幕亚洲精品在线观看 | 日韩在线视频免费观看 | 在线天堂免费中文字幕视频 | 国产一区不卡 | 国产精品久久亚洲7777 | 亚洲精品第一国产综合野 | 91精品久久久久久久久久 | 成人欧美一区二区三区在线播放 | 亚洲色欲色欲www | 一区二区三区高清 | 欧美中文| 91精品一区| 久久成人免费 |