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 %}
+
+{% 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 %}