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

具有 Eloquent 關系的空對象模式

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

問題描述

經(jīng)常有這樣的情況,某個 eloquent 模型的關系未設置(即在書籍表中,author_id 為空),因此調用諸如 $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 所以我總是能夠在它上面調用 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?

本質上,我想避免在調用進一步的方法/屬性之前檢查 $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)在有一個內置的方法來實現(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 關系實施.它最終可能會遷移到 BelongsToMorphOneMorphTo 關系,但我不能肯定.

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ù)我所知,沒有內置的方法可以做到這一點,但有幾種解決方法.

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)站聲明】本站部分內容來源于互聯(lián)網(wǎng),旨在幫助大家更快的解決問題,如果有圖片或者內容侵犯了您的權益,請聯(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(響應內容必須是實現(xiàn) __toString()、“boolean和“boolean的字符串或對象.移動到 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())
主站蜘蛛池模板: 久久综合影院 | 欧美精品在线一区二区三区 | 国产一级视频在线播放 | 日日摸日日碰夜夜爽亚洲精品蜜乳 | 国产精品久久久久久久久久免费看 | 欧美激情欧美激情在线五月 | 欧美 日韩 国产 一区 | 日本三级网| 日本视频中文字幕 | 欧美精品一区三区 | 2020国产在线 | 久久久久久国产精品免费免费男同 | 中文字幕91 | 国产精品久久久久久久粉嫩 | 久久国产精品一区二区三区 | 在线观看日韩av | 精品毛片 | 亚洲欧洲精品一区 | 精品国产免费一区二区三区五区 | 久久久久国产成人精品亚洲午夜 | 久久精品国产亚洲夜色av网站 | 亚洲福利视频一区二区 | 香蕉91| 中文字幕在线看 | 成人午夜精品 | 成人在线精品视频 | 国产亚洲日本精品 | 国产精品视频在线观看 | 国产美女在线精品免费 | 久久精品成人热国产成 | 久久久久国产 | 午夜视频在线免费观看 | 欧美aⅴ片 | 日本综合在线观看 | 中文字幕亚洲视频 | 久久99一区二区 | 欧美日韩国产在线观看 | 日韩欧美视频 | 在线一区 | av喷水 | 亚洲一区二区三区乱码aⅴ 四虎在线视频 |