feat: admin-managed roles and hotel codes
This commit is contained in:
@@ -5,6 +5,7 @@ declare(strict_types=1);
|
||||
namespace App\Form\Admin\Filter;
|
||||
|
||||
use App\Form\Model\Filter\UserFilterDto;
|
||||
use App\Security\Role;
|
||||
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
|
||||
@@ -13,28 +14,12 @@ use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
*/
|
||||
class UserFilterType extends AbstractListFilterType
|
||||
{
|
||||
/**
|
||||
* The roles that are actually assigned to accounts. ROLE_USER is left out because every
|
||||
* account has it implicitly and filtering by it would match everything.
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
public const ROLES = [
|
||||
'ROLE_ADMIN',
|
||||
'ROLE_MANAGER',
|
||||
'ROLE_TEAMER',
|
||||
'ROLE_CUSTOMER',
|
||||
'ROLE_HOUSE_MANAGER',
|
||||
'ROLE_GROUPS_ADMIN',
|
||||
'ROLE_GROUPS_MANAGER',
|
||||
];
|
||||
|
||||
protected function filterFields(array $options): array
|
||||
{
|
||||
return [
|
||||
'role' => [ChoiceType::class, [
|
||||
'label' => 'Rolle',
|
||||
'choices' => array_combine($options['roles'], $options['roles']),
|
||||
'choices' => array_flip(Role::labels()),
|
||||
'placeholder' => 'alle',
|
||||
'required' => false,
|
||||
]],
|
||||
@@ -47,9 +32,7 @@ class UserFilterType extends AbstractListFilterType
|
||||
|
||||
$resolver->setDefaults([
|
||||
'data_class' => UserFilterDto::class,
|
||||
'roles' => [],
|
||||
]);
|
||||
$resolver->setAllowedTypes('roles', 'string[]');
|
||||
}
|
||||
|
||||
protected function searchPlaceholder(): string
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Form\Admin;
|
||||
|
||||
use App\Entity\User;
|
||||
use App\Security\Role;
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
|
||||
/**
|
||||
* Lets an administrator assign roles and hotel codes to an existing account.
|
||||
*
|
||||
* This is the only way those two get changed after the account was created — BpnAuthenticator
|
||||
* imports them once and never touches them again.
|
||||
*
|
||||
* @extends AbstractType<User>
|
||||
*/
|
||||
class UserType extends AbstractType
|
||||
{
|
||||
/**
|
||||
* @param array<string, string> $hotelCodes code => label
|
||||
*/
|
||||
public function __construct(private readonly array $hotelCodes = [])
|
||||
{
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder, array $options): void
|
||||
{
|
||||
$user = $builder->getData();
|
||||
|
||||
$builder
|
||||
->add('roles', ChoiceType::class, [
|
||||
'label' => 'Rollen',
|
||||
'choices' => array_flip(Role::labels()),
|
||||
'multiple' => true,
|
||||
'expanded' => true,
|
||||
'required' => false,
|
||||
// User::getRoles() prepends the implicit ROLE_USER, which must not be written back.
|
||||
'getter' => static fn (User $user): array => array_values(array_diff($user->getRoles(), ['ROLE_USER'])),
|
||||
'setter' => static function (User $user, array $roles): void {
|
||||
$user->setRoles(array_values(array_unique($roles)));
|
||||
},
|
||||
])
|
||||
->add('hotelCodes', ChoiceType::class, [
|
||||
'label' => 'Häuser',
|
||||
'choices' => $this->hotelCodeChoices($user),
|
||||
'multiple' => true,
|
||||
'expanded' => true,
|
||||
'required' => false,
|
||||
'setter' => static function (User $user, array $hotelCodes): void {
|
||||
$user->setHotelCodes(array_values(array_unique($hotelCodes)));
|
||||
},
|
||||
])
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* Codes already stored on the account are always offered, even when they are missing from
|
||||
* the configured catalog — otherwise saving the form would silently drop them.
|
||||
*
|
||||
* @return array<string, string> label => code
|
||||
*/
|
||||
private function hotelCodeChoices(?User $user): array
|
||||
{
|
||||
$codes = $this->hotelCodes;
|
||||
|
||||
foreach ($user?->getHotelCodes() ?? [] as $code) {
|
||||
$codes[$code] ??= $code;
|
||||
}
|
||||
|
||||
ksort($codes);
|
||||
|
||||
return array_flip($codes);
|
||||
}
|
||||
|
||||
public function configureOptions(OptionsResolver $resolver): void
|
||||
{
|
||||
$resolver->setDefaults([
|
||||
'data_class' => User::class,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ declare(strict_types=1);
|
||||
namespace App\Form\Model\Filter;
|
||||
|
||||
use App\Model\ListFilterChip;
|
||||
use App\Security\Role;
|
||||
|
||||
class UserFilterDto extends AbstractListFilterDto
|
||||
{
|
||||
@@ -15,7 +16,7 @@ class UserFilterDto extends AbstractListFilterDto
|
||||
$chips = parent::activeFilters();
|
||||
|
||||
if (null !== $this->role && '' !== $this->role) {
|
||||
$chips[] = new ListFilterChip('Rolle', $this->role, ['role']);
|
||||
$chips[] = new ListFilterChip('Rolle', Role::labels()[$this->role] ?? $this->role, ['role']);
|
||||
}
|
||||
|
||||
return $chips;
|
||||
|
||||
Reference in New Issue
Block a user