WIP: feature_paste #1

Draft
Miroslavsckaya wants to merge 24 commits from feature_paste into master
4 changed files with 148 additions and 111 deletions
Showing only changes of commit ffcfa29968 - Show all commits

View file

@ -1,53 +1,53 @@
<?php <?php
skobkin marked this conversation as resolved
Review

I can't leave you a comment on src/Controller/.gitignore, so I'll ask here.

Why do you need it?

I can't leave you a comment on `src/Controller/.gitignore`, so I'll ask here. Why do you need it?
declare(strict_types = 1); declare(strict_types = 1);
namespace App\Controller; namespace App\Controller;
use App\Form\Type\PasteForm; use App\Form\Type\PasteForm;
use App\Entity\Paste; use App\Entity\Paste;
use App\Repository\PasteRepository; use App\Repository\PasteRepository;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Routing\Annotation\Route; use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
class PasteController extends AbstractController class PasteController extends AbstractController
{ {
#[Route('/')] #[Route('/')]
Review

I'd suggest explicitly defining which request methods we're processing here.

P.S. We'll move this to YAML in the end.

I'd suggest explicitly defining which request methods we're processing here. P.S. We'll move this to YAML in the end.
public function new(Request $request, PasteRepository $pasteRepository): Response { public function new(Request $request, PasteRepository $pasteRepository): Response
$paste = new Paste(); {
$form = $this->createForm(PasteForm::class, $paste); $paste = new Paste();
$form = $this->createForm(PasteForm::class, $paste);
$form->handleRequest($request); $form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) { if ($form->isSubmitted() && $form->isValid()) {
$paste = $form->getData(); $paste = $form->getData();
$paste->setIp($request->getClientIp()); $paste->setIp($request->getClientIp());
$paste->setPublishDate(new \DateTime()); $paste->setPublishDate(new \DateTime());
if ($paste->isPrivate()) { if ($paste->isPrivate()) {
$paste->setSecret(hash('sha1', random_bytes(25))); $paste->setSecret(hash('sha1', random_bytes(25)));
} }
$pasteRepository->save($paste); $pasteRepository->save($paste);
return $this->redirectToRoute($request->attributes->get('_route')); return $this->redirectToRoute($request->attributes->get('_route'));
} }
return $this->render('paste.html.twig', [ return $this->render('paste.html.twig', [
'form' => $form, 'form' => $form,
]); ]);
Review

show_paste at least.

`show_paste` at least.
} }
#[Route('/{id}/{secret}')] #[Route('/{id}/{secret}')]
public function show_paste(PasteRepository $pasteRepository, Request $request, string $id, ?string $secret=NULL): Response { public function showPaste(PasteRepository $pasteRepository, Request $request, string $id, ?string $secret=NULL): Response
{
$paste = $pasteRepository->findOneBy(['id' => $id, 'secret' => $secret]); $paste = $pasteRepository->findOneBy(['id' => $id, 'secret' => $secret]);
$form = $this->createForm(PasteForm::class, $paste); $form = $this->createForm(PasteForm::class, $paste);
return $this->render('paste.html.twig', [ return $this->render('paste.html.twig', [
Review

I'd suggest you implementing Twig extension wih filter and function to use highlighter in the template.

I'd suggest you implementing Twig extension wih filter and function to use highlighter in the template.
'form' => $form, 'form' => $form,
]); ]);
} }
} }

View file

@ -1,12 +1,12 @@
<?php <?php
declare(strict_types = 1); declare(strict_types = 1);
namespace App\Entity; namespace App\Entity;
use App\Repository\PasteRepository; use App\Repository\PasteRepository;
use Doctrine\DBAL\Types\Types; use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM; use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert; use Symfony\Component\Validator\Constraints as Assert;
Review

I'd suggest explicitly defining Table attribute here.

Especially since you're defining Column attributes below ⬇️

I'd suggest explicitly defining `Table` attribute here. Especially since you're defining `Column` attributes below ⬇️
Review

I'd also suggest to make this entity readonly. It'll give some performance benefits.

You can read about that here.

