简体   繁体   中英

Laravel 5.3 Polymorphic many to many - how to get all the related rows regardless of their table sorted by pivot column?

I have a model Page and many models called SomethingSection - they're connected through a polymorphic mm realtionship and the pivot has an additional column 'position'.

I need to write a relationship (or accessor maybe?) on the Page model that will return a collection of all connected Sections, regardless of their model (read: table).

My models:

class Page extends Model {

    public function introSections()
    {
        return $this->morphedByMany(IntroSection::class, 'pagable');
    }

    public function anotherSections()
    {
        return $this->morphedByMany(AnotherSection::class, 'pagable');
    }
}

class IntroSection extends Model {

    public function pages()
    {
        return $this->morphToMany(Page::class, 'pagable');
    }
}

class AnotherSection extends Model {

    public function pages()
    {
        return $this->morphToMany(Page::class, 'pagable');
    }
}

The pivot column looks like this:

pagables
    -page_id
    -pagable_id
    -pagable_type
    -position

I'm looking for a way to call a method/attribute on the Page model and get all the connected sections in a single collection, sorted too. What would be a good way to go about this?

I understand that the connected sections do not have the same interface, but in my case that's not a problem at all (in terms of what I will do with the data).

I also understand that relationships perform a separate query (for each relationship), so getting all of them with 1 query is impossible (also different interfaces would be a problem here). And for the same reason the sorting will need to be done on the collection level, not in query.

How could I make this as maintainable as possible and preferably with as small a performance hit as possible.

Thanks in advance.

You can use withPivot() method after your relationship to get the pivot columns with relation like this:

class Page extends Model {

    public function introSections()
    {
        return $this->morphedByMany(\HIT\Models\Sections\IntroSection::class, 'pagable')
                                ->withPivot(['position']);
    }

    public function anotherSections()
    {
        return $this->morphedByMany(AnotherSection::class, 'pagable');
    }
}

class IntroSection extends Model {

    public function pages()
    {
        return $this->morphToMany(Page::class, 'pagable')
                                ->withPivot(['position']);
    }
}

and you can use collection's sortBy to sort the collection by using sortBy() method like this:

$sorted_collection = IntroSection::pages->sortBy('pagables.position');

UPDATE :

You can use collection's combine() method to get all the relationships like this, add this method inside your Page Class:

public function getAllSections()
{
    return $this->introSections->combine($this->anotherSections-toArray())
                ->sortBy('pagables.position'):
}

Hope this helps!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM