Skip to content

Commit 5375aea

Browse files
committed
Static pages
1 parent 4c7648f commit 5375aea

14 files changed

Lines changed: 699 additions & 222 deletions

src/App/templates/layout/default.html.twig

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
<a class="nav-link px-3 fw-semibold fs-5 transition-all" target="_blank" href="https://docs.dotkernel.org/">Documentation</a>
3535
</li>
3636
<li class="nav-item">
37-
<a class="nav-link px-3 fw-semibold fs-5 transition-all" href="{{ url('page::dotkernel-packages-oss-lifecycle') }}">Packages Lifecycle</a>
37+
<a class="nav-link px-3 fw-semibold fs-5 transition-all" href="{{ url('page::static-page', {'static-page': 'dotkernel-packages-oss-lifecycle'}) }}">Packages Lifecycle</a>
3838
</li>
3939
<li class="nav-item">
4040
<a class="nav-link px-3 fw-semibold fs-5 transition-all" href="{{ url('page::category-resource', {slug: 'how-to'}) }}">How to's</a>
@@ -47,7 +47,7 @@
4747
</li>
4848
</ul>
4949
<div class="d-none d-lg-block">
50-
<a href="{{ url('page::contact') }}" class="btn btn-primary rounded-pill px-4">Contact</a>
50+
<a href="{{ url('page::static-page', {'static-page': 'contact'}) }}" class="btn btn-primary rounded-pill px-4">Contact</a>
5151
</div>
5252
</div>
5353
</div>

src/App/templates/partial/left-menu.html.twig

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@
2323
class="list-group-item list-group-item-action border-0 px-1 py-2 rounded">
2424
<p class="mb-1 small fw-semibold text-dark lh-sm">{{ article.title }}</p>
2525
<span class="text-muted" >
26-
<i class="bi bi-calendar3 me-1"></i>{{ article.postDate|date('M d, Y') }}
27-
</span>
26+
<i class="bi bi-calendar3 me-1"></i>{{ article.postDate|date('M d, Y') }}
27+
</span>
2828
</a>
2929
{% else %}
3030
<p class="text-muted small mb-0">No recent articles.</p>
@@ -52,9 +52,31 @@
5252
See all categories <i class="bi bi-arrow-right fs-7"></i>
5353
</a>
5454
</div>
55+
</div>
56+
</div>
57+
{% if posts is defined and posts %}
58+
<div class="card border-0 shadow-sm rounded-3 my-2">
59+
<div class="card-body p-3">
60+
<h6 class="fw-bold text-uppercase text-muted small px-1 mb-2">Recent Articles</h6>
5561

62+
<div class="list-group list-group-flush">
63+
64+
{% for post in posts %}
65+
<a href="{{ url('page::blog-resource', {categorySlug: post.category.slug, slug: post.slug}) }}"
66+
class="list-group-item list-group-item-action border-0 px-1 py-2 rounded">
67+
<p class="mb-1 small fw-semibold text-dark lh-sm">{{ post.title }}</p>
68+
<span class="text-muted">
69+
<i class="bi bi-calendar3 me-1"></i>{{ post.postDate|date('M d, Y') }}
70+
</span>
71+
</a>
72+
{% else %}
73+
<p class="text-muted small mb-0">No recent articles.</p>
74+
{% endfor %}
75+
76+
</div>
77+
</div>
5678
</div>
79+
{% endif %}
5780

58-
</div>
5981
</div>
6082
</aside>

