From 484ea436b30498857079264f8056f0cdfdcd673d Mon Sep 17 00:00:00 2001 From: Bob den Otter Date: Sun, 16 Sep 2018 10:39:54 +0200 Subject: [PATCH] Working --- src/Controller/BlogController.php | 20 ++ src/DataFixtures/ContentFixtures.php | 210 ++++++++++++++++++ .../{AppFixtures.php => X_AppFixtures.php} | 4 +- src/Entity/Content.php | 104 +++++++-- src/Entity/Field.php | 25 ++- src/Migrations/Version20180912145527.php | 30 --- ...13184018.php => Version20180916083018.php} | 30 +-- src/Repository/ContentRepository.php | 32 +++ templates/blog/listing.html.twig | 46 ++++ 9 files changed, 421 insertions(+), 80 deletions(-) create mode 100644 src/DataFixtures/ContentFixtures.php rename src/DataFixtures/{AppFixtures.php => X_AppFixtures.php} (99%) delete mode 100644 src/Migrations/Version20180912145527.php rename src/Migrations/{Version20180913184018.php => Version20180916083018.php} (52%) create mode 100644 templates/blog/listing.html.twig diff --git a/src/Controller/BlogController.php b/src/Controller/BlogController.php index d4f6b1ae..78e69573 100644 --- a/src/Controller/BlogController.php +++ b/src/Controller/BlogController.php @@ -3,9 +3,11 @@ namespace Bolt\Controller; use Bolt\Entity\Comment; +use Bolt\Entity\Content; use Bolt\Entity\Post; use Bolt\Events; use Bolt\Form\CommentType; +use Bolt\Repository\ContentRepository; use Bolt\Repository\PostRepository; use Bolt\Repository\TagRepository; use Sensio\Bundle\FrameworkExtraBundle\Configuration\Cache; @@ -52,6 +54,24 @@ class BlogController extends AbstractController return $this->render('blog/index.'.$_format.'.twig', ['posts' => $latestPosts]); } + /** + * @Route("/content", methods={"GET"}, name="content_listing") + * @param ContentRepository $content + * @param Request $request + * @return Response + */ + public function contentShow(ContentRepository $content, Request $request): Response + { + $tag = null; + $page = 1; + if ($request->query->has('tag')) { + $tag = $tags->findOneBy(['name' => $request->query->get('tag')]); + } + $latestContent = $content->findLatest($page, $tag); + + return $this->render('blog/listing.html.twig', ['records' => $latestContent]); + } + /** * @Route("/posts/{slug}", methods={"GET"}, name="blog_post") * diff --git a/src/DataFixtures/ContentFixtures.php b/src/DataFixtures/ContentFixtures.php new file mode 100644 index 00000000..ac732264 --- /dev/null +++ b/src/DataFixtures/ContentFixtures.php @@ -0,0 +1,210 @@ +passwordEncoder = $passwordEncoder; + } + + public function load(ObjectManager $manager) + { + $this->loadUsers($manager); + $this->loadContent($manager); + + $manager->flush(); + } + + private function loadUsers(ObjectManager $manager) + { + foreach ($this->getUserData() as [$fullname, $username, $password, $email, $roles]) { + $user = new User(); + $user->setFullName($fullname); + $user->setUsername($username); + $user->setPassword($this->passwordEncoder->encodePassword($user, $password)); + $user->setEmail($email); + $user->setRoles($roles); + + $manager->persist($user); + $this->addReference($username, $user); + } + + $manager->flush(); + } + + private function getUserData(): array + { + return [ + // $userData = [$fullname, $username, $password, $email, $roles]; + ['Jane Doe', 'jane_admin', 'kitten', 'jane_admin@symfony.com', ['ROLE_ADMIN']], + ['Tom Doe', 'tom_admin', 'kitten', 'tom_admin@symfony.com', ['ROLE_ADMIN']], + ['John Doe', 'john_user', 'kitten', 'john_user@symfony.com', ['ROLE_USER']], + ]; + } + + + private function loadContent(ObjectManager $manager) + { + foreach (range(1, 15) as $i) { + $author = $this->getReference(['jane_admin', 'tom_admin'][0 === $i ? 0 : random_int(0, 1)]); + + $content = new Content(); + $content->setContenttype($this->getRandomContentType()); + $content->setAuthor($author); + $content->setStatus($this->getRandomStatus()); + $content->setCreatedAt(new \DateTime('now - ' . rand(1, 9000) . 'hours')); + $content->setModifiedAt(new \DateTime('now - ' . rand(1, 9000) . 'hours')); + $content->setPublishedAt(new \DateTime('now - ' . rand(1, 9000) . 'hours')); + $content->setDepublishedAt(new \DateTime('now - ' . rand(1, 9000) . 'hours')); + + /** + * * id + * contenttype `['pages', 'entries', 'homepage', 'blocks', 'showcases']` + * author_id + * status `['published', 'held', 'draft', 'timed']` + * created_at + * modified_at + * published_at + * depublished_at + */ + + foreach (range(1, 5) as $i) { + $fieldtype = $this->getRandomFieldType(); + + $field = new Field(); + $field->setName('title'); + $field->setType($fieldtype); + $field->setValue($this->getValuesforFieldType($fieldtype)); + $field->setSortorder($i * 5); + + $content->addField($field); + + /** + * * id + * content_id + * name + * type `['text', 'textarea', 'html', 'markdown', 'image']` + * value (JSON) + * parent_id + * sortorder + * (later) locale + * (later) version + */ + } + + $manager->persist($content); + + } + } + + private function getRandomContentType() + { + $contentTypes = ['pages', 'entries', 'homepage', 'blocks', 'showcases']; + + return $contentTypes[array_rand($contentTypes)]; + } + + private function getRandomFieldType() + { + $fieldTypes = ['slug', 'text', 'textarea', 'html', 'markdown', 'image']; + + return $fieldTypes[array_rand($fieldTypes)]; + } + + + private function getRandomStatus() + { + $statuses = ['published', 'held', 'draft', 'timed']; + + return $statuses[array_rand($statuses)]; + } + + private function getValuesforFieldType($type) + { + switch ($type) { + case 'html': + case 'textarea': + case 'markdown': + $data = ['value' => $this->getRandomText() ]; + break; + case 'image': + $data = ['filename' => 'kitten.jpg', 'alt' => 'A cute kitten']; + break; + case 'slug': + $data = ['value' => Slugger::slugify($this->getRandomPhrase()) ]; + break; + default : + $data = ['value' => $this->getRandomPhrase() ]; + } + + return $data; + } + + private function getRandomPhrase(): string + { + $phrases = $this->getPhrases(); + + return $phrases[array_rand($phrases)]; + } + + private function getPhrases(): array + { + return [ + 'Lorem ipsum dolor sit amet consectetur adipiscing elit', + 'Pellentesque vitae velit ex', + 'Mauris dapibus risus quis suscipit vulputate', + 'Eros diam egestas libero eu vulputate risus', + 'In hac habitasse platea dictumst', + 'Morbi tempus commodo mattis', + 'Ut suscipit posuere justo at vulputate', + 'Ut eleifend mauris et risus ultrices egestas', + 'Aliquam sodales odio id eleifend tristique', + 'Urna nisl sollicitudin id varius orci quam id turpis', + 'Nulla porta lobortis ligula vel egestas', + 'Curabitur aliquam euismod dolor non ornare', + 'Sed varius a risus eget aliquam', + 'Nunc viverra elit ac laoreet suscipit', + 'Pellentesque et sapien pulvinar consectetur', + 'Ubi est barbatus nix', + 'Abnobas sunt hilotaes de placidus vita', + 'Ubi est audax amicitia', + 'Eposs sunt solems de superbus fortis', + 'Vae humani generis', + 'Diatrias tolerare tanquam noster caesium', + 'Teres talis saepe tractare de camerarius flavum sensorem', + 'Silva de secundus galatae demitto quadra', + 'Sunt accentores vitare salvus flavum parses', + 'Potus sensim ad ferox abnoba', + 'Sunt seculaes transferre talis camerarius fluctuies', + 'Era brevis ratione est', + 'Sunt torquises imitari velox mirabilis medicinaes', + 'Mineralis persuadere omnes finises desiderium', + 'Bassus fatalis classiss virtualiter transferre de flavum', + ]; + } + + private function getRandomText(int $maxLength = 255): string + { + $phrases = $this->getPhrases(); + shuffle($phrases); + + while (mb_strlen($text = implode('. ', $phrases).'.') > $maxLength) { + array_pop($phrases); + } + + return $text; + } + +} diff --git a/src/DataFixtures/AppFixtures.php b/src/DataFixtures/X_AppFixtures.php similarity index 99% rename from src/DataFixtures/AppFixtures.php rename to src/DataFixtures/X_AppFixtures.php index 9482715e..239b96fc 100644 --- a/src/DataFixtures/AppFixtures.php +++ b/src/DataFixtures/X_AppFixtures.php @@ -11,7 +11,7 @@ use Doctrine\Bundle\FixturesBundle\Fixture; use Doctrine\Common\Persistence\ObjectManager; use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface; -class AppFixtures extends Fixture +class X_AppFixtures extends Fixture { private $passwordEncoder; @@ -22,7 +22,7 @@ class AppFixtures extends Fixture public function load(ObjectManager $manager) { - $this->loadUsers($manager); +// $this->loadUsers($manager); $this->loadTags($manager); $this->loadPosts($manager); } diff --git a/src/Entity/Content.php b/src/Entity/Content.php index b93dfa40..30393a88 100644 --- a/src/Entity/Content.php +++ b/src/Entity/Content.php @@ -2,6 +2,8 @@ namespace Bolt\Entity; +use Doctrine\Common\Collections\ArrayCollection; +use Doctrine\Common\Collections\Collection; use Doctrine\ORM\Mapping as ORM; /** @@ -10,6 +12,8 @@ use Doctrine\ORM\Mapping as ORM; */ class Content { + public const NUM_ITEMS = 10; + /** * @ORM\Id() * @ORM\GeneratedValue() @@ -23,9 +27,12 @@ class Content private $contenttype; /** - * @ORM\Column(type="integer") + * @var User + * + * @ORM\ManyToOne(targetEntity="Bolt\Entity\User") + * @ORM\JoinColumn(nullable=false) */ - private $author_id; + private $author; /** * @ORM\Column(type="string", length=191) @@ -35,22 +42,42 @@ class Content /** * @ORM\Column(type="datetime") */ - private $created_at; + private $createdAt; /** * @ORM\Column(type="datetime") */ - private $modified_at; + private $modifiedAt; /** * @ORM\Column(type="datetime", nullable=true) */ - private $published_at; + private $publishedAt; /** * @ORM\Column(type="datetime") */ - private $depublished_at; + private $depublishedAt; + + /** + * @ORM\OneToMany(targetEntity="Bolt\Entity\Field", mappedBy="content", orphanRemoval=true, cascade={"persist"}) + */ + private $fields; + + public function __toString(): string + { + return (string) "Content # " . $this->getId(); + } + + public function __construct() + { + $this->createdAt = new \DateTime(); + $this->modifiedAt = new \DateTime(); + $this->publishedAt = new \DateTime(); + $this->depublishedAt = new \DateTime(); + $this->fields = new ArrayCollection(); + } + public function getId(): ?int { @@ -69,16 +96,14 @@ class Content return $this; } - public function getAuthorId(): ?int + public function getAuthor(): User { - return $this->author_id; + return $this->author; } - public function setAuthorId(int $author_id): self + public function setAuthor(?User $author): void { - $this->author_id = $author_id; - - return $this; + $this->author = $author; } public function getStatus(): ?string @@ -95,48 +120,79 @@ class Content public function getCreatedAt(): ?\DateTimeInterface { - return $this->created_at; + return $this->createdAt; } - public function setCreatedAt(\DateTimeInterface $created_at): self + public function setCreatedAt(\DateTimeInterface $createdAt): self { - $this->created_at = $created_at; + $this->createdAt = $createdAt; return $this; } public function getModifiedAt(): ?\DateTimeInterface { - return $this->modified_at; + return $this->modifiedAt; } - public function setModifiedAt(\DateTimeInterface $modified_at): self + public function setModifiedAt(\DateTimeInterface $modifiedAt): self { - $this->modified_at = $modified_at; + $this->modifiedAt = $modifiedAt; return $this; } public function getPublishedAt(): ?\DateTimeInterface { - return $this->published_at; + return $this->publishedAt; } - public function setPublishedAt(?\DateTimeInterface $published_at): self + public function setPublishedAt(?\DateTimeInterface $publishedAt): self { - $this->published_at = $published_at; + $this->publishedAt = $publishedAt; return $this; } public function getDepublishedAt(): ?\DateTimeInterface { - return $this->depublished_at; + return $this->depublishedAt; } - public function setDepublishedAt(\DateTimeInterface $depublished_at): self + public function setDepublishedAt(\DateTimeInterface $depublishedAt): self { - $this->depublished_at = $depublished_at; + $this->depublishedAt = $depublishedAt; + + return $this; + } + + /** + * @return Collection|Field[] + */ + public function getFields(): Collection + { + return $this->fields; + } + + public function addField(Field $field): self + { + if (!$this->fields->contains($field)) { + $this->fields[] = $field; + $field->setContent($this); + } + + return $this; + } + + public function removeField(Field $field): self + { + if ($this->fields->contains($field)) { + $this->fields->removeElement($field); + // set the owning side to null (unless already changed) + if ($field->getContent() === $this) { + $field->setContent(null); + } + } return $this; } diff --git a/src/Entity/Field.php b/src/Entity/Field.php index 16691430..da6fe808 100644 --- a/src/Entity/Field.php +++ b/src/Entity/Field.php @@ -38,7 +38,7 @@ class Field private $value = []; /** - * @ORM\Column(type="integer") + * @ORM\Column(type="integer", nullable=true) */ private $parent_id; @@ -57,6 +57,17 @@ class Field */ private $version; + /** + * @ORM\ManyToOne(targetEntity="Bolt\Entity\Content", inversedBy="fields") + * @ORM\JoinColumn(nullable=false) + */ + private $content; + + public function __toString(): string + { + return implode(", " , $this->getValue()); + } + public function getId(): ?int { return $this->id; @@ -157,4 +168,16 @@ class Field return $this; } + + public function getContent(): ?Content + { + return $this->content; + } + + public function setContent(?Content $content): self + { + $this->content = $content; + + return $this; + } } diff --git a/src/Migrations/Version20180912145527.php b/src/Migrations/Version20180912145527.php deleted file mode 100644 index 3520d4a7..00000000 --- a/src/Migrations/Version20180912145527.php +++ /dev/null @@ -1,30 +0,0 @@ -abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.'); - - $this->addSql('CREATE TABLE content (id INT AUTO_INCREMENT NOT NULL, contenttype VARCHAR(191) NOT NULL, author_id INT NOT NULL, status VARCHAR(191) NOT NULL, created_at DATETIME NOT NULL, modified_at DATETIME NOT NULL, published_at DATETIME DEFAULT NULL, depublished_at DATETIME NOT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci ENGINE = InnoDB'); - $this->addSql('CREATE TABLE field (id INT AUTO_INCREMENT NOT NULL, content_id INT NOT NULL, name VARCHAR(191) NOT NULL, type VARCHAR(191) NOT NULL, value LONGTEXT NOT NULL COMMENT \'(DC2Type:json)\', parent_id INT NOT NULL, sortorder INT NOT NULL, locale VARCHAR(191) DEFAULT NULL, version INT DEFAULT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci ENGINE = InnoDB'); - } - - public function down(Schema $schema) : void - { - // this down() migration is auto-generated, please modify it to your needs - $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.'); - - $this->addSql('DROP TABLE content'); - $this->addSql('DROP TABLE field'); - } -} diff --git a/src/Migrations/Version20180913184018.php b/src/Migrations/Version20180916083018.php similarity index 52% rename from src/Migrations/Version20180913184018.php rename to src/Migrations/Version20180916083018.php index c259523f..422c8741 100644 --- a/src/Migrations/Version20180913184018.php +++ b/src/Migrations/Version20180916083018.php @@ -8,35 +8,27 @@ use Doctrine\Migrations\AbstractMigration; /** * Auto-generated Migration: Please modify to your needs! */ -final class Version20180913184018 extends AbstractMigration +final class Version20180916083018 extends AbstractMigration { public function up(Schema $schema) : void { // this up() migration is auto-generated, please modify it to your needs $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.'); - $this->addSql('ALTER TABLE symfony_demo_comment DROP FOREIGN KEY FK_53AD8F834B89032C'); - $this->addSql('ALTER TABLE symfony_demo_post_tag DROP FOREIGN KEY FK_6ABC1CC44B89032C'); - $this->addSql('ALTER TABLE symfony_demo_post_tag DROP FOREIGN KEY FK_6ABC1CC4BAD26311'); - $this->addSql('ALTER TABLE symfony_demo_comment DROP FOREIGN KEY FK_53AD8F83F675F31B'); - $this->addSql('ALTER TABLE symfony_demo_post DROP FOREIGN KEY FK_58A92E65F675F31B'); $this->addSql('CREATE TABLE bolt_post (id INT AUTO_INCREMENT NOT NULL, author_id INT NOT NULL, title VARCHAR(255) NOT NULL, slug VARCHAR(255) NOT NULL, summary VARCHAR(255) NOT NULL, content LONGTEXT NOT NULL, published_at DATETIME NOT NULL, INDEX IDX_807F8D56F675F31B (author_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci ENGINE = InnoDB'); $this->addSql('CREATE TABLE bolt_post_tag (post_id INT NOT NULL, tag_id INT NOT NULL, INDEX IDX_C7690CD4B89032C (post_id), INDEX IDX_C7690CDBAD26311 (tag_id), PRIMARY KEY(post_id, tag_id)) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci ENGINE = InnoDB'); $this->addSql('CREATE TABLE bolt_tag (id INT AUTO_INCREMENT NOT NULL, name VARCHAR(190) NOT NULL, UNIQUE INDEX UNIQ_96D0BCE85E237E06 (name), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci ENGINE = InnoDB'); $this->addSql('CREATE TABLE bolt_user (id INT AUTO_INCREMENT NOT NULL, full_name VARCHAR(255) NOT NULL, username VARCHAR(190) NOT NULL, email VARCHAR(190) NOT NULL, password VARCHAR(255) NOT NULL, roles LONGTEXT NOT NULL COMMENT \'(DC2Type:json)\', UNIQUE INDEX UNIQ_57663792F85E0677 (username), UNIQUE INDEX UNIQ_57663792E7927C74 (email), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci ENGINE = InnoDB'); - $this->addSql('CREATE TABLE bolt_content (id INT AUTO_INCREMENT NOT NULL, contenttype VARCHAR(191) NOT NULL, author_id INT NOT NULL, status VARCHAR(191) NOT NULL, created_at DATETIME NOT NULL, modified_at DATETIME NOT NULL, published_at DATETIME DEFAULT NULL, depublished_at DATETIME NOT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci ENGINE = InnoDB'); - $this->addSql('CREATE TABLE bolt_field (id INT AUTO_INCREMENT NOT NULL, content_id INT NOT NULL, name VARCHAR(191) NOT NULL, type VARCHAR(191) NOT NULL, value LONGTEXT NOT NULL COMMENT \'(DC2Type:json)\', parent_id INT NOT NULL, sortorder INT NOT NULL, locale VARCHAR(191) DEFAULT NULL, version INT DEFAULT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci ENGINE = InnoDB'); + $this->addSql('CREATE TABLE bolt_content (id INT AUTO_INCREMENT NOT NULL, author_id INT NOT NULL, contenttype VARCHAR(191) NOT NULL, status VARCHAR(191) NOT NULL, created_at DATETIME NOT NULL, modified_at DATETIME NOT NULL, published_at DATETIME DEFAULT NULL, depublished_at DATETIME NOT NULL, INDEX IDX_F5AB2E9CF675F31B (author_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci ENGINE = InnoDB'); + $this->addSql('CREATE TABLE bolt_field (id INT AUTO_INCREMENT NOT NULL, content_id INT NOT NULL, name VARCHAR(191) NOT NULL, type VARCHAR(191) NOT NULL, value LONGTEXT NOT NULL COMMENT \'(DC2Type:json)\', parent_id INT DEFAULT NULL, sortorder INT NOT NULL, locale VARCHAR(191) DEFAULT NULL, version INT DEFAULT NULL, INDEX IDX_4A2EBBE584A0A3ED (content_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci ENGINE = InnoDB'); $this->addSql('CREATE TABLE bolt_comment (id INT AUTO_INCREMENT NOT NULL, post_id INT NOT NULL, author_id INT NOT NULL, content LONGTEXT NOT NULL, published_at DATETIME NOT NULL, INDEX IDX_9F1A4C594B89032C (post_id), INDEX IDX_9F1A4C59F675F31B (author_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci ENGINE = InnoDB'); $this->addSql('ALTER TABLE bolt_post ADD CONSTRAINT FK_807F8D56F675F31B FOREIGN KEY (author_id) REFERENCES bolt_user (id)'); $this->addSql('ALTER TABLE bolt_post_tag ADD CONSTRAINT FK_C7690CD4B89032C FOREIGN KEY (post_id) REFERENCES bolt_post (id) ON DELETE CASCADE'); $this->addSql('ALTER TABLE bolt_post_tag ADD CONSTRAINT FK_C7690CDBAD26311 FOREIGN KEY (tag_id) REFERENCES bolt_tag (id) ON DELETE CASCADE'); + $this->addSql('ALTER TABLE bolt_content ADD CONSTRAINT FK_F5AB2E9CF675F31B FOREIGN KEY (author_id) REFERENCES bolt_user (id)'); + $this->addSql('ALTER TABLE bolt_field ADD CONSTRAINT FK_4A2EBBE584A0A3ED FOREIGN KEY (content_id) REFERENCES bolt_content (id)'); $this->addSql('ALTER TABLE bolt_comment ADD CONSTRAINT FK_9F1A4C594B89032C FOREIGN KEY (post_id) REFERENCES bolt_post (id)'); $this->addSql('ALTER TABLE bolt_comment ADD CONSTRAINT FK_9F1A4C59F675F31B FOREIGN KEY (author_id) REFERENCES bolt_user (id)'); - $this->addSql('DROP TABLE symfony_demo_comment'); - $this->addSql('DROP TABLE symfony_demo_post'); - $this->addSql('DROP TABLE symfony_demo_post_tag'); - $this->addSql('DROP TABLE symfony_demo_tag'); - $this->addSql('DROP TABLE symfony_demo_user'); } public function down(Schema $schema) : void @@ -48,17 +40,9 @@ final class Version20180913184018 extends AbstractMigration $this->addSql('ALTER TABLE bolt_comment DROP FOREIGN KEY FK_9F1A4C594B89032C'); $this->addSql('ALTER TABLE bolt_post_tag DROP FOREIGN KEY FK_C7690CDBAD26311'); $this->addSql('ALTER TABLE bolt_post DROP FOREIGN KEY FK_807F8D56F675F31B'); + $this->addSql('ALTER TABLE bolt_content DROP FOREIGN KEY FK_F5AB2E9CF675F31B'); $this->addSql('ALTER TABLE bolt_comment DROP FOREIGN KEY FK_9F1A4C59F675F31B'); - $this->addSql('CREATE TABLE symfony_demo_comment (id INT AUTO_INCREMENT NOT NULL, post_id INT NOT NULL, author_id INT NOT NULL, content LONGTEXT NOT NULL COLLATE utf8mb4_unicode_ci, published_at DATETIME NOT NULL, INDEX IDX_53AD8F834B89032C (post_id), INDEX IDX_53AD8F83F675F31B (author_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB'); - $this->addSql('CREATE TABLE symfony_demo_post (id INT AUTO_INCREMENT NOT NULL, author_id INT NOT NULL, title VARCHAR(255) NOT NULL COLLATE utf8mb4_unicode_ci, slug VARCHAR(255) NOT NULL COLLATE utf8mb4_unicode_ci, summary VARCHAR(255) NOT NULL COLLATE utf8mb4_unicode_ci, content LONGTEXT NOT NULL COLLATE utf8mb4_unicode_ci, published_at DATETIME NOT NULL, INDEX IDX_58A92E65F675F31B (author_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB'); - $this->addSql('CREATE TABLE symfony_demo_post_tag (post_id INT NOT NULL, tag_id INT NOT NULL, INDEX IDX_6ABC1CC44B89032C (post_id), INDEX IDX_6ABC1CC4BAD26311 (tag_id), PRIMARY KEY(post_id, tag_id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB'); - $this->addSql('CREATE TABLE symfony_demo_tag (id INT AUTO_INCREMENT NOT NULL, name VARCHAR(190) NOT NULL COLLATE utf8mb4_unicode_ci, UNIQUE INDEX UNIQ_4D5855405E237E06 (name), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB'); - $this->addSql('CREATE TABLE symfony_demo_user (id INT AUTO_INCREMENT NOT NULL, full_name VARCHAR(255) NOT NULL COLLATE utf8mb4_unicode_ci, username VARCHAR(190) NOT NULL COLLATE utf8mb4_unicode_ci, email VARCHAR(190) NOT NULL COLLATE utf8mb4_unicode_ci, password VARCHAR(255) NOT NULL COLLATE utf8mb4_unicode_ci, roles LONGTEXT NOT NULL COLLATE utf8mb4_unicode_ci COMMENT \'(DC2Type:json)\', UNIQUE INDEX UNIQ_8FB094A1F85E0677 (username), UNIQUE INDEX UNIQ_8FB094A1E7927C74 (email), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB'); - $this->addSql('ALTER TABLE symfony_demo_comment ADD CONSTRAINT FK_53AD8F834B89032C FOREIGN KEY (post_id) REFERENCES symfony_demo_post (id)'); - $this->addSql('ALTER TABLE symfony_demo_comment ADD CONSTRAINT FK_53AD8F83F675F31B FOREIGN KEY (author_id) REFERENCES symfony_demo_user (id)'); - $this->addSql('ALTER TABLE symfony_demo_post ADD CONSTRAINT FK_58A92E65F675F31B FOREIGN KEY (author_id) REFERENCES symfony_demo_user (id)'); - $this->addSql('ALTER TABLE symfony_demo_post_tag ADD CONSTRAINT FK_6ABC1CC44B89032C FOREIGN KEY (post_id) REFERENCES symfony_demo_post (id) ON DELETE CASCADE'); - $this->addSql('ALTER TABLE symfony_demo_post_tag ADD CONSTRAINT FK_6ABC1CC4BAD26311 FOREIGN KEY (tag_id) REFERENCES symfony_demo_tag (id) ON DELETE CASCADE'); + $this->addSql('ALTER TABLE bolt_field DROP FOREIGN KEY FK_4A2EBBE584A0A3ED'); $this->addSql('DROP TABLE bolt_post'); $this->addSql('DROP TABLE bolt_post_tag'); $this->addSql('DROP TABLE bolt_tag'); diff --git a/src/Repository/ContentRepository.php b/src/Repository/ContentRepository.php index a3c8df79..6e276465 100644 --- a/src/Repository/ContentRepository.php +++ b/src/Repository/ContentRepository.php @@ -3,7 +3,11 @@ namespace Bolt\Repository; use Bolt\Entity\Content; +use Bolt\Entity\Tag; use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; +use Doctrine\ORM\Query; +use Pagerfanta\Adapter\DoctrineORMAdapter; +use Pagerfanta\Pagerfanta; use Symfony\Bridge\Doctrine\RegistryInterface; /** @@ -19,6 +23,34 @@ class ContentRepository extends ServiceEntityRepository parent::__construct($registry, Content::class); } + + public function findLatest(int $page = 1, Tag $tag = null): Pagerfanta + { + $qb = $this->createQueryBuilder('p') + ->addSelect('a') //, 't' + ->innerJoin('p.author', 'a') +// ->leftJoin('p.tags', 't') + ->where('p.publishedAt <= :now') + ->orderBy('p.publishedAt', 'DESC') + ->setParameter('now', new \DateTime()); + +// if (null !== $tag) { +// $qb->andWhere(':tag MEMBER OF p.tags') +// ->setParameter('tag', $tag); +// } + + return $this->createPaginator($qb->getQuery(), $page); + } + + private function createPaginator(Query $query, int $page): Pagerfanta + { + $paginator = new Pagerfanta(new DoctrineORMAdapter($query)); + $paginator->setMaxPerPage(Content::NUM_ITEMS); + $paginator->setCurrentPage($page); + + return $paginator; + } + // /** // * @return Content[] Returns an array of Content objects // */ diff --git a/templates/blog/listing.html.twig b/templates/blog/listing.html.twig new file mode 100644 index 00000000..c0424336 --- /dev/null +++ b/templates/blog/listing.html.twig @@ -0,0 +1,46 @@ +{% extends 'base.html.twig' %} + +{% block body_id 'blog_index' %} + +{% block main %} + {{ dump(records) }} + {% for record in records %} + {{ dump(record) }} + {% endfor %} + {# +
+

+ + {{ post.title }} + +

+ + + + {{ post.summary|md2html }} + + {{ include('blog/_post_tags.html.twig') }} +
+ {% else %} +
{{ 'post.no_posts_found'|trans }}
+ {% endfor %} + + #} + + {% if records.haveToPaginate %} + + {% endif %} + +{% endblock %} + +{% block sidebar %} + {{ parent() }} + + {{ show_source_code(_self) }} + {{ include('blog/_rss.html.twig') }} +{% endblock %}