Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Global select list not respected in belongsToMany relationship #22482

Closed
KKSzymanowski opened this issue Dec 19, 2017 · 2 comments
Closed

Global select list not respected in belongsToMany relationship #22482

KKSzymanowski opened this issue Dec 19, 2017 · 2 comments

Comments

@KKSzymanowski
Copy link
Contributor

KKSzymanowski commented Dec 19, 2017

  • Laravel Version: 5.5.24
  • PHP Version: 7.1.11
  • Database Driver & Version: MySQL 15.1 Distrib 10.2.10-MariaDB

Description:

I'm working with a legacy database with an enormous number of columns in tables and I want to fetch only few of them. Usually I restrict the column list globally by adding a query scope in the boot method of the model and it works fine with one-to-many relationships but with a many-to-many relationship all columns from the related table are being fetched.

This is because the scopes are applied after the column list on the query instance is checked in BelongsToMany::get()

public function get($columns = ['*'])
{
    $columns = $this->query->getQuery()->columns ? [] : $columns;

    $builder = $this->query->applyScopes();

    // ...
}

Is there a reason behind this? Can this order be reversed like so:

public function get($columns = ['*'])
{
    $builder = $this->query->applyScopes();

    $columns = $builder->getQuery()->columns ? [] : $columns;

    // ...
}
@KKSzymanowski KKSzymanowski changed the title Column list restriction not respected in belongsToMany relationship Global select list not respected in belongsToMany relationship Dec 19, 2017
@Dylan-DPC-zz
Copy link

This repo is for bug tracking. Use the forums or slack channel for solving your issue

@KKSzymanowski
Copy link
Contributor Author

KKSzymanowski commented Dec 21, 2017

I believe it is a bug, because the scope treatment is inconsistent across relationship.
Edit: To be precise, the scope treatment is quite the same, just for BelongsToMany the scopes are applied too late, rendering them useless in particular cases.

Here are steps needed to reproduce, so you have a full bug report:

Steps to reproduce

  1. Create a User model
class User extends Authenticatable
{
    protected $fillable = ['name'];

    public function permissions()
    {
        return $this->belongsToMany(Permission::class);
    }
}
  1. Create a Permission model
class Permission extends Model
{
    public static function boot()
    {
        parent::boot();

        static::addGlobalScope(function(Builder $query) {
            $query->select('name');
        });
    }
}
  1. Create migrations for the models and the intermediary table:
Schema::create('users', function (Blueprint $table) {
    $table->increments('id');
    $table->string('name');
    $table->timestamps();
});
Schema::create('permissions', function (Blueprint $table) {
    $table->increments('id');
    $table->string('name');
    $table->text('description');
    $table->timestamps();
});
Schema::create('permission_user', function (Blueprint $table) {
    $table->increments('id');
    $table->integer('permission_id');
    $table->integer('user_id');
});
  1. Migrate the database
  2. Create a user
\App\User::create([
    'name' => 'John Doe',
]);
  1. Create a test route:
Route::get('/', function () {
    $user = \App\User::first();

    DB::listen(function ($query) {
        dump($query->sql);
    });

    $user->permissions()->get();
});

What is expected

Only the name column should be fetched from the permissions table and the dumped query
should look something like this:

select 
    `name`, 
    `permission_user`.`user_id` as `pivot_user_id`, 
    `permission_user`.`permission_id` as `pivot_permission_id` 
from `permissions` 
inner join `permission_user` on `permissions`.`id` = `permission_user`.`permission_id` 
where `permission_user`.`user_id` = ? 

What is actually happening

All columns are fetched from the permissions table and the query looks like this:

select 
    `name`, 
    `permissions`.*, 
    `permission_user`.`user_id` as `pivot_user_id`, 
    `permission_user`.`permission_id` as `pivot_permission_id` 
from `permissions` 
inner join `permission_user` on `permissions`.`id` = `permission_user`.`permission_id` 
where `permission_user`.`user_id` = ? 

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants