Skip to content

Commit

Permalink
Listing pagination aid
Browse files Browse the repository at this point in the history
  • Loading branch information
cybersai committed Dec 21, 2023
1 parent 55eee5f commit 3bdecec
Show file tree
Hide file tree
Showing 8 changed files with 263 additions and 21 deletions.
2 changes: 1 addition & 1 deletion readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ Build Ussd (Unstructured Supplementary Service Data) applications with laravel w
You can install the package via composer:

``` bash
composer require sparors/laravel-ussd:^3.0
composer require sparors/laravel-ussd:dev-3.x
```

Laravel Ussd provides zero configuration out of the box. To publish the config, run the vendor publish command:
Expand Down
16 changes: 16 additions & 0 deletions src/Attributes/Paginate.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

namespace Sparors\Ussd\Attributes;

use Attribute;
use Sparors\Ussd\Contracts\Decision;

#[Attribute(Attribute::TARGET_CLASS)]
final class Paginate
{
public function __construct(
public string|array|Decision $next,
public null|string|array|Decision $previous = null,
public null|string|array $callback = null
) { }
}
10 changes: 10 additions & 0 deletions src/Support/Paginator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

namespace Sparors\Ussd\Support;

class Paginator
{
public function __construct(
public array $items
) { }
}
61 changes: 61 additions & 0 deletions src/Traits/WithPagination.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<?php

namespace Sparors\Ussd\Traits;

use Illuminate\Support\Str;
use Illuminate\Support\Facades\App;
use Sparors\Ussd\Record;

trait WithPagination
{
private static $currentPage;

private function lastPage(): int
{
return ceil(count($this->getItems()) / $this->perPage());
}

public function currentPage(): int
{
if (isset(self::$currentPage)) {
return self::$currentPage;
}

/** @var Record */ $record = App::make(Record::class);
$pageId = Str::of(get_called_class())->replace('\\', '')->snake()->append('_page')->value();
$page = $record->get($pageId, 1);

self::$currentPage = $page;

return $page;
}

public function isFirstPage(): int
{
return 1 === $this->currentPage();
}

public function isLastPage(): int
{
return $this->currentPage() === $this->lastPage();
}

public function hasNextPage(): bool
{
return $this->currentPage() < $this->lastPage();
}

public function hasPreviousPage(): bool
{
return $this->currentPage() > 1;
}

abstract public function getItems(): array;

abstract public function perPage(): int;

public function __destruct()
{
self::$currentPage = null;
}
}
59 changes: 52 additions & 7 deletions src/Ussd.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,27 @@
namespace Sparors\Ussd;

use Closure;
use DateInterval;
use DateTimeInterface;
use Exception;
use DateInterval;
use ReflectionClass;
use DateTimeInterface;
use Illuminate\Support\Str;
use InvalidArgumentException;
use Sparors\Ussd\Contracts\State;
use Sparors\Ussd\Contracts\Action;
use Illuminate\Support\Facades\App;
use Sparors\Ussd\Tests\PendingTest;
use Sparors\Ussd\Contracts\Response;
use Sparors\Ussd\Attributes\Paginate;
use Sparors\Ussd\Attributes\Terminate;
use Sparors\Ussd\Attributes\Transition;
use Sparors\Ussd\Traits\WithPagination;
use Sparors\Ussd\Contracts\Configurator;
use Sparors\Ussd\Contracts\InitialState;
use Sparors\Ussd\Contracts\ContinueState;
use Sparors\Ussd\Contracts\ExceptionHandler;
use Sparors\Ussd\Contracts\InitialAction;
use Sparors\Ussd\Contracts\InitialState;
use Sparors\Ussd\Contracts\ExceptionHandler;
use Sparors\Ussd\Exceptions\NextStateNotFoundException;
use Sparors\Ussd\Tests\PendingTest;

