Ad

OctoberCMS Filter Relation Widget Based From Currently Selected Record

- 1 answer

The title says it all, but to give an example. I have a Member record and a Group. A member can have memberships in many groups and a group can have many members. (So that's many to many and I would have a pivot table for it.)

Now, each group has membership grades. E.g., (Free, Freemium, Premium, Super Premium). So the membership_grade shall belong to the pivot table, right? But here's the problem, not all groups share the same grades. Some might have Free and Freemium only, some might have all.

In the fields.yaml of the Membership pivot model, I defined the membership_grades as a Relation Widget, like this:

pivot[grade]:
  label: Membership Grade
  span: full
  type: relation
  nameFrom: name

And in its relationship in Membership.php like this:

public $belongsTo = [
    'grade' => [
        'Acme\Models\Grade',
    ]
];

Obviously, this will expose ALL grades, since I'm pulling data from the Grade model. What I want is to expose the grades that is just available on that group, not all.

What I've thought to do (but I didn't, because it seemed impossible) is to try to pull data from the grades relationship of the Group, but how am I suppose to do that? (Since Relation widget manages the relation of the Model, I cannot simply pull data from other sources just like that).

Also I've tried to do scopes but how am I suppose to pass the current Group I'm in? Since it is needed as the filter, like this:

// Membership.php

public $belongsTo = [
    'grade' => [
        'Acme\Models\Grade',
        'scope' => 'filteredIt'
     ],
     // added this relationship to try the scopes approach
     'group' => [
        'Acme\Models\Group'
     ]
];

// Grade.php

public function scopeFilteredIt($query, Membership $m) 
// yes, the second parameter in the scope will be the 
// current Membership model. I've tried it.
{
    // this won't work, since we want the overall relation filter;
    // an instance of Membership won't help.
    // this would work if I can find a way to pass the 
    // current Group (record) selected, and get its grades, then use it here.
    return $query->whereIn('id', $m->group->grades->pluck('id')->all());
}

Any thoughts?

Ad

Answer

I have noticed some post values during pivot model ajax call.

When you add new record and when your pivot model opens post values are like this

Array (
    [_relation_field] => groups
    [_relation_extra_config] => W10=
    [foreign_id] => 1
    [_session_key] => VrSCoKQrSkIsZNGIju5QIqpdbS3AADoGQRHAsv1e
)

So good thing is that we can now get foreign_id as it will be your selected group id and we can use it at creation time and for update time you know we have relation so we use that.

public function scopefilteredIt($query, Membership $m)
{
    // we are checking relation is there or not
    if($m->group) {
        // yes group is there we use it 
        return $query->whereIn('id', $m->group->grades->pluck('id')->all());
    }
    else {
        // seems new record then use foreign_id
        $foreign_id = post('foreign_id'); //<-this will be your selected group id
        if($foreign_id) { // <- double check if its there
            $group = Group::find($foreign_id);
            return $query->whereIn('id', $group->grades->pluck('id')->all());
        }
    }
    return $query;
}

please comment if you get any issue.

to check post

public function scopefilteredIt($query, Membership $m)
{

    // will show flash message with post data array
    $post = print_r(post(), true);
    \Flash::success($post);

    // we are checking relation is there or not
    if($m->group) {
        // yes group is there we use it 
        return $query->whereIn('id', $m->group->grades->pluck('id')->all());
    }
    else {
        // seems new record then use foreign_id
        $foreign_id = post('foreign_id'); //<-this will be your selected group id
        if($foreign_id) { // <- double check if its there
            $group = Group::find($foreign_id);
            return $query->whereIn('id', $group->grades->pluck('id')->all());
        }
    }
    return $query;
}
Ad
source: stackoverflow.com
Ad