src/Blog/src/ConfigProvider.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,13 @@
1414
use Light\Blog\Factory\Post\PostCollectionHandlerFactory;
1515
use Light\Blog\Factory\Post\PostCollectionRepositoryFactory;
1616
use Light\Blog\Factory\Post\PostResourceHandlerFactory;
17+
use Light\Blog\Factory\StaticPages\GetStaticPageDataFactory;
1718
use Light\Blog\Handler\GetAuthorResourceHandler;
1819
use Light\Blog\Handler\GetCategoryCollectionHandler;
1920
use Light\Blog\Handler\GetCategoryResourceHandler;
2021
use Light\Blog\Handler\GetPostCollectionHandler;
2122
use Light\Blog\Handler\GetPostResourceHandler;
23+
use Light\Blog\Handler\GetStaticPageDataHandler;
2224
use Light\Blog\Repository\AuthorRepository;
2325
use Light\Blog\Repository\CategoryRepository;
2426
use Light\Blog\Repository\PostRepository;
@@ -64,6 +66,7 @@ private function getDependencies(): array
6466
GetCategoryResourceHandler::class => CategoryResourceHandlerFactory::class,
6567
AuthorRepository::class => AuthorResourceRepositoryFactory::class,
6668
GetAuthorResourceHandler::class => AuthorResourceHandlerFactory::class,
69+
GetStaticPageDataHandler::class => GetStaticPageDataFactory::class,
6770
],
6871
];
6972
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Light\Blog\Factory\StaticPages;
6+
7+
use Light\Blog\Handler\GetStaticPageDataHandler;
8+
use Light\Blog\Repository\CategoryRepository;
9+
use Light\Blog\Repository\PostRepository;
10+
use Mezzio\Template\TemplateRendererInterface;
11+
use Psr\Container\ContainerExceptionInterface;
12+
use Psr\Container\ContainerInterface;
13+
use Psr\Container\NotFoundExceptionInterface;
14+
15+
use function assert;
16+
17+
class GetStaticPageDataFactory
18+
{
19+
/**
20+
* @throws ContainerExceptionInterface
21+
* @throws NotFoundExceptionInterface
22+
*/
23+
public function __invoke(ContainerInterface $container, string $requestedName): GetStaticPageDataHandler
24+
{
25+
$repository = $container->get(PostRepository::class);
26+
$categoryRepository = $container->get(CategoryRepository::class);
27+
$template = $container->get(TemplateRendererInterface::class);
28+
29+
assert($repository instanceof PostRepository);
30+
assert($template instanceof TemplateRendererInterface);
31+
32+
return new GetStaticPageDataHandler($template, $repository, $categoryRepository);
33+
}
34+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Light\Blog\Handler;
6+
7+
use Laminas\Diactoros\Response\HtmlResponse;
8+
use Light\Blog\Repository\CategoryRepository;
9+
use Light\Blog\Repository\PostRepository;
10+
use Mezzio\Template\TemplateRendererInterface;
11+
use Psr\Http\Message\ResponseInterface;
12+
use Psr\Http\Message\ServerRequestInterface;
13+
use Psr\Http\Server\RequestHandlerInterface;
14+
use Throwable;
15+
16+
class GetStaticPageDataHandler implements RequestHandlerInterface
17+
{
18+
public function __construct(
19+
protected TemplateRendererInterface $template,
20+
protected PostRepository $articleRepository,
21+
protected CategoryRepository $categoryRepository,
22+
) {
23+
}
24+
25+
public function handle(ServerRequestInterface $request): ResponseInterface
26+
{
27+
$staticPage = $request->getAttribute('static-page');
28+
29+
$posts = $this->articleRepository->getRecentPosts(3);
30+
$categories = $this->categoryRepository->getCategories();
31+
32+
try {
33+
$html = $this->template->render('page::' . $staticPage, [
34+
'categories' => $categories,
35+
'posts' => $posts,
36+
]);
37+
} catch (Throwable $e) {
38+
return $this->notFound();
39+
}
40+
41+
return new HtmlResponse($html);
42+
}
43+
44+
private function notFound(): HtmlResponse
45+
{
46+
$categories = $this->categoryRepository->getCategories();
47+
48+
return new HtmlResponse(
49+
$this->template->render('error::404', [
50+
'categories' => $categories,
51+
]),
52+
404
53+
);
54+
}
55+
}

src/Blog/src/Repository/PostRepository.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,4 +67,20 @@ public function getArticleByAuthor(Author $author, array $params): DoctrinePagin
6767

6868
return new DoctrinePaginator($qb->getQuery());
6969
}
70+
71+
/**
72+
* @return array<int, Post>
73+
*/
74+
public function getRecentPosts(int $limit = 5): array
75+
{
76+
$qb = $this->getQueryBuilder()
77+
->select('articles')
78+
->from(Post::class, 'articles')
79+
->where('articles.status = :published')
80+
->setParameter('published', PostStatusEnum::Published)
81+
->orderBy('articles.postDate', 'DESC')
82+
->setMaxResults($limit);
83+
84+
return $qb->getQuery()->getResult();
85+
}
7086
}

src/Blog/src/RoutesDelegator.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use Light\Blog\Handler\GetCategoryResourceHandler;
1010
use Light\Blog\Handler\GetPostCollectionHandler;
1111
use Light\Blog\Handler\GetPostResourceHandler;
12+
use Light\Blog\Handler\GetStaticPageDataHandler;
1213
use Mezzio\Application;
1314
use Psr\Container\ContainerInterface;
1415

@@ -25,6 +26,8 @@ public function __invoke(ContainerInterface $container, string $serviceName, cal
2526
$app->get('/categories/', [GetCategoryCollectionHandler::class], 'page::categories');
2627
$app->get('/author/{slug}/', [GetAuthorResourceHandler::class], 'page::author-resource');
2728
$app->get('/{categorySlug}/{slug}/', [GetPostResourceHandler::class], 'page::blog-resource');
29+
30+
$app->get('/{static-page}/', [GetStaticPageDataHandler::class], 'page::static-page');
2831
return $app;
2932
}
3033
}

src/Blog/templates/page/category-resource/architecture.html.twig

Lines changed: 0 additions & 41 deletions
This file was deleted.

src/Blog/templates/page/category-resource/default.html.twig

Lines changed: 0 additions & 41 deletions
This file was deleted.

src/Blog/templates/page/category-resource/dotkernel.html.twig

Lines changed: 0 additions & 41 deletions
This file was deleted.

0 commit comments

Comments
 (0)