Skip to content

Commit

Permalink
Merge pull request #32 from ray-di/dynamic_per_page
Browse files Browse the repository at this point in the history
Support dynamic perPage parameter
  • Loading branch information
koriym committed Jun 9, 2022
2 parents db5b694 + 9de4339 commit 2b2fa65
Show file tree
Hide file tree
Showing 11 changed files with 303 additions and 130 deletions.
6 changes: 6 additions & 0 deletions README.ja.md
Expand Up @@ -237,6 +237,12 @@ interface TodoList
}
```

ページ毎のアイテム数をperPageで指定しますが、動的な値の場合は以下のようにページ数を表す引数の名前を文字列を指定します。
```php
#[DbQuery, Pager(perPage: 'pageNum', template: '/{?page}')]
public function __invoke($pageNum): PagesInterface;
```

`count()`で件数が取得でき、ページ番号で配列アクセスをするとページオブジェクトが取得できます。
`Pages`はSQL遅延実行オブジェクトです。

Expand Down
7 changes: 7 additions & 0 deletions README.md
Expand Up @@ -250,6 +250,13 @@ interface TodoList
You can get the number of pages with `count()`, and you can get the page object with array access by page number.
`Pages` is a SQL lazy execution object.

The number of items per page is specified by `perPage`, but for dynamic values, specify a string with the name of the argument representing the number of pages as follows

```php
#[DbQuery, Pager(perPage: 'pageNum', template: '/{?page}')]
public function __invoke($pageNum): PagesInterface;
```

```php
$pages = ($todoList)();
$cnt = count($page); // When count() is called, the count SQL is generated and queried.
Expand Down
7 changes: 5 additions & 2 deletions src/Annotation/Pager.php
Expand Up @@ -15,13 +15,16 @@
#[Attribute(Attribute::TARGET_METHOD)]
final class Pager
{
/** @var int */
/** @var int|string */
public $perPage;

/** @var string */
public $template;

public function __construct(int $perPage = 10, string $template = '/{?page}')
/**
* @param int|string $perPage int:the number of items, string: the name of the argument of the number of items
*/
public function __construct($perPage = 10, string $template = '/{?page}')
{
$this->perPage = $perPage;
$this->template = $template;
Expand Down
43 changes: 38 additions & 5 deletions src/DbQueryInterceptor.php
Expand Up @@ -9,8 +9,13 @@
use Ray\Aop\MethodInvocation;
use Ray\MediaQuery\Annotation\DbQuery;
use Ray\MediaQuery\Annotation\Pager;
use Ray\MediaQuery\Exception\InvalidPerPageVarNameException;
use Ray\MediaQuery\Exception\PerPageNotIntTypeException;

use function assert;
use function class_exists;
use function is_int;
use function is_string;
use function method_exists;

class DbQueryInterceptor implements MethodInterceptor
Expand All @@ -37,17 +42,17 @@ public function __construct(SqlQueryInterface $sqlQuery, MediaQueryLoggerInterfa
public function invoke(MethodInvocation $invocation)
{
$method = $invocation->getMethod();
/** @var DbQuery $dbQury */
$dbQury = $method->getAnnotation(DbQuery::class);
/** @var DbQuery $dbQuery */
$dbQuery = $method->getAnnotation(DbQuery::class);
$pager = $method->getAnnotation(Pager::class);
$values = $this->paramInjector->getArgumentes($invocation);
if ($pager instanceof Pager) {
return $this->getPager($dbQury->id, $values, $pager);
return $this->getPager($dbQuery->id, $values, $pager);
}

$fetchStyle = $this->getFetchMode($dbQury);
$fetchStyle = $this->getFetchMode($dbQuery);

return $this->sqlQuery($dbQury, $values, $fetchStyle, $dbQury->entity);
return $this->sqlQuery($dbQuery, $values, $fetchStyle, $dbQuery->entity);
}

/**
Expand Down Expand Up @@ -87,10 +92,38 @@ private function sqlQuery(DbQuery $dbQuery, array $values, int $fetchStyle, $fet
*/
private function getPager(string $queryId, array $values, Pager $pager): PagesInterface
{
if (is_string($pager->perPage)) {
$values = $this->getDynamicPerPage($pager, $values);
}

assert(is_int($pager->perPage));
$this->logger->start();
$result = $this->sqlQuery->getPages($queryId, $values, $pager->perPage, $pager->template);
$this->logger->log($queryId, $values);

return $result;
}

/**
* @param array<string, mixed> $values
*
* @return array<string, mixed>
*/
private function getDynamicPerPage(Pager $pager, array $values): array
{
$perPage = $pager->perPage;
if (! isset($values[$perPage])) {
throw new InvalidPerPageVarNameException((string) $perPage);
}

if (! is_int($values[$perPage])) {
throw new PerPageNotIntTypeException((string) $perPage);
}

$perPageInValues = $values[$perPage];
$pager->perPage = $perPageInValues;
unset($values[$perPage]);

return $values;
}
}
12 changes: 12 additions & 0 deletions src/Exception/InvalidPerPageVarNameException.php
@@ -0,0 +1,12 @@
<?php

declare(strict_types=1);

namespace Ray\MediaQuery\Exception;

/**
* The argument name specified in PerPage does not exist in the arguments of that method
*/
class InvalidPerPageVarNameException extends LogicException
{
}
12 changes: 12 additions & 0 deletions src/Exception/PerPageNotIntTypeException.php
@@ -0,0 +1,12 @@
<?php

declare(strict_types=1);

namespace Ray\MediaQuery\Exception;

/**
* PerPage type should be int
*/
class PerPageNotIntTypeException extends LogicException
{
}
36 changes: 36 additions & 0 deletions tests/DbQueryModuleTest.php
Expand Up @@ -13,6 +13,11 @@
use Ray\Di\Injector;
use Ray\MediaQuery\Entity\Todo;
use Ray\MediaQuery\Entity\TodoConstruct;
use Ray\MediaQuery\Exception\InvalidPerPageVarNameException;
use Ray\MediaQuery\Exception\PerPageNotIntTypeException;
use Ray\MediaQuery\Queries\DynamicPerPageInterface;
use Ray\MediaQuery\Queries\DynamicPerPageInvalidInterface;
use Ray\MediaQuery\Queries\DynamicPerPageInvalidType;
use Ray\MediaQuery\Queries\PromiseAddInterface;
use Ray\MediaQuery\Queries\PromiseItemInterface;
use Ray\MediaQuery\Queries\PromiseListInterface;
Expand Down Expand Up @@ -49,6 +54,9 @@ protected function setUp(): void
PromiseListInterface::class,
TodoEntityInterface::class,
TodoConstcuctEntityInterface::class,
DynamicPerPageInterface::class,
DynamicPerPageInvalidInterface::class,
DynamicPerPageInvalidType::class,
]);
$sqlDir = dirname(__DIR__) . '/tests/sql';
$dbQueryConfig = new DbQueryConfig($sqlDir);
Expand Down Expand Up @@ -144,4 +152,32 @@ public function testEntityWithConstructor(): void
$item = $todoList->getItem('1');
$this->assertInstanceOf(TodoConstruct::class, $item);
}

