Skip to content

Commit

Permalink
feat: paginator support (#142)
Browse files Browse the repository at this point in the history
* feat: mark count() methods as <0, max> range

* feat: paginator
  • Loading branch information
dkarlovi authored Jul 19, 2022
1 parent 615bb60 commit 10c112c
Show file tree
Hide file tree
Showing 28 changed files with 432 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ public function process(ContainerBuilder $container): void
}
$this->classMetadataFactory = $classMetadata;

/** @var array<string, array{storage: string, class: class-string, options?: array}> $configuredDatabases */
/** @var array<string, array{storage: string, class: class-string, page_limit: int<1, max>, options?: array}> $configuredDatabases */
$configuredDatabases = $container->getParameter('sigwin_yassg.databases_spec');
foreach ($configuredDatabases as $name => $database) {
$type = $database['storage'];
Expand Down Expand Up @@ -109,6 +109,7 @@ public function process(ContainerBuilder $container): void
->setArgument(0, new Reference($storageId))
->setArgument(1, new Reference('sigwin_yassg.expression_language'))
->setArgument(2, $this->getProperties($databaseClass))
->setArgument(3, $database['page_limit'])
->addTag('sigwin_yassg.database', ['name' => $name]);
$databaseId = sprintf('sigwin_yassg.database.%1$s', $name);
$container->setDefinition($databaseId, $databaseDefinition);
Expand Down
5 changes: 5 additions & 0 deletions src/Bridge/Symfony/DependencyInjection/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,11 @@ public function getConfigTreeBuilder(): TreeBuilder
->scalarNode('class')
->isRequired()
->end()
->scalarNode('page_limit')
->defaultValue(20)
->cannotBeEmpty()
->info('How many items per page are by default used when paginating this database')
->end()
->variableNode('options')
// only with type: filesystem
->end()
Expand Down
10 changes: 10 additions & 0 deletions src/Bridge/Symfony/ExpressionLanguage/FunctionProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,16 @@ public function getFunctions(): array

return $provider->getDatabase($name)->findAll(...$arguments);
}),
new ExpressionFunction('yassg_pages', static function (string $name): string {
return sprintf('$provider->getDatabase(%s)', $name);
}, static function (array $variables, string $name, ?string $condition = null, ?int $limit = null) {
/** @var DatabaseProvider $provider */
$provider = $variables['provider'];
$database = $provider->getDatabase($name);
$count = $database->count($condition);

return range(1, ceil($count / ($limit ?? $database->getPageLimit())));
}),
new ExpressionFunction('yassg_get', static function (string $name): string {
return sprintf('$provider->getDatabase(%s)', $name);
}, static function (array $variables, string $name, string $id) {
Expand Down
48 changes: 48 additions & 0 deletions src/Bridge/Twig/Extension/PaginatorExtension.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?php

declare(strict_types=1);

/*
* This file is part of the yassg project.
*
* (c) sigwin.hr
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/

namespace Sigwin\YASSG\Bridge\Twig\Extension;

use Sigwin\YASSG\DatabaseProvider;
use Twig\Extension\AbstractExtension;
use Twig\TwigFunction;

final class PaginatorExtension extends AbstractExtension
{
private DatabaseProvider $provider;

public function __construct(DatabaseProvider $provider)
{
$this->provider = $provider;
}

public function getFunctions(): array
{
return [
new TwigFunction('yassg_pages', function (string $name, ?string $condition = null, ?int $limit = null) {
$database = $this->provider->getDatabase($name);
$count = $database->count($condition);

return range(1, ceil($count / ($limit ?? $database->getPageLimit())));
}),
new TwigFunction('yassg_paginate', function (string $name, int $page, array $conditions = []) {
$database = $this->provider->getDatabase($name);

$conditions['limit'] ??= $database->getPageLimit();
$conditions['offset'] = ($page - 1) * $conditions['limit'];

return $database->findAll(...$conditions);
}),
];
}
}
2 changes: 2 additions & 0 deletions src/Collection.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,6 @@
interface Collection extends \ArrayAccess, \Countable, \IteratorAggregate
{
public function column(string $name): array;

public function total(): int;
}
9 changes: 8 additions & 1 deletion src/Collection/ReadOnlyCollection.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,19 +25,26 @@ final class ReadOnlyCollection implements Collection
private ExpressionLanguage $expressionLanguage;
private array $names;
private array $data;
private int $total;

public function __construct(ExpressionLanguage $expressionLanguage, array $names, array $data)
public function __construct(ExpressionLanguage $expressionLanguage, array $names, array $data, ?int $total = null)
{
$this->expressionLanguage = $expressionLanguage;
$this->names = $names;
$this->data = $data;
$this->total = $total ?? \count($data);
}

public function __get(string $name): object
{
return $this->data[$name];
}

public function total(): int
{
return $this->total;
}

public function column(string $name): array
{
$expression = $this->expressionLanguage->parse($name, $this->names);
Expand Down
11 changes: 11 additions & 0 deletions src/Database.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,19 @@
*/
interface Database
{
/**
* @return int<1, max>
*/
public function getPageLimit(): int;

/**
* @return int<0, max>
*/
public function count(?string $condition = null): int;

/**
* @return int<0, max>
*/
public function countBy(array $condition): int;

/**
Expand Down
8 changes: 6 additions & 2 deletions src/Database/CachingDatabase.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,16 +36,20 @@ public function __construct(string $name, Database $database, CacheItemPoolInter
$this->localeContext = $localeContext;
$this->expressionLanguage = $expressionLanguage;
$this->names = $names;
$this->limit = $this->database->getPageLimit();
}

/**
* @return int<0, max>
*/
public function count(?string $condition = null): int
{
$locale = $this->localeContext->getLocale()[LocaleContext::LOCALE];
$cacheKey = $this->name.'_count_'.$locale.'_'.$condition;

$item = $this->cacheItemPool->getItem($cacheKey);
if ($item->isHit()) {
/** @var int $count */
/** @var int<0, max> $count */
$count = $item->get();

return $count;
Expand Down Expand Up @@ -73,7 +77,7 @@ public function findAll(?string $condition = null, ?array $sort = null, ?int $li
$storage[$id] = $this->get($id);
}

return $this->createCollection($storage);
return $this->createCollection($storage, $this->database->count($condition));
}

$collection = $this->database->findAll($condition, $sort, $limit, $offset, $select);
Expand Down
20 changes: 18 additions & 2 deletions src/Database/DatabaseTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,22 @@ trait DatabaseTrait
private ExpressionLanguage $expressionLanguage;
private array $names;

/**
* @var int<1, max>
*/
private int $limit;

/**
* @return int<1, max>
*/
public function getPageLimit(): int
{
return $this->limit;
}

/**
* @return int<0, max>
*/
public function countBy(array $condition): int
{
return $this->count($this->conditionArrayToString($condition));
Expand Down Expand Up @@ -96,8 +112,8 @@ private function conditionArrayToString(array $condition): ?string
return implode(' AND ', $condition);
}

private function createCollection(array $storage): Collection
private function createCollection(array $storage, int $total): Collection
{
return new Collection\ReadOnlyCollection($this->expressionLanguage, $this->names, $storage);
return new Collection\ReadOnlyCollection($this->expressionLanguage, $this->names, $storage, $total);
}
}
7 changes: 5 additions & 2 deletions src/Database/MemoryDatabase.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,14 @@ final class MemoryDatabase implements Database

/**
* @param array<string> $names
* @param int<1, max> $limit
*/
public function __construct(Storage $storage, ExpressionLanguage $expressionLanguage, array $names)
public function __construct(Storage $storage, ExpressionLanguage $expressionLanguage, array $names, int $limit)
{
$this->storage = $storage;
$this->expressionLanguage = $expressionLanguage;
$this->names = $names;
$this->limit = $limit;
}

public function count(?string $condition = null): int
Expand Down Expand Up @@ -75,12 +77,13 @@ public function findAll(?string $condition = null, ?array $sort = null, ?int $li
});
}

$total = \count($storage);
$storage = \array_slice($storage, $offset, $limit, true);
if ($select !== null) {
$storage = array_combine(array_keys($storage), array_column($storage, $select));
}

return $this->createCollection($storage);
return $this->createCollection($storage, $total);
}

