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

Add modvar and create new pager #4194

Merged
merged 7 commits into from
Mar 31, 2020
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
2 changes: 2 additions & 0 deletions CHANGELOG-3.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,8 @@
- Added `Zikula\Bundle\CoreBundle\Helper\LocalDotEnvHelper` to assist in writing to the `.env.local` file.
- Added email notification to deleted pending registrations (#2915).
- Added CLI Command to edit password, email, username properties of ZAuth user mappings (a replacement for the old Zikula Recovery Console).
- Added new Doctrine Paginator wrapper `Zikula\Bundle\CoreBundle\Doctrine\Paginator` and paginator template. See docs.
- Added new AlphaFilter class `Zikula\Bundle\CoreBundle\Filter\AlphaFilter` and template. See docs.

- Vendor updates:
- antishov/doctrine-extensions-bundle updated from 1.2.2 to 1.4.2
Expand Down
36 changes: 36 additions & 0 deletions docs/LayoutDesign/Templating/Dev/AlphaFilter.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
---
currentMenu: templating
---
# AlphaFilter

In large result sets that are alphanumerically based, it is often helpful to display a filter selector that can
quickly link to results beginning with that letter or number. Zikula provides a quick method to do so.
In order to utilize Zikula's AlphaFilter, the following steps should be followed:

### In the controller
```php
use Zikula\Bundle\CoreBundle\Filter\AlphaFilter;
// ...

return [
'templateParam' => $value,
'alpha' => new AlphaFilter('mycustomroute', $routeParameters, $currentLetter),
];
```

### In the template

```twig
{{ include(alpha.template) }}
```

### Options

By default, the filter does not display digits. In order to enable them, add a fourth argument to the constructor:

```php
new AlphaFilter('mycustomroute', $routeParameters, $currentLetter, true);
```

The template can be customized by overriding `@Core/Filter/AlphaFilter.html.twig` in all the normal ways.
You can also simply set your own custom template in the controller `$myAlphaFilter->setTemplate('@MyBundle/Custom/Template.html.twig');`
44 changes: 44 additions & 0 deletions docs/LayoutDesign/Templating/Dev/Pagination.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
---
currentMenu: templating
---
# Pagination

Large result sets should be paginated. Doctrine provides a method to limit its result sets to do this, but it doesn't
provide an UI for proper display. Zikula provides a 'wrapper' class in order to facilitate easier UI.
In order to utilize Zikula's paginator, the following steps should be followed:

### In the repository class

```php
use Zikula\Bundle\CoreBundle\Doctrine\Paginator;
// ...

$qb = $this->createQueryBuilder('m')
->select('m');
return (new Paginator($qb, $pageSize))->paginate($page); // returns Paginator object
```

### In the controller

```php
$latestPosts = $repository->getLatestPosts($criteria, $pageSize);
$latestPosts->setRoute('mycustomroute');
$latestPosts->setRouteParameters(['foo' => 'bar']);
return $this->render('blog/index.'.$_format.'.twig', [
'paginator' => $latestPosts,
]);
```

### In the template

```twig
{% for post in paginator.results %}
{{ post.title }}
{% endfor %}
{{ include(paginator.template) }}
```

### Customization

The template can be customized by overriding `@Core/Paginator/Paginator.html.twig` in all the normal ways.
You can also simply set your own custom template in the controller `$latestPosts->setTemplate('@MyBundle/Custom/Template.html.twig');`
2 changes: 2 additions & 0 deletions docs/LayoutDesign/Templating/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,5 @@ Zikula uses the Twig template engine, like Symfony does.
## For developers

- [PageAssetApi](Dev/PageAssetApi.md)
- [Pagination of large result sets](Dev/Pagination.md)
- [Display an Alpha filter](Dev/AlphaFilter.md)
174 changes: 174 additions & 0 deletions src/Zikula/CoreBundle/Doctrine/Paginator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
<?php

declare(strict_types=1);

/*
* This file is part of the Zikula package.
*
* Copyright Zikula Foundation - https://ziku.la/
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Zikula\Bundle\CoreBundle\Doctrine;

use Doctrine\ORM\QueryBuilder as DoctrineQueryBuilder;
use Doctrine\ORM\Tools\Pagination\CountWalker;
use Doctrine\ORM\Tools\Pagination\Paginator as DoctrinePaginator;

/**
* @author Javier Eguiluz <javier.eguiluz@gmail.com>
* Most of this file is copied from https://github.com/javiereguiluz/symfony-demo/blob/master/src/Pagination/Paginator.php
*
* usage:
* in Repository class:
* return (new Paginator($qb, $pageSize))->paginate($pageNumber);
* in controller:
* $latestPosts = $repository->getLatestPosts($criteria, $pageSize);
* return $this->render('blog/index.'.$_format.'.twig', [
* 'paginator' => $latestPosts,
* ]);
* results in template {% for post in paginator.results %}
* include template: {{ include(paginator.template) }}
*/
class Paginator
{
private const PAGE_SIZE = 25;

private $queryBuilder;

private $currentPage;

private $pageSize;

private $results;

private $numResults;

private $route;

private $routeParameters;

private $template = '@Core/Paginator/Paginator.html.twig';

public function __construct(DoctrineQueryBuilder $queryBuilder, int $pageSize = self::PAGE_SIZE)
{
$this->queryBuilder = $queryBuilder;
$this->pageSize = $pageSize;
}

public function paginate(int $page = 1): self
{
$this->currentPage = max(1, $page);
$firstResult = ($this->currentPage - 1) * $this->pageSize;

$query = $this->queryBuilder
->setFirstResult($firstResult)
->setMaxResults($this->pageSize)
->getQuery();

if (0 === \count($this->queryBuilder->getDQLPart('join'))) {
$query->setHint(CountWalker::HINT_DISTINCT, false);
}

$paginator = new DoctrinePaginator($query, true);

$useOutputWalkers = \count($this->queryBuilder->getDQLPart('having') ?: []) > 0;
$paginator->setUseOutputWalkers($useOutputWalkers);

$this->results = $paginator->getIterator();
$this->numResults = $paginator->count();

return $this;
}

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

public function getLastPage(): int
{
return (int) ceil($this->numResults / $this->pageSize);
}

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

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

public function getPreviousPage(): int
{
return max(1, $this->currentPage - 1);
}

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

public function getNextPage(): int
{
return min($this->getLastPage(), $this->currentPage + 1);
}

public function hasToPaginate(): bool
{
return $this->numResults > $this->pageSize;
}

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

public function getResults(): \Traversable
{
return $this->results;
}

public function setRoute(string $route): self
{
$this->route = $route;

return $this;
}

public function getRoute(): string
{
return $this->route;
}

public function setRouteParameters(array $parameters): self
{
$this->routeParameters = $parameters;

return $this;
}

public function setRouteParameter(string $name, string $value): void
{
$this->routeParameters[$name] = $value;
}

public function getRouteParameters(): array
{
return $this->routeParameters;
}

public function setTemplate(string $templateName): void
{
$this->template = $templateName;
}

public function getTemplate(): string
{
return $this->template;
}
}
99 changes: 99 additions & 0 deletions src/Zikula/CoreBundle/Filter/AlphaFilter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
<?php

declare(strict_types=1);

/*
* This file is part of the Zikula package.
*
* Copyright Zikula Foundation - https://ziku.la/
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Zikula\Bundle\CoreBundle\Filter;

/**
* Assist in the display of an alphabetical selector for large result sets
* In controller:
* return [
* 'templateParam' => $value,
* 'alpha' => new AlphaFilter('mycustomroute', $routeParameters, $currentLetter),
* ];
* In template:
* {{ include(alpha.template) }}
*/
class AlphaFilter
{
private $currentLetter;

private $route;

private $routeParameters;

private $template = '@Core/Filter/AlphaFilter.html.twig';

private $includeNumbers = false;

public function __construct(string $route, array $routeParameters = [], $currentLetter = 'a', $includeNumbers = false)
{
$this->route = $route;
$this->routeParameters = $routeParameters;
$this->currentLetter = $currentLetter;
$this->includeNumbers = $includeNumbers;
}

public function getCurrentLetter(): string
{
return $this->currentLetter;
}

public function setRoute(string $route): self
{
$this->route = $route;

return $this;
}

public function getRoute(): string
{
return $this->route;
}

public function setRouteParameters(array $parameters): self
{
$this->routeParameters = $parameters;

return $this;
}

public function setRouteParameter(string $name, ?string $value): void
{
$this->routeParameters[$name] = $value;
}

public function getRouteParameters(): array
{
return $this->routeParameters;
}

public function setTemplate(string $templateName): void
{
$this->template = $templateName;
}

public function getTemplate(): string
{
return $this->template;
}

public function setIncludeNumbers(bool $include): void
{
$this->includeNumbers = $include;
}

public function getIncludeNumbers(): bool
{
return $this->includeNumbers;
}
}
Loading