public function testDynamicPerPage(): void
{
$todoList = $this->injector->getInstance(DynamicPerPageInterface::class);
assert($todoList instanceof DynamicPerPageInterface);
$list = ($todoList)(2);
/** @var Page $page */
$page = $list[1];
$this->assertSame([['id' => '1', 'title' => 'run']], $page->data);
$this->assertSame(2, $page->maxPerPage);
$log = (string) $this->logger;
$this->assertStringContainsString('query: todo_list', $log);
}

public function testDynamicPerPageVariableNameNotGiven(): void
{
$this->expectException(InvalidPerPageVarNameException::class);
$todoList = $this->injector->getInstance(DynamicPerPageInvalidInterface::class);
assert($todoList instanceof DynamicPerPageInvalidInterface);
($todoList)(1);
}

public function testGivenPerPageShouldBeInt(): void
{
$this->expectException(PerPageNotIntTypeException::class);
$todoList = $this->injector->getInstance(DynamicPerPageInvalidType::class);
$todoList('1'); // @phpstan-ignore-line
}
}
19 changes: 19 additions & 0 deletions tests/Fake/Queries/DynamicPerPageInterface.php
@@ -0,0 +1,19 @@
<?php

declare(strict_types=1);

namespace Ray\MediaQuery\Queries;

use Ray\MediaQuery\Annotation\DbQuery;
use Ray\MediaQuery\Annotation\Pager;
use Ray\MediaQuery\Pages;

interface DynamicPerPageInterface
{
/**
* @DbQuery("todo_list")
* @Pager(perPage="perPage", template="/{?page}")
*/
#[DbQuery('todo_list'), Pager(perPage: 'perPage', template: '/{?page}')]
public function __invoke(int $perPage): Pages;
}
19 changes: 19 additions & 0 deletions tests/Fake/Queries/DynamicPerPageInvalidInterface.php
@@ -0,0 +1,19 @@
<?php

declare(strict_types=1);

namespace Ray\MediaQuery\Queries;

use Ray\MediaQuery\Annotation\DbQuery;
use Ray\MediaQuery\Annotation\Pager;
use Ray\MediaQuery\Pages;

interface DynamicPerPageInvalidInterface
{
/**
* @DbQuery("todo_list")
* @Pager(perPage="__not_exsits_", template="/{?page}")
*/
#[DbQuery('todo_list'), Pager(perPage: '__not_exsits_', template: '/{?page}')]
public function __invoke(int $num): Pages;
}
19 changes: 19 additions & 0 deletions tests/Fake/Queries/DynamicPerPageInvalidType.php
@@ -0,0 +1,19 @@
<?php

declare(strict_types=1);

namespace Ray\MediaQuery\Queries;

use Ray\MediaQuery\Annotation\DbQuery;
use Ray\MediaQuery\Annotation\Pager;
use Ray\MediaQuery\Pages;

interface DynamicPerPageInvalidType
{
/**
* @DbQuery("todo_list")
* @Pager(perPage="perPage", template="/{?page}")
*/
#[DbQuery('todo_list'), Pager(perPage: 'perPage', template: '/{?page}')]
public function __invoke($perPage): Pages;
}

0 comments on commit 2b2fa65

Please sign in to comment.