sleepless
sleepless

Reputation: 1789

Laravel - many-to-many where the many-to-many table is (part-) polymorph

I have a table called bonus. A user can get a bonus (it's like an reward) for certain actions. Well, the bonus can be assigned to many users and many users can get the same bonus. So it's a many to many relation between user and bonus.

This is no problem so far. But users can get the same bonus for different actions. So let's say there is a bonus for voting on a picture. Well, one user could vote on one picture and another one could vote on another picture which I'd like to save in the many-to-many table.

Furthermore there could be a bonus for writing a comment which is clearly another table than picture votes.

The problem here is that I would need to save the polymorphic type in the bonus table and the ID in the many-to-many table.

I think this should be the best way but how would I realize it with laravel? I think this is not a normal use case. But still I'd like to use it as other relations in laravel so that I could fetch a user and get his bonuses with the correct polymorphic relation.

Do you have any ideas?

Upvotes: 0

Views: 192

Answers (1)

ajameswolf
ajameswolf

Reputation: 1660

You are probably going to have to develop your own relationship classes. Ex:

MODEL

public function answers()
{
    $instance = new Response();
    $instance->setSid($this->sid);
    return new QuestionAnswerRelation($instance->newQuery(),$this);
}

RELATIONSHIP

use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Relations\Relation;
use Pivotal\Survey\Models\Answer;
use Pivotal\Survey\Models\Collections\AnswerCollection;
use Pivotal\Survey\Models\QuestionInterface;
use Pivotal\Survey\Models\SurveyInterface;

class QuestionAnswerRelation extends Relation
{

    /**
     * Create a new relation instance.
     *
     * @param  \Illuminate\Database\Eloquent\Builder  $query
     * @param  \Illuminate\Database\Eloquent\Model  $parent
     * @return void
     */
    public function __construct(Builder $query, QuestionInterface $parent)
    {
        $table = $query->getModel()->getTable();
        $this->query = $query
            ->select(array(
                \DB::raw($parent->sid.'X'.$parent->gid.'X'.$parent->qid . ' AS value'),
                'id'
            ));

        $this->query = $query;
        $this->parent = $parent;
        $this->related = $query->getModel();
        $this->addConstraints();
    }


    public function addEagerConstraints(array $models)
    {
        parent::addEagerConstraints($models);
    }

    public function initRelation(array $models, $relation)
    {

    }

    public function addConstraints()
    {

    }

    public function match(array $models, Collection $results, $relation)
    {

    }

    public function getResults()
    {
        $results = $this->query->get();
        $answerCollection = new AnswerCollection();

        foreach($results as $result)
        {
            $answer = new Answer($result->toArray());
            $answer->question = $this->parent;
            $answerCollection->add($answer);
        }

        return $answerCollection;
    }

In this case we are using Lime Survey which creates a unique table (note the $instance->setSid() changes the table name) for each of its surveys and a unique column for each of its answer -> question values. ( note $parent->sid.'X'.$parent->gid.'X'.$parent->qid. 'AS value')

Where sid = survey_id, gid = group_id(I think) and qid = question_id

Its was quite irritating.

Note how I reference values from the parent to further develop the query. You should be able to follow a similar route to achieve whatever your heart desires and still maintain the feasibility to use Eloquent.

Upvotes: 1

Related Questions