WIP: feature_paste #1
10
.env
|
@ -18,3 +18,13 @@
|
||||||
APP_ENV=dev
|
APP_ENV=dev
|
||||||
APP_SECRET=90c78b17302e6ff2e14213f129e3f5f4
|
APP_SECRET=90c78b17302e6ff2e14213f129e3f5f4
|
||||||
skobkin marked this conversation as resolved
Outdated
|
|||||||
###< symfony/framework-bundle ###
|
###< symfony/framework-bundle ###
|
||||||
|
|
||||||
|
###> doctrine/doctrine-bundle ###
|
||||||
|
# Format described at https://www.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/configuration.html#connecting-using-a-url
|
||||||
|
# IMPORTANT: You MUST configure your server version, either here or in config/packages/doctrine.yaml
|
||||||
|
#
|
||||||
|
# DATABASE_URL="sqlite:///%kernel.project_dir%/var/data.db"
|
||||||
|
# DATABASE_URL="mysql://app:!ChangeMe!@127.0.0.1:3306/app?serverVersion=8.0.32&charset=utf8mb4"
|
||||||
|
# DATABASE_URL="mysql://app:!ChangeMe!@127.0.0.1:3306/app?serverVersion=10.11.2-MariaDB&charset=utf8mb4"
|
||||||
|
DATABASE_URL="postgresql://app:!ChangeMe!@127.0.0.1:5432/app?serverVersion=15&charset=utf8"
|
||||||
|
###< doctrine/doctrine-bundle ###
|
||||||
|
|
|
@ -7,15 +7,19 @@
|
||||||
"php": ">=8.1",
|
"php": ">=8.1",
|
||||||
"ext-ctype": "*",
|
"ext-ctype": "*",
|
||||||
"ext-iconv": "*",
|
"ext-iconv": "*",
|
||||||
|
"doctrine/doctrine-bundle": "^2.10",
|
||||||
|
"doctrine/doctrine-migrations-bundle": "^3.2",
|
||||||
|
"doctrine/orm": "^2.15",
|
||||||
"symfony/console": "6.3.*",
|
"symfony/console": "6.3.*",
|
||||||
skobkin
commented
Why so specific? Why so specific?
|
|||||||
"symfony/dotenv": "6.3.*",
|
"symfony/dotenv": "6.3.*",
|
||||||
"symfony/flex": "^2",
|
"symfony/flex": "^2",
|
||||||
|
"symfony/form": "6.3.*",
|
||||||
"symfony/framework-bundle": "6.3.*",
|
"symfony/framework-bundle": "6.3.*",
|
||||||
"symfony/runtime": "6.3.*",
|
"symfony/runtime": "6.3.*",
|
||||||
|
"symfony/twig-bundle": "6.3.*",
|
||||||
|
"symfony/validator": "6.3.*",
|
||||||
"symfony/yaml": "6.3.*"
|
"symfony/yaml": "6.3.*"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
|
||||||
},
|
|
||||||
"config": {
|
"config": {
|
||||||
"allow-plugins": {
|
"allow-plugins": {
|
||||||
"php-http/discovery": true,
|
"php-http/discovery": true,
|
||||||
|
@ -63,5 +67,8 @@
|
||||||
"allow-contrib": false,
|
"allow-contrib": false,
|
||||||
"require": "6.3.*"
|
"require": "6.3.*"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"symfony/maker-bundle": "^1.50"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
2550
composer.lock
generated
|
@ -2,4 +2,8 @@
|
||||||
|
|
||||||
return [
|
return [
|
||||||
Symfony\Bundle\FrameworkBundle\FrameworkBundle::class => ['all' => true],
|
Symfony\Bundle\FrameworkBundle\FrameworkBundle::class => ['all' => true],
|
||||||
|
Doctrine\Bundle\DoctrineBundle\DoctrineBundle::class => ['all' => true],
|
||||||
|
Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle::class => ['all' => true],
|
||||||
|
Symfony\Bundle\MakerBundle\MakerBundle::class => ['dev' => true],
|
||||||
|
Symfony\Bundle\TwigBundle\TwigBundle::class => ['all' => true],
|
||||||
];
|
];
|
||||||
|
|
46
config/packages/doctrine.yaml
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
doctrine:
|
||||||
|
dbal:
|
||||||
|
url: '%env(resolve:DATABASE_URL)%'
|
||||||
|
|
||||||
|
# IMPORTANT: You MUST configure your server version,
|
||||||
|
# either here or in the DATABASE_URL env var (see .env file)
|
||||||
|
#server_version: '15'
|
||||||
|
orm:
|
||||||
|
auto_generate_proxy_classes: true
|
||||||
|
enable_lazy_ghost_objects: true
|
||||||
|
report_fields_where_declared: true
|
||||||
|
validate_xml_mapping: true
|
||||||
|
naming_strategy: doctrine.orm.naming_strategy.underscore_number_aware
|
||||||
|
auto_mapping: true
|
||||||
|
mappings:
|
||||||
|
App:
|
||||||
|
is_bundle: false
|
||||||
|
dir: '%kernel.project_dir%/src/Entity'
|
||||||
|
prefix: 'App\Entity'
|
||||||
|
alias: App
|
||||||
|
|
||||||
|
when@test:
|
||||||
|
doctrine:
|
||||||
|
dbal:
|
||||||
|
# "TEST_TOKEN" is typically set by ParaTest
|
||||||
|
dbname_suffix: '_test%env(default::TEST_TOKEN)%'
|
||||||
|
|
||||||
|
when@prod:
|
||||||
|
doctrine:
|
||||||
|
orm:
|
||||||
|
auto_generate_proxy_classes: false
|
||||||
|
proxy_dir: '%kernel.build_dir%/doctrine/orm/Proxies'
|
||||||
|
query_cache_driver:
|
||||||
|
type: pool
|
||||||
|
pool: doctrine.system_cache_pool
|
||||||
|
result_cache_driver:
|
||||||
|
type: pool
|
||||||
|
pool: doctrine.result_cache_pool
|
||||||
|
|
||||||
|
framework:
|
||||||
|
cache:
|
||||||
|
pools:
|
||||||
|
doctrine.result_cache_pool:
|
||||||
|
adapter: cache.app
|
||||||
|
doctrine.system_cache_pool:
|
||||||
|
adapter: cache.system
|
6
config/packages/doctrine_migrations.yaml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
doctrine_migrations:
|
||||||
|
migrations_paths:
|
||||||
|
# namespace is arbitrary but should be different from App\Migrations
|
||||||
|
# as migrations classes should NOT be autoloaded
|
||||||
|
'DoctrineMigrations': '%kernel.project_dir%/migrations'
|
||||||
|
enable_profiler: false
|
6
config/packages/twig.yaml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
twig:
|
||||||
|
default_path: '%kernel.project_dir%/templates'
|
||||||
|
|
||||||
|
when@test:
|
||||||
|
twig:
|
||||||
|
strict_variables: true
|
13
config/packages/validator.yaml
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
framework:
|
||||||
|
validation:
|
||||||
|
email_validation_mode: html5
|
||||||
|
|
||||||
|
# Enables validator auto-mapping support.
|
||||||
|
# For instance, basic validation constraints will be inferred from Doctrine's metadata.
|
||||||
|
#auto_mapping:
|
||||||
|
# App\Entity\: []
|
||||||
|
|
||||||
|
when@test:
|
||||||
|
framework:
|
||||||
|
validation:
|
||||||
|
not_compromised_password: false
|
0
migrations/.gitignore
vendored
Normal file
34
migrations/Version20230720115905.php
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace DoctrineMigrations;
|
||||||
|
|
||||||
|
use Doctrine\DBAL\Schema\Schema;
|
||||||
|
use Doctrine\Migrations\AbstractMigration;
|
||||||
|
|
||||||
|
/**
|
||||||
skobkin marked this conversation as resolved
Outdated
skobkin
commented
Either describe what these migrations do or remove meaningless comments. Either describe what these migrations do or remove meaningless comments.
|
|||||||
|
* Auto-generated Migration: Please modify to your needs!
|
||||||
|
*/
|
||||||
|
final class Version20230720115905 extends AbstractMigration
|
||||||
skobkin marked this conversation as resolved
skobkin
commented
Do you need it here if it's empty? Do you need it here if it's empty?
|
|||||||
|
{
|
||||||
|
public function getDescription(): string
|
||||||
|
{
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function up(Schema $schema): void
|
||||||
|
{
|
||||||
skobkin
commented
This shouldn't be here. This shouldn't be here.
|
|||||||
|
// this up() migration is auto-generated, please modify it to your needs
|
||||||
|
$this->addSql('CREATE SEQUENCE paste_id_seq INCREMENT BY 1 MINVALUE 1 START 1');
|
||||||
|
$this->addSql('CREATE TABLE paste (id INT NOT NULL, text TEXT NOT NULL, private BOOLEAN NOT NULL, language VARCHAR(25) NOT NULL, description TEXT NOT NULL, filename VARCHAR(128) NOT NULL, author VARCHAR(128) NOT NULL, publish_date TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, expiration_date TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, ip VARCHAR(15) NOT NULL, secret VARCHAR(40) NOT NULL, PRIMARY KEY(id))');
|
||||||
|
}
|
||||||
|
|
||||||
skobkin
commented
This shouldn't be here. This shouldn't be here.
|
|||||||
|
public function down(Schema $schema): void
|
||||||
|
{
|
||||||
|
// this down() migration is auto-generated, please modify it to your needs
|
||||||
|
$this->addSql('CREATE SCHEMA public');
|
||||||
skobkin marked this conversation as resolved
Outdated
skobkin
commented
This should probably not be here. I'd say that it's most likely a but caused by you not setting the We can discuss PostgreSQL specifics later. This should probably not be here.
I'd say that it's most likely a but caused by you not setting the `schema` parameter for your `Table` attributes.
We can discuss PostgreSQL specifics later.
|
|||||||
|
$this->addSql('DROP SEQUENCE paste_id_seq CASCADE');
|
||||||
|
$this->addSql('DROP TABLE paste');
|
||||||
|
}
|
||||||
|
}
|
38
migrations/Version20230720125632.php
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace DoctrineMigrations;
|
||||||
|
|
||||||
|
use Doctrine\DBAL\Schema\Schema;
|
||||||
|
use Doctrine\Migrations\AbstractMigration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Auto-generated Migration: Please modify to your needs!
|
||||||
|
*/
|
||||||
|
final class Version20230720125632 extends AbstractMigration
|
||||||
skobkin marked this conversation as resolved
Outdated
skobkin
commented
Before merging this we should ideally have only one migration which does everything from scratch or from previous database version. There is no need to repeat entire development process on the production. Before merging this we should ideally have only one migration which does everything from scratch or from previous database version. There is no need to repeat entire development process on the production.
|
|||||||
|
{
|
||||||
|
public function getDescription(): string
|
||||||
|
{
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function up(Schema $schema): void
|
||||||
|
{
|
||||||
|
// this up() migration is auto-generated, please modify it to your needs
|
||||||
|
$this->addSql('ALTER TABLE paste ALTER language DROP NOT NULL');
|
||||||
|
$this->addSql('ALTER TABLE paste ALTER description DROP NOT NULL');
|
||||||
|
$this->addSql('ALTER TABLE paste ALTER filename DROP NOT NULL');
|
||||||
|
$this->addSql('ALTER TABLE paste ALTER expiration_date DROP NOT NULL');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(Schema $schema): void
|
||||||
|
{
|
||||||
|
// this down() migration is auto-generated, please modify it to your needs
|
||||||
|
$this->addSql('CREATE SCHEMA public');
|
||||||
skobkin marked this conversation as resolved
Outdated
skobkin
commented
same. same.
|
|||||||
|
$this->addSql('ALTER TABLE paste ALTER language SET NOT NULL');
|
||||||
|
$this->addSql('ALTER TABLE paste ALTER description SET NOT NULL');
|
||||||
|
$this->addSql('ALTER TABLE paste ALTER filename SET NOT NULL');
|
||||||
|
$this->addSql('ALTER TABLE paste ALTER expiration_date SET NOT NULL');
|
||||||
|
}
|
||||||
|
}
|
32
migrations/Version20230720130259.php
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace DoctrineMigrations;
|
||||||
|
|
||||||
|
use Doctrine\DBAL\Schema\Schema;
|
||||||
|
use Doctrine\Migrations\AbstractMigration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Auto-generated Migration: Please modify to your needs!
|
||||||
|
*/
|
||||||
|
final class Version20230720130259 extends AbstractMigration
|
||||||
|
{
|
||||||
|
public function getDescription(): string
|
||||||
|
{
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function up(Schema $schema): void
|
||||||
|
{
|
||||||
|
// this up() migration is auto-generated, please modify it to your needs
|
||||||
|
$this->addSql('ALTER TABLE paste ALTER secret DROP NOT NULL');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(Schema $schema): void
|
||||||
|
{
|
||||||
|
// this down() migration is auto-generated, please modify it to your needs
|
||||||
|
$this->addSql('CREATE SCHEMA public');
|
||||||
|
$this->addSql('ALTER TABLE paste ALTER secret SET NOT NULL');
|
||||||
|
}
|
||||||
|
}
|
54
src/Controller/PasteController.php
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
<?php
|
||||||
skobkin marked this conversation as resolved
skobkin
commented
I can't leave you a comment on 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?
|
|||||||
|
|
||||||
skobkin marked this conversation as resolved
Outdated
skobkin
commented
Please do not forget Please do not forget `declare(strict_types=1);`
|
|||||||
|
namespace App\Controller;
|
||||||
|
|
||||||
|
use App\Form\Type\PasteForm;
|
||||||
|
use App\Entity\Paste;
|
||||||
|
use App\Repository\PasteRepository;
|
||||||
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
|
use Symfony\Component\Routing\Annotation\Route;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
|
||||||
|
|
||||||
|
class PasteController extends AbstractController
|
||||||
|
{
|
||||||
|
#[Route('/')]
|
||||||
skobkin
commented
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, EntityManagerInterface $entityManager): Response {
|
||||||
skobkin marked this conversation as resolved
Outdated
skobkin
commented
You don't really need Make your repository implement You don't really need `EntityManager` here.
Make your repository implement `save` like I showed you and use it instead.
|
|||||||
|
$paste = new Paste();
|
||||||
skobkin marked this conversation as resolved
Outdated
skobkin
commented
I'd suggest we refactor this to to DTO usage and make our I'd suggest we refactor this to to DTO usage and make our `Paste` entity immutable.
|
|||||||
|
$form = $this->createForm(PasteForm::class, $paste);
|
||||||
|
|
||||||
|
$form->handleRequest($request);
|
||||||
|
if ($form->isSubmitted() && $form->isValid()) {
|
||||||
|
$paste = $form->getData();
|
||||||
|
$paste->setIp($request->getClientIp());
|
||||||
|
$paste->setPublishDate(new \DateTime());
|
||||||
skobkin marked this conversation as resolved
Outdated
skobkin
commented
You can just set it in the constructor. You can just set it in the constructor.
|
|||||||
|
|
||||||
skobkin marked this conversation as resolved
Outdated
skobkin
commented
Do you need IP in Do you need IP in `PasteData`?
|
|||||||
|
if ($paste->isPrivate()) {
|
||||||
|
$paste->setSecret(hash("sha1", random_bytes(25)));
|
||||||
skobkin marked this conversation as resolved
Outdated
skobkin
commented
Do we need double quotes here? By the way, we can also do that in the constructor. Do we need double quotes here?
By the way, we can also do that in the constructor.
skobkin marked this conversation as resolved
Outdated
skobkin
commented
This still could be done in the entity itself. This still could be done in the entity itself.
|
|||||||
|
}
|
||||||
|
|
||||||
|
$entityManager->persist($paste);
|
||||||
|
$entityManager->flush();
|
||||||
skobkin marked this conversation as resolved
Outdated
skobkin
commented
I still suggest to make I still suggest to make `Paste::fromFormData()`.
|
|||||||
|
|
||||||
|
return $this->redirectToRoute($request->attributes->get('_route'));
|
||||||
skobkin marked this conversation as resolved
Outdated
skobkin
commented
Just set a BTW, where are you redirecting exactly? 🤔 You should be redirecting to the route which is processed by Just set a `name` for your route and you won't need such workarounds.
BTW, where are you redirecting exactly? 🤔 You should be redirecting to the route which is processed by `PasteController::show_paste()` as far as I understand your code.
|
|||||||
|
|
||||||
skobkin marked this conversation as resolved
Outdated
skobkin
commented
I see you needed some space 🤔 I see you needed some space 🤔
|
|||||||
|
}
|
||||||
|
|
||||||
|
return $this->render('paste.html.twig', [
|
||||||
skobkin marked this conversation as resolved
Outdated
skobkin
commented
I mean you don't need to pass creation date here at all. I mean you don't need to pass creation date here at all.
|
|||||||
|
'form' => $form,
|
||||||
skobkin
commented
`show_paste` at least.
|
|||||||
|
]);
|
||||||
|
}
|
||||||
skobkin marked this conversation as resolved
Outdated
skobkin
commented
- it's a good idea to add `,` to the last argument too if you use multi-line formatting
- if you're doing this in the controller, you can just do something like `$pasteData->private ? \hash('sha1', \random_bytes(25)) : null`. But I suggest to do that in the static method (named constructor) as I also suggested nearby.
|
|||||||
|
|
||||||
|
#[Route('/{id}/{secret}')]
|
||||||
|
public function show_paste(PasteRepository $pasteRepository, Request $request, string $id, ?string $secret=NULL): Response {
|
||||||
skobkin marked this conversation as resolved
Outdated
skobkin
commented
You're violating Symfony code style here which as I can guess you used above. You can just set Symfony style in the settings of your IDE for this project and auto-format this file to fix. Or fix it manually if you want. You're violating [Symfony code style](https://symfony.com/doc/current/contributing/code/standards.html#symfony-coding-standards-in-detail) here which as I can guess you used above.
You can just set Symfony style in the settings of your IDE for this project and auto-format this file to fix. Or fix it manually if you want.
|
|||||||
|
$paste = $pasteRepository->findOneBy(["id" => $id, "secret" => $secret]);
|
||||||
skobkin marked this conversation as resolved
Outdated
skobkin
commented
Do you need double quotes here too? Do you need double quotes here too?
|
|||||||
|
$form = $this->createForm(PasteForm::class, $paste);
|
||||||
|
|
||||||
|
return $this->render('paste.html.twig', [
|
||||||
skobkin
commented
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,
|
||||||
|
]);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
0
src/Entity/.gitignore
vendored
Normal file
139
src/Entity/Paste.php
Normal file
|
@ -0,0 +1,139 @@
|
||||||
|
<?php
|
||||||
|
namespace App\Entity;
|
||||||
skobkin marked this conversation as resolved
Outdated
skobkin
commented
Please do not forget Please do not forget `declare(strict_types=1);`
|
|||||||
|
|
||||||
|
use App\Repository\PasteRepository;
|
||||||
|
use Doctrine\DBAL\Types\Types;
|
||||||
|
use Doctrine\ORM\Mapping as ORM;
|
||||||
|
use Symfony\Component\Validator\Constraints as Assert;
|
||||||
|
|
||||||
|
#[ORM\Entity(repositoryClass: PasteRepository::class)]
|
||||||
skobkin
commented
I'd suggest explicitly defining Especially since you're defining I'd suggest explicitly defining `Table` attribute here.
Especially since you're defining `Column` attributes below ⬇️
skobkin
commented
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).
|
|||||||
|
class Paste
|
||||||
|
{
|
||||||
|
#[ORM\Id]
|
||||||
|
#[ORM\GeneratedValue]
|
||||||
|
#[ORM\Column(nullable: false)]
|
||||||
skobkin marked this conversation as resolved
Outdated
skobkin
commented
I don't think you need But I'd suggest to explicitly set it for every other I don't think you need `nullable=false` here since it's a Primary Key.
But I'd suggest to explicitly set it for every other `Column` and also set a `name` for them.
|
|||||||
|
private int $id;
|
||||||
skobkin
commented
Why not also constructor promotion though? Why not also constructor promotion though?
|
|||||||
|
|
||||||
|
#[ORM\Column(type: "text", nullable: false)]
|
||||||
skobkin marked this conversation as resolved
Outdated
skobkin
commented
No need for double quotes here too. No need for double quotes here too.
|
|||||||
|
#[Assert\NotBlank]
|
||||||
|
private string $text;
|
||||||
|
|
||||||
|
#[ORM\Column(type: "boolean", nullable: false)]
|
||||||
|
#[Assert\Type(\boolean::class)]
|
||||||
|
private bool $private;
|
||||||
|
|
||||||
|
#[ORM\Column(length: 25, nullable: true)]
|
||||||
skobkin
commented
What type? Why 25 exactly? What type? Why 25 exactly?
skobkin
commented
Why 128? Why 128?
|
|||||||
|
private ?string $language;
|
||||||
|
|
||||||
skobkin marked this conversation as resolved
Outdated
skobkin
commented
Why not nullable? Why not nullable?
|
|||||||
|
#[ORM\Column(type: "text", nullable: true)]
|
||||||
|
private ?string $description;
|
||||||
|
|
||||||
|
#[ORM\Column(length: 128, nullable: true)]
|
||||||
|
private ?string $filename;
|
||||||
|
|
||||||
|
#[ORM\Column(length: 128, nullable: false)]
|
||||||
|
#[Assert\NotBlank]
|
||||||
|
private string $author = "anonymous";
|
||||||
skobkin marked this conversation as resolved
Outdated
skobkin
commented
Why double quotes? Why double quotes?
|
|||||||
|
|
||||||
|
#[ORM\Column(type: Types::DATETIME_MUTABLE, nullable: false)]
|
||||||
skobkin
commented
You can use You can use `self` as return type hint too.
|
|||||||
|
#[Assert\Type(\DateTime::class)]
|
||||||
|
private \DateTime $publishDate;
|
||||||
skobkin marked this conversation as resolved
Outdated
skobkin
commented
Why mutable date? Do you plan to change publish date? Why mutable date? Do you plan to change publish date?
|
|||||||
|
|
||||||
|
#[ORM\Column(type: Types::DATETIME_MUTABLE, nullable: true)]
|
||||||
|
#[Assert\Type(\DateTime::class)]
|
||||||
|
private ?\DateTime $expirationDate;
|
||||||
|
|
||||||
|
#[ORM\Column(length: 15, nullable: false)]
|
||||||
|
private string $ip;
|
||||||
|
|
||||||
|
#[ORM\Column(length: 40, nullable: true)]
|
||||||
|
private ?string $secret;
|
||||||
|
|
||||||
|
public function getId(): int {
|
||||||
skobkin marked this conversation as resolved
Outdated
skobkin
commented
Same code style problem like above. You're leaving It's ok if you're doing multi-line arguments, but not in this case. Same code style problem like above. You're leaving `{` on the same line with return type.
It's ok if you're doing multi-line arguments, but not in this case.
|
|||||||
|
return $this->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setId(int $id): void {
|
||||||
skobkin marked this conversation as resolved
Outdated
skobkin
commented
Let this thread be for now, but we'd better make this entity immutable and remove every setter method from here. This way we can use Let this thread be for now, but we'd better make this entity immutable and remove every setter method from here.
This way we can use `private readonly` instead of just `private` properties. Or even `public readonly` 🤔
|
|||||||
|
$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 {
|
||||||
skobkin marked this conversation as resolved
Outdated
skobkin
commented
You don't need this. You don't need this.
|
|||||||
|
$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 {
|
||||||
skobkin marked this conversation as resolved
Outdated
skobkin
commented
You don't need this. You don't need this.
|
|||||||
|
$this->secret = $secret;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isPrivate(): bool {
|
||||||
|
return $this->private;
|
||||||
skobkin marked this conversation as resolved
Outdated
skobkin
commented
Do you really need this You can just Do you really need this `bool` flag?
You can just `return $this->secret !== null`.
|
|||||||
|
}
|
||||||
|
|
||||||
|
public function setPrivate(bool $private): void {
|
||||||
|
$this->private = $private;
|
||||||
|
}
|
||||||
|
}
|
28
src/Form/Type/PasteForm.php
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
<?php
|
||||||
|
namespace App\Form\Type;
|
||||||
skobkin marked this conversation as resolved
Outdated
skobkin
commented
Please do not forget Please do not forget `declare(strict_types=1);`
|
|||||||
|
|
||||||
|
use Symfony\Component\Form\AbstractType;
|
||||||
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\DateTimeType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
|
||||||
|
|
||||||
|
|
||||||
|
class PasteForm extends AbstractType
|
||||||
|
{
|
||||||
|
public function buildForm(FormBuilderInterface $builder, array $options): void {
|
||||||
|
$builder
|
||||||
|
->add("language", ChoiceType::class, ["choices" => ["Python" => "python", "PHP" => "php", "Plain text" => NULL]])
|
||||||
skobkin marked this conversation as resolved
Outdated
skobkin
commented
Double quotes? Also please multi-line format arrays with more than one element for readability. Double quotes?
Also please multi-line format arrays with more than one element for readability.
|
|||||||
|
->add("description", TextType::class, ["required" => false])
|
||||||
|
->add("text", TextareaType::class)
|
||||||
|
->add("author", TextType::class, ["attr" => ["maxlength" =>128]])
|
||||||
skobkin marked this conversation as resolved
Outdated
skobkin
commented
You can probably extract You can probably extract `128` to the constant and use here and in the validation attribute.
|
|||||||
|
->add("filename", TextType::class, ["required" => false, "attr" => ["maxlength" =>128]])
|
||||||
|
->add("expirationDate", DateTimeType::class, ["required" => false, "date_widget" => "single_text", "input" => "datetime"])
|
||||||
skobkin marked this conversation as resolved
Outdated
skobkin
commented
This should be a combo-box ( This should be a combo-box (`select` in HTML terms) with a list of available periods like "10 minutes", "1 year" and "Never".
|
|||||||
|
->add("private", CheckboxType::class, ["required" => false])
|
||||||
|
->add("save", SubmitType::class)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
0
src/Repository/.gitignore
vendored
Normal file
14
src/Repository/PasteRepository.php
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
<?php
|
||||||
skobkin marked this conversation as resolved
skobkin
commented
Can't leave a comment for Do you need it? Can't leave a comment for `src/Repository/.gitignore`, so I'll ask here.
Do you need it?
|
|||||||
|
|
||||||
skobkin marked this conversation as resolved
Outdated
skobkin
commented
Please do not forget Please do not forget `declare(strict_types=1);`
|
|||||||
|
namespace App\Repository;
|
||||||
|
|
||||||
|
use App\Entity\Paste;
|
||||||
|
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||||
|
use Doctrine\Persistence\ManagerRegistry;
|
||||||
|
|
||||||
|
class PasteRepository extends ServiceEntityRepository
|
||||||
|
{
|
||||||
|
public function __construct(ManagerRegistry $registry) {
|
||||||
|
parent::__construct($registry, Paste::class);
|
||||||
|
}
|
||||||
skobkin marked this conversation as resolved
Outdated
skobkin
commented
I'd suggest adding I'd suggest adding `save()` here like I showed you.
skobkin
commented
Better with optional Better with optional `flush`.
Flushng from the repo itself should be a rare action.
|
|||||||
|
}
|
61
symfony.lock
|
@ -1,4 +1,31 @@
|
||||||
{
|
{
|
||||||
|
"doctrine/doctrine-bundle": {
|
||||||
|
"version": "2.10",
|
||||||
|
"recipe": {
|
||||||
|
"repo": "github.com/symfony/recipes",
|
||||||
|
"branch": "main",
|
||||||
|
"version": "2.10",
|
||||||
|
"ref": "f0d8c9a4da17815830aac0d63e153a940ae176bb"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"config/packages/doctrine.yaml",
|
||||||
|
"src/Entity/.gitignore",
|
||||||
|
"src/Repository/.gitignore"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"doctrine/doctrine-migrations-bundle": {
|
||||||
|
"version": "3.2",
|
||||||
|
"recipe": {
|
||||||
|
"repo": "github.com/symfony/recipes",
|
||||||
|
"branch": "main",
|
||||||
|
"version": "3.1",
|
||||||
|
"ref": "1d01ec03c6ecbd67c3375c5478c9a423ae5d6a33"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"config/packages/doctrine_migrations.yaml",
|
||||||
|
"migrations/.gitignore"
|
||||||
|
]
|
||||||
|
},
|
||||||
"symfony/console": {
|
"symfony/console": {
|
||||||
"version": "6.3",
|
"version": "6.3",
|
||||||
"recipe": {
|
"recipe": {
|
||||||
|
@ -42,6 +69,15 @@
|
||||||
"src/Kernel.php"
|
"src/Kernel.php"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"symfony/maker-bundle": {
|
||||||
|
"version": "1.50",
|
||||||
|
"recipe": {
|
||||||
|
"repo": "github.com/symfony/recipes",
|
||||||
|
"branch": "main",
|
||||||
|
"version": "1.0",
|
||||||
|
"ref": "fadbfe33303a76e25cb63401050439aa9b1a9c7f"
|
||||||
|
}
|
||||||
|
},
|
||||||
"symfony/routing": {
|
"symfony/routing": {
|
||||||
"version": "6.3",
|
"version": "6.3",
|
||||||
"recipe": {
|
"recipe": {
|
||||||
|
@ -54,5 +90,30 @@
|
||||||
"config/packages/routing.yaml",
|
"config/packages/routing.yaml",
|
||||||
"config/routes.yaml"
|
"config/routes.yaml"
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
"symfony/twig-bundle": {
|
||||||
|
"version": "6.3",
|
||||||
|
"recipe": {
|
||||||
|
"repo": "github.com/symfony/recipes",
|
||||||
|
"branch": "main",
|
||||||
|
"version": "6.3",
|
||||||
|
"ref": "b7772eb20e92f3fb4d4fe756e7505b4ba2ca1a2c"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"config/packages/twig.yaml",
|
||||||
|
"templates/base.html.twig"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"symfony/validator": {
|
||||||
|
"version": "6.3",
|
||||||
|
"recipe": {
|
||||||
|
"repo": "github.com/symfony/recipes",
|
||||||
|
"branch": "main",
|
||||||
|
"version": "5.3",
|
||||||
|
"ref": "c32cfd98f714894c4f128bb99aa2530c1227603c"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"config/packages/validator.yaml"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
16
templates/base.html.twig
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>{% block title %}Welcome!{% endblock %}</title>
|
||||||
|
<link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 128 128%22><text y=%221.2em%22 font-size=%2296%22>⚫️</text></svg>">
|
||||||
|
{% block stylesheets %}
|
||||||
skobkin
commented
It's better not to rely on external CDN's when you can. It's better not to rely on external CDN's when you can.
You can just save needed resources in the repository since we're not making our front-end too complex to make dynamic build.
|
|||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block javascripts %}
|
||||||
|
{% endblock %}
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
skobkin
commented
Same here. Same here.
|
|||||||
|
{% block body %}{% endblock %}
|
||||||
|
</body>
|
||||||
|
</html>
|
1
templates/paste.html.twig
Normal file
|
@ -0,0 +1 @@
|
||||||
|
{{ form(form) }}
|
||||||
skobkin marked this conversation as resolved
Outdated
skobkin
commented
Did you forget to extend Did you forget to extend `base.html.twig` and use it's `body` block?
skobkin
commented
Why double quotes again? Why double quotes again?
skobkin
commented
BTW, if you're including it in the BTW, if you're including it in the `show_paste.html.twig`, then you don't need to extend `base.html.twig` here.
|
You should use some placeholder value here like
your_secret_please_set_on_local_env
.