public function get(string $id): object
Expand Down
1 change: 1 addition & 0 deletions tests/functional/site/config/packages/yassg_databases.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ sigwin_yassg:
articles:
class: Sigwin\YASSG\Test\Functional\Site\Model\Article
storage: filesystem
page_limit: 2
options:
root:
- "%sigwin_yassg.base_dir%/content/articles"
Expand Down
6 changes: 6 additions & 0 deletions tests/functional/site/config/packages/yassg_routes.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ sigwin_yassg:
path: /{_locale}/article/{slug}
catalog:
slug: "yassg_find_all('articles').column('slug')"
articles:
path: /{_locale}/articles/{page}
defaults:
page: 1
catalog:
page: "yassg_pages('articles', 'item.publishedAt.getTimestamp() <= 1658238497')"
product:
path: /{_locale}/{slug}
catalog:
Expand Down
4 changes: 2 additions & 2 deletions tests/functional/site/content/articles/hello-world.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
---
title: Hello World!
slug: hello-world
publishedAt: "2022-07-18 12:44:13"
---
# Hello World!

here I am, writing some Markdown.

Fine.
Expand Down
17 changes: 17 additions & 0 deletions tests/functional/site/content/articles/lists.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
title: Lists!
slug: lists
publishedAt: "2022-07-19 12:13:00"
---