class Ussd
{
Expand Down Expand Up @@ -252,8 +255,7 @@ private function operate(): array

$state = App::make($nextState);

/** @var Menu */
$menu = App::call([$state, 'render']);
/** @var Menu */ $menu = App::call([$state, 'render']);

return [(string) $menu, $this->terminating($state)];
}
Expand All @@ -262,6 +264,49 @@ private function next(State $state): string
{
$reflected = new ReflectionClass($state);

$attributes = $reflected->getAttributes(Paginate::class);

foreach ($attributes as $attribute) {
$paginate = $attribute->newInstance();

foreach(['next', 'previous'] as $key) {
if (is_array($paginate->{$key})) {
$paginate->{$key} = new $paginate->{$key}[0](...array_slice($paginate->{$key}, 1));
} elseif (is_string($paginate->{$key})) {
$paginate->{$key} = new $paginate->{$key};
} elseif (is_null($paginate->{$key})) {
continue;
}

if ($paginate->{$key}->decide($this->context->input())) {
if (class_uses($state)[WithPagination::class] ?? null) {
/** @var WithPagination $state */
/** @var Record */ $record = App::make(Record::class);
$pageId = Str::of($state::class)->replace('\\', '')->snake()->append('_page')->value();
$page = $record->get($pageId, 1);

if ('next' === $key && $state->hasNextPage()) {
$record->set($pageId, $page + 1);
} elseif ('previous' === $key && $state->hasPreviousPage()) {
$record->set($pageId, $page - 1);
} else {
continue;
}
}

if ($paginate->callback) {
if (is_array($paginate->callback) && is_string($paginate->callback[0])) {
$paginate->callback[0] = App::make($paginate->callback[0]);
}

App::call($paginate->callback);
}

return $state::class;
}
}
}

$attributes = $reflected->getAttributes(Transition::class);

foreach($attributes as $attribute) {
Expand Down
22 changes: 19 additions & 3 deletions tests/Dummy/IntermediateState.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,37 @@

namespace Sparors\Ussd\Tests\Dummy;

use Sparors\Ussd\Attributes\Paginate;
use Sparors\Ussd\Attributes\Transition;
use Sparors\Ussd\Menu;
use Sparors\Ussd\Contracts\State;
use Sparors\Ussd\Decisions\Equal;
use Sparors\Ussd\Record;
use Sparors\Ussd\Traits\WithPagination;

#[Paginate([Equal::class, '#'], [Equal::class, '0'])]
#[Transition(GrandAction::class, [Equal::class, 1], DoTheThing::class)]
class IntermediateState implements State
{
use WithPagination;

public function render(Record $record): Menu
{
return Menu::build()
->text('Now see the magic...')
->text('Pick one...')
->when($record->has('wow'), function (Menu $menu) {
$menu->lineBreak()->text('Booooom!');
});
$menu->line('Booooom!');
})
->listing($this->getItems(), page: $this->currentPage(), perPage: $this->perPage());
}

public function getItems(): array
{
return ['Foo', 'Bar', 'Baz'];
}

public function perPage(): int
{
return 2;
}
}
10 changes: 7 additions & 3 deletions tests/Integration/AssestionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,16 @@ public function test_assestion_runs_successfully()
->assertContextMissing('baz')
->assertRecordMissing('wow')
->input('1')
->assertSee('Now see the magic...')
->assertSee('Pick one...')
->assertSee('Foo')
->assertRecordHas('wow')
->input('#')
->assertSee('Pick one...')
->assertSee('Baz')
->actingAs('benjamin')
->assertSee('In the beginning...')
->input('1')
->assertSee('Now see the magic...')
->assertSee('Pick one...')
->actingAs('isaac')
->input('1')
->assertSee('Tadaa...')
Expand All @@ -41,7 +45,7 @@ public function test_assestion_runs_successfully()
->input('9')
->assertSee('In the beginning...')
->input('1')
->assertSee('Now see the magic...')
->assertSee('Pick one...')
->actingAs('isaac');
}
}
Loading

0 comments on commit 3bdecec

Please sign in to comment.