Bladeren bron

Merge branch 'develop' into features/background

François Drouhard 3 jaren geleden
bovenliggende
commit
ac5ad163d3

+ 32 - 0
migrations/Version20211105162807.php

@@ -0,0 +1,32 @@
+<?php
+
+declare(strict_types=1);
+
+namespace DoctrineMigrations;
+
+use Doctrine\DBAL\Schema\Schema;
+use Doctrine\Migrations\AbstractMigration;
+
+/**
+ * Auto-generated Migration: Please modify to your needs!
+ */
+final class Version20211105162807 extends AbstractMigration
+{
+    public function getDescription(): string
+    {
+        return '';
+    }
+
+    public function up(Schema $schema): void
+    {
+        // this up() migration is auto-generated, please modify it to your needs
+        $this->addSql('CREATE TABLE profile (id INT AUTO_INCREMENT NOT NULL, user_id INT NOT NULL, view INT NOT NULL, UNIQUE INDEX UNIQ_8157AA0FA76ED395 (user_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
+        $this->addSql('ALTER TABLE profile ADD CONSTRAINT FK_8157AA0FA76ED395 FOREIGN KEY (user_id) REFERENCES user (id)');
+    }
+
+    public function down(Schema $schema): void
+    {
+        // this down() migration is auto-generated, please modify it to your needs
+        $this->addSql('DROP TABLE profile');
+    }
+}

+ 69 - 0
src/Command/UpdateOptionsCommand.php

@@ -0,0 +1,69 @@
+<?php
+
+namespace App\Command;
+
+use App\Entity\Profile;
+use App\Repository\UserRepository;
+use Doctrine\ORM\EntityManagerInterface;
+use Symfony\Component\Console\Attribute\AsCommand;
+use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Input\InputOption;
+use Symfony\Component\Console\Output\OutputInterface;
+use Symfony\Component\Console\Style\SymfonyStyle;
+
+class UpdateOptionsCommand extends Command
+{
+    protected $em;
+    protected $repoUser;
+    
+    public function __construct(EntityManagerInterface $em, UserRepository $repoUser)
+    {
+        $this->em = $em;
+        $this->repoUser = $repoUser;
+        parent::__construct();
+    }
+
+    protected function configure(): void
+    {
+        $this
+            ->setName('app:update:options')
+            ->setDescription('Commande pour rattacher une entité Profile aux users existants')
+            //->addArgument('arg1', InputArgument::OPTIONAL, 'Argument description')
+            ->addOption('force', null, InputOption::VALUE_NONE, 'Forcer la création des profils utilisateur')
+        ;
+    }
+
+    protected function execute(InputInterface $input, OutputInterface $output): int
+    {
+        $io = new SymfonyStyle($input, $output);
+        /*$arg1 = $input->getArgument('arg1');
+
+        if ($arg1) {
+            $io->note(sprintf('You passed an argument: %s', $arg1));
+        }*/
+
+        if ($input->getOption('force')) {
+            $users = $this->repoUser->findAll();
+            foreach($users as $user) {
+                if ($user->getProfile() === null)
+                {
+                    $io->note(sprintf('%s : pas de profil', $user->getNomComplet()));
+                    $profil = new Profile;
+                    $profil->setUser($user);
+                    $this->em->persist($profil);
+                    $this->em->flush();
+                }
+            }
+
+
+            $io->success(sprintf('La bdd a été modifiée.'));
+            return Command::SUCCESS;
+        } else {
+            $io->note(sprintf('La bdd n\'a pas été modifiée. Utilisez l\'option --force.'));
+
+            return Command::SUCCESS;
+        }
+    }
+}

+ 23 - 1
src/Controller/ProfilController.php

@@ -3,8 +3,11 @@
 namespace App\Controller;
 
 use Doctrine\ORM\EntityManagerInterface;
+use App\Form\UserEditProfilType;
+use App\Form\ProfileType;
 use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
 use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Response;
 use Symfony\Component\Routing\Annotation\Route;
 
 class ProfilController extends AbstractController
@@ -15,7 +18,7 @@ class ProfilController extends AbstractController
     public function monProfilAction(Request $request, EntityManagerInterface $em)
     {
         $user = $this->getUser();
-        $form = $this->createForm('App\Form\UserEditProfilType', $user);
+        $form = $this->createForm(UserEditProfilType::class , $user);
         $form->handleRequest($request);
         if ($form->isSubmitted() && $form->isValid())
         {
@@ -30,6 +33,25 @@ class ProfilController extends AbstractController
         ));
     }
 
