From 6327c3509e67e66934b9c6b67e5cde9d8acfb827 Mon Sep 17 00:00:00 2001 From: Joe Carstairs Date: Sat, 17 May 2025 22:47:20 +0100 Subject: [PATCH] can write and read notes --- .env | 4 +- composer.json | 2 +- composer.lock | 2 +- migrations/Version20250517200832.php | 53 +++++++++++++++++++++ migrations/Version20250517212750.php | 47 +++++++++++++++++++ src/Controller/GuiController.php | 69 ++++++++++++++++++++++++++++ src/Entity/Note.php | 66 ++++++++++++++++++++++++++ src/Form/Type/NoteType.php | 27 +++++++++++ src/Repository/NoteRepository.php | 62 +++++++++++++++++++++++++ templates/note.html.twig | 9 ++++ templates/notes.html.twig | 7 +++ templates/write_note.html.twig | 8 ++++ 12 files changed, 352 insertions(+), 4 deletions(-) create mode 100644 migrations/Version20250517200832.php create mode 100644 migrations/Version20250517212750.php create mode 100644 src/Entity/Note.php create mode 100644 src/Form/Type/NoteType.php create mode 100644 src/Repository/NoteRepository.php create mode 100644 templates/note.html.twig create mode 100644 templates/notes.html.twig create mode 100644 templates/write_note.html.twig diff --git a/.env b/.env index 42ad71d..ae5c7f3 100644 --- a/.env +++ b/.env @@ -23,10 +23,10 @@ APP_SECRET= # 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_%kernel.environment%.db" +DATABASE_URL="sqlite:///%kernel.project_dir%/var/data_%kernel.environment%.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=16&charset=utf8" +# DATABASE_URL="postgresql://app:!ChangeMe!@127.0.0.1:5432/app?serverVersion=16&charset=utf8" ###< doctrine/doctrine-bundle ### ###> symfony/messenger ### diff --git a/composer.json b/composer.json index a15eb4b..4f0a367 100644 --- a/composer.json +++ b/composer.json @@ -101,7 +101,7 @@ "symfony/browser-kit": "7.2.*", "symfony/css-selector": "7.2.*", "symfony/debug-bundle": "7.2.*", - "symfony/maker-bundle": "^1.0", + "symfony/maker-bundle": "^1.63", "symfony/phpunit-bridge": "^7.2", "symfony/stopwatch": "7.2.*", "symfony/web-profiler-bundle": "7.2.*" diff --git a/composer.lock b/composer.lock index be9538c..123b5ab 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "f7d3da4051931b357a1b2691d865cbd3", + "content-hash": "be4d1d2b4515d0af292b8887b9724e0b", "packages": [ { "name": "composer/semver", diff --git a/migrations/Version20250517200832.php b/migrations/Version20250517200832.php new file mode 100644 index 0000000..960d92f --- /dev/null +++ b/migrations/Version20250517200832.php @@ -0,0 +1,53 @@ +addSql(<<<'SQL' + CREATE TABLE note (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, content VARCHAR(255) NOT NULL, published_date DATE NOT NULL) + SQL); + $this->addSql(<<<'SQL' + CREATE TABLE messenger_messages (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, body CLOB NOT NULL, headers CLOB NOT NULL, queue_name VARCHAR(190) NOT NULL, created_at DATETIME NOT NULL --(DC2Type:datetime_immutable) + , available_at DATETIME NOT NULL --(DC2Type:datetime_immutable) + , delivered_at DATETIME DEFAULT NULL --(DC2Type:datetime_immutable) + ) + SQL); + $this->addSql(<<<'SQL' + CREATE INDEX IDX_75EA56E0FB7336F0 ON messenger_messages (queue_name) + SQL); + $this->addSql(<<<'SQL' + CREATE INDEX IDX_75EA56E0E3BD61CE ON messenger_messages (available_at) + SQL); + $this->addSql(<<<'SQL' + CREATE INDEX IDX_75EA56E016BA31DB ON messenger_messages (delivered_at) + SQL); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql(<<<'SQL' + DROP TABLE note + SQL); + $this->addSql(<<<'SQL' + DROP TABLE messenger_messages + SQL); + } +} diff --git a/migrations/Version20250517212750.php b/migrations/Version20250517212750.php new file mode 100644 index 0000000..491ccc7 --- /dev/null +++ b/migrations/Version20250517212750.php @@ -0,0 +1,47 @@ +addSql(<<<'SQL' + ALTER TABLE note ADD COLUMN slug VARCHAR(255) NOT NULL + SQL); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql(<<<'SQL' + CREATE TEMPORARY TABLE __temp__note AS SELECT id, content, published_date FROM note + SQL); + $this->addSql(<<<'SQL' + DROP TABLE note + SQL); + $this->addSql(<<<'SQL' + CREATE TABLE note (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, content VARCHAR(255) NOT NULL, published_date DATE NOT NULL) + SQL); + $this->addSql(<<<'SQL' + INSERT INTO note (id, content, published_date) SELECT id, content, published_date FROM __temp__note + SQL); + $this->addSql(<<<'SQL' + DROP TABLE __temp__note + SQL); + } +} diff --git a/src/Controller/GuiController.php b/src/Controller/GuiController.php index cf6dddb..395b863 100644 --- a/src/Controller/GuiController.php +++ b/src/Controller/GuiController.php @@ -1,8 +1,15 @@ 'Joe Carstairs\' personal website', ]; } + + #[Route('/notes', name: 'notes')] + #[Template('/notes.html.twig')] + public function notes(): Array { + return [ + 'title' => 'Joe Carstairs\' notes', + 'description' => 'Joe Carstairs\' notes', + ]; + } + + #[Route('/note/{slug}', name: 'note')] + #[Template('/note.html.twig')] + public function note( + EntityManagerInterface $entityManager, + string $slug, + ): array { + $repository = $entityManager->getRepository(Note::class); + $note = $repository->findOneBy(['slug' => $slug]); + + return [ + 'title' => 'Joe Carstairs\' notes', + 'description' => 'Joe Carstairs\' notes', + 'note' => $note, + ]; + } + + #[Route('/notes/write')] + #[Template('/write_note.html.twig')] + public function writeNote( + EntityManagerInterface $entityManager, + Request $request, + ): Response { + $note = new Note(); + $form = $this->createForm(NoteType::class, $note); + + $form->handleRequest($request); + if ($form->isSubmitted() && $form->isValid()) { + $note = $form->getData(); + + $now = new DateTime('now'); + $note->setPublishedDate($now); + + $num_existing_notes_today = $entityManager->getRepository(Note::class)->countWherePublishedOnDate($now); + $note->getPublishedDate()->setTimezone(new DateTimeZone('Europe/London')); + $slug = $note->getPublishedDate()->format('Y-m-d'); + if ($num_existing_notes_today > 0) { + $slug = $slug . '-' . $num_existing_notes_today; + } + $note->setSlug($slug); + + $entityManager->persist($note); + $entityManager->flush(); + + return $this->redirectToRoute('note', ['slug' => $note->getSlug()]); + } + + return $this->render('/write_note.html.twig', [ + 'title' => 'Write for Joe Carstairs', + 'description' => 'The authoring page for Joe Carstairs\' personal website', + 'form' => $form, + ]); + } } diff --git a/src/Entity/Note.php b/src/Entity/Note.php new file mode 100644 index 0000000..17dac1f --- /dev/null +++ b/src/Entity/Note.php @@ -0,0 +1,66 @@ +id; + } + + public function getContent(): ?string + { + return $this->content; + } + + public function setContent(string $content): static + { + $this->content = $content; + + return $this; + } + + public function getPublishedDate(): ?\DateTime + { + return $this->published_date; + } + + public function setPublishedDate(\DateTime $published_date): static + { + $this->published_date = $published_date; + + return $this; + } + + public function getSlug(): ?string + { + return $this->slug; + } + + public function setSlug(string $slug): static + { + $this->slug = $slug; + + return $this; + } +} diff --git a/src/Form/Type/NoteType.php b/src/Form/Type/NoteType.php new file mode 100644 index 0000000..554603e --- /dev/null +++ b/src/Form/Type/NoteType.php @@ -0,0 +1,27 @@ +add('content', TextType::class) + ->add('post', SubmitType::class) + ; + } + + public function configureOptions(OptionsResolver $resolver): void + { + $resolver->setDefaults([ + 'data_class' => Note::class, + ]); + } +} diff --git a/src/Repository/NoteRepository.php b/src/Repository/NoteRepository.php new file mode 100644 index 0000000..2322699 --- /dev/null +++ b/src/Repository/NoteRepository.php @@ -0,0 +1,62 @@ + + */ +class NoteRepository extends ServiceEntityRepository +{ + public function __construct(ManagerRegistry $registry) + { + parent::__construct($registry, Note::class); + } + + public function countWherePublishedOnDate(DateTime $date): int { + $min = new DateTime($date->format('c')); + $min->setTime(0, 0, 0, 0); + $max = new DateTime($min->format('c')); + $max->add(DateInterval::createFromDateString('1 day')); + + $wherePublishedOnDate = $this->createQueryBuilder('n') + ->andWhere('n.published_date >= :min') + ->andWhere('n.published_date < :max') + ->setParameter('min', $min) + ->setParameter('max', $max) + ->getQuery() + ->execute(); + + return count($wherePublishedOnDate); + } + + // /** + // * @return Note[] Returns an array of Note objects + // */ + // public function findByExampleField($value): array + // { + // return $this->createQueryBuilder('n') + // ->andWhere('n.exampleField = :val') + // ->setParameter('val', $value) + // ->orderBy('n.id', 'ASC') + // ->setMaxResults(10) + // ->getQuery() + // ->getResult() + // ; + // } + + // public function findOneBySomeField($value): ?Note + // { + // return $this->createQueryBuilder('n') + // ->andWhere('n.exampleField = :val') + // ->setParameter('val', $value) + // ->getQuery() + // ->getOneOrNullResult() + // ; + // } +} diff --git a/templates/note.html.twig b/templates/note.html.twig new file mode 100644 index 0000000..4cc29a3 --- /dev/null +++ b/templates/note.html.twig @@ -0,0 +1,9 @@ +{% extends 'base.html.twig' %} + +{% block content %} +
+

Note

+
+{% endblock %} diff --git a/templates/notes.html.twig b/templates/notes.html.twig new file mode 100644 index 0000000..fe65f80 --- /dev/null +++ b/templates/notes.html.twig @@ -0,0 +1,7 @@ +{% extends 'base.html.twig' %} + +{% block content %} +
+

Notes

+
+{% endblock %} diff --git a/templates/write_note.html.twig b/templates/write_note.html.twig new file mode 100644 index 0000000..04d07df --- /dev/null +++ b/templates/write_note.html.twig @@ -0,0 +1,8 @@ +{% extends 'base.html.twig' %} + +{% block content %} +
+

Write a note

+ {{ form(form) }} +
+{% endblock %}