Search code examples
laraveleloquentlaravel-jetstream

Use a form to insert data to a pivot table


I am building a landing page where you can see different events from a table calls events, and when you click one of the events, you will see the event information and a form, that form contains diferent questions, those questions comes from a table calls questions.

So because an event can have many questions and a question can be in many events, so what I want to do is create a form where I can create the event with its questions, in that way the information page can show the correct event information and its questions.

How can I do this?

** MODELS:**

EVENT MODEL: enter image description here

QUESTION MODEL:

enter image description here

CONTROLLER:

Return the differents events base on the date:

enter image description here

Return a view with a specific event information y its questions when you click one of the event in the lading page:

enter image description here

TABLES:

EVENTS:

enter image description here

QUESTIONS:

enter image description here

PIVOT TABLE: EVENT_QUESTION:

enter image description here

Thanks


Solution

  • To achieve this, you need to establish a many-to-many relationship between the Event and Question models, which can be done using a pivot table.

    First, you need to define the relationship in your Event and Question models. In your Event model, add the following method:

       public function questions()
    {
        return $this->belongsToMany(Question::class)->withPivot('answer');
    }
    
    

    This method establishes a many-to-many relationship between the Event and Question models, with an additional 'answer' attribute stored in the pivot table.

    In your Question model, add the following method:

    public function events()
    {
        return $this->belongsToMany(Event::class)->withPivot('answer');
    }
    

    This method establishes the inverse many-to-many relationship between the Question and Event models.

    Next, you need to create the pivot table using a migration. You can do this by running the following command:

    php artisan make:migration create_event_question_table --create=event_question

    In the migration file, define the pivot table schema as follows:

    public function up()
    {
        Schema::create('event_question', function (Blueprint $table) {
            $table->id();
            $table->unsignedBigInteger('event_id');
            $table->unsignedBigInteger('question_id');
            $table->string('answer')->nullable();
            $table->timestamps();
    
            $table->foreign('event_id')->references('id')->on('events')->onDelete('cascade');
            $table->foreign('question_id')->references('id')->on('questions')->onDelete('cascade');
        });
    }
    

    This migration creates a pivot table named 'event_question' with foreign keys referencing the 'id' fields of the 'events' and 'questions' tables.

    Finally, in your EventController, you can create a new event with its associated questions using the following code:

    public function store(Request $request)
    {
        $event = new Event;
        $event->title = $request->title;
        $event->description = $request->description;
        $event->date = $request->date;
        $event->save();
    
        foreach ($request->questions as $question) {
            $event->questions()->attach($question['id'], ['answer' => $question['answer']]);
        }
    
        return redirect()->route('events.index');
    }
    
    

    This code creates a new event, then attaches its associated questions with their answers to the pivot table using the attach() method on the questions() relationship.

    In your EventController, you can retrieve an event with its associated questions using the following code:

    public function show($id)
    {
        $event = Event::with('questions')->findOrFail($id);
        return view('events.show', compact('event'));
    }
    
    

    This code retrieves the event with its associated questions using the with() method on the questions() relationship, then passes it to the 'show' view.

    In your view, you can display the event information and its associated questions using the following code:

    <h1>{{ $event->title }}</h1>
    <p>{{ $event->description }}</p>
    <p>{{ $event->date }}</p>
    
    <form action="{{ route('events.submit', $event->id) }}" method="POST">
        @csrf
        @foreach ($event->questions as $question)
            <label>{{ $question->text }}</label>
            <input type="{{ $question->type }}" name="{{ $question->id }}" value="{{ old($question->id, $question->pivot->answer) }}">
        @endforeach
        <button type="submit">Submit</button>
    </form>
    
    

    and date, then loops through the associated questions and displays their text and input fields based on their type (which you have not provided in the models or tables). The old() function is used to pre-fill the input fields with any previously submitted answers, while the pivot->answer property is used to display the current answer stored in the pivot table.

    Finally, the form is submitted to a route named events.submit with the event ID as a parameter.

    In your EventController, you can handle the form submission and update the pivot table with the submitted answers using the following code:

    public function submit(Request $request, $id)
    {
        $event = Event::findOrFail($id);
    
        foreach ($request->except('_token') as $question_id => $answer) {
            $event->questions()->updateExistingPivot($question_id, ['answer' => $answer]);
        }
    
        return redirect()->back()->with('success', 'Answers submitted successfully.');
    }
    
    

    This code retrieves the event based on the provided ID, then loops through the submitted answers and updates the pivot table with the new answers using the updateExistingPivot() method. The method accepts the question ID and an array of pivot table values to update.

    Finally, the user is redirected back to the event information page with a success message.

    Overall, this approach allows you to create events with their associated questions, display the event information and its questions, and update the answers to those questions as needed.