Posts administration
This commit is contained in:
parent
1a03203d01
commit
513d5ff4d4
8 changed files with 188 additions and 13 deletions
|
@ -19,8 +19,8 @@ class HomeController extends AbstractController
|
||||||
$repo = $this->getDoctrine()->getRepository(Post::class);
|
$repo = $this->getDoctrine()->getRepository(Post::class);
|
||||||
return $this->render('home/index.html.twig', [
|
return $this->render('home/index.html.twig', [
|
||||||
'controller_name' => 'HomeController',
|
'controller_name' => 'HomeController',
|
||||||
'posts' => $repo->findBy(array(), array('publishedAt' => 'DESC'), 5, $page*5),
|
'posts' => $repo->getPublished($page*5, 5),
|
||||||
'pages' => round($repo->count(array())/5, 0, PHP_ROUND_HALF_UP),
|
'pages' => round(count($repo->getPublished())/5, 0, PHP_ROUND_HALF_UP),
|
||||||
'page' => $page
|
'page' => $page
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,14 +2,17 @@
|
||||||
|
|
||||||
namespace App\Controller;
|
namespace App\Controller;
|
||||||
|
|
||||||
|
use App\Entity\Category;
|
||||||
use App\Entity\Comment;
|
use App\Entity\Comment;
|
||||||
use App\Entity\Post;
|
use App\Entity\Post;
|
||||||
use App\Form\CommentType;
|
use App\Form\CommentType;
|
||||||
|
use App\Form\PostType;
|
||||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
use Symfony\Component\Form\FormInterface;
|
use Symfony\Component\Form\FormInterface;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
use Symfony\Component\Routing\Annotation\Route;
|
use Symfony\Component\Routing\Annotation\Route;
|
||||||
|
use Symfony\Component\String\Slugger\AsciiSlugger;
|
||||||
|
|
||||||
class PostController extends AbstractController
|
class PostController extends AbstractController
|
||||||
{
|
{
|
||||||
|
@ -22,7 +25,7 @@ class PostController extends AbstractController
|
||||||
public function index(Request $request, string $slug): Response
|
public function index(Request $request, string $slug): Response
|
||||||
{
|
{
|
||||||
$post = $this->getDoctrine()->getRepository(Post::class)->findOneBy(array('slug' => $slug));
|
$post = $this->getDoctrine()->getRepository(Post::class)->findOneBy(array('slug' => $slug));
|
||||||
$form = $this->formGenerator($post);
|
$form = $this->commentFormGenerator($post);
|
||||||
$form->handleRequest($request);
|
$form->handleRequest($request);
|
||||||
if ($form->isSubmitted() && $form->isValid()) {
|
if ($form->isSubmitted() && $form->isValid()) {
|
||||||
$comment = $form->getData();
|
$comment = $form->getData();
|
||||||
|
@ -31,7 +34,7 @@ class PostController extends AbstractController
|
||||||
$manager = $this->getDoctrine()->getManager();
|
$manager = $this->getDoctrine()->getManager();
|
||||||
$manager->persist($comment);
|
$manager->persist($comment);
|
||||||
$manager->flush();
|
$manager->flush();
|
||||||
$form = $this->formGenerator($post);
|
$form = $this->commentFormGenerator($post);
|
||||||
}
|
}
|
||||||
return $this->render('post/index.html.twig', [
|
return $this->render('post/index.html.twig', [
|
||||||
'controller_name' => 'PostController',
|
'controller_name' => 'PostController',
|
||||||
|
@ -47,11 +50,82 @@ class PostController extends AbstractController
|
||||||
{
|
{
|
||||||
return $this->render('post/posts.html.twig', [
|
return $this->render('post/posts.html.twig', [
|
||||||
'controller_name' => 'PostController',
|
'controller_name' => 'PostController',
|
||||||
'posts' => $this->getDoctrine()->getRepository(Post::class)->findAll()
|
'posts' => $this->getDoctrine()->getRepository(Post::class)->findBy(array(), array('publishedAt' => 'DESC'))
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function formGenerator(Post $post) : FormInterface
|
/**
|
||||||
|
* @Route("/admin/posts/add", name="post-add")
|
||||||
|
* @param Request $request
|
||||||
|
* @return Response
|
||||||
|
*/
|
||||||
|
public function add(Request $request): Response
|
||||||
|
{
|
||||||
|
$post = new Post();
|
||||||
|
$form = $this->createForm(PostType::class, $post);
|
||||||
|
$form->handleRequest($request);
|
||||||
|
if ($form->isSubmitted() && $form->isValid()) {
|
||||||
|
$post = $form->getData();
|
||||||
|
$post->setSlug((new AsciiSlugger())->slug($post->getTitle()));
|
||||||
|
$manager = $this->getDoctrine()->getManager();
|
||||||
|
$manager->persist($post);
|
||||||
|
$manager->flush();
|
||||||
|
return $this->redirectToRoute('posts');
|
||||||
|
}
|
||||||
|
return $this->render('post/posts-form.html.twig', [
|
||||||
|
'controller_name' => 'PostController',
|
||||||
|
'form' => $form->createView(),
|
||||||
|
'title' => 'Add new post'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Route("/admin/posts/edit/{slug}", name="post-edit")
|
||||||
|
* @param Request $request
|
||||||
|
* @param string $slug
|
||||||
|
* @return Response
|
||||||
|
*/
|
||||||
|
public function edit(Request $request, string $slug): Response
|
||||||
|
{
|
||||||
|
$manager = $this->getDoctrine()->getManager();
|
||||||
|
$post = $manager->getRepository(Post::class)->findOneBy(array('slug' => $slug));
|
||||||
|
if (!$post) {
|
||||||
|
throw $this->createNotFoundException("Post not found");
|
||||||
|
}
|
||||||
|
$form = $this->createForm(PostType::class, $post);
|
||||||
|
$form->handleRequest($request);
|
||||||
|
if ($form->isSubmitted() && $form->isValid()) {
|
||||||
|
$post = $form->getData();
|
||||||
|
$post->setUpdatedAt(new \DateTime());
|
||||||
|
$post->setSlug((new AsciiSlugger())->slug($post->getTitle()));
|
||||||
|
$manager->flush();
|
||||||
|
return $this->redirectToRoute('posts');
|
||||||
|
}
|
||||||
|
return $this->render('post/posts-form.html.twig', [
|
||||||
|
'controller_name' => 'PostController',
|
||||||
|
'form' => $form->createView(),
|
||||||
|
'title' => 'Edit '.$post->getTitle()
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Route("/admin/posts/remove/{slug}", name="post-remove")
|
||||||
|
* @param string $slug
|
||||||
|
* @return Response
|
||||||
|
*/
|
||||||
|
public function remove(string $slug): Response
|
||||||
|
{
|
||||||
|
$manager = $this->getDoctrine()->getManager();
|
||||||
|
$post = $manager->getRepository(Post::class)->findOneBy(array('slug' => $slug));
|
||||||
|
if (!$post) {
|
||||||
|
throw $this->createNotFoundException("Post not found");
|
||||||
|
}
|
||||||
|
$manager->remove($post);
|
||||||
|
$manager->flush();
|
||||||
|
return $this->redirectToRoute('posts');
|
||||||
|
}
|
||||||
|
|
||||||
|
private function commentFormGenerator(Post $post) : FormInterface
|
||||||
{
|
{
|
||||||
$comment = new Comment();
|
$comment = new Comment();
|
||||||
$comment->setPost($post);
|
$comment->setPost($post);
|
||||||
|
|
|
@ -68,6 +68,10 @@ class Post
|
||||||
{
|
{
|
||||||
$this->comments = new ArrayCollection();
|
$this->comments = new ArrayCollection();
|
||||||
$this->categories = new ArrayCollection();
|
$this->categories = new ArrayCollection();
|
||||||
|
$date = new \DateTime();
|
||||||
|
$this->createdAt = $date;
|
||||||
|
$this->publishedAt = $date;
|
||||||
|
$this->updatedAt = $date;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getId(): ?int
|
public function getId(): ?int
|
||||||
|
|
36
src/Form/PostType.php
Normal file
36
src/Form/PostType.php
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Form;
|
||||||
|
|
||||||
|
use App\Entity\Category;
|
||||||
|
use App\Entity\Post;
|
||||||
|
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
|
||||||
|
use Symfony\Component\Form\AbstractType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\DateTimeType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||||
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
|
||||||
|
class PostType extends AbstractType
|
||||||
|
{
|
||||||
|
public function buildForm(FormBuilderInterface $builder, array $options): void
|
||||||
|
{
|
||||||
|
$builder
|
||||||
|
->add('title', TextType::class, ['attr' => ['class' => 'form-control']])
|
||||||
|
->add('description', TextType::class, ['attr' => ['class' => 'form-control']])
|
||||||
|
->add('content', TextareaType::class, ['attr' => ['class' => 'form-control']])
|
||||||
|
->add('publishedAt', DateTimeType::class, ['attr' => ['class' => 'form-control']])
|
||||||
|
->add('categories', EntityType::class, ['attr' => ['class' => 'form-control'], 'class' => Category::class, 'choice_label' => 'name', 'multiple' => true, 'expanded' => true, 'by_reference' => false])
|
||||||
|
->add('save', SubmitType::class, ['attr' => ['class' => 'btn btn-primary btn-block']])
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function configureOptions(OptionsResolver $resolver)
|
||||||
|
{
|
||||||
|
$resolver->setDefaults([
|
||||||
|
'data_class' => Post::class
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
|
@ -19,6 +19,21 @@ class PostRepository extends ServiceEntityRepository
|
||||||
parent::__construct($registry, Post::class);
|
parent::__construct($registry, Post::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getPublished(int $offset = null, int $max = null) {
|
||||||
|
$q = $this->createQueryBuilder("p")
|
||||||
|
->andWhere('p.publishedAt <= :now')
|
||||||
|
->setParameter('now', new \DateTime())
|
||||||
|
->orderBy('p.publishedAt', 'DESC');
|
||||||
|
if ($offset) {
|
||||||
|
$q->setFirstResult($offset);
|
||||||
|
}
|
||||||
|
if ($max) {
|
||||||
|
$q->setMaxResults($max);
|
||||||
|
}
|
||||||
|
return $q->getQuery()
|
||||||
|
->getResult();
|
||||||
|
}
|
||||||
|
|
||||||
// /**
|
// /**
|
||||||
// * @return Post[] Returns an array of Post objects
|
// * @return Post[] Returns an array of Post objects
|
||||||
// */
|
// */
|
||||||
|
|
|
@ -1,7 +0,0 @@
|
||||||
{% extends 'admin/base-admin.html.twig' %}
|
|
||||||
|
|
||||||
{% block title %}Hello AdminController!{% endblock %}
|
|
||||||
|
|
||||||
{% block body %}
|
|
||||||
|
|
||||||
{% endblock %}
|
|
34
templates/post/posts-form.html.twig
Normal file
34
templates/post/posts-form.html.twig
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
{% extends 'admin/base-admin.html.twig' %}
|
||||||
|
{% block title %}{{ title }}{% endblock %}
|
||||||
|
|
||||||
|
{% block body %}
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h1>{{ title }}</h1>
|
||||||
|
{{ form_start(form) }}
|
||||||
|
{{ form_errors(form) }}
|
||||||
|
<div class="form-outline">
|
||||||
|
{{ form_widget(form.title) }}
|
||||||
|
{{ form_label(form.title, null, {'label_attr': {'class': 'form-label'}}) }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-outline">
|
||||||
|
{{ form_widget(form.description) }}
|
||||||
|
{{ form_label(form.description, null, {'label_attr': {'class': 'form-label'}}) }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-outline">
|
||||||
|
{{ form_widget(form.content) }}
|
||||||
|
{{ form_label(form.content, null, {'label_attr': {'class': 'form-label'}}) }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-outline">
|
||||||
|
{{ form_label(form.publishedAt) }}
|
||||||
|
{{ form_widget(form.publishedAt) }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{ form_row(form.categories) }}
|
||||||
|
|
||||||
|
{{ form_row(form.save) }}
|
||||||
|
{{ form_end(form) }}
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
19
templates/post/posts.html.twig
Normal file
19
templates/post/posts.html.twig
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
{% extends 'admin/base-admin.html.twig' %}
|
||||||
|
|
||||||
|
{% block title %}Administration - Posts{% endblock %}
|
||||||
|
|
||||||
|
{% block body %}
|
||||||
|
<div class="container-fluid">
|
||||||
|
{% for post in posts %}
|
||||||
|
<div class="card text-center">
|
||||||
|
<div class="card-body">
|
||||||
|
<h5 class="card-title">{{ post.title }}</h5>
|
||||||
|
<p class="card-text">{{ post.description }}</p>
|
||||||
|
<a href="{{ path('post-remove', {slug: post.slug}) }}" class="btn btn-danger">Delete</a>
|
||||||
|
<a href="{{ path('post-edit', {slug: post.slug}) }}" class="btn btn-primary">Edit</a>
|
||||||
|
</div>
|
||||||
|
<div class="card-footer text-muted">{{ post.publishedAt.format('Y-m-d H:i:s') }}</div>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
Reference in a new issue