Projekt - část 13

Projekt - část 13

V tomto úkolu si zprovozníme načítání článků na blog z databáze.

1. Nejprve si v admineru vytvoříme tabulku s názvem blog_post s následující strukturou:

adminer

2. Dále ve složce Class vytvoříme soubory BlogPost.php a BlogPostRepository.php s následujícím obsahem:

<?php

class BlogPost
{
  private ?int $id;

  private string $title;

  private string $subtitle;

  private string $text;

  private string $image;

  private string $author;

  private DateTime $createdAt;

  public function __construct(string $title, string $subtitle, string $text, string $image, string $author, DateTime $createdAt, ?int $id = null)
  {
    $this->id = $id;
    $this->title = $title;
    $this->subtitle = $subtitle;
    $this->text = $text;
    $this->image = $image;
    $this->author = $author;
    $this->createdAt = $createdAt;
  }


  public function getId(): int|null
  {
    return $this->id;
  }

  public function setId(int|null $id): void
  {
    $this->id = $id;
  }

  public function getTitle(): string
  {
    return $this->title;
  }

  public function setTitle(string $title): void
  {
    $this->title = $title;
  }

  public function getSubtitle(): string
  {
    return $this->subtitle;
  }

  public function setSubtitle(string $subtitle): void
  {
    $this->subtitle = $subtitle;
  }

  public function getText(): string
  {
    return $this->text;
  }

  public function setText(string $text): void
  {
    $this->text = $text;
  }

  public function getImage(): string
  {
    return $this->image;
  }

  public function setImage(string $image): void
  {
    $this->image = $image;
  }

  public function getAuthor(): string
  {
    return $this->author;
  }

  public function setAuthor(string $author): void
  {
    $this->author = $author;
  }

  public function getCreatedAt(): DateTime
  {
    return $this->createdAt;
  }

  public function setCreatedAt(DateTime $createdAt): void
  {
    $this->createdAt = $createdAt;
  }
}
<?php

class BlogPostRepository
{
  private PDO $pdo;

  public function __construct()
  {
    $this->pdo = (new Connection())->getPdo();
  }

  public function findBlogPostById(int $id): ?BlogPost
  {
    $stmt = $this->pdo->prepare('SELECT * FROM blog_post WHERE id = :id');

    $stmt->execute([':id' => $id]);
    $blogPost = $stmt->fetch(PDO::FETCH_ASSOC);

    if ($blogPost) {
      return new BlogPost($blogPost['title'], $blogPost['subtitle'], $blogPost['text'], $blogPost['image'], $blogPost['author'], new DateTime($blogPost['created_at']), $blogPost['id']);
    }

    return null;
  }

  public function findBlogPosts(?int $limit = null): array
  {
    if ($limit) {
      $stmt = $this->pdo->prepare('SELECT * FROM blog_post ORDER BY created_at DESC limit :limit');
      $stmt->bindParam(':limit', $limit, PDO::PARAM_INT);
    } else {
      $stmt = $this->pdo->prepare('SELECT * FROM blog_post ORDER BY created_at DESC');
    }

    $stmt->execute();
    $result = $stmt->fetchAll(PDO::FETCH_ASSOC);
    $blogPosts = [];
    foreach ($result as $blogPost) {
      $blogPosts[] = new BlogPost($blogPost['title'], $blogPost['subtitle'], $blogPost['text'], $blogPost['image'], $blogPost['author'], new DateTime($blogPost['created_at']), $blogPost['id']);
    }

    return $blogPosts;
  }

  public function saveBlogPost(BlogPost $blogPost): BlogPost
  {
    if (!$blogPost->getId()) {
      $stmt = $this->pdo->prepare('INSERT INTO blog_post (title, subtitle, text, image, author, created_at) VALUES (:title, :subtitle, :text, :image, :author, :created_at)');
      $stmt->execute([
        ':title' => $blogPost->getTitle(),
        ':subtitle' => $blogPost->getSubtitle(),
        ':text' => $blogPost->getText(),
        ':image' => $blogPost->getImage(),
        ':author' => $blogPost->getAuthor(),
        ':created_at' => $blogPost->getCreatedAt()->format('Y-m-d H:i:s'),
      ]);

      return $this->findBlogPostById($this->pdo->lastInsertId());
    } else {
      $stmt = $this->pdo->prepare('UPDATE blog_post SET title = :title, subtitle = :subtitle, text = :text, image = :image, author = :author, created_at = :created_at  WHERE id = :id');
      $stmt->execute([
        ':title' => $blogPost->getTitle(),
        ':subtitle' => $blogPost->getSubtitle(),
        ':text' => $blogPost->getText(),
        ':image' => $blogPost->getImage(),
        ':author' => $blogPost->getAuthor(),
        ':created_at' => $blogPost->getCreatedAt()->format('Y-m-d H:i:s'),
        ':id' => $blogPost->getId(),
      ]);

      return $this->findBlogPostById($blogPost->getId());
    }
  }

  public function getBlogPostsTotalCount(): int
  {
    $stmt = $this->pdo->prepare('SELECT count(*) FROM blog_post');
    $stmt->execute();

    return (int) $stmt->fetchColumn();
  }

  public function deleteBlogPost(BlogPost $blogPost): int
  {
    $stmt = $this->pdo->prepare('DELETE FROM blog_post WHERE id = :id');
    $stmt->execute([':id' => $blogPost->getId()]);

    return $blogPost->getId();
  }
}

3. Dále vytvoříme ve složce controller soubor blog.php s následujícím obsahem:

<?php

$blogPostRepository = new BlogPostRepository();

