如何使用Eloquent筛选数据透视表?

39

我在我的项目中使用透视表来获取用户的作品。

例如:User::find(1)->works可以给我ID为1的用户的作品。

问题是我想用额外的透视数据来过滤这些结果。

类似于:

User::find(1)->works->pivot->where('active',1)->get();

我的user_works数据表中,活动所在的列是我设置的。

以下是我User.php模型的相关部分:

<?php

class User extends Cartalyst\Sentry\Users\Eloquent\User {

    public function works() {
        return $this->belongsToMany('Work','user_works')->withPivot('active')->withTimestamps();
    }

}

这是我的 Work.php 模型相关部分:

<?php

class Work extends Eloquent {

    public function users() {
        return $this->belongsToMany('User','user_works')->withPivot('active')->withTimestamps();
    }
}

这是我的数据透视表结构:

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;

class CreateUserWorksTable extends Migration {

    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('user_works', function(Blueprint $table) {
            $table->increments('id');

            $table->integer('user_id')->unsigned()->default(0);
            $table->integer('work_id')->unsigned()->default(0);

            $table->enum('active',array('0','1'))->default(1);

            $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
            $table->foreign('work_id')->references('id')->on('works')->onDelete('cascade');

            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::drop('user_works');
    }

}

如何在不创建新的数据透视表模型的情况下获取数据?

提前致谢。

编辑: 我可以通过以下方式进行筛选:

return User::find(1)->works()->where('user_works.active','=','1')->get();

我必须输入表名“raw”。但是除了使用它之外,有更好的方法吗?


你在编辑中提供的内容看起来对我来说很好。 '=' 作为第二个参数并不是必需的,->where('user_works.active', 1) 应该可以正常工作。 - deefour
@Deefour 嗯,还会有其他参数,比如更大或更小等。我只是复制粘贴而已。我想知道的是,除了将表名保护为公共的,我能否动态地捕获表名。这将是我需要放置原始表名的唯一位置,这感觉不太对。 - Arda
3个回答

53

Laravel 4.1引入了原生的wherePivotorWherePivot 方法,这直接解决了我的问题。


5
每当您调用withPivot('foo')时,Laravel会执行以下操作:
SELECT ... `table`.`foo` AS `pivot_foo` FROM `table` ...

固定答案:

特别是MySQL允许在HAVINGGROUP BYORDER BY子句中使用列别名,但不允许在WHERE子句中使用。

HAVINGWHERE都用于过滤查询,但它们的行为略有不同:HAVING应用于GROUP BY之后,而WHERE则是在之前。

作为一般的SQL规则,不应该对分组、过滤或类似操作使用列别名(在这种情况下是pivot_foo),因为它可能无法与其他SQL数据库一起使用。

虽然不建议使用,但仍然可以使用:

return User::find(1)->works()->having('pivot_active','=','1')->get();

确实,您是正确的先生。我从未在where子句中使用过它,根据MySQL文档,您只能在groupBy、orderBy和having上使用列别名。我已经修正了答案。 - vFragosop
很好,这正如我所预期的那样工作。谢谢!(附言:我不是那个给你投反对票的人,但我投了赞成票) - Arda
@vFragshop,还要感谢您提供详细的解释,我目前正在保存这两种解决方案以备不时之需。 - Arda
抱歉,我不得不取消您的答案作为最佳答案,因为Laravel 4.1为我的问题提供了新的本地方法。 - Arda

5

我尝试在双向上设置所有关系,因为这样可以使用动态属性,例如$user->works()

class Collection extends Eloquent {
    public function contents()
    {
        return $this->belongsToMany('Content', 'collection_content', 'collection_id', 'content_id')->withPivot('collection_id', 'group_id', 'field_identifier');
    }
}

class Content extends Eloquent {
    public function collections()
    {
        return $this->belongsToMany('Collection', 'collection_content', 'collection_id', 'content_id')->withPivot('collection_id', 'group_id', 'field_identifier');
    }
}

class CollectionContent extends Eloquent {
    public function content()
    {
        return $this->belongsTo('Content');
    }

    public function collection()
    {
        return $this->belongsTo('Collection');
    }
}

接下来查询:

$works = User::find(1)->works()->where('active', 1)->get();

Eloquent 在使用关联表时的文档不佳。这篇优秀教程讲述了如何在 Laravel 4 中使用关联表进行添加和移除操作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接