<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace App\Controller\Admin;
use App\Entity\Post;
use App\Form\PostType;
use App\Repository\PostRepository;
use App\Security\PostVoter;
use Doctrine\ORM\EntityManagerInterface;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\IsGranted;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
/**
* Controller used to manage blog contents in the backend.
*
* Please note that the application backend is developed manually for learning
* purposes. However, in your real Symfony application you should use any of the
* existing bundles that let you generate ready-to-use backends without effort.
* See https://symfony.com/bundles
*
* @author Ryan Weaver <weaverryan@gmail.com>
* @author Javier Eguiluz <javier.eguiluz@gmail.com>
*/
#[Route('/admin/post'), IsGranted('ROLE_ADMIN')]
class BlogController extends AbstractController
{
/**
* Lists all Post entities.
*
* This controller responds to two different routes with the same URL:
* * 'admin_post_index' is the route with a name that follows the same
* structure as the rest of the controllers of this class.
* * 'admin_index' is a nice shortcut to the backend homepage. This allows
* to create simpler links in the templates. Moreover, in the future we
* could move this annotation to any other controller while maintaining
* the route name and therefore, without breaking any existing link.
*/
#[
Route('/', methods: ['GET'], name: 'admin_index'),
Route('/', methods: ['GET'], name: 'admin_post_index'),
]
public function index(PostRepository $posts): Response
{
$authorPosts = $posts->findBy(['author' => $this->getUser()], ['publishedAt' => 'DESC']);
return $this->render('admin/blog/index.html.twig', ['posts' => $authorPosts]);
}
/**
* Creates a new Post entity.
*
* NOTE: the Method annotation is optional, but it's a recommended practice
* to constraint the HTTP methods each controller responds to (by default
* it responds to all methods).
*/
#[Route('/new', methods: ['GET', 'POST'], name: 'admin_post_new')]
public function new(Request $request, EntityManagerInterface $entityManager): Response
{
$post = new Post();
$post->setAuthor($this->getUser());
// See https://symfony.com/doc/current/form/multiple_buttons.html
$form = $this->createForm(PostType::class, $post)
->add('saveAndCreateNew', SubmitType::class);
$form->handleRequest($request);
// the isSubmitted() method is completely optional because the other
// isValid() method already checks whether the form is submitted.
// However, we explicitly add it to improve code readability.
// See https://symfony.com/doc/current/forms.html#processing-forms
if ($form->isSubmitted() && $form->isValid()) {
$entityManager->persist($post);
$entityManager->flush();
// Flash messages are used to notify the user about the result of the
// actions. They are deleted automatically from the session as soon
// as they are accessed.
// See https://symfony.com/doc/current/controller.html#flash-messages
$this->addFlash('success', 'post.created_successfully');
if ($form->get('saveAndCreateNew')->isClicked()) {
return $this->redirectToRoute('admin_post_new');
}
return $this->redirectToRoute('admin_post_index');
}
return $this->render('admin/blog/new.html.twig', [
'post' => $post,
'form' => $form->createView(),
]);
}
/**
* Finds and displays a Post entity.
*/
#[Route('/{id<\d+>}', methods: ['GET'], name: 'admin_post_show')]
public function show(Post $post): Response
{
// This security check can also be performed
// using a PHP attribute: #[IsGranted('show', subject: 'post', message: 'Posts can only be shown to their authors.')]
$this->denyAccessUnlessGranted(PostVoter::SHOW, $post, 'Posts can only be shown to their authors.');
return $this->render('admin/blog/show.html.twig', [
'post' => $post,
]);
}
/**
* Displays a form to edit an existing Post entity.
*/
#[Route('/{id<\d+>}/edit', methods: ['GET', 'POST'], name: 'admin_post_edit')]
#[IsGranted('edit', subject: 'post', message: 'Posts can only be edited by their authors.')]
public function edit(Request $request, Post $post, EntityManagerInterface $entityManager): Response
{
$form = $this->createForm(PostType::class, $post);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$entityManager->flush();
$this->addFlash('success', 'post.updated_successfully');
return $this->redirectToRoute('admin_post_edit', ['id' => $post->getId()]);
}
return $this->render('admin/blog/edit.html.twig', [
'post' => $post,
'form' => $form->createView(),
]);
}
/**
* Deletes a Post entity.
*/
#[Route('/{id}/delete', methods: ['POST'], name: 'admin_post_delete')]
#[IsGranted('delete', subject: 'post')]
public function delete(Request $request, Post $post, EntityManagerInterface $entityManager): Response
{
if (!$this->isCsrfTokenValid('delete', $request->request->get('token'))) {
return $this->redirectToRoute('admin_post_index');
}
// Delete the tags associated with this blog post. This is done automatically
// by Doctrine, except for SQLite (the database used in this application)
// because foreign key support is not enabled by default in SQLite
$post->getTags()->clear();
$entityManager->remove($post);
$entityManager->flush();
$this->addFlash('success', 'post.deleted_successfully');
return $this->redirectToRoute('admin_post_index');
}
}