$id = $_GET['id'] ?? null;

if ($id) {
  $clanek = $blogPostRepository->findBlogPostById($id);
  if ($clanek) {
    $sablona = 'blogDetail';
  } else {
    $sablona = '404';
  }
} else {
  $sablona = 'blog';

  $clanky = $blogPostRepository->findBlogPosts();
}

4. Controller pro blog funguje tak, že se pokusí najít GET parametr id, pokud jej najde, tak bude zobrazovat šablonu pro detail článku a pokud ne, tak vypíše všechny články. Nyní si teda ve složce sablony vytvoříme soubory blog.php a blogDetail.php

<!--blog.php-->
<!-- Page Header-->
<header class="masthead" style="background-image: url('assets/img/home-bg.jpg')">
  <div class="container position-relative px-4 px-lg-5">
    <div class="row gx-4 gx-lg-5 justify-content-center">
      <div class="col-md-10 col-lg-8 col-xl-7">
        <div class="site-heading">
          <h1>Blog</h1>
          <span class="subheading">Moje články na blogu</span>
        </div>
      </div>
    </div>
  </div>
</header>
<!-- Main Content-->
<div class="container px-4 px-lg-5 mt-4">
  <div class="row gx-4 gx-lg-5 justify-content-center">

    <!-- Blog section -->
    <section class="col-md-10 m-a">
      <h2>Blog</h2>
      <?php
      /** @var BlogPost $clanek */
      foreach ($clanky as $clanek) :
      ?>
        <!-- Post preview-->
        <article class="post-preview">
          <a href="?stranka=blog&id=<?php echo $clanek->getId(); ?>">
            <div class="row">
              <div class="col-md-4">
                <img src="<?php echo $clanek->getImage(); ?>" class="img-fluid" />
              </div>
              <div class="col-md-8">
                <h3 class="post-title">
                  <?php echo $clanek->getTitle(); ?>
                </h3>
              </div>
              <div class="col-12 mt-3">
                <h4 class="post-subtitle">
                  <?php echo $clanek->getSubtitle(); ?>
                </h4>
              </div>
            </div>
          </a>
          <p class="post-meta">
            Posted by
            <em><?php echo $clanek->getAuthor(); ?></em>
            on <?php echo $clanek->getCreatedAt()->format('j. n. Y'); ?>
          </p>
        </article>
        <!-- Divider-->
        <hr class="my-4" />
      <?php endforeach; ?>
    </section>
  </div>
</div>
<!--blogDetail.php-->
<?php

/** @var BlogPost $clanek */
?>
<!-- Page Header-->
<header class="masthead" style="background-image: url('<?php echo $clanek->getImage(); ?>')">
  <div class="container position-relative px-4 px-lg-5">
    <div class="row gx-4 gx-lg-5 justify-content-center">
      <div class="col-md-10 col-lg-8 col-xl-7">
        <div class="post-heading">
          <h1><?php echo $clanek->getTitle(); ?></h1>
          <h2 class="subheading">
            <?php echo $clanek->getSubtitle(); ?>
          </h2>
          <span class="meta">
            Posted by
            <?php echo $clanek->getAuthor(); ?>
            dne <?php echo $clanek->getCreatedAt()->format('j. n. Y'); ?>
          </span>
        </div>
      </div>
    </div>
  </div>
</header>
<!-- Post Content-->
<article class="mb-4">
  <div class="container px-4 px-lg-5">
    <div class="row gx-4 gx-lg-5 justify-content-center">
      <div class="col-md-10 col-lg-8 col-xl-7">
        <?php echo $clanek->getText(); ?>
      </div>
    </div>
  </div>
</article>

5. Poslední tři články z blogu zobrazujeme i na domovské stránce, upravíme tedy i controller domů a část šablony s výpisem článků:

<?php

$sablona = 'domu';

$blogPostRepository = new BlogPostRepository();

$pocetClanku = $blogPostRepository->getBlogPostsTotalCount();

$clanky = $blogPostRepository->findBlogPosts(3);
<!-- ! Jedná se pouze o část šablony domu.php (section pro Blog)-->
<!-- Blog section -->
    <section class="col-md-10 col-lg-8">
      <h2>Blog</h2>
      <p>
        <?php
        echo preloz('homepage.countArticles');
        echo $pocetClanku;
        ?>.
      </p>
      <?php
      /** @var BlogPost $clanek */
      foreach ($clanky as $clanek) :
      ?>
        <!-- Post preview-->
        <article class="post-preview">
          <a href="?stranka=blog&id=<?php echo $clanek->getId(); ?>">
            <div class="row">
              <div class="col-md-4">
                <img src="<?php echo $clanek->getImage(); ?>" class="img-fluid" />
              </div>
              <div class="col-md-8">
                <h3 class="post-title">
                  <?php echo $clanek->getTitle(); ?>
                </h3>
              </div>
              <div class="col-12 mt-3">
                <h4 class="post-subtitle">
                  <?php echo $clanek->getSubtitle(); ?>
                </h4>
              </div>
            </div>
          </a>
          <p class="post-meta">
            Posted by
            <em><?php echo $clanek->getAuthor(); ?></em>
            on <?php echo $clanek->getCreatedAt()->format('j. n. Y'); ?>
          </p>
        </article>
        <!-- Divider-->
        <hr class="my-4" />
      <?php endforeach; ?>

      <!-- Pager-->
      <div class="d-flex justify-content-end mb-4">
        <a class="btn btn-primary text-uppercase" href="?stranka=blog">Starší články →</a>
      </div>
    </section>