Search code examples
phplaraveleloquentlaravel-5.3

laravel save one to one and one to many relationship


I am creating an application that has a simple multiple choice quiz feature in it. So I have a Question entity and an Answer entity. I have 2 relationships defined, one to many (question can have many answers) and a one to one (question can have one correct answer). Here is what I have so far:

Question model:

class Question extends Model
{
public $table = 'question';

public $primaryKey = 'question_id';

public $fillable = ['question', 'answer_id'];

public function answers()
{
    return $this->hasMany('App\Models\Answer');
}

public function correctanswer()
{
    return $this->hasOne('App\Models\Answer');
}
}

Answer Model:

class Answer extends Model
{
public $table = 'answer';

public $primaryKey = 'answer_id';

public $guarded = ['created_at', 'updated_at'];

public function question()
{
    return $this->belongsTo('App\Models\Question');
}

public function correctquestion()
{
    return $this->belongsTo('App\Models\Question');
}

}

And in my controller:

    $input = $request->all();
    $answers = $input['answer'];
    unset($input['answer']);

    $question = Question::create($input);

    foreach($answers as $key=>$a){
        $arr['question_id'] = $question->question_id;
        $arr['answer'] = $a;
        $answer = new Answer($arr);
        $question->answers()->save($answer); //save all answers - this works
        if($key == 0){ //the first submitted answer is the correct one
            $question->correctanswer()->save($answer); //save correct answer - this doesn't work
        }
    }

And my db table definitions:

CREATE TABLE IF NOT EXISTS question (
question_id int(11) unsigned NOT NULL AUTO_INCREMENT,
question text,
created_at timestamp,
updated_at timestamp,
answer_id int(11) unsigned,
PRIMARY KEY (question_id),
FOREIGN KEY (answer_id)
    REFERENCES answer(answer_id)
    ON DELETE NO ACTION
    ON UPDATE NO ACTION
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

CREATE TABLE IF NOT EXISTS answer (
answer_id int(11) unsigned NOT NULL AUTO_INCREMENT,
answer text,
created_at timestamp,
updated_at timestamp,
question_id int(11) unsigned,
PRIMARY KEY (answer_id),
FOREIGN KEY (question_id)
    REFERENCES question(question_id)
    ON DELETE CASCADE
    ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

The problem is that my Question entity is not saving the correct answer. All of the answers are saving properly in the Answer table, but I just need to make it so I know which is correct.

Can anyone see what I am doing wrong?

Thanks in advance!


Solution

  • It turns out that it was a problem of which entity owned the relationship. This is what I changed to make it work:

    in my Question Model:

    public function correctanswer()
    {
        return $this->hasOne('App\Models\Answer');
    }
    

    should be

    public function correctanswer()
    {
        return $this->belongsTo('App\Models\Answer', 'answer_id', 'answer_id');
    }
    

    And in my Answer Model:

    public function correctquestion()
    {
        return $this->belongsTo('App\Models\Question');
    }
    

    should be:

    public function correctquestion()
    {
        return $this->hasOne('App\Models\Question');
    }
    

    And then in my controller, I just changed how I saved the correct answer:

        $question = Question::create($input);
    
        foreach($answers as $key=>$a){
            $arr['question_id'] = $question->question_id;
            $arr['answer'] = $a;
            $answer = new Answer($arr);
            $question->answers()->save($answer);
            if($key == 0){
                //$question->correctanswer()->save($answer);
                $answer->correctquestion()->save($question);
            }
        }
    

    I'm not an expert with Laravel yet, so I'm not sure why that makes a difference.