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

Possible to merge two Relations? #8

Closed
NicksonYap opened this issue Oct 19, 2018 · 9 comments
Closed

Possible to merge two Relations? #8

NicksonYap opened this issue Oct 19, 2018 · 9 comments

Comments

@NicksonYap
Copy link

Hi

I've successfully implemented this Laravel package, it's awesome

I have two possible Relations:

Order -> belongs to many -> DeliveryOrder -> belongs to many -> Invoices
Order -> belongs to many -> Invoices

Some Orders can relate directly to Invoices, some will have to go through DeliveryOrder

They have different possible paths but the start and end Models of the possible paths are the same

I'm able to use hasManyDeep to get both relations, separately

But how can we add support or workaround to combine the two Relations into one?

(not asking to convert into a Collection or array and merge them, that's cheating)

Thanks!

@staudenmeir
Copy link
Owner

Should the merged relationship be a "real" relationship (with support for eager loading etc.)? Or do you just want to get the invoices from both sources in a single query?

@NicksonYap
Copy link
Author

NicksonYap commented Oct 20, 2018

@staudenmeir
Real relationship with eager loading 😅

@staudenmeir
Copy link
Owner

I don't see a (feasible) way to do this.

@NicksonYap
Copy link
Author

If you look at it, it's not literally combining Relations

The Starting and Ending model must be the same

But the ones in between can jump to another model or skip a model

So I suppose there is like an OR when doing JOINS?

Not sure if i made sense :/

@staudenmeir
Copy link
Owner

I don't think it's that simple. The only way I see is a UNION query.

@NicksonYap
Copy link
Author

@staudenmeir

I've managed to union() two manyToMany & hasManyDeep relations, however there were a number of workarounds required.

one would normally do this: (the following does not work)

public function combined_relations(){
  return $this->firstRelation()->union($this->secondRelation());
}

However because Laravel has issues applying union to manyToMany relationships, this has to be done:

public function combined_relations(){
  //fix due to extra columns from pivot tables
  return $this->firstRelation()->select('table_name.*')->union($this->secondRelation()->select('table_name.*'));
}

But it returns a Builder instance, not a Relations instance like belongsToMany() or hasMany()

So it does not work with whereHas() or with()

Do you know how to convert a Builder instance into a Relations instance?

I managed to get an array and hydrate() it back into Eloquent/Model

@staudenmeir
Copy link
Owner

I've created a package for merging relationships using views:
https://github.com/staudenmeir/laravel-merged-relations

First, create the merge view in a migration:

use Staudenmeir\LaravelMergedRelations\Facades\Schema;

Schema::createMergeView(
    'all_invoices', [(new Order)->invoices(), (new Order)->deliveryInvoices()]
);

If you want to get unique results:

use Staudenmeir\LaravelMergedRelations\Facades\Schema;

Schema::createMergeViewWithoutDuplicates(
    'all_invoices', [(new Order)->invoices(), (new Order)->deliveryInvoices()]
);

Then define the relationship:

class Order extends Model
{
    use \Staudenmeir\LaravelMergedRelations\Eloquent\HasMergedRelationships;

    public function allInvoices()
    {
        return $this->mergedRelationWithModel(Invoice::class, 'all_invoices');
    }

    public function invoices()
    {
        return $this->belongsToMany(Invoice::class);
    }

    public function deliveryInvoices()
    {
        return $this->hasManyDeep(
            Invoice::class,
            ['delivery_order_order', DeliveryOrder::class, 'delivery_order_invoice']
        );
    }
}

Order::find($id)->allInvoices;

Order::with('allInvoices')->get();

@androidhands
Copy link

@staudenmeir I have used your package and when run migration I get this error. Call to undefined method Staudenmeir\LaravelMergedRelations\Facades\Schema::createMergeView() . Please can you help me.

@staudenmeir
Copy link
Owner

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

3 participants