Distant HasManyThrough

大憨熊 提交于 2019-12-24 03:44:52

问题


I have four Models:

  1. User
  2. Client
  3. Store
  4. Opportunity

The relationships are defined as such:

  • User hasMany Client
  • Client hasMany Store
  • Store hasMany Opportunity
  • User hasManyThrough Store, Client (this works)

The problem is that I'm attempting to access the User->Opportunity relationship via built-in Laravel relationships, but it doesn't seem as if I can do it without a custom Query or an additional user_id column on the opportunities table to allow direct access (even though one can be inferred from the Store->Client relationship). I'm also not a fan of nested foreach loops if they can be avoided.

My question:

Is there a way to go one level deeper and directly access a User's Opportunities in this scenario? The actual Model code and all relevant relationships are as follows:

User

class User extends Eloquent{
    public function clients(){
        return $this->hasMany('Client');
    }
    public function stores(){
        return $this->hasManyThrough('Store', 'Client');
    }
    public function proposals(){
        return $this->hasMany('Proposal');
    }
    public function opportunities(){ //This does the job, but I feel like it could be better
        return Opportunity::join('stores', 'stores.id', '=', 'opportunities.store_id')->
                            join('clients', 'clients.id', '=', 'stores.client_id')->
                            join('users', 'users.id', '=', 'clients.user_id')->
                            select('opportunities.*')->
                            where('users.id', $this->id);
    }
    public function getOpportunitiesAttribute(){ //This just helps mimic the hasManyThrough shorthand
        return $this->opportunities()->get();       
    }
}

Client

class Client extends Eloquent{
    public function stores(){
        return $this->hasMany('Store');
    }
    public function user(){
        return $this->belongsTo('User');
    }
    public function opportunities(){
        return $this->hasManyThrough('Opportunity', 'Store');
    }
}

Store

class Store extends Eloquent {
    public function client(){
        return $this->belongsTo('Client');
    }
    public function opportunities(){
        return $this->hasMany('Opportunity');
    }
}

Opportunity

class Opportunity extends Eloquent {
    public function store(){
        return $this->belongsTo('Store');
    }
}

回答1:


I don't think there is such method in Laravel. You have to create your custom query. This custom query can be very expensive since multiple queries will be performed. Thus, the optimum solution for this, according to me, is to relate User and Opportunity with a foreign key.

However, if you don't desire to link User and Opportunity with a foreign key, then you can create a custom query to handle this. Simply add a "hasManyThrough" relation between Opportunity and Client model like,

    <?php
    class Client extends Eloquent{
        public function store(){
            return $this->hasMany('Store');
        }
        public function user(){
            return $this->belongsTo('User');
        }

        public function opportunity(){
            return $this->hasManyThrough('Opportunity', 'Store');
        }
    }

Then create a static function in User model.

    <?php

    class User extends Eloquent implements UserInterface, RemindableInterface {

        use UserTrait, RemindableTrait;

        public function client(){
            return $this->hasMany('Client');
        }
        public function store(){
            return $this->hasManyThrough('Store', 'Client');
        }

        public static function getOpportunityOfUser($userId)
        {
             $clients = User::find($userId)->client;

            foreach ($clients as $client) {
                $opportunities[] = Client::find($client->id)->opportunity;
            }

            return $opportunities;
        }
    }

Now you can access Opportunity realted to a User in one go like,

    Route::get('/', function()
    {   
         return $usersOpportunities = User::getOpportunityOfUser(1);
    });

This will return all opportunity of all clients related to User with id '1'.




回答2:


I created a HasManyThrough relationship with unlimited levels: Repository on GitHub

After the installation, you can use it like this:

class User extends Model {
    use \Staudenmeir\EloquentHasManyDeep\HasRelationships;

    public function opportunities() {
        return $this->hasManyDeep(Opportunity::class, [Client::class, Store::class]);
    }
}


来源:https://stackoverflow.com/questions/25938081/distant-hasmanythrough

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!