I'd also suggest to make this entity readonly. It'll give some performance benefits. You can read about that [here](https://www.doctrine-project.org/projects/doctrine-orm/en/2.15/reference/attributes-reference.html#attrref_entity).
#[ORM\Entity(repositoryClass: PasteRepository::class)] #[ORM\Entity(repositoryClass: PasteRepository::class)]
class Paste class Paste
@ -14,128 +14,150 @@ class Paste
#[ORM\Id] #[ORM\Id]
#[ORM\GeneratedValue] #[ORM\GeneratedValue]
Review

Why not also constructor promotion though?

Why not also constructor promotion though?
#[ORM\Column(nullable: false)] #[ORM\Column(nullable: false)]
private int $id; private int $id;
#[ORM\Column(type: 'text', nullable: false)] #[ORM\Column(type: 'text', nullable: false)]
#[Assert\NotBlank] #[Assert\NotBlank]
private string $text; private string $text;
#[ORM\Column(type: 'boolean', nullable: false)] #[ORM\Column(type: 'boolean', nullable: false)]
#[Assert\Type(\boolean::class)] #[Assert\Type(\boolean::class)]
private bool $private; private bool $private;
Review

Why 128?

Why 128?
#[ORM\Column(length: 25, nullable: true)] #[ORM\Column(length: 25, nullable: true)]
private ?string $language; private ?string $language;
#[ORM\Column(type: 'text', nullable: true)] #[ORM\Column(type: 'text', nullable: true)]
private ?string $description; private ?string $description;
#[ORM\Column(length: 128, nullable: true)] #[ORM\Column(length: 128, nullable: true)]
skobkin marked this conversation as resolved
Review

IPv6?

IPv6?
private ?string $filename; private ?string $filename;
#[ORM\Column(length: 128, nullable: false)] #[ORM\Column(length: 128, nullable: false)]
#[Assert\NotBlank] #[Assert\NotBlank]
private string $author = 'anonymous'; private string $author = 'anonymous';
Review

You can use self as return type hint too.

You can use `self` as return type hint too.
#[ORM\Column(type: Types::DATETIME_MUTABLE, nullable: false)] #[ORM\Column(type: Types::DATETIME_MUTABLE, nullable: false)]
#[Assert\Type(\DateTime::class)] #[Assert\Type(\DateTime::class)]
private \DateTime $publishDate; private \DateTime $publishDate;
#[ORM\Column(type: Types::DATETIME_MUTABLE, nullable: true)] #[ORM\Column(type: Types::DATETIME_MUTABLE, nullable: true)]
#[Assert\Type(\DateTime::class)] #[Assert\Type(\DateTime::class)]
private ?\DateTime $expirationDate; private ?\DateTime $expirationDate;
#[ORM\Column(length: 15, nullable: false)] #[ORM\Column(length: 15, nullable: false)]
private string $ip; private string $ip;
#[ORM\Column(length: 40, nullable: true)] #[ORM\Column(length: 40, nullable: true)]
private ?string $secret; private ?string $secret;
public function getId(): int { public function getId(): int
return $this->id; {
return $this->id;
} }
public function setId(int $id): void { public function setId(int $id): void
$this->id = $id; {
$this->id = $id;
} }
public function getText(): string { public function getText(): string
return $this->text; {
return $this->text;
} }
public function setText(string $text): void { public function setText(string $text): void
$this->text = $text; {
$this->text = $text;
} }
public function getLanguage(): ?string { public function getLanguage(): ?string
return $this->language; {
return $this->language;
} }
public function setLanguage(?string $language): void { public function setLanguage(?string $language): void
$this->language = $language; {
$this->language = $language;
} }
public function getDescription(): ?string { public function getDescription(): ?string
return $this->description; {
return $this->description;
} }
public function setDescription(?string $description): void { public function setDescription(?string $description): void
$this->description = $description; {
$this->description = $description;
} }
public function getFilename(): ?string { public function getFilename(): ?string
return $this->filename; {
return $this->filename;
} }
public function setFilename(?string $filename): void { public function setFilename(?string $filename): void
$this->filename = $filename; {
$this->filename = $filename;
} }
public function getAuthor(): string { public function getAuthor(): string
return $this->author; {
return $this->author;
} }
public function setAuthor(string $author): void { public function setAuthor(string $author): void
$this->author = $author; {
$this->author = $author;
} }
public function getPublishDate(): \DateTime { public function getPublishDate(): \DateTime
return $this->publishDate; {
return $this->publishDate;
} }
public function setPublishDate(\DateTime $date): void { public function setPublishDate(\DateTime $date): void
$this->publishDate = $date; {
$this->publishDate = $date;
} }
public function getExpirationDate(): ?\DateTime { public function getExpirationDate(): ?\DateTime
return $this->expirationDate; {
return $this->expirationDate;
} }
public function setExpirationDate(?\DateTime $date): void { public function setExpirationDate(?\DateTime $date): void
$this->expirationDate = $date; {
$this->expirationDate = $date;
} }
public function getIp(): string { public function getIp(): string
return $this->ip; {
return $this->ip;
} }
public function setIP(string $ip): void { public function setIP(string $ip): void
$this->ip = $ip; {
$this->ip = $ip;
} }
public function getSecret(): ?string { public function getSecret(): ?string
return $this->secret; {
return $this->secret;
} }
public function setSecret(?string $secret): void { public function setSecret(?string $secret): void
$this->secret = $secret; {
$this->secret = $secret;
} }
public function isPrivate(): bool { public function isPrivate(): bool
return $this->private; {
return $this->private;
} }
public function setPrivate(bool $private): void { public function setPrivate(bool $private): void
$this->private = $private; {
$this->private = $private;
} }
} }

