WIP: feature_paste #1

Draft
Miroslavsckaya wants to merge 24 commits from feature_paste into master
3 changed files with 163 additions and 155 deletions
Showing only changes of commit 1d08cfdc09 - Show all commits

View file

@ -3,8 +3,9 @@ declare(strict_types = 1);
namespace App\Controller; namespace App\Controller;
use App\Form\Type\PasteForm; use App\DTO\PasteFormData;
use App\Entity\Paste; use App\Entity\Paste;
use App\Form\Type\PasteForm;
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;
@ -17,19 +18,29 @@ class PasteController extends AbstractController
#[Route('/')] #[Route('/')]
public function new(Request $request, PasteRepository $pasteRepository): Response public function new(Request $request, PasteRepository $pasteRepository): Response
{ {
$paste = new Paste(); $pasteData = new PasteFormData();
$form = $this->createForm(PasteForm::class, $paste); $form = $this->createForm(PasteForm::class, $pasteData);
$form->handleRequest($request); $form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) { if ($form->isSubmitted() && $form->isValid()) {
$paste = $form->getData(); $pasteData = $form->getData();
$paste->setIp($request->getClientIp());
$paste->setPublishDate(new \DateTime());
if ($paste->isPrivate()) { $secret = null;
$paste->setSecret(hash('sha1', random_bytes(25))); if ($pasteData->isPrivate()) {
$secret = hash('sha1', random_bytes(25));
} }
$paste = new Paste(
$pasteData->getText(),
$pasteData->getLanguage(),
$pasteData->getDescription(),
$pasteData->getFilename(),
$pasteData->getAuthor(),
new \DateTimeImmutable(),
$pasteData->getExpirationDate(),
Review

show_paste at least.

`show_paste` at least.
$request->getClientIp(),
$secret
);
$pasteRepository->save($paste); $pasteRepository->save($paste);
return $this->redirectToRoute($request->attributes->get('_route')); return $this->redirectToRoute($request->attributes->get('_route'));

122
src/DTO/PasteFormData.php Normal file
View file

@ -0,0 +1,122 @@
<?php
declare(strict_types = 1);
namespace App\DTO;
use Symfony\Component\Validator\Constraints as Assert;
class PasteFormData
{
private int $id;
#[Assert\NotBlank]
private string $text;
#[Assert\Type(\boolean::class)]
private bool $private;
private ?string $language = null;
skobkin marked this conversation as resolved
Review

Why string and Assert\NotBlank?

Why `string` and `Assert\NotBlank`?
private ?string $description = null;
skobkin marked this conversation as resolved
Review

Is this validation being processed BEFORE storing the data in the DTO?
If not, it's pointless as with bool field earlier.

Is this validation being processed BEFORE storing the data in the DTO? If not, it's pointless as with `bool` field earlier.
private ?string $filename = null;
skobkin marked this conversation as resolved
Review

Or you can make constructor private, use property promotion and add fromPaste() method to create it from the entity.

Or you can make constructor `private`, use property promotion and add `fromPaste()` method to create it from the entity.
#[Assert\NotBlank]
private string $author = 'anonymous';
#[Assert\Type(\DateTimeImmutable::class)]
private ?\DateTimeImmutable $expirationDate;
private ?string $secret;
public function getId(): int
{
return $this->id;
}
public function setId(int $id): void
{
$this->id = $id;
}
public function getText(): string
{
return $this->text;
}
public function setText(string $text): void
{
$this->text = $text;
}
public function getLanguage(): ?string
{
return $this->language;
}
public function setLanguage(?string $language): void
{
$this->language = $language;
}
public function getDescription(): ?string
{
return $this->description;
}
public function setDescription(?string $description): void
{
$this->description = $description;
}
public function getFilename(): ?string
{
return $this->filename;
}
public function setFilename(?string $filename): void
{
$this->filename = $filename;
}
public function getAuthor(): string
{
return $this->author;
}
public function setAuthor(string $author): void
{
$this->author = $author;
}
public function getExpirationDate(): ?\DateTime
{
return $this->expirationDate;
}
public function setExpirationDate(?\DateTime $date): void
{
$this->expirationDate = $date;
}
public function getSecret(): ?string
{
return $this->secret;
}
public function setSecret(?string $secret): void
{
$this->secret = $secret;
}
public function isPrivate(): bool
{
return $this->private;
}
public function setPrivate(bool $private): void
{
$this->private = $private;
}
}

View file

@ -6,158 +6,33 @@ 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;
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
{ {
#[ORM\Id] #[ORM\Id]
#[ORM\GeneratedValue] #[ORM\GeneratedValue]
#[ORM\Column(nullable: false)] #[ORM\Column]
Review

Why not also constructor promotion though?

Why not also constructor promotion though?
private int $id; public readonly int $id;
public function __construct(
#[ORM\Column(type: 'text', nullable: false)] #[ORM\Column(type: 'text', nullable: false)]
#[Assert\NotBlank] public readonly string $text,
private string $text;
#[ORM\Column(type: 'boolean', nullable: false)]
#[Assert\Type(\boolean::class)]
private bool $private;
#[ORM\Column(length: 25, nullable: true)] #[ORM\Column(length: 25, nullable: true)]
private ?string $language; public readonly ?string $language,
#[ORM\Column(type: 'text', nullable: true)] #[ORM\Column(type: 'text', nullable: true)]
private ?string $description; public readonly ?string $description,
#[ORM\Column(length: 128, nullable: true)] #[ORM\Column(length: 128, nullable: true)]
Review

Why 128?

Why 128?
private ?string $filename; public readonly ?string $filename,
#[ORM\Column(length: 128, nullable: false)] #[ORM\Column(length: 128, nullable: false)]
#[Assert\NotBlank] public readonly string $author,
private string $author = 'anonymous'; #[ORM\Column(type: Types::DATETIME_IMMUTABLE, nullable: false)]
public readonly \DateTimeImmutable $publishDate,
#[ORM\Column(type: Types::DATETIME_MUTABLE, nullable: false)] #[ORM\Column(type: Types::DATETIME_IMMUTABLE, nullable: true)]
#[Assert\Type(\DateTime::class)] public readonly ?\DateTimeImmutable $expirationDate,
private \DateTime $publishDate;
#[ORM\Column(type: Types::DATETIME_MUTABLE, nullable: true)]
#[Assert\Type(\DateTime::class)]
private ?\DateTime $expirationDate;
#[ORM\Column(length: 15, nullable: false)] #[ORM\Column(length: 15, nullable: false)]
skobkin marked this conversation as resolved
Review

IPv6?

IPv6?
private string $ip; public readonly string $ip,
#[ORM\Column(length: 40, nullable: true)] #[ORM\Column(length: 40, nullable: true)]
private ?string $secret; public readonly ?string $secret,
) {}
public function getId(): int
{
return $this->id;
}
public function setId(int $id): void
{
$this->id = $id;
}
public function getText(): string
{
return $this->text;
}
public function setText(string $text): void
{
$this->text = $text;
}
public function getLanguage(): ?string
{
return $this->language;
}
public function setLanguage(?string $language): void
{
$this->language = $language;
}
public function getDescription(): ?string
{
return $this->description;
}
public function setDescription(?string $description): void
{
$this->description = $description;
}
public function getFilename(): ?string
{
return $this->filename;
}
public function setFilename(?string $filename): void
{
$this->filename = $filename;
}
public function getAuthor(): string
{
return $this->author;
}
public function setAuthor(string $author): void
{
$this->author = $author;
}
public function getPublishDate(): \DateTime
{
return $this->publishDate;
}
public function setPublishDate(\DateTime $date): void
{
$this->publishDate = $date;
}
public function getExpirationDate(): ?\DateTime
{
return $this->expirationDate;
}
public function setExpirationDate(?\DateTime $date): void
{
$this->expirationDate = $date;
}
public function getIp(): string
{
return $this->ip;
}
public function setIP(string $ip): void
{
$this->ip = $ip;
}
public function getSecret(): ?string
{
return $this->secret;
}
public function setSecret(?string $secret): void
{
$this->secret = $secret;
}
public function isPrivate(): bool
{
return $this->private;
}
public function setPrivate(bool $private): void
{
$this->private = $private;
}
} }
Review

You can use self as return type hint too.

You can use `self` as return type hint too.