Skip to content

Commit

Permalink
Make Pagination objects immutable #1887
Browse files Browse the repository at this point in the history
  • Loading branch information
lukasbestle authored and bastianallgeier committed Oct 7, 2019
1 parent c712ef0 commit be9ec07
Show file tree
Hide file tree
Showing 2 changed files with 97 additions and 49 deletions.
108 changes: 75 additions & 33 deletions src/Toolkit/Pagination.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@
*/
class Pagination
{
use Properties {
setProperties as protected baseSetProperties;
}

/**
* The current page
*
Expand All @@ -41,11 +45,11 @@ class Pagination
* Creates a new pagination object
* with the given parameters
*
* @param array $params
* @param array $props
*/
public function __construct(array $params = [])
public function __construct(array $props = [])
{
$this->setProperties($params);
$this->setProperties($props);
}

/**
Expand Down Expand Up @@ -114,13 +118,13 @@ public static function for(Collection $collection, ...$arguments)
/**
* Getter for the current page
*
* @deprecated 3.3.0 Setter is no longer supported, use $pagination->setProperties()
* @deprecated 3.3.0 Setter is no longer supported, use $pagination->clone()
* @return int
*/
public function page(int $page = null): int
{
if ($page !== null) {
throw new Exception('$pagination->page() setter is no longer supported, use $pagination->setProperties()'); // @codeCoverageIgnore
throw new Exception('$pagination->page() setter is no longer supported, use $pagination->clone()'); // @codeCoverageIgnore
}

return $this->page;
Expand All @@ -129,13 +133,13 @@ public function page(int $page = null): int
/**
* Getter for the total number of items
*
* @deprecated 3.3.0 Setter is no longer supported, use $pagination->setProperties()
* @deprecated 3.3.0 Setter is no longer supported, use $pagination->clone()
* @return int
*/
public function total(int $total = null): int
{
if ($total !== null) {
throw new Exception('$pagination->total() setter is no longer supported, use $pagination->setProperties()'); // @codeCoverageIgnore
throw new Exception('$pagination->total() setter is no longer supported, use $pagination->clone()'); // @codeCoverageIgnore
}

return $this->total;
Expand All @@ -144,13 +148,13 @@ public function total(int $total = null): int
/**
* Getter for the number of items per page
*
* @deprecated 3.3.0 Setter is no longer supported, use $pagination->setProperties()
* @deprecated 3.3.0 Setter is no longer supported, use $pagination->clone()
* @return int
*/
public function limit(int $limit = null): int
{
if ($limit !== null) {
throw new Exception('$pagination->limit() setter is no longer supported, use $pagination->setProperties()'); // @codeCoverageIgnore
throw new Exception('$pagination->limit() setter is no longer supported, use $pagination->clone()'); // @codeCoverageIgnore
}

return $this->limit;
Expand Down Expand Up @@ -381,42 +385,80 @@ public function rangeEnd(int $range = 5): int
* Sets the properties limit, total and page
* and validates that the properties match
*
* @param array $params Array with keys limit, total and/or page
* @param array $props Array with keys limit, total and/or page
* @return self
*/
public function setProperties(array $params)
protected function setProperties(array $props)
{
if (isset($params['limit'])) {
if (is_numeric($params['limit']) !== true || $params['limit'] < 1) {
throw new Exception('Invalid pagination limit: ' . $params['limit']);
}
$this->baseSetProperties($props);

$this->limit = (int)$params['limit'];
// ensure that page is set to something, otherwise
// generate "default page" based on other params
if ($this->page === null) {
$this->page = $this->firstPage();
}

if (isset($params['total'])) {
if (is_numeric($params['total']) !== true || $params['total'] < 0) {
throw new Exception('Invalid total number of items: ' . $params['total']);
}
// validate page based on all params
$min = $this->firstPage();
$max = $this->pages();
if ($this->page < $min || $this->page > $max) {
throw new ErrorPageException('Pagination page ' . $this->page . ' is out of bounds, expected ' . $min . '-' . $max);
}

$this->total = (int)$params['total'];
return $this;
}

/**
* Sets the number of items per page
*
* @param int $limit
* @return self
*/
protected function setLimit(int $limit = 20)
{
if ($limit < 1) {
throw new Exception('Invalid pagination limit: ' . $limit);
}

if (isset($params['page'])) {
if (is_numeric($params['page']) !== true || $params['page'] < 0) {
throw new Exception('Invalid page number: ' . $params['page']);
}
$this->limit = $limit;
return $this;
}

$this->page = (int)$params['page'];
} elseif ($this->page === null) {
// generate "default page" based on other params if not set already
$this->page = $this->firstPage();
/**
* Sets the total number of items
*
* @param int $total
* @return self
*/
protected function setTotal(int $total = 0)
{
if ($total < 0) {
throw new Exception('Invalid total number of items: ' . $total);
}

$min = $this->firstPage();
$max = $this->pages();
if ($this->page < $min || $this->page > $max) {
throw new ErrorPageException('Pagination page ' . $this->page . ' is out of bounds, expected ' . $min . '-' . $max);
$this->total = $total;
return $this;
}

/**
* Sets the current page
*
* @param int|string|null $page Int or int in string form;
* automatically determined if null
* @return self
*/
protected function setPage($page = null)
{
// if $page is null, it is set to a default in the setProperties() method
if ($page !== null) {
if (is_numeric($page) !== true || $page < 0) {
throw new Exception('Invalid page number: ' . $page);
}

$this->page = (int)$page;
}

return $this;
}

/**
Expand Down
38 changes: 22 additions & 16 deletions tests/Toolkit/PaginationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ public function testPage()
$this->assertEquals(2, $pagination->page());
}

public function testPageString()
{
$pagination = new Pagination(['total' => 100, 'page' => '2']);
$this->assertEquals(2, $pagination->page());
}

public function testTotalDefault()
{
$pagination = new Pagination();
Expand Down Expand Up @@ -54,11 +60,11 @@ public function testStart()
$this->assertEquals(1, $pagination->start());

// go to the second page
$pagination->setProperties(['page' => 2]);
$pagination = $pagination->clone(['page' => 2]);
$this->assertEquals(21, $pagination->start());

// set a different limit
$pagination->setProperties(['limit' => 10]);
$pagination = $pagination->clone(['limit' => 10]);
$this->assertEquals(11, $pagination->start());
}

Expand All @@ -71,11 +77,11 @@ public function testEnd()
$this->assertEquals(20, $pagination->end());

// go to the second page
$pagination->setProperties(['page' => 2]);
$pagination = $pagination->clone(['page' => 2]);
$this->assertEquals(40, $pagination->end());

// set a different limit
$pagination->setProperties(['limit' => 10]);
$pagination = $pagination->clone(['limit' => 10]);
$this->assertEquals(20, $pagination->end());
}

Expand Down Expand Up @@ -283,59 +289,59 @@ public function testRange()
$this->assertEquals(10, $pagination->rangeEnd(12));
}

public function testSetProperties()
public function testClone()
{
$pagination = new Pagination();
$pagination->setProperties(['limit' => 3, 'total' => 5, 'page' => 2]);
$pagination = $pagination->clone(['limit' => 3, 'total' => 5, 'page' => 2]);

$this->assertSame(3, $pagination->limit());
$this->assertSame(5, $pagination->total());
$this->assertSame(2, $pagination->page());
}

public function testSetPropertiesInvalid1()
public function testCloneInvalid1()
{
$this->expectException('Kirby\Exception\Exception');
$this->expectExceptionMessage('Invalid pagination limit: 0');

$pagination = new Pagination();
$pagination->setProperties(['limit' => 0]);
$pagination = $pagination->clone(['limit' => 0]);
}

public function testSetPropertiesInvalid2()
public function testCloneInvalid2()
{
$this->expectException('Kirby\Exception\Exception');
$this->expectExceptionMessage('Invalid total number of items: -1');

$pagination = new Pagination();
$pagination->setProperties(['total' => -1]);
$pagination = $pagination->clone(['total' => -1]);
}

public function testSetPropertiesInvalid3()
public function testCloneInvalid3()
{
$this->expectException('Kirby\Exception\Exception');
$this->expectExceptionMessage('Invalid page number: -1');

$pagination = new Pagination();
$pagination->setProperties(['page' => -1]);
$pagination = $pagination->clone(['page' => -1]);
}

public function testSetPropertiesOutOfBounds1()
public function testCloneOutOfBounds1()
{
$this->expectException('Kirby\Exception\ErrorPageException');
$this->expectExceptionMessage('Pagination page 3 is out of bounds, expected 1-2');

$pagination = new Pagination();
$pagination->setProperties(['page' => 3, 'total' => 10, 'limit' => 5]);
$pagination = $pagination->clone(['page' => 3, 'total' => 10, 'limit' => 5]);
}

public function testSetPropertiesOutOfBounds2()
public function testCloneOutOfBounds2()
{
$this->expectException('Kirby\Exception\ErrorPageException');
$this->expectExceptionMessage('Pagination page 0 is out of bounds, expected 1-2');

$pagination = new Pagination();
$pagination->setProperties(['page' => 0, 'total' => 10, 'limit' => 5]);
$pagination = $pagination->clone(['page' => 0, 'total' => 10, 'limit' => 5]);
}

public function testToArray()
Expand Down

0 comments on commit be9ec07

Please sign in to comment.