View file

@ -1,30 +1,43 @@
<?php <?php
declare(strict_types = 1); declare(strict_types = 1);
namespace App\Form\Type; namespace App\Form\Type;
use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType; use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType; use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType; use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\Extension\Core\Type\DateTimeType; use Symfony\Component\Form\Extension\Core\Type\DateTimeType;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType; use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
class PasteForm extends AbstractType class PasteForm extends AbstractType
{ {
public function buildForm(FormBuilderInterface $builder, array $options): void { public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder $builder
->add('language', ChoiceType::class, ['choices' => ['Python' => 'python', 'PHP' => 'php', 'Plain text' => NULL]]) ->add('language', ChoiceType::class, [
'choices' => [
'Python' => 'python',
'PHP' => 'php',
'Plain text' => NULL,
]
]
)
->add('description', TextType::class, ['required' => false]) ->add('description', TextType::class, ['required' => false])
->add('text', TextareaType::class) ->add('text', TextareaType::class)
->add('author', TextType::class, ['attr' => ['maxlength' =>128]]) ->add('author', TextType::class, ['attr' => ['maxlength' =>128]])
->add('filename', TextType::class, ['required' => false, 'attr' => ['maxlength' =>128]]) ->add('filename', TextType::class, ['required' => false, 'attr' => ['maxlength' =>128]])
Review

Why 128?

Why 128?
->add('expirationDate', DateTimeType::class, ['required' => false, 'date_widget' => 'single_text', 'input' => 'datetime']) ->add('expirationDate', DateTimeType::class, [
'required' => false,
'date_widget' => 'single_text',
'input' => 'datetime',
]
)
->add('private', CheckboxType::class, ['required' => false]) ->add('private', CheckboxType::class, ['required' => false])
->add('save', SubmitType::class) ->add('save', SubmitType::class)
; ;
} }
} }

View file

@ -1,21 +1,23 @@
<?php <?php
skobkin marked this conversation as resolved
Review

Can't leave a comment for src/Repository/.gitignore, so I'll ask here.

Do you need it?

Can't leave a comment for `src/Repository/.gitignore`, so I'll ask here. Do you need it?
declare(strict_types = 1); declare(strict_types = 1);
namespace App\Repository; namespace App\Repository;
use App\Entity\Paste; use App\Entity\Paste;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry; use Doctrine\Persistence\ManagerRegistry;
class PasteRepository extends ServiceEntityRepository class PasteRepository extends ServiceEntityRepository
{ {
public function __construct(ManagerRegistry $registry) { public function __construct(ManagerRegistry $registry)
parent::__construct($registry, Paste::class); {
parent::__construct($registry, Paste::class);
} }
public function save(Paste $paste): void { public function save(Paste $paste): void
$entityManager = $this->getEntityManager(); {
$entityManager->persist($paste); $entityManager = $this->getEntityManager();
$entityManager->flush(); $entityManager->persist($paste);
$entityManager->flush();
} }
} }