complete homemade, terrible, CRUD for entities
This commit is contained in:
parent
d5609f63d3
commit
be579da23c
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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']
|
||||
]);
|
||||
;
|
||||
}
|
||||
|
||||
|
|
|
@ -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']);
|
||||
}
|
||||
|
|
|
@ -1,4 +1 @@
|
|||
{{ form_start(form) }}
|
||||
{{ form_widget(form) }}
|
||||
<button class="btn">{{ button_label|default('Save') }}</button>
|
||||
{{ form_end(form) }}
|
||||
{{ form(form) }}
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
</tr>
|
||||
<tr>
|
||||
<th>Audio</th>
|
||||
<td><mark>TODO</mark></td>
|
||||
<td><audio controls src="{{ files_path }}{{ episode.audioFilename }}"></audio></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Publication date</th>
|
||||
|
|
Loading…
Reference in a new issue