Projets Laravel France

Controller : Table de pivot

Avatar de Mathissou
Mathissou

Bonjour tout le monde, j'aurai besoin d'aide sur une fonctionnalité que j'essaye de créer.

Alors pour commencer dans /ressources/views/ il y a les vues "appel" , "newappel" et "list_appel".Il y a aussi le controller "AppelController" et le model "Appel" , pour être claire il y aussi la migration "create_appels_table" qui peut t'aider à comprendre.

Je souhaite pouvoir créer des appels, comme à l'école pour savoir qui est absent et présent.Sur ma table appels ou peut ajouter "createur" qui est le professeur qui a créé l'appel (c'est un string).Une timestamp permet d'enregistrer le moment ou l'appel est créée.

Donc dans mon controllers je peut créer cet appel (fonction: new_appel).A ce moment la le champ "id","createur" et la "timestamp" est rempli.Ensuite sur la vue "list_appel" je souhaiterai pouvoir afficher toutes la listes des élèves via la table "student".

Puis a coté de chaque prénom d'étudiants je veux afficher une "checkbox" pour cocher si l'élèves est présent ou non.Pour faire tout cela j'ai donc créer une table de pivot "create_appel_student_table" qui possède 2 foreign key.Elle possède "appel_id" qui récupère l'id de l'appel , puis la foreign key "student_id" qui récupère tout les id de la table "student".

Schème de la table de pivot :

id id_appel. id_student. present

  1.   1.              1.               1
    
  2.   1.              2.               0
    
  3.   1.               3.              1
    

Je voudrai pouvoir créer mon appel ce qui est fonctionnel.Donc j'ajoute le créateur de l'appel puis je valide et ensuite être redirigé sur la page "list_appel" ou s'affiche la liste des élèves et pouvoir cocher si il est présent ou non et ensuite enregistrer cet appel.

J'ai déjà reussi a créer mon appel et ensuite afficher la liste des élèves mais je dois réussir a passer l'id de l'appel que je viens de créer a appel_list.Après cela je dois trouver comment enregistrer les élèves présent ou absent donc dans mon champs "présent" avec 0 ou 1. Je pense que ce n'est pas si compliqué mais je suis un peu novice dans ce genre de choses.Merci d'avance !

Je m'excuse si c'est mal expliqué ou autre raison. Si il est possible que quelqu'un m'aide via un appel Discord/ via Liveshare pour pouvoir voir mon code et me corriger afin d'en apprendre plus et me debloquer car je suis bloqué depuis très longtemps. Mon Discord : Mathis#8076

Posté il y a 2 mois
Avatar de khalyomede
khalyomede

Bonjour Mathissou,

Pour ton problème, tu pourrais afficher sur ton formulaire ("newappel.blade.php" j'imagine) un formulaire avec les champs que tu as mentionné ("createur" et le timestamp), puis en dessous une liste de cases à cocher pour chaque étudiant. Ca pourrait donner quelque chose comme (exemple avec Bootstrap 5) :

@foreach ($students as $student)
  <div class="form-check">
    <input class="form-check-input" name="students[]" type="checkbox" value="{{ $student->id }}" id="student-{{ $student->id }}" />
    <label class="form-check-label" for="flexCheckDefault">
      {{ $student->name }}
    </label>
  </div>
@endforeach

Et dans ton controlleur tu n'auras plus qu'à ajouter ces étudiants dans ta table pivot "appel_student" (en admettant que la méthode qui stock l'appel s'appelle "store" :

namespace App\Http\Controllers;

use App\Models\Appel;
use App\Models\Student;
use Illuminate\Http\Request;

class AppelController extends Controller
{
  public function store(Request $request)
  {
    $appel = Appel::create([
      "createur" => $request->createur,
      "timestamp" => $request->timestamp, // Tu pourrais aussi laisser Laravel gérer ça automatiquement
    ]);

    $appel->students()->attach($request->students, [
      "present" => true,
    ]);

    // Assume que la colonne "present" est à "false" par défaut dans ta migration, voir migration ci-dessous
    $appel->students()->attach(Student::whereNotIn("id", $request->students)->get());

    return redirect()->route("appel.index");
  }
}

Et comme mentionné dans le commentaire, ça suppose que ta migration qui crée ta table de pivot ressemble à ça :

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateAppelStudentTable extends Migration
{
  public function up()
  {
    Schema::create("appel_student", function (Blueprint $table) {
      $table->foreignId("appel_id")->constrained();
      $table->foreignId("student_id")->constrained();
      $table->boolean("present")->default(false);
      $table->timestamps();
    });
  }

  public function down()
  {
    Schema::dropIfExists("appel_student");
  }
}

Et je te met le model Appel pour que tu voies comment la relation te permet de stocker les students directement depuis le model (comme je l'ai mis dans le controlleur avec la syntaxe $appel->students()->attach() :

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Appel extends Model
{
  use HasFactory;

  public function students()
  {
    return $this->belongsToMany(Student::class, "appel_student")->withTimestamps();
  }
}

J'espère que ça t'aidera à te débloquer !

Et si tu souhaites en savoir plus sur la documentation officielle sur le fonctionnement du belongsToMany :

Posté il y a 2 mois
Avatar de Mathissou
Mathissou

Bonjour,

J'avais déjà un peu commencer a écrire quelque petit trucs comme la migrations le model et le début du controller ainsi que ma views "newappel".

Alors voici ma migration qui je pense est okay :

 public function up()
    {
        Schema::create('appel_student', function (Blueprint $table) {
            $table->id();
            $table->foreignId('appel_id')->constrained()->onDelete('cascade');
            $table->foreignId('student_id')->constrained();
            $table->boolean('present')->default(false);
            $table->timestamps();

        });
    }

Ainsi que mon model "appel" ,"student" et "appel_student" qui je pense sont correct.


class Appel extends Model
{
    use HasFactory;

    protected $fillable = [
        'createur'
    ];

    public function students(){
        return $this->BelongsToMany(Student::class, "appel_student")->withTimestamps();
    }

}
```Model Student:
class Student extends Model
{
    use HasFactory, HasUuid;

    protected $fillable = [
        'first_name','last_name','email_address','phone_number','street_address','city','postal_code','school','level','rules','choices',
    ];
    protected $primaryKey = 'id';
    protected $keyType = 'int';

    public function appels(){
        return $this->BelongsToMany(Appel::class);
    }
    
}
``` Model AppelStudent:
class StudentAppel extends Model
{
    use HasFactory;
}

J'arrive a afficher dans ma vu "newappel" , mon input ou je dois rentrer le nom du createur ainsi que les élèves de la table "student". Grace avec ceci dans mon controller et ceci dans ma view.


 public function new(){
   
    return view('newappel',['appels'=>Appel::all()])
    ->with('students', Student::all());
  }
View newappel:

                <form action="{{ route('add_appel') }}" method="POST">
                @csrf
                                <p class="bg-gray-50 border font-weight-bold mt-3 text-center h5 text-gray-700  text-wrap">La date de création de l'appel est créée automatiquement</p>
                                      <label for="createur" class="block text-sm font-medium text-gray-700">Créer par</label>
                              <input name="createur" type="text" id="createur" list="createur" placeholder="Nom de l'intervenant (Cliquer 2 fois pour obtenir la liste)" class="mt-1 block w-full sm:text-sm form-input rounded-md">
                               <datalist id="createur">
                                <option value="Dahbi ABDERRAZAK">
                                <option value="Elio">
                                <option value="Eloise">
                              </datalist>
                                     <table class="min-w-full divide-y divide-gray-200">
                                  <thead>
                      <tr>
                        <th scope="col" class="px-6 py-3 bg-gray-50 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
                          Nom
                        </th>    
                        <th scope="col" class="px-6 py-3 bg-gray-50 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
                          Prénom
                        </th>
                        <th scope="col" class="px-6 py-3 bg-gray-50 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
                          Présent
                        </th>
                      </tr>
                                  </thead>
                  @foreach ($students as $student)
                   <tbody class="bg-white divide-y divide-gray-200">
                      <tr>
                        <td class="px-6 py-4 whitespace-nowrap">                
                              <div class="text-sm font-medium text-gray-900">
                      {{$student->last_name}}
                          </div>
                        </td>
                        <td class="px-6 py-4 whitespace-nowrap">
                            <div class="text-sm font-medium text-gray-900">
                          {{$student->first_name}}
                            </div>
                        </td>
                        <td class="px-6 py-4 whitespace-nowrap">
                            <div class="text-sm font-medium text-gray-900">      
                             <input class="form-check-input" type="checkbox" name="students[{{ $student->id }}]" id="student-{{ $student->id }}">  
                            </div>
                        </td>
                      </tr>
                    </tbody> 
                    @endforeach 
                  </table>
                              <a href="{{ route('appel') }}" class="inline-flex justify-center py-2 px-4 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-indigo-600 hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-800">
                        Annuler
                      </a>  
                        <a href=""><button type="submit" class="inline-flex justify-center py-2 px-4 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
                        Enregistrer
                      </button></a>  
                 </form>
 

Cependant lors de la sauvegarde de l'appel donc en utilisant la method post "add_appel" qui est dans mon "AppelController" j'ai plusieurs erreur différent comme "Undefined variable: {"createur":"Roger Pierre","updated_at":"2022-03-16T11:19:36.000000Z","created_at":"2022-03-16T11:19:36.000000Z","id":7}" et je pense en avoir encore plus tard.

Voici la fonction dans mon controllers :

public function add_appel(Request $request){
      $messages = [
          'required' => 'Le champ ":attribute" est manquant',
          'string' => ':attribute n\'est pas valide',
        ];

        $attributes = [
          'createur' => 'Createur de lappel',
        ];

        $validateData = Validator::make($request->all(), [
          'createur' => 'required | string',
        ], $messages, $attributes);

        if ($validateData->fails()) {
            $errors = $validateData->errors();
            foreach ($errors->all() as $message) {
              connectify('error','Erreur',$message);
            }
            return redirect("/appel/new");
        }
        else {
              //  $appel = \App\Models\Appel::first(); // (ligne commenter donc non utiliser
          $students = \App\Models\Student::all();
          $appel = Appel::create([
            "createur" => $request->createur, 
         ]);
          $$appel->students()->attach($request->students, [
           "present" => true,
         ]);
          $appel->students()->attach(Student::whereNotIn("id", $request->students)->get());
           $appel->save();
          return redirect("/appel");
        }
    }

Voila je vous remercie de votre aide !

Posté il y a 2 mois
Avatar de khalyomede
khalyomede

Bonjour, je vois un double $$ sur la variable "appel", peux tu essayer avec un seul $ et voir si ça résoud le problème ?

Posté il y a 2 mois
Avatar de Mathissou
Mathissou

J'avais déjà un peu commencer

Posté il y a 2 mois
Avatar de Mathissou
Mathissou

Re:

J'ai une erreur "Invalid datetime format: 1366 Incorrect integer value: 'on' for column tresunion.appel_student.student_id at row 1 (SQL: insert into appel_student (appel_id, created_at, present, student_id, updated_at) values (2, 2022-03-16 15:50:15, 1, on, 2022-03-16 15:50:15), (2, 2022-03-16 15:50:15, 1, on, 2022-03-16 15:50:15)) "

Mon code est le même que celui que j'ai envoyé avant

Posté il y a 2 mois
Avatar de khalyomede
khalyomede

Je pense que si tu fais un dd($request->students) tu devrais voir la cause : à mon avis les valeurs ne sont pas les identifiants (id) de student, mais la valeur "on".

Il faut que tu précise l'attribut "value" sur ton input de type "checkbox", en y mettant l'id du student pour que ton code insère l'entier plutôt que "on" (qui est une valeur que le navigateur remplit si il n'y a pas d'attribute "value", pratique pour tout ce qui est acceptation de condition d'utilisation etc).

Dans ma première réponse tu as le premier extrait de code qui contient ce qu'il faut mettre si besoin.

Posté il y a 2 mois
Avatar de Mathissou
Mathissou

Wow ça fonctionne !

Merci beaucoup Khalyomede !

En te souhaitant une bonne continuation !

Posté il y a 2 mois

Vous ne pouvez pas répondre à ce sujet.