Skip to content

Commit

Permalink
Merge pull request #3066 from oto-technology/feature/user-backend-sor…
Browse files Browse the repository at this point in the history
…t-filter

Add the possibility to sort and filter users in the backend
  • Loading branch information
bobdenotter authored Jan 28, 2022
2 parents 373101a + 7c04e4c commit c0e175c
Show file tree
Hide file tree
Showing 5 changed files with 124 additions and 1 deletion.
3 changes: 3 additions & 0 deletions config/bolt/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -238,3 +238,6 @@ reset_password_settings:
mail_name: "Bolt CMS"
mail_subject: "Your password reset request"
mail_template: "reset_password/email.html.twig"

# Adds sorting and filtering users in backend
user_show_sort&filter: true
1 change: 1 addition & 0 deletions src/Configuration/Parser/GeneralParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ protected function getDefaultConfig(): array
'extensions_allowed' => ['png', 'jpeg', 'jpg', 'gif'],
'default_avatar' => '',
],
'user_show_sort&filter' => false
];
}
}
14 changes: 13 additions & 1 deletion src/Controller/Backend/UserController.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,17 @@ public function __construct(UserRepository $users)
*/
public function users(Query $query): Response
{
$users = new ArrayAdapter($this->users->findBy([], ['username' => 'ASC'], 1000));
$order = 'username';
if ($this->request->get('sortBy')) {
$order = $this->getFromRequest('sortBy');
}

$like = '';
if ($this->request->get('filter')) {
$like = '%' . $this->getFromRequest('filter') . '%';
}

$users = new ArrayAdapter($this->users->findUsers($like, $order));
$currentPage = (int) $this->getFromRequest('page', '1');
$users = new Pagerfanta($users);
$users->setMaxPerPage(self::PAGESIZE)
Expand All @@ -45,6 +55,8 @@ public function users(Query $query): Response
'title' => 'controller.user.title',
'subtitle' => 'controller.user.subtitle',
'users' => $users,
'sortBy' => $this->getFromRequest('sortBy'),
'filterValue' => $this->getFromRequest('filter'),
];

return $this->render('@bolt/users/listing.html.twig', $twigVars);
Expand Down
35 changes: 35 additions & 0 deletions src/Repository/UserRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,14 @@

use Bolt\Entity\User;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\ORM\Query\Expr;
use Doctrine\Persistence\ManagerRegistry;

class UserRepository extends ServiceEntityRepository
{
/** @var string[] */
private $userColumns = ['id', 'displayName', 'username', 'roles', 'email', 'lastIp'];

public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, User::class);
Expand Down Expand Up @@ -46,6 +50,25 @@ public function findOneByCredentials(string $username): ?User
return $user instanceof User ? $user : null;
}

public function findUsers(string $like, string $orderBy = null)
{
$alias = 'user';
$qb = $this->createQueryBuilder($alias);

if ($like) {
foreach ($this->userColumns as $col) {
$qb
->orWhere(
$qb->expr()->like(sprintf('%s.%s', $alias, $col), sprintf(':%s', $col))
)
->setParameter($col, $like);
}
}
$qb->orderBy($this->createSortBy($orderBy, $alias));

return $qb->getQuery()->getResult();
}

public function getFirstAdminUser(): ?User
{
$qb = $this->createQueryBuilder('user');
Expand All @@ -71,4 +94,16 @@ public static function factory(string $displayName = '', string $username = '',

return $user;
}

private function createSortBy($order, $alias): Expr\OrderBy
{
if (mb_strpos($order, '-') === 0) {
$direction = 'DESC';
$order = sprintf('%s.%s', $alias, mb_substr($order, 1));
} else {
$direction = 'ASC';
$order = sprintf('%s.%s', $alias, $order);
}
return new Expr\OrderBy($order, $direction);
}
}
72 changes: 72 additions & 0 deletions templates/users/listing.html.twig
Original file line number Diff line number Diff line change
Expand Up @@ -146,4 +146,76 @@
{# The 'aside' section is the right sidebar of the page. If omitted, 'main' will take up the full width. #}
{% block aside %}
{{ widgets('users_aside_top') }}

{% if config.get('general/user_show_sort&filter') %}
{% set filterOptions = {
'id': "id",
'displayName': "displayName",
'username': "username",
'roles': "roles",
'lastseenAt': "lastseenAt",
'lastIp': "lastIp"
} %}

<div class="card mb-3">
<div class="card-header">
{{ macro.icon('star') }} {{ title|trans }}
</div>
<div class="card-body">
<p>
{% if is_granted('user:add') %}
<a class="btn btn-secondary" href="{{ path('bolt_user_add') }}" data-patience="virtue">
{{ macro.icon('user-plus') }} {{ __('action.add_user') }}
</a>
<a
class="btn btn-tertiary"
href="{{ path('bolt_file_edit', {'location': 'config', 'file': '/bolt/permissions.yaml'}) }}"
data-patience="virtue"
>
{{ macro.icon('user-cog') }} {{ __('action.edit_permissions') }}
</a>
{% endif %}
</p>
<form>
<div class="form-group">
<p>
<strong>{{ 'listing.title_sortby'|trans }}</strong>:
<select class="form-control" name="sortBy" title="{{ 'listing.title_sortby'|trans }}">
<option value="" {% if sortBy is empty %}selected{% endif %}>
{{ 'listing.option_select_sortby'|trans }}
</option>
{% for key, filterOption in filterOptions %}
<option value="{{ key }}" {% if sortBy == key %}selected{% endif %}>
{{ filterOption }}
</option>
<option value="-{{ key }}" {% if sortBy == '-' ~ key %}selected{% endif %}>
-{{ filterOption }}
</option>
{% endfor %}
</select>
</p>

<p>
<strong>{{ 'listing.title_filterby'|trans }}</strong>:
<input
class="form-control"
type="text"
name="filter"
id="content-filter"
value="{{ filterValue }}"
placeholder="{{ 'listing.placeholder_filter'|trans }}"
title="{{ 'listing.placeholder_filter'|trans }}"
/>
</p>
</div>

{{ macro.button('listing.button_filter', 'filter', 'secondary mb-0', {'type': 'submit'}) }}

{% if sortBy is not empty or filterValue is not empty %}
{{ macro.buttonlink('listing.button_clear', path('bolt_users'), 'times', 'tertiary mb-0') }}
{% endif %}
</form>
</div>
</div>
{% endif %}
{% endblock %}

0 comments on commit c0e175c

Please sign in to comment.