Laravel - 多态多对多返回空

时间:2014-03-07 15:34:44

标签: php laravel-4 polymorphism many-to-many

我现在已经在这5个小时了,似乎无法弄清楚错误。我在Laravel 4.1中使用多态多对多关系。

作业和活动每个都可以有一个标签,我相应地设置了这些东西。但每当我打电话

$job->tags

它返回空。

我有这三个类(BaseModel扩展了Eloquent,命名空间总是App \ Models,我必须在例如“morphToMany”函数中引用它们,不能用“use”):

class Job extends BaseModel {

    public function tags()
    {
        return $this->morphToMany('\App\Models\Tag', 'taggable');
    }
    [...]
}

标签模型:

class Tag extends BaseModel {

    public function jobs(){
        return $this->morphedByMany('\App\Models\Job', 'taggable');
    }

    public function events(){
        return $this->morphedByMany('\App\Models\Event', 'taggable');
    }
[...]
}

活动模型(会议期间的“活动”,研讨会 - 有自己的命名空间App \ Models以避免冲突):

class Event extends BaseModel {
    [... nothing relevant yet ...]
}

在我的JobsController中,我有(测试用例,存在ID 14的作业)

public function show($slug)
{
    $job = Job::find(14);
    return \View::make('jobs.show', ['job' => $job]);
}

和我的app / views / jobs / show.blade.php

[...]
echo $job->name;
echo $job->company;
foreach($job->tags as $tag) {
    echo $tag->name;
}
[...]

第一个输出工作正常,它正确显示$ job->名称和$ job->公司,因此它正确地从作业表中读取,但

$job->tags

返回空AND $ tag->名称永远不会被调用。我有一个标签和可标记表(MySQL),这里是相关的行

taggables (table)
-> id->increments()
-> tag_id->integer()->unsigned()->index
    ->foreign('tag_id')->references('id')->on('tag')
-> taggable_id->integer()->unsigned()->index()
-> taggable_type->string()->index()

tags (table)
-> id->increments()
-> name->string()
-> slug->string()

测试1

当我这样做时

$jobs = Job::has('tags')->get();

在我的JobsController.php视图中,它实际上只返回带有标签的作业,所以我有点希望它有点工作。

测试2

但是当我尝试获取标签时,例如在这个index.blade.php案例中

foreach($jobs as $job){
    foreach($job->tags as $tag){
        echo $tag->name;
    }
}

它进入$ jobs循环就好了,但它没有进入$ job->标签循环。 在我的taggables表中,我有一个数据集

taggables
id: 1
tag_id: 1 (exists)
taggable_id: 14 (via foreign key)
taggable_type: Job

我疯了,无法弄清问题所在。我错过了什么吗?

2 个答案:

答案 0 :(得分:2)

清洁解决方案

我已经使用了扩展Eloquent的BaseModel。然后模型只扩展BaseModel,所以我可以对Eloquent做一些更改,所以说。然后,我可以轻松地使用相同的内容覆盖Eloquent morphToMany()函数,只需稍作修改:

<?php namespace App\Models;

class BaseModel extends \Illuminate\Database\Eloquent\Model {

    public function morphToMany($related, $name, $table = null, $foreignKey = null, $otherKey = null, $inverse = false)
    {
        $caller = $this->getBelongsToManyCaller();
        $foreignKey = $foreignKey ?: $name.'_id';
        $instance = new $related;
        $otherKey = $otherKey ?: $instance->getForeignKey();
        $query = $instance->newQuery();
        $table = $table ?: str_plural($name);

        // Only Change: MyMorphToMany instead of the standard MorphToMany
        return new \MyMorphToMany(
          $query, $this, $name, $table, $foreignKey,
          $otherKey, $caller, $inverse
        );
    }
[...]
}

由于morphedByMany()函数实际上也调用morphToMany(),因此不需要为多态多对多关系重写它。然后我继续复制整个

vendor/laravel/framework/src/Illuminate/Database/Eloquent/Relations/MorphToMany.php

app/models/MyMorphToMany.php

只做了一些改动:

<?
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Relations\MorphPivot;

// no namespace, instead call it when extending
// additionally use Illuminate\Database\Eloquent\Relations\MorphPivot;

// Class MyMorphToMany instead of MorphToMany
class MyMorphToMany extends Illuminate\Database\Eloquent\Relations\BelongsToMany {
    [...]
    public function __construct(Builder $query, Model $parent, $name, $table, $foreignKey, $otherKey, $relationName = null, $inverse = false)
    {
        $this->inverse = $inverse;
        $this->morphType = $name.'_type';
        $this->morphClass = $inverse ? get_class($query->getModel()) : get_class($parent);

        // This is the change to cut everything after "\" in the namespaced Class
        $this->morphClass = substr($this->morphClass, strrpos($this->morphClass, '\\') + 1);
        parent::__construct($query, $parent, $table, $foreignKey, $otherKey, $relationName);
    }
    [...]
}

我认为应该这样做。你现在应该可以使用例如morphToMany('App\Models\Tag', 'taggable');现在为Laravel中的多态多对多关系。

感谢https://stackoverflow.com/a/19884991/3347365提示。

以前的评论/解决方案

这很奇怪。当我删除命名空间时,它的工作原理!我删除了Job和Tag类的命名空间,所以我可以通过

调用
public function tags(){
    return $this->morphToMany('Tag', 'taggable');
}

在作业模型中而不是

public function tags(){
    return $this->morphToMany('App\Models\Tag', 'taggable');
}

它有效!这是一个错误还是我错误地实现了什么?我主要使用PSR-4,但我不确定它是否与它有任何关系。

答案 1 :(得分:1)

对于较新版本的Laravel,有一个内置的解决方案:morphMap https://laravel.com/docs/7.x/eloquent-relationships#custom-polymorphic-types