diff --git a/src/Controller/EpisodeController.php b/src/Controller/EpisodeController.php index e4bca37..a28ff6f 100644 --- a/src/Controller/EpisodeController.php +++ b/src/Controller/EpisodeController.php @@ -2,6 +2,7 @@ namespace App\Controller; +use App\Constants; use App\Entity\Episode; use App\Form\EpisodeType; use App\Repository\EpisodeRepository; @@ -20,25 +21,25 @@ use Symfony\Component\String\Slugger\SluggerInterface; #[Route('/manage/episodes')] class EpisodeController extends AbstractController { - public function __construct(protected LoggerInterface $logger) - {} + public function __construct( + protected EpisodeRepository $episodeRepo, + protected PodcastRepository $podcastRepo, + protected EntityManagerInterface $em, + protected LoggerInterface $logger, + protected SluggerInterface $slugger + ) { + } #[Route('/', name: 'app_episode_index', methods: ['GET'])] - public function index(EpisodeRepository $episodeRepository): Response + public function index(): Response { return $this->render('episode/index.html.twig', [ - 'episodes' => $episodeRepository->findAll(), + 'episodes' => $this->episodeRepo->findAll(), ]); } #[Route('/new', name: 'app_episode_new', methods: ['GET', 'POST'])] - public function new( - Request $request, - EntityManagerInterface $entityManager, - PodcastRepository $podcastRepository, - SluggerInterface $slugger, - ): Response - { + public function new(Request $request): Response { $queryPodcastId = $request->query->getInt('podcast', 0); $episode = new Episode(); @@ -53,28 +54,29 @@ class EpisodeController extends AbstractController $form->handleRequest($request); if ($form->isSubmitted() && $form->isValid()) { - $this->logger->info("FLUMZO " . json_encode($form->getData())); - // Check that the user is the owner of the podcast this episode should belong to. $podcastId = $form->get('podcast')->getData(); - $podcast = $podcastRepository->find($podcastId ?? $queryPodcastId); + $podcast = $this->podcastRepo->find($podcastId ?? $queryPodcastId); if ( - $podcast === null - || $podcast->getOwner()->getId() !== $this->getUser()->getId() + null === $podcast + || $podcast->getOwner()?->getId() !== $this->getUser()?->getId() ) { $form->get('podcast')->addError(new FormError('Invalid podcast.')); + return $this->render('episode/new.html.twig', ['episode' => $episode, 'form' => $form]); } $episode->setPodcast($podcast); // Ensure the uploaded audio file is saved properly. - if (!$this->handleAudioChange($form, $episode, $slugger)) { - $form->get('logo')->addError(new FormError('Could not upload audio.')); + if (!$this->handleAudioChange($form, $episode)) { + $form->get('audio')->addError(new FormError('Could not upload audio.')); + return $this->render('episode/new.html.twig', ['episode' => $episode, 'form' => $form]); } - $entityManager->persist($episode); - $entityManager->flush(); + $this->em->persist($episode); + $this->em->flush(); + return $this->redirectToRoute('app_episode_index', [], Response::HTTP_SEE_OTHER); } @@ -89,11 +91,12 @@ class EpisodeController extends AbstractController { return $this->render('episode/show.html.twig', [ 'episode' => $episode, + 'files_path' => Constants::FILES_BASE_PATH ]); } #[Route('/{id}/edit', name: 'app_episode_edit', methods: ['GET', 'POST'])] - public function edit(Request $request, Episode $episode, EntityManagerInterface $entityManager): Response + public function edit(Episode $episode, Request $request): Response { $form = $this->createForm( EpisodeType::class, @@ -103,7 +106,17 @@ class EpisodeController extends AbstractController $form->handleRequest($request); if ($form->isSubmitted() && $form->isValid()) { - $entityManager->flush(); + $data = $form->getData(); + $this->logger->notice(json_encode($data)); + // Ensure the uploaded audio file is saved properly. + if (!$this->handleAudioChange($form, $episode)) { + $form->get('audio')->addError(new FormError('Could not upload audio.')); + + return $this->render('episode/edit.html.twig', ['episode' => $episode, 'form' => $form]); + } + + $this->em->persist($episode); + $this->em->flush(); return $this->redirectToRoute('app_episode_index', [], Response::HTTP_SEE_OTHER); } @@ -115,31 +128,32 @@ class EpisodeController extends AbstractController } #[Route('/{id}', name: 'app_episode_delete', methods: ['POST'])] - public function delete(Request $request, Episode $episode, EntityManagerInterface $entityManager): Response + public function delete(Episode $episode, Request $request): Response { - if ($this->isCsrfTokenValid('delete'.$episode->getId(), $request->request->get('_token'))) { - $entityManager->remove($episode); - $entityManager->flush(); + if ($this->isCsrfTokenValid('delete'.$episode->getId(), strval($request->request->get('_token')))) { + $this->em->remove($episode); + $this->em->flush(); } return $this->redirectToRoute('app_episode_index', [], Response::HTTP_SEE_OTHER); } - protected function handleAudioChange( - FormInterface $form, - Episode $episode, - SluggerInterface $slugger - ): bool + protected function handleAudioChange(FormInterface $form, Episode $episode): bool { $audioFile = $form->get('audio')->getData(); if ($audioFile) { $originalFilename = pathinfo($audioFile->getClientOriginalName(), PATHINFO_FILENAME); - $safeFilename = $slugger->slug($originalFilename); - $newFilename = $safeFilename . '-' . uniqid() . '.' . $audioFile->guessExtension(); + $safeFilename = $this->slugger->slug($originalFilename); + $newFilename = $safeFilename.'-'.uniqid().'.'.$audioFile->guessExtension(); try { $audioFile->move($this->getParameter('audio_directory'), $newFilename); - } catch (FileException $e) { + } catch (FileException $exc) { + $this->logger->error( + 'Failed to move audio file to audio directory: {msg}', + ['msg' => $exc->getMessage()] + ); + return false; } diff --git a/src/Controller/PodcastController.php b/src/Controller/PodcastController.php index da401b6..bc92ab6 100644 --- a/src/Controller/PodcastController.php +++ b/src/Controller/PodcastController.php @@ -7,6 +7,7 @@ use App\Form\PodcastType; use App\Repository\EpisodeRepository; use App\Repository\PodcastRepository; use Doctrine\ORM\EntityManagerInterface; +use Psr\Log\LoggerInterface; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\Form\FormError; use Symfony\Component\Form\FormInterface; @@ -19,28 +20,35 @@ use Symfony\Component\String\Slugger\SluggerInterface; #[Route('/manage/podcasts')] class PodcastController extends AbstractController { + public function __construct( + protected PodcastRepository $podcastRepo, + protected EntityManagerInterface $em, + protected LoggerInterface $logger, + protected SluggerInterface $slugger + ) { + } + #[Route('/', name: 'app_podcast_index', methods: ['GET'])] - public function index(PodcastRepository $podcastRepository): Response + public function index(): Response { + $user = $this->getUser(); + return $this->render('podcast/index.html.twig', [ - 'podcasts' => $podcastRepository->findOwnedBy($this->getUser()) + 'podcasts' => $user ? $this->podcastRepo->findOwnedBy($user) : [], ]); } #[Route('/new', name: 'app_podcast_new', methods: ['GET', 'POST'])] - public function new( - Request $request, - EntityManagerInterface $entityManager, - SluggerInterface $slugger, - ): Response + public function new(Request $request): Response { $podcast = new Podcast(); $form = $this->createForm(PodcastType::class, $podcast); $form->handleRequest($request); if ($form->isSubmitted() && $form->isValid()) { - if (!$this->handleLogoChange($form, $podcast, $slugger)) { + if (!$this->handleLogoChange($form, $podcast)) { $form->get('logo')->addError(new FormError('Could not upload logo.')); + return $this->render('podcast/new.html.twig', [ 'podcast' => $podcast, 'form' => $form, @@ -52,8 +60,9 @@ class PodcastController extends AbstractController } $podcast->setOwner($owner); - $entityManager->persist($podcast); - $entityManager->flush(); + $this->em->persist($podcast); + $this->em->flush(); + return $this->redirectToRoute('app_podcast_index', [], Response::HTTP_SEE_OTHER); } @@ -72,21 +81,19 @@ class PodcastController extends AbstractController } #[Route('/{id}/edit', name: 'app_podcast_edit', methods: ['GET', 'POST'])] - public function edit( - Request $request, - Podcast $podcast, - EntityManagerInterface $entityManager, - SluggerInterface $slugger, - ): Response + public function edit(Podcast $podcast, Request $request): Response { $form = $this->createForm(PodcastType::class, $podcast); $form->handleRequest($request); if ($form->isSubmitted() && $form->isValid()) { - if (!$this->handleLogoChange($form, $podcast, $slugger)) { + $data = $form->getData(); + $this->logger->notice(json_encode($data)); + if (!$this->handleLogoChange($form, $podcast)) { $form->get('logo')->addError(new FormError('Could not upload logo.')); } else { - $entityManager->flush(); + $this->em->flush(); + return $this->redirectToRoute('app_podcast_index', [], Response::HTTP_SEE_OTHER); } } @@ -98,31 +105,23 @@ class PodcastController extends AbstractController } #[Route('/{id}', name: 'app_podcast_delete', methods: ['POST'])] - public function delete( - Request $request, - Podcast $podcast, - EntityManagerInterface $entityManager - ): Response + public function delete(Podcast $podcast, Request $request): Response { if ($this->isCsrfTokenValid('delete'.$podcast->getId(), $request->request->get('_token'))) { - $entityManager->remove($podcast); - $entityManager->flush(); + $this->em->remove($podcast); + $this->em->flush(); } return $this->redirectToRoute('app_podcast_index', [], Response::HTTP_SEE_OTHER); } - protected function handleLogoChange( - FormInterface $form, - Podcast $podcast, - SluggerInterface $slugger - ): bool + protected function handleLogoChange(FormInterface $form, Podcast $podcast): bool { $logoFile = $form->get('logo')->getData(); if ($logoFile) { $originalFilename = pathinfo($logoFile->getClientOriginalName(), PATHINFO_FILENAME); - $safeFilename = $slugger->slug($originalFilename); - $newFilename = $safeFilename . '-' . uniqid() . '.' . $logoFile->guessExtension(); + $safeFilename = $this->slugger->slug($originalFilename); + $newFilename = $safeFilename.'-'.uniqid().'.'.$logoFile->guessExtension(); try { $logoFile->move($this->getParameter('images_directory'), $newFilename); @@ -137,10 +136,7 @@ class PodcastController extends AbstractController } #[Route('/{id}/episodes', name: 'app_podcast_episodes_index', methods: ['GET'])] - public function episodes_index( - Podcast $podcast, - EpisodeRepository $episodeRepository - ): Response + public function episodes_index(Podcast $podcast, EpisodeRepository $episodeRepository): Response { return $this->render('episode/index.html.twig', [ 'podcast' => $podcast, diff --git a/src/Form/EpisodeType.php b/src/Form/EpisodeType.php index bdd23ed..725f375 100644 --- a/src/Form/EpisodeType.php +++ b/src/Form/EpisodeType.php @@ -9,6 +9,7 @@ use Doctrine\ORM\QueryBuilder; use Symfony\Bridge\Doctrine\Form\Type\EntityType; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\Type\FileType; +use Symfony\Component\Form\Extension\Core\Type\SubmitType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\Validator\Constraints\File; @@ -28,7 +29,7 @@ class EpisodeType extends AbstractType 'mapped' => false, 'required' => false, 'constraints' => new File([ - 'maxSize' => '4m', + 'maxSize' => '512m', 'mimeTypes' => ['audio/mpeg', 'audio/ogg', 'audio/opus', 'audio/aac', 'audio/flac', 'audio/webm'], 'mimeTypesMessage' => 'Please select an audio file (MP3, OGG audio, Opus, AAC, FLAC, WebM audio).', ]), @@ -54,8 +55,12 @@ class EpisodeType extends AbstractType }, 'placeholder' => false, 'disabled' => $podcastId !== null, - 'empty_data' => "$podcastId", + 'empty_data' => strval($podcastId), ]) + ->add('submit', SubmitType::class, [ + 'label' => 'Save', + 'attr' => ['class' => 'btn btn-primary'] + ]); ; } diff --git a/src/Repository/PodcastRepository.php b/src/Repository/PodcastRepository.php index 3a5bbfc..b6b56fe 100644 --- a/src/Repository/PodcastRepository.php +++ b/src/Repository/PodcastRepository.php @@ -3,7 +3,7 @@ namespace App\Repository; use App\Entity\Podcast; -use App\Entity\User; +use Symfony\Component\Security\Core\User\UserInterface; use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; use Doctrine\Persistence\ManagerRegistry; @@ -40,7 +40,8 @@ class PodcastRepository extends ServiceEntityRepository } } - public function findOwnedBy(User $user): array + /** @return Podcast[] */ + public function findOwnedBy(UserInterface $user): array { return $this->findBy(['owner' => $user], ['id' => 'ASC']); } diff --git a/templates/episode/_form.html.twig b/templates/episode/_form.html.twig index bf20b98..0c1a4ce 100644 --- a/templates/episode/_form.html.twig +++ b/templates/episode/_form.html.twig @@ -1,4 +1 @@ -{{ form_start(form) }} - {{ form_widget(form) }} - -{{ form_end(form) }} +{{ form(form) }} diff --git a/templates/episode/show.html.twig b/templates/episode/show.html.twig index e828bed..a6f23c7 100644 --- a/templates/episode/show.html.twig +++ b/templates/episode/show.html.twig @@ -32,7 +32,7 @@