Browse Source

¨Les tris fonctionnent

Francois DROUHARD 901 2 months ago
parent
commit
9e6e27b066

+ 29 - 6
assets/controllers/sortable_controller.js

@@ -4,19 +4,42 @@ import Sortable from 'sortablejs'
 export default class extends Controller {
     connect() {
         this.sortable = Sortable.create(this.element, {
+            group: 'shared',
+            sort: this.data.get('sortable') ?? false,
+            filter: '.title',
             onEnd: this.end.bind(this)
         });
     }
 
     end(event) {
-        // Envoyer les nouvelles positions au serveur
-        const data = new FormData();
-        data.append('oldIndex', event.oldIndex);
-        data.append('newIndex', event.newIndex);
+        const filmId = event.item.dataset.id;
+        const fromList = event.from.classList.contains('user-list') ? 'user' : 'common';
+        const toList = event.to.classList.contains('user-list') ? 'user' : 'common';
+        const oldIndex = event.oldIndex
+        const newIndex = event.newIndex
+        const order = this.sortable.toArray();
 
-        fetch('/update-order', {
+        console.log(oldIndex, newIndex)
+        console.log(order)
+
+        fetch(this.data.get('url'), {
             method: 'POST',
-            body: data
+            headers: {
+                'Content-Type': 'application/json'
+            },
+            body: JSON.stringify({ filmId: filmId, fromList: fromList, toList: toList, oldIndex: oldIndex, newIndex: newIndex, order: order })
+        })
+        .then(response => response.json())
+        .then(data => {
+            if(data.success) {
+                console.log('Liste updated successfully');
+            } else {
+                console.error('Failed to update list');
+            }
+        })
+        .catch(error => {
+            console.error('Error:', error);
         });
+        ;
     }
 }

+ 8 - 5
migrations/Version20250113100815.php → migrations/Version20250113132626.php

@@ -10,7 +10,7 @@ use Doctrine\Migrations\AbstractMigration;
 /**
  * Auto-generated Migration: Please modify to your needs!
  */
-final class Version20250113100815 extends AbstractMigration
+final class Version20250113132626 extends AbstractMigration
 {
     public function getDescription(): string
     {
@@ -21,20 +21,23 @@ final class Version20250113100815 extends AbstractMigration
     {
         // this up() migration is auto-generated, please modify it to your needs
         $this->addSql('CREATE SEQUENCE user_list_id_seq INCREMENT BY 1 MINVALUE 1 START 1');
-        $this->addSql('CREATE TABLE user_list (id INT NOT NULL, viewer_id INT NOT NULL, position INT DEFAULT NULL, PRIMARY KEY(id))');
+        $this->addSql('CREATE SEQUENCE user_list_film_id_seq INCREMENT BY 1 MINVALUE 1 START 1');
+        $this->addSql('CREATE TABLE user_list (id INT NOT NULL, viewer_id INT NOT NULL, PRIMARY KEY(id))');
         $this->addSql('CREATE INDEX IDX_3E49B4D16C59C752 ON user_list (viewer_id)');
-        $this->addSql('CREATE TABLE user_list_film (user_list_id INT NOT NULL, film_id INT NOT NULL, PRIMARY KEY(user_list_id, film_id))');
+        $this->addSql('CREATE TABLE user_list_film (id INT NOT NULL, user_list_id INT DEFAULT NULL, film_id INT NOT NULL, position INT DEFAULT NULL, PRIMARY KEY(id))');
         $this->addSql('CREATE INDEX IDX_C76AEC2F65A30881 ON user_list_film (user_list_id)');
         $this->addSql('CREATE INDEX IDX_C76AEC2F567F5183 ON user_list_film (film_id)');
         $this->addSql('ALTER TABLE user_list ADD CONSTRAINT FK_3E49B4D16C59C752 FOREIGN KEY (viewer_id) REFERENCES "user" (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
-        $this->addSql('ALTER TABLE user_list_film ADD CONSTRAINT FK_C76AEC2F65A30881 FOREIGN KEY (user_list_id) REFERENCES user_list (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE');
-        $this->addSql('ALTER TABLE user_list_film ADD CONSTRAINT FK_C76AEC2F567F5183 FOREIGN KEY (film_id) REFERENCES film (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE');
+        $this->addSql('ALTER TABLE user_list_film ADD CONSTRAINT FK_C76AEC2F65A30881 FOREIGN KEY (user_list_id) REFERENCES user_list (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
+        $this->addSql('ALTER TABLE user_list_film ADD CONSTRAINT FK_C76AEC2F567F5183 FOREIGN KEY (film_id) REFERENCES film (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
     }
 
     public function down(Schema $schema): void
     {
         // this down() migration is auto-generated, please modify it to your needs
+        $this->addSql('CREATE SCHEMA public');
         $this->addSql('DROP SEQUENCE user_list_id_seq CASCADE');
+        $this->addSql('DROP SEQUENCE user_list_film_id_seq CASCADE');
         $this->addSql('ALTER TABLE user_list DROP CONSTRAINT FK_3E49B4D16C59C752');
         $this->addSql('ALTER TABLE user_list_film DROP CONSTRAINT FK_C76AEC2F65A30881');
         $this->addSql('ALTER TABLE user_list_film DROP CONSTRAINT FK_C76AEC2F567F5183');

+ 97 - 4
src/Controller/IndexController.php

@@ -4,10 +4,16 @@ namespace App\Controller;
 
 use App\Entity\CommonList;
 use App\Entity\Film;
+use App\Entity\UserList;
+use App\Entity\UserListFilm;
 use App\Form\FilmType;
 use App\Repository\CommonListRepository;
 use App\Repository\FilmRepository;
+use App\Repository\UserListFilmRepository;
+use App\Repository\UserListRepository;
+use Doctrine\ORM\EntityManagerInterface;
 use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
+use Symfony\Component\HttpFoundation\JsonResponse;
 use Symfony\Component\HttpFoundation\RedirectResponse;
 use Symfony\Component\HttpFoundation\Request;
 use Symfony\Component\HttpFoundation\Response;
@@ -16,12 +22,23 @@ use Symfony\Component\Routing\Attribute\Route;
 class IndexController extends AbstractController
 {
     #[Route('/{id?}', name: 'app_index', methods: ['GET', 'POST'], requirements: ['id' => '\d+'])]
-    public function index(Request $request, FilmRepository $filmRepository, CommonListRepository $commonListRepository, ?Film $film = null): Response
+    public function index(
+        Request $request,
+        FilmRepository $filmRepository,
+        CommonListRepository $commonListRepository,
+        UserListRepository $userListRepository,
+        UserListFilmRepository $userListFilmRepository,
+        ?Film $film = null
+    ): Response
     {
         $film = $film ?? new Film();
         $form = $this->createForm(FilmType::class, $film);
 
-        $commonList = $commonListRepository->findAll();
+        $listeFilms = $commonListRepository->findAll();
+        $userList = $userListRepository->findOneBy(['viewer' => $this->getUser()]);
+        $userListFilms = $userListFilmRepository->findBy(criteria: ['userList' => $userList], orderBy: ['position' => 'ASC']);
+        $mesFilms = array_map(fn($value): Film => $value->getFilm(), $userListFilms);
+        //dd($mesFilms);
 
         $form->handleRequest($request);
 
@@ -31,13 +48,17 @@ class IndexController extends AbstractController
             }
 
             $filmRepository->save($film, true);
-            $commonListRepository->save($commonList, true);
+            
+            if (isset($commonList)) {
+                $commonListRepository->save($commonList, true);
+            }
 
             return $this->redirectToRoute('app_index', [], RedirectResponse::HTTP_SEE_OTHER);
         }
 
         return $this->render('index/index.html.twig', [
-            'commonList' => $commonList,
+            'mesFilms' => $mesFilms,
+            'listeFilms' => $listeFilms,
             'form' => $form
         ]);
     }
@@ -51,4 +72,76 @@ class IndexController extends AbstractController
 
         return new Response('Order updated', Response::HTTP_OK);
     }
+
+    #[Route('/update-list', name: 'update_list', methods: ['POST'])]
+    public function updateList(
+        Request $request,
+        FilmRepository $filmRepository,
+        UserListRepository $userListRepository,
+        UserListFilmRepository $userListFilmRepository,
+        EntityManagerInterface $entityManager): Response
+    {
+        $data = json_decode($request->getContent(), true);
+        $filmId = $data['filmId'];
+        $fromList = $data['fromList'];
+        $toList = $data['toList'];
+        $oldIndex = $data['oldIndex'];
+        $newIndex = $data['newIndex'];
+        $order = $data['order'];
+
+        $film = $filmRepository->find($filmId);
+        $user = $this->getUser();
+
+        // Récupérer ou créer la liste personnelle de l'utilisateur
+        $userList = $userListRepository->findOneBy(['viewer' => $user]);
+        if (!$userList) {
+            $userList = new UserList();
+            $userList->setViewer($user);
+            $entityManager->persist($userList);
+            $entityManager->flush();
+        }
+
+        $userListFilm = $userListFilmRepository->findOneBy(['userList' => $userList, 'film' => $film]);
+        if ($toList === 'user') {
+            // Ajouter le film à la liste personnelle de l'utilisateur
+            $userListFilm = $userListFilm ?? new UserListFilm();
+            $userListFilm->setUserList($userList);
+            $userListFilm->setFilm($film);
+            //$userListFilm->setPosition($userListFilm->getPosition() ?? $newIndex);
+
+            $this->updatePositions($userList, $userListFilmRepository, $fromList, $toList, $order, $userListFilm);
+
+            $entityManager->persist($userListFilm);
+        } else {
+            // Retirer le film de la liste personnelle de l'utilisateur
+            
+            if ($userListFilm) {
+                $entityManager->remove($userListFilm);
+                $entityManager->flush();
+
+                $this->updatePositions($userList, $userListFilmRepository, $fromList, $toList, $order);
+            }
+        }
+
+        $entityManager->flush();
+
+        return new JsonResponse(['success' => true]);
+    }
+
+    private function updatePositions(UserList $userList, UserListFilmRepository $userListFilmRepository, string $fromList, string $toList, array $order, ?UserListFilm $newUserListFilm = null)
+    {
+        $userListFilms = $userListFilmRepository->findBy(['userList' => $userList], ['position' => 'ASC']);
+        if($fromList === 'user') {
+            foreach($userListFilms as $userListFilm) {
+                $idFilm = $userListFilm->getFilm()->getId();
+                $userListFilm->setPosition(array_search((string) $idFilm, $order));
+            }
+        } elseif ($fromList === 'common' && $toList === 'user') {
+            $last = end($userListFilms);
+            $positionLast = $last->getPosition();
+            $newUserListFilm->setPosition($positionLast + 1);
+
+        }
+    }
+
 }

+ 17 - 14
src/Entity/Film.php

@@ -31,15 +31,15 @@ class Film
     private Collection $commonLists;
 
     /**
-     * @var Collection<int, UserList>
+     * @var Collection<int, UserListFilm>
      */
-    #[ORM\ManyToMany(targetEntity: UserList::class, mappedBy: 'films')]
-    private Collection $userLists;
+    #[ORM\OneToMany(targetEntity: UserListFilm::class, mappedBy: 'film', orphanRemoval: true)]
+    private Collection $userListFilms;
 
     public function __construct()
     {
         $this->commonLists = new ArrayCollection();
-        $this->userLists = new ArrayCollection();
+        $this->userListFilms = new ArrayCollection();
     }
 
     public function getId(): ?int
@@ -114,27 +114,30 @@ class Film
     }
 
     /**
-     * @return Collection<int, UserList>
+     * @return Collection<int, UserListFilm>
      */
-    public function getUserLists(): Collection
+    public function getUserListFilms(): Collection
     {
-        return $this->userLists;
+        return $this->userListFilms;
     }
 
-    public function addUserList(UserList $userList): static
+    public function addUserListFilm(UserListFilm $userListFilm): static
     {
-        if (!$this->userLists->contains($userList)) {
-            $this->userLists->add($userList);
-            $userList->addFilm($this);
+        if (!$this->userListFilms->contains($userListFilm)) {
+            $this->userListFilms->add($userListFilm);
+            $userListFilm->setFilm($this);
         }
 
         return $this;
     }
 
-    public function removeUserList(UserList $userList): static
+    public function removeUserListFilm(UserListFilm $userListFilm): static
     {
-        if ($this->userLists->removeElement($userList)) {
-            $userList->removeFilm($this);
+        if ($this->userListFilms->removeElement($userListFilm)) {
+            // set the owning side to null (unless already changed)
+            if ($userListFilm->getFilm() === $this) {
+                $userListFilm->setFilm(null);
+            }
         }
 
         return $this;

+ 18 - 27
src/Entity/UserList.php

@@ -20,17 +20,14 @@ class UserList
     private ?User $viewer = null;
 
     /**
-     * @var Collection<int, Film>
+     * @var Collection<int, UserListFilm>
      */
-    #[ORM\ManyToMany(targetEntity: Film::class, inversedBy: 'userLists')]
-    private Collection $films;
-
-    #[ORM\Column(nullable: true)]
-    private ?int $position = null;
+    #[ORM\OneToMany(targetEntity: UserListFilm::class, mappedBy: 'userList')]
+    private Collection $userListFilms;
 
     public function __construct()
     {
-        $this->films = new ArrayCollection();
+        $this->userListFilms = new ArrayCollection();
     }
 
     public function getId(): ?int
@@ -51,37 +48,31 @@ class UserList
     }
 
     /**
-     * @return Collection<int, Film>
+     * @return Collection<int, UserListFilm>
      */
-    public function getFilms(): Collection
+    public function getUserListFilms(): Collection
     {
-        return $this->films;
+        return $this->userListFilms;
     }
 
-    public function addFilm(Film $film): static
+    public function addUserListFilm(UserListFilm $userListFilm): static
     {
-        if (!$this->films->contains($film)) {
-            $this->films->add($film);
+        if (!$this->userListFilms->contains($userListFilm)) {
+            $this->userListFilms->add($userListFilm);
+            $userListFilm->setUserList($this);
         }
 
         return $this;
     }
 
-    public function removeFilm(Film $film): static
-    {
-        $this->films->removeElement($film);
-
-        return $this;
-    }
-
-    public function getPosition(): ?int
+    public function removeUserListFilm(UserListFilm $userListFilm): static
     {
-        return $this->position;
-    }
-
-    public function setPosition(?int $position): static
-    {
-        $this->position = $position;
+        if ($this->userListFilms->removeElement($userListFilm)) {
+            // set the owning side to null (unless already changed)
+            if ($userListFilm->getUserList() === $this) {
+                $userListFilm->setUserList(null);
+            }
+        }
 
         return $this;
     }

+ 66 - 0
src/Entity/UserListFilm.php

@@ -0,0 +1,66 @@
+<?php
+
+namespace App\Entity;
+
+use App\Repository\UserListFilmRepository;
+use Doctrine\ORM\Mapping as ORM;
+
+#[ORM\Entity(repositoryClass: UserListFilmRepository::class)]
+class UserListFilm
+{
+    #[ORM\Id]
+    #[ORM\GeneratedValue]
+    #[ORM\Column]
+    private ?int $id = null;
+
+    #[ORM\ManyToOne(inversedBy: 'userListFilms')]
+    private ?UserList $userList = null;
+
+    #[ORM\Column(nullable: true)]
+    private ?int $position = null;
+
+    #[ORM\ManyToOne(inversedBy: 'userListFilms')]
+    #[ORM\JoinColumn(nullable: false)]
+    private ?Film $film = null;
+
+    public function getId(): ?int
+    {
+        return $this->id;
+    }
+
+    public function getUserList(): ?UserList
+    {
+        return $this->userList;
+    }
+
+    public function setUserList(?UserList $userList): static
+    {
+        $this->userList = $userList;
+
+        return $this;
+    }
+
+    public function getPosition(): ?int
+    {
+        return $this->position;
+    }
+
+    public function setPosition(?int $position): static
+    {
+        $this->position = $position;
+
+        return $this;
+    }
+
+    public function getFilm(): ?Film
+    {
+        return $this->film;
+    }
+
+    public function setFilm(?Film $film): static
+    {
+        $this->film = $film;
+
+        return $this;
+    }
+}

+ 43 - 0
src/Repository/UserListFilmRepository.php

@@ -0,0 +1,43 @@
+<?php
+
+namespace App\Repository;
+
+use App\Entity\UserListFilm;
+use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
+use Doctrine\Persistence\ManagerRegistry;
+
+/**
+ * @extends ServiceEntityRepository<UserListFilm>
+ */
+class UserListFilmRepository extends ServiceEntityRepository
+{
+    public function __construct(ManagerRegistry $registry)
+    {
+        parent::__construct($registry, UserListFilm::class);
+    }
+
+    //    /**
+    //     * @return UserListFilm[] Returns an array of UserListFilm objects
+    //     */
+    //    public function findByExampleField($value): array
+    //    {
+    //        return $this->createQueryBuilder('u')
+    //            ->andWhere('u.exampleField = :val')
+    //            ->setParameter('val', $value)
+    //            ->orderBy('u.id', 'ASC')
+    //            ->setMaxResults(10)
+    //            ->getQuery()
+    //            ->getResult()
+    //        ;
+    //    }
+
+    //    public function findOneBySomeField($value): ?UserListFilm
+    //    {
+    //        return $this->createQueryBuilder('u')
+    //            ->andWhere('u.exampleField = :val')
+    //            ->setParameter('val', $value)
+    //            ->getQuery()
+    //            ->getOneOrNullResult()
+    //        ;
+    //    }
+}

+ 29 - 2
templates/index/index.html.twig

@@ -17,9 +17,15 @@
             <th>Date d'ajout</th>
         </tr>
     </thead>
-    <tbody data-controller="sortable" data-sortable-url="{{ path('update_order') }}">
-        {% for entry in commonList %}
+    <tbody>
+        <tr>
+            <th colspan="6" class="title">Liste complète</th>
+        </tr>
+    </tbody>
+    <tbody class="common-list" data-controller="sortable" data-sortable-group="shared" data-sortable-url="{{ path('update_list') }}">
+        {% for entry in listeFilms %}
         {% set film = entry.film %}
+        {% if film not in mesFilms %}
         <tr data-id="{{ film.id }}">
             <td>
                 <a href="{{ path('app_index', {'id': film.id} ) }}"><i class="fa fa-edit"></i></a>
@@ -30,6 +36,27 @@
             <td>{{ entry.addedBy.email }}</td>
             <td>{{ entry.dateAdded | date('d/m/Y') }}
         </tr>
+        {% endif %}
+        {% endfor %}
+    </tbody>
+    <tbody>
+        <tr>
+            <th colspan="6" class="title">Ma liste</th>
+        </tr>
+    </tbody>
+    <tbody class="user-list" data-sortable-sortable="true" data-controller="sortable" data-sortable-group="shared" data-sortable-url="{{ path('update_list') }}">
+        
+        {% for film in mesFilms %}
+        <tr data-id="{{ film.id }}">
+            <td>
+                <a href="{{ path('app_index', {'id': film.id} ) }}"><i class="fa fa-edit"></i></a>
+            </td>
+            <td>{{ film.name }}</td>
+            <td>{{ film.realisateur }}</td>
+            <td>{{ film.genre }}</td>
+            <td></td>
+            <td></td>
+        </tr>
         {% endfor %}
     </tbody>
 </table>