【问题标题】:Eloquent MorphMany relationship proxy attributeEloquent MorphMany 关系代理属性
【发布时间】:2015-05-11 15:02:07
【问题描述】:

在我的应用程序中,我做了一个奇怪的观察,一个看似相等的操作与另一个操作有不同的结果。

我有以下表格:

aliases:

$table->engine = "InnoDB";
$table->increments("id");
$table->morphs("aliasable");
$table->string("alias");
$table->string("locale");

categories:

$table->engine = "InnoDB";
$table->increments('id');

Category 模型与Alias 模型有关系:

public function aliases()
{
    return $this->morphMany("Alias", "aliasable");
}

当试图操作一个类别的别名数据时,以下两种方法是有区别的:

$category = Category::find(1);
$alias = $category->aliases()->first();
$alias->alias = "test";
$alias->save();

$category = Category::find(1);
$alias = $category->aliases()->first()->alias = "test";
$category->aliases()->first()->save();

第一个正在工作,第二个没有保存更改。 我想让第二个版本工作,因为我尝试在我的 Category 模型上实现代理属性,以便像这样更改别名:

$category = Category::find(1);
$category->germanAlias = "Heidi";
$category->push();

你知道为什么我的方法没有按预期工作吗?

【问题讨论】:

    标签: laravel eloquent laravel-5


    【解决方案1】:

    这里要理解的关键是关系在模型上的缓存方式。当您直接访问关系方法时,不会发生缓存。您基本上是根据该关系定义实例化一个新的查询。

    $query = $category->aliases();
    $alias = $query->first();
    

    如果您像访问模型的成员/属性一样访问关系,那么它会将关系加载并缓存为模型上的集合。

    $collection = $category->aliases;
    $alias = $collection->first();
    

    未来通过此方法访问相关模型的尝试将引用相同的缓存模型集合。这应该可以。

    $category->aliases->first()->alias = 'test';
    $category->aliases->first()->save();
    

    /Illuminate/Database/Eloquent/Model 中,__get() 是一种神奇的方法,它将对未定义成员的请求重定向到 getAttribute() 方法。代码 cmets 很好地解释了其余部分,但基本上它检查、加载、缓存和重用关系。

    【讨论】:

    • 感谢您阐明缓存的相关逻辑。现在的问题是,我仍然想让我的“代理属性”工作。我的意思是一个虚拟属性,它以某种方式将所有更改映射到具有特定语言环境的相关别名模型。 $category->thisMapsToGermanAlias = "Deutsch";echo $category->thisMapsToGermanAlias;你会怎么做?
    • 您正在寻找突变体。查看我上面链接的 getAttribute() 方法中的第一个注释块。您会看到它会检查“get mutator”。长话短说 ->germanAlias 将由 ->getGermanAliasAttribute() 如果您在模型上定义它进行评估。这是有关该主题的 Laravel 文档的链接。 laravel.com/docs/4.2/eloquent#accessors-and-mutators
    • 我以前读过所有这些,但我没有让它工作,所以我必须像保存普通属性一样保存这个属性。要么我直接将它保存在 Mutator 中,要么再次出现缓存问题......
    【解决方案2】:
    $category->aliases()->first()->save();
    

    这一行选择第一个别名并保存它。实际上什么都不做。你的第一种方法是正确的。你也可以这样做

    $category->aliases()->first()->update(['alias' => 'test']);
    

    如果您的别名字段包含在 Alias 模型的 $fillable 属性中

    编辑

    运行下面的代码并比较对象id;

    $alias = $category->aliases()->first()->alias = "test";
    var_dump(alias);
    dd($category->aliases()->first());
    

    【讨论】:

    • 但是为什么引用的行没有保存更改?我假设它再次获取模型,丢弃任何更改。是这样吗?
    • 您每次都在创建获取模型的新实例。
    猜你喜欢
    • 2015-11-22
    • 2020-12-20
    • 2017-04-02
    • 2020-09-07
    • 1970-01-01
    • 2020-06-18
    • 2020-01-07
    • 2021-09-08
    • 1970-01-01
    相关资源
    最近更新 更多