Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: update demo #162

Merged
merged 1 commit into from
Jul 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
# 0.16.1

* fix: fix `QueryBuilderAdapter` error when WHERE statement is empty
* chore: update demo

# 0.16.0

Expand Down
11 changes: 6 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,13 @@ your data.

### Queries

This library supports queries with multiple sort columns.
Multiple sort columns are supported. The library will automatically generate the
WHERE query for you, including the complex cases involving more than two sort
columns. The only requirement is that the query needs to have a deterministic
sort order.

The required query for performing keyset pagination is complex, especially if
more than one column is used for sorting. This library handles that task
automatically. The only requirement is that the query needs to have a
deterministic sort order.
Some backends also have the option to use SQL row values syntax for a slightly
better performance.

### Bidirectional Navigation and Page Skipping

Expand Down
183 changes: 181 additions & 2 deletions tests/public/prism.css
Original file line number Diff line number Diff line change
@@ -1,3 +1,182 @@
/* PrismJS 1.29.0
https://prismjs.com/download.html#themes=prism&languages=markup+markup-templating+php */
code[class*=language-],pre[class*=language-]{color:#000;font-weight:500;background:0 0;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none}code[class*=language-] ::-moz-selection,code[class*=language-]::-moz-selection,pre[class*=language-] ::-moz-selection,pre[class*=language-]::-moz-selection{text-shadow:none;background:#b3d4fc}code[class*=language-] ::selection,code[class*=language-]::selection,pre[class*=language-] ::selection,pre[class*=language-]::selection{text-shadow:none;background:#b3d4fc}@media print{code[class*=language-],pre[class*=language-]{text-shadow:none}}pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto}:not(pre)>code[class*=language-]:not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em;white-space:normal}.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#708090}.token.punctuation{color:#999}.token.namespace{opacity:.7}.token.boolean,.token.constant,.token.deleted,.token.number,.token.property,.token.symbol,.token.tag{color:#905}.token.attr-name,.token.builtin,.token.char,.token.inserted,.token.selector,.token.string{color:#690}.language-css .token.string,.style .token.string,.token.entity,.token.operator,.token.url{color:#9a6e3a;background:hsla(0,0%,100%,.5)}.token.atrule,.token.attr-value,.token.keyword{color:#07a}.token.class-name,.token.function{color:#dd4a68}.token.important,.token.regex,.token.variable{color:#e90}.token.bold,.token.important{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help}
https://prismjs.com/download.html#themes=prism-coy&languages=markup+markup-templating+php+sql */
code[class*=language-],
pre[class*=language-] {
color: #000;
background: 0 0;
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
font-size: 1em;
text-align: left;
white-space: pre-wrap;
word-spacing: normal;
word-break: normal;
word-wrap: normal;
line-height: 1.5;
-moz-tab-size: 4;
-o-tab-size: 4;
tab-size: 4;
-webkit-hyphens: none;
-moz-hyphens: none;
-ms-hyphens: none;
hyphens: none
}

pre[class*=language-] {
position: relative;
margin: .5em 0;
overflow: visible;
padding: 1px
}

pre[class*=language-]>code {
position: relative;
z-index: 1;
border-left: 10px solid #358ccb;
box-shadow: -1px 0 0 0 #358ccb, 0 0 0 1px #dfdfdf;
background-color: #fdfdfd;
background-size: 3em 3em;
background-origin: content-box;
background-attachment: local
}

code[class*=language-] {
max-height: inherit;
height: inherit;
padding: 0 1em;
display: block;
overflow: auto
}

:not(pre)>code[class*=language-],
pre[class*=language-] {
background-color: #fdfdfd;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
margin-bottom: 1em
}

:not(pre)>code[class*=language-] {
position: relative;
padding: .2em;
border-radius: .3em;
color: #c92c2c;
border: 1px solid rgba(0, 0, 0, .1);
display: inline;
white-space: normal
}

.token.block-comment,
.token.cdata,
.token.comment,
.token.doctype,
.token.prolog {
color: #7d8b99
}

.token.punctuation {
color: #5f6364
}

.token.boolean,
.token.constant,
.token.deleted,
.token.function-name,
.token.number,
.token.property,
.token.symbol,
.token.tag {
color: #c92c2c
}

.token.attr-name,
.token.builtin,
.token.char,
.token.function,
.token.inserted,
.token.selector,
.token.string {
color: #2f9c0a
}

.token.entity,
.token.operator,
.token.url,
.token.variable {
color: #a67f59;
background: rgba(255, 255, 255, .5)
}

.token.atrule,
.token.attr-value,
.token.class-name,
.token.keyword {
color: #1990b8
}

.token.important,
.token.regex {
color: #e90
}

.language-css .token.string,
.style .token.string {
color: #a67f59;
background: rgba(255, 255, 255, .5)
}

.token.important {
font-weight: 400
}

.token.bold {
font-weight: 700
}

.token.italic {
font-style: italic
}

.token.entity {
cursor: help
}

.token.namespace {
opacity: .7
}

@media screen and (max-width:767px) {

pre[class*=language-]:after,
pre[class*=language-]:before {
bottom: 14px;
box-shadow: none
}
}

pre[class*=language-].line-numbers.line-numbers {
padding-left: 0
}

pre[class*=language-].line-numbers.line-numbers code {
padding-left: 3.8em
}

pre[class*=language-].line-numbers.line-numbers .line-numbers-rows {
left: 0
}

pre[class*=language-][data-line] {
padding-top: 0;
padding-bottom: 0;
padding-left: 0
}

pre[data-line] code {
position: relative;
padding-left: 4em
}

pre .line-highlight {
margin-top: 0
}
3 changes: 2 additions & 1 deletion tests/public/prism.js

Large diffs are not rendered by default.

124 changes: 96 additions & 28 deletions tests/src/App/Controller/DemoController.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,36 +13,59 @@

namespace Rekalogika\Rekapager\Tests\App\Controller;

use Doctrine\ORM\EntityManagerInterface;
use Rekalogika\Contracts\Rekapager\PageableInterface;
use Rekalogika\Rekapager\Bundle\Contracts\PagerFactoryInterface;
use Rekalogika\Rekapager\Bundle\PagerOptions;
use Rekalogika\Rekapager\Tests\App\Contracts\PageableGeneratorInterface;
use Rekalogika\Rekapager\Tests\App\Doctrine\SqlLogger;
use Rekalogika\Rekapager\Tests\App\Entity\Post;
use Rekalogika\Rekapager\Tests\App\Form\PagerParameters;
use Rekalogika\Rekapager\Tests\App\Form\PagerParametersType;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\DependencyInjection\Attribute\TaggedIterator;
use Symfony\Component\DependencyInjection\Attribute\AutowireIterator;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\VarDumper\Cloner\VarCloner;
use Symfony\Component\VarDumper\Dumper\HtmlDumper;

/** @psalm-suppress PropertyNotSetInConstructor */
class DemoController extends AbstractController
{
/**
* @var array<array-key,PageableGeneratorInterface<array-key,mixed>>
*/
private readonly array $pageableGenerators;

/**
* @param iterable<PageableGeneratorInterface<array-key,mixed>> $pageableGenerators
* @psalm-suppress DeprecatedClass
*/
public function __construct(
#[TaggedIterator('rekalogika.rekapager.pageable_generator', defaultIndexMethod: 'getKey')]
private readonly iterable $pageableGenerators,
#[AutowireIterator('rekalogika.rekapager.pageable_generator', defaultIndexMethod: 'getKey')]
iterable $pageableGenerators
) {
/**
* @psalm-suppress InvalidArgument
* @psalm-suppress MixedPropertyTypeCoercion
*/
$this->pageableGenerators = iterator_to_array($pageableGenerators);
}

#[Route('/', name: 'index')]
public function index(): Response
{
return $this->render('app/index.html.twig', [
'pageable_generators' => $this->pageableGenerators,
]);
}

/**
* @param PagerFactoryInterface<PagerOptions> $pagerFactory
*/
#[Route('/{key?}', name: 'rekapager')]
public function index(
#[Route('/page/{key?}', name: 'page')]
public function page(
Request $request,
SqlLogger $logger,
PagerFactoryInterface $pagerFactory,
Expand All @@ -53,27 +76,7 @@ public function index(
/** @var PagerParameters */
$pagerParameters = $form->getData();


/** @psalm-suppress InvalidArgument */
$pageableGenerators = iterator_to_array($this->pageableGenerators);

/** @var array<string,PageableGeneratorInterface<array-key,mixed>> $pageableGenerators */

if ($key === null) {
foreach ($pageableGenerators as $pageableGenerator) {
$key = $pageableGenerator::getKey();
break;
}

\assert($key !== null);
$pageableGenerator = $pageableGenerators[$key];
} else {
$pageableGenerator = $pageableGenerators[$key] ?? null;
}

if ($pageableGenerator === null) {
throw $this->createNotFoundException();
}
$pageableGenerator = $this->pageableGenerators[$key] ?? throw $this->createNotFoundException();

$pageable = $pageableGenerator->generatePageable(
itemsPerPage: $pagerParameters->itemsPerPage,
Expand All @@ -93,11 +96,21 @@ public function index(

$title = $pageableGenerator->getTitle();

return $this->render('app/index.html.twig', [
$pageIdentifier = $pager->getCurrentPage()->getPageIdentifier();
$cloner = new VarCloner();
$dumper = new HtmlDumper();

$dumper->setTheme('light');
$output = fopen('php://memory', 'r+b') ?: throw new \RuntimeException('Failed to open memory stream');
$dumper->dump($cloner->cloneVar($pageIdentifier), $output);
$output = stream_get_contents($output, -1, 0);

return $this->render('app/page.html.twig', [
'title' => $title,
'pager' => $pager,
'sql' => $logger,
'pageable_generators' => $pageableGenerators,
'page_identifier' => $output,
'pageable_generators' => $this->pageableGenerators,
'source_code' => $this->getSourceCode($pageableGenerator::class),
'form' => $form->createView(),
'template' => $pagerParameters->template,
Expand All @@ -106,6 +119,61 @@ public function index(
]);
}

#[Route('/batch/{key?}', name: 'batch')]
public function batch(
SqlLogger $logger,
EntityManagerInterface $entityManager,
?string $key,
): Response {
$pageableGenerator = $this->pageableGenerators[$key] ?? throw $this->createNotFoundException();

/** @var PageableInterface<array-key,Post> */
$pageable = $pageableGenerator->generatePageable(
itemsPerPage: 5,
count: false,
setName: 'medium',
);

// @highlight-start

$output = '<ul>';

foreach ($pageable->withItemsPerPage(5)->getPages() as $page) {
$output .= '<li>';
$output .= sprintf('Processing page %d', $page->getPageNumber() ?? 'null');

$output .= '<ul>';

foreach ($page as $item) {
$output .= sprintf(
'<li>Processing item id %s, date %s, title %s</li>',
$item->getId(),
$item->getDate()?->format('Y-m-d') ?? 'null',
$item->getTitle() ?? 'null'
);
}

$output .= '</ul>';
$output .= '</li>';

$entityManager->clear();
}

$output .= '</ul>';
// @highlight-end

$title = $pageableGenerator->getTitle();

return $this->render('app/batch.html.twig', [
'title' => $title,
'sql' => $logger,
'pageable_generators' => $this->pageableGenerators,
'source_code' => $this->getSourceCode($pageableGenerator::class) . "\n" .
$this->getSourceCode(self::class),
'output' => $output,
]);
}

/**
* @param class-string $class
*/
Expand Down
Loading