## Ordered lists

1. one
2. two
3. three

## Unordered lists

- a thing
- another thing
- yet another thing
10 changes: 10 additions & 0 deletions tests/functional/site/content/articles/paragraphs.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
title: Paragraphs!
slug: paragraphs
publishedAt: "2022-07-19 12:09:00"
---
Paragraph.

Paragraph.

Paragraph.
6 changes: 6 additions & 0 deletions tests/functional/site/content/articles/the-future.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
title: Welcome to the world of tomorrow!
slug: world-of-tomorrow
publishedAt: "9999-12-31 23:59:59"
---
Welcome!
17 changes: 17 additions & 0 deletions tests/functional/site/content/articles/titles.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
title: Titles!
slug: titles
publishedAt: "2022-07-19 12:11:00"
---

# Title 1

## Title 2

### Title 3

#### Title 4

##### Title 5

###### Title 6
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="https://cdn.tailwindcss.com?plugins=typography"></script>

<title>hello-world</title>
<title>Hello World!</title>

<link rel="stylesheet" href="/sub/dir/another/assets/app.d4da4e7e.css" integrity="sha384-t9qUhz8OfBEKvYdnnNndPZAf+S5Q3p0dBnxLn+5SShoNhInHUF+Bu8WJTo+FQJYJ">
</head>
Expand All @@ -15,7 +15,8 @@
<div class="mt-8 sm:mx-auto sm:w-full sm:max-w-xl">
<div class="bg-white py-8 px-4 shadow sm:rounded-lg sm:px-10 prose">
<h1>Hello World!</h1>
<p>here I am, writing some Markdown.</p>
<p>18.07.2022. 12:44</p>
<p>here I am, writing some Markdown.</p>
<p>Fine.</p>
<pre><code class="language-php hljs php" data-lang="php"><span class="loc"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">HelloWorld</span></span></span>
<span class="loc"><span class="hljs-class"></span>{</span>
Expand Down
38 changes: 38 additions & 0 deletions tests/functional/site/fixtures/en/article/lists/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="https://cdn.tailwindcss.com?plugins=typography"></script>

<title>Lists!</title>

<link rel="stylesheet" href="/sub/dir/another/assets/app.d4da4e7e.css" integrity="sha384-t9qUhz8OfBEKvYdnnNndPZAf+S5Q3p0dBnxLn+5SShoNhInHUF+Bu8WJTo+FQJYJ">
</head>
<body>

<main class="min-h-full flex flex-col justify-center py-12 sm:px-6 lg:px-8">
<div class="mt-8 sm:mx-auto sm:w-full sm:max-w-xl">
<div class="bg-white py-8 px-4 shadow sm:rounded-lg sm:px-10 prose">
<h1>Lists!</h1>
<p>19.07.2022. 12:13</p>
<h2>Ordered lists</h2>
<ol>
<li>one</li>
<li>two</li>
<li>three</li>
</ol>
<h2>Unordered lists</h2>
<ul>
<li>a thing</li>
<li>another thing</li>
<li>yet another thing</li>
</ul>

</div>
</div>
</main>

<script src="/sub/dir/another/assets/runtime.4d1205b9.js" integrity="sha384-J2jFm3DPgrcqyvls0fZlS51nUYgiBB+JLwWiU5v7vxEbLwKolmaHrRuz4BjP6qaE"></script><script src="/sub/dir/another/assets/app.9267444a.js" integrity="sha384-WbAUi92ziCGFD1kGZRzpOP8Nxymnw5vXM3szOB1JmBrCU+MVGXBRReCttizXHDdI"></script>
</body>
</html>
Loading

0 comments on commit 10c112c

Please sign in to comment.