在PHP

时间:2017-10-17 07:32:22

标签: php laravel eloquent

长时间读者,第一次问问。我对Java / C这样的东西很有经验,但PHP对我来说是新的。

我遇到的问题是作业没有分配到我期望的位置。

我通过Eloquent方法从MySQL数据库中获取数组,特别是:

$result= TableA::where('tableA.id', '=', $id)
            ->with('tableB.tableC')
            ->get();

作为参考,打印$ result out看起来像这样:

[{"id":105, /*TableA fields*/, "tableB":null},
{"id":106, /*TableA fields*/, "tableB":null},
{"id":107, /*TableA fields*/, "tableB":{/*tableB fields*/, "tableC":
{"id":104, /*TableC fields*/}}},
{"id":108, /*TableA fields*/, "tableB":{/*tableB fields*/, "tableC":
{"id":105, /*TableC fields*/}}}]

在某些情况下,TableA元组将在tableB中具有关联记录,因此tableC中具有关联记录,其他时候tableB中没有关联记录。如果没有相关记录我想要通过并使临时“虚拟”记录通过而不是通过null。我用来做的代码是:

for ($i=0; $i < count($result); $i++) 
{
    if($result[$i]["tableB"] == null)
    {
        Log:info($result); //Print line A
        $result[$i]["tableB"] = OtherController::makeDummyTableB(); //Assignment line
        Log::info($result); //Print line B
        Log::info($result[$i]["tableB"]); //Print line C
    }
}

问题是赋值行没有分配给$ result中返回的对象/数组中的“tableB”字段。在打印行A和B上打印$ result会得到相同的结果,前两个记录的“tableB”为空。然而,打印行C给出了我期望的输出,这是我正在创建的虚拟记录

{"tableC":{/*TableC fields*/}}

所以赋值正在做某事,但它并没有分配给已经存在的$ result中的字段,而是将其分配给其他地方(当我尝试将其分配时)显示它)

如果有人能让我知道我当前的代码实际在做什么,以及如何让它做我期望的事情(用"tableB":null替换"tableB":{"tableC":{/*TableC fields*/}}),我们将非常感激

3 个答案:

答案 0 :(得分:2)

雄辩的模特有很多&#34;魔法&#34;在后台继续。表中的字段将加载到attributes属性中,并且关系将加载到relations属性中。

您遇到的问题是tableB是关系字段,而不是表字段。其数据存储在relations属性中。但是,relations属性不能像您尝试的那样直接修改。当您尝试使用$result[$i]["tableB"]对其进行修改时,该代码实际上正在修改tableB属性中的attributes字段。

然后是获取数据的问题。当您尝试使用$result[$i]["tableB"]直接读取数据时,它会先查看attributes属性,如果找不到,那么它会查看relations属性。

但是,使用Log::info($result);转储整个对象时,relations属性中的任何数据都会覆盖attributes属性中的数据。因此,在使用$result[$i]["tableB"] = 'asdf'进行直接分配后,Log::info($result)将不会显示更改(因为relations会覆盖attributes),而Log::info($result[$i]["tableB"])将显示更改(从它首先查看attributes

因此,分析您的代码,我们有:

for ($i=0; $i < count($result); $i++) {
    if($result[$i]["tableB"] == null) {
        // At this point:
        // - tableB relation is null
        // - tableB attribute does not exist

        // This is a full dump, so the relations overwrites the attributes.
        // tableB will show null
        Log:info($result);

        // After this assignment executes:
        // - tableB relation will be null
        // - tableB attribute will be the dummy object
        $result[$i]["tableB"] = OtherController::makeDummyTableB();

        // This is a full dump, so relations (null) overwrites the attributes (dummy object).
        // tableB will show null
        Log::info($result); //Print line B

        // This is direct access, which accesses attributes (dummy object) before relations (null).
        // tableB will show dummy object
        Log::info($result[$i]["tableB"]); //Print line C
    }
}

如果你真的想这样做,你应该使用setRelation()方法:

$result[$i]->setRelation('tableB', OtherController::makeDummyTableB());

这将在tableB属性上专门设置relations,这是您尝试做的事情。这应该让一切都适合你。

话虽如此,你或许可以用不同的方式解决这个问题。如果您使用Laravel&gt; = 5.3且您的tableB关系是HasOne(5.3+)或BelongsTo(5.4+)关系,则可以在关系上使用withDefault()功能,当数据库中不存在默认模型时,它将自动生成默认模型。您可以阅读有关此in the documentation here的更多信息。

因此,您的关系定义类似于:

public function tableB()
{
    return $this->hasOne('App\TableB')->withDefault();
}

现在,如果不存在tableB条记录,则系统会使用新的空TableB对象加载关系,而不是null

如果您需要的不仅仅是空TableB个对象,您可以将函数传递给withDefault()方法,该函数将用于生成默认对象。

答案 1 :(得分:0)

Eloquent不返回普通的PHP数组,当使用get方法时,它将返回Illuminate\Support\Collection的实例,你不能简单地将这样的对象分配到Collection。为此,您必须首先将集合转换为数组:

$result = TableA::where('tableA.id', '=', $id)
        ->with('tableB.tableC')
        ->get();

// Convert collection to array
$result = $result->toArray();

for ($i=0; $i < count($result); $i++) 
{
    if($result[$i]["tableB"] == null)
    {
        Log:info($result); //Print line A
        $result[$i]["tableB"] = OtherController::makeDummyTableB(); //Assignment line
        Log::info($result); //Print line B
        Log::info($result[$i]["tableB"]); //Print line C
    }
}

现在你应该正确分配你的价值了。

答案 2 :(得分:0)

尝试

foreach ($result as $whatever) 
{
    if($whatever->tableB == null)
    {
        $whatever->tableB = OtherController::makeDummyTableB();
    }
}

问题是你不能将tableB对象分配给tableA模型的数组字段...... 您的tableB模型最有可能(我假设,取决于您如何构建它)通过&#34; tableB_id&#34;与您的tableA模型相关。领域。因此,如果您使用作业,最终会使用

$tableA["tableB_id"] //id of the related tableB, in your case null
$tableA["tableB"] //your newly assigned model, which has nothing to do with your relationship, because that should work on tableB_id

不要使用奇怪的数组语法进行关系