+    /**
+     * @Route("/preferences/", name="user_preferences")
+     */
+    public function mesPreferencesAction(Request $request, EntityManagerInterface $em): Response
+    {
+        $profile = $this->getUser()->getProfile();
+        $form = $this->createForm(ProfileType::class , $profile);
+        $form->handleRequest($request);
+        if ($form->isSubmitted() && $form->isValid())
+        {
+            $profile = $form->getData();
+            $em->flush();
+            $this->addFlash('success', "Les préférences ont été modifiées");
+        }
+
+        return $this->render('profil/mespreferences.html.twig', [
+            'form'  =>  $form->createView()
+        ]);
+    }
 
 
 }

+ 6 - 1
src/Controller/SearchController.php

@@ -14,8 +14,13 @@ class SearchController extends AbstractController
      */
     public function searchAction(Request $request, Search $filmSearch)
     {
+        if ($this->getUser()->getProfile()->getView() === 0) {
+            $type = "tableaux";
+        } else {
+            $type = "vignettes";
+        }
         $query = $request->query->get('q', "");
-        return $this->render('videotheque/liste.html.twig', array(
+        return $this->render('videotheque/liste_'.$type.'.html.twig', array(
             'listeFilms'    =>  $filmSearch->search($query),
             'titre'         =>  'Recherche '. $query,
             'query'         =>  $query

+ 19 - 3
src/Controller/VideothequeController.php

@@ -28,8 +28,13 @@ class VideothequeController extends AbstractController
 	public function listeAction(Request $request, FilmRepository $repo)
 	{
         $listeFilms = $repo->findTous();
+        if ($this->getUser()->getProfile()->getView() === 0) {
+            $type = "tableaux";
+        } else {
+            $type = "vignettes";
+        }
 
-		return $this->render('videotheque/liste.html.twig', array(
+		return $this->render("videotheque/liste_$type.html.twig", array(
             'listeFilms'	=>	$listeFilms,
             'titre'         =>  'Liste complète',
 		));
@@ -41,8 +46,13 @@ class VideothequeController extends AbstractController
 	public function  listeParGenreAction(\App\Entity\Genre $genre, FilmRepository $repo)
     {
         $films = $repo->findFilmWithGenre(array($genre->getName()));
+        if ($this->getUser()->getProfile()->getView() === 0) {
+            $type = "tableaux";
+        } else {
+            $type = "vignettes";
+        }
 
-        return $this->render('videotheque/liste.html.twig', array(
+        return $this->render("videotheque/liste_$type.html.twig", array(
             'listeFilms'    => $films,
             'titre'         => 'Films par catégorie : '.$genre->getName()
         ));
@@ -55,7 +65,13 @@ class VideothequeController extends AbstractController
     {
         $films = $repo->findFilmWithReal(array($realisateur->getNomComplet()));
 
-        return $this->render('videotheque/liste.html.twig', array(
+        if ($this->getUser()->getProfile()->getView() === 0) {
+            $type = "tableaux";
+        } else {
+            $type = "vignettes";
+        }
+
+        return $this->render("videotheque/liste_$type.html.twig", array(
             'listeFilms'    => $films,
             'titre'         => 'Films par réalisateur : '.$realisateur->getNomComplet()
         ));

+ 7 - 1
src/Controller/VideothequePersonnelleController.php

@@ -18,7 +18,13 @@ class VideothequePersonnelleController extends AbstractController
     {
         $films = $repo->findTousFavoritesByUser($this->getUser());
 
-        return $this->render('videotheque/liste.html.twig', array(
+        if ($this->getUser()->getProfile()->getView() === 0) {
+            $type = "tableaux";
+        } else {
+            $type = "vignettes";
+        }
+
+        return $this->render('videotheque/liste_'.$type.'.html.twig', array(
             'listeFilms'    =>  $films,
             'titre'         =>  'Ma liste de films à voir'
         ));

+ 66 - 0
src/Entity/Profile.php

@@ -0,0 +1,66 @@
+<?php
+
+namespace App\Entity;
+
+use App\Repository\ProfileRepository;
+use Doctrine\ORM\Mapping as ORM;
+
+/**
+ * @ORM\Entity(repositoryClass=ProfileRepository::class)
+ */
+class Profile
+{
+    public static $VIEW = ['liste' => 0, 'vignette' => 1];
+
+    /**
+     * @ORM\Id
+     * @ORM\GeneratedValue
+     * @ORM\Column(type="integer")
+     */
+    private $id;
+
+    /**
+     * @ORM\OneToOne(targetEntity=User::class, inversedBy="profile", cascade={"persist", "remove"})
+     * @ORM\JoinColumn(nullable=false)
+     */
+    private $user;
+
+    /**
+     * @ORM\Column(type="integer")
+     */
+    private $view;
+
+    public function __construct()
+    {
+        $this->setView(Profile::$VIEW['vignette']);
+    }
+
+    public function getId(): ?int
+    {
+        return $this->id;
+    }
+
+    public function getUser(): ?User
+    {
+        return $this->user;
+    }
+
+    public function setUser(User $user): self
+    {
+        $this->user = $user;
+
+        return $this;
+    }
+
+    public function getView(): ?int
+    {
+        return $this->view;
+    }
+
+    public function setView(int $view): self
+    {
+        $this->view = $view;
+
+        return $this;
+    }
+}

+ 22 - 0
src/Entity/User.php

@@ -147,6 +147,11 @@ class User implements UserInterface,PasswordAuthenticatedUserInterface
      */
     private $filmsVus;
 
+    /**
+     * @ORM\OneToOne(targetEntity=Profile::class, mappedBy="user", cascade={"persist", "remove"})
+     */
+    private $profile;
+
 
     /**
      * Get id
@@ -551,4 +556,21 @@ class User implements UserInterface,PasswordAuthenticatedUserInterface
         return $this->getFilmsVus()->contains($film);
     }
 
+    public function getProfile(): ?Profile
+    {
+        return $this->profile;
+    }
+
+    public function setProfile(Profile $profile): self
+    {
+        // set the owning side of the relation if necessary
+        if ($profile->getUser() !== $this) {
+            $profile->setUser($this);
+        }
+
+        $this->profile = $profile;
+
+        return $this;
+    }
+
 }

+ 33 - 0
src/Form/ProfileType.php

@@ -0,0 +1,33 @@
+<?php
+
+namespace App\Form;
+
+use App\Entity\Profile;
+use Symfony\Component\Form\AbstractType;
+use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
+use Symfony\Component\Form\Extension\Core\Type\SubmitType;
+use Symfony\Component\Form\FormBuilderInterface;
+use Symfony\Component\OptionsResolver\OptionsResolver;
+
+class ProfileType extends AbstractType
+{
+    public function buildForm(FormBuilderInterface $builder, array $options): void
+    {
+        $builder
+            ->add('view', ChoiceType::class, [
+                'choices'   => [
+                    'Liste' => 0,
+                    'Vignette'  => 1
+                ]
+            ])
+            ->add('save', SubmitType::class, array('label' => 'Enregistrer'))
+        ;
+    }
+
+    public function configureOptions(OptionsResolver $resolver): void
+    {
+        $resolver->setDefaults([
+            'data_class' => Profile::class,
+        ]);
+    }
+}

+ 50 - 0
src/Repository/ProfileRepository.php

@@ -0,0 +1,50 @@
+<?php
+
+namespace App\Repository;
+
+use App\Entity\Profile;
+use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
+use Doctrine\Persistence\ManagerRegistry;
+
+/**
+ * @method Profile|null find($id, $lockMode = null, $lockVersion = null)
+ * @method Profile|null findOneBy(array $criteria, array $orderBy = null)
+ * @method Profile[]    findAll()
+ * @method Profile[]    findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
+ */
+class ProfileRepository extends ServiceEntityRepository
+{
+    public function __construct(ManagerRegistry $registry)
+    {
+        parent::__construct($registry, Profile::class);
+    }
+
+    // /**
+    //  * @return Profile[] Returns an array of Profile objects
+    //  */
+    /*
+    public function findByExampleField($value)
+    {
+        return $this->createQueryBuilder('p')
+            ->andWhere('p.exampleField = :val')
+            ->setParameter('val', $value)
+            ->orderBy('p.id', 'ASC')
+            ->setMaxResults(10)
+            ->getQuery()
+            ->getResult()
+        ;
+    }
+    */
+
+    /*
+    public function findOneBySomeField($value): ?Profile
+    {
+        return $this->createQueryBuilder('p')
+            ->andWhere('p.exampleField = :val')
+            ->setParameter('val', $value)
+            ->getQuery()
+            ->getOneOrNullResult()
+        ;
+    }
+    */
+}

+ 1 - 0
templates/navbar.html.twig

@@ -107,6 +107,7 @@
                     </a>
                     <div class="dropdown-menu dropdown-menu-right" aria-labelledby="navbarUserDropdown">
                         <a class="dropdown-item" href="{{ path('user_profil') }}">Profil</a>
+                        <a class="dropdown-item" href="{{ path('user_preferences') }}">Préférences</a>
                         <div class="dropdown-divider"></div>
                         <a class="dropdown-item" href="{{ path('app_logout') }}">Se déconnecter</a>
                     </div>

+ 11 - 0
templates/profil/mespreferences.html.twig

@@ -0,0 +1,11 @@
+{% extends "base.html.twig" %}
+
+{% block title %}{{ parent() }} - Mes préférences{%  endblock %}
+{% block titre %}Modifier mes préférences{%  endblock %}
+
+{% block body %}
+    <div class="d-flex">
+        {{ form(form) }}
+    </div>
+    <a href="{{ path('videotheque_liste') }}" class="btn btn-link" role="button">Retour à l'accueil</a>
+{% endblock %}

+ 136 - 0
templates/videotheque/liste_tableaux.html.twig

@@ -0,0 +1,136 @@
+{% extends "videotheque/base.html.twig" %}
+
+{% block title %}
+{% if titre is defined %}{{ parent() }} - {{ titre }}{% else %}{{ parent() }}{% endif %}
+{% endblock %}
+
+{% block titre %}
+{% if titre is defined %}{{ titre }}{% else %}{{ parent() }}{% endif %}
+{% endblock %}
+
+{% block body %}
+	<div class="row">
+		{% if is_granted('IS_AUTHENTICATED_REMEMBERED') %}
+		<p><a class="btn btn-primary" role="button" href="{{ path('videotheque_ajouter') }}"><i class="fa fa-plus-square fa-lg"></i> Ajouter un film</a></p>
+		{% endif %}
+		<p>Filtrer par film au dessus de
+		<input class="rating"
+			data-disabled="false"
+			data-show-clear="true"
+			data-show-caption="false"
+			data-theme="krajee-fa"
+			data-toggle="star-filter"
+			data-path="#tableFilms"
+			style="display:none;"
+			min=0
+			max=5
+			data-step=1
+			data-size="sm"
+			value="0">
+		</p>
+	</div>
+	<div class="row">
+		<table class="table table-bordered table-hover table-sm align-middle">
+			<thead class="">
+				<tr>
+					{% if is_granted('IS_AUTHENTICATED_REMEMBERED') %}
+						<th style="width:1em;"></th>
+						<th style="width:1em;"></th>
+						<th>Ajouté par</th>
+					{% endif %}
+					<th>Titre</th>
+					<th>Genre</th>
+					<th>Réalisateur</th>
+					<th style="width:5em;">Note</th>
+					<th style="width:5em;">Année</th>
+				</tr>
+			</thead>
+			<tbody id="tableFilms">
+				{% for film in listeFilms %}
+				<tr data-auteur="{{ film.authered.nomComplet }}">
+					{% if is_granted('IS_AUTHENTICATED_REMEMBERED') %}
+						<td>
+							{%  if app.user.wantToSee(film) %}
+								{% set follow_icone = "fa fa-bookmark fa-lg" %}
+								{% set follow_texte = "Supprimer ce film de votre liste à voir" %}
+							{% else %}
+								{% set follow_icone = "fa fa-bookmark-o text-secondary fa-lg" %}
+								{% set follow_texte = "Ajouter ce film à votre liste à voir" %}
+							{% endif %}
+							<a href="#" data-fonction="switch"
+										data-icone-actif="fa fa-bookmark fa-lg"
+										data-icone-inactif="fa fa-bookmark-o text-secondary fa-lg"
+										data-path="{{ path('maliste_modifier_a_voir') }}"
+										data-bs-toggle="tooltip"
+										title="{{ follow_texte }}"
+										data-content="{{ film.id }}">
+								<i class="{{ follow_icone }}"></i>
+							</a>
+						</td>
+						<td>
+							{%  if app.user.haveSeen(film) %}
+								{% set vu_icone = '<i class="fa fa-eye fa-lg text-success"></i>' %}
+							{% else %}
+								{% set vu_icone = '<i class="fa fa-eye-slash fa-lg text-secondary"></i>' %}
+							{% endif %}				
+							<a href="#" data-fonction="switch"
+										data-path="{{ path('maliste_modifier_vus') }}"
+										data-content="{{ film.id }}"
+										data-icone-actif = "fa fa-eye fa-lg text-success"
+										data-icone-inactif = "fa fa-eye-slash fa-lg text-secondary">
+								{{ vu_icone | raw }}
+							</a>
+						</td>
+						<td>
+							{%  if film.authered is defined %}
+								{% if film.authered.activeNow %}
+									<i class="fa fa-user text-success" data-bs-toggle="tooltip" title="En ligne"></i>
+								{% else %}
+									<i class="fa fa-user-o text-secondary" data-bs-toggle="tooltip" title="Hors ligne"></i>
+								{% endif %}
+								{{ film.authered.username }}
+							{% endif %}
+						</td>
+					{% endif %}
+					<td>
+						<a href="{{ path('videotheque_voirfilm', {'id': film.id}) }}"><span data-bs-toggle="tooltip" data-placement="right" title="{{ film.information }}">{{ film.titre }}</span></a>
+						{% if film.new %}<span class="badge bg-success">New</span>{% endif %}
+						{% if film.nbComs %}<span class="badge bg-warning rounded-pill" data-bs-toggle="tooltip" title="{{ film.nbComs }} commentaire(s)">{{ film.nbComs }}</span>{% endif %}
+
+					</td>
+					<td>
+						{% if film.genres is defined %}
+							{% for genre in film.genres %}
+								<a href="{{ path("videotheque_listepargenre", {"id": genre.id}) }}"><span class="badge bg-secondary">{{ genre.name }}</span></a>
+							{% endfor %}
+						{% endif %}
+					</td>
+					<td>
+					{% if film.realisateurs is defined %}
+						{%  for realisateur in film.realisateurs %}
+							<a href="{{ path('videotheque_listeparreal', {"id": realisateur.id}) }}"><span class="badge bg-info">{{ realisateur.nomComplet }}</span></a>
+						{%  endfor %}
+					{% endif %}
+					</td>
+					<td>
+						{% if film.note > 0 %}
+							<input class="rating"
+								data-disabled="true"
+								data-show-clear="false"
+								data-show-caption="false"
+								data-theme="krajee-fa"
+								style="display:none;"
+								min=0
+								max=5
+								data-step=0.5
+								data-size="xs"
+								value="{{ film.note }}">
+						{% endif %}
+					</td>
+					<td>{{ film.annee | date('Y') }}</td>
+				</tr>
+				{% endfor %}
+			</tbody>
+		</table>
+	</div>
+{% endblock %}

+ 0 - 0
templates/videotheque/liste.html.twig → templates/videotheque/liste_vignettes.html.twig


+ 2 - 0
translations/messages.fr.yaml

@@ -19,6 +19,8 @@ Prenom: Prénom
 Nom: Nom
 Mail: Email
 
+View: Vue
+
 Roles: Roles
 Administrateur: Administrateur
 User: Utilisateur