From 3ede651680552b694c8f75744f46446030740f1e Mon Sep 17 00:00:00 2001 From: Silas Joisten Date: Tue, 8 May 2018 09:32:00 +0200 Subject: [PATCH] new RolesMatrixType to display available actions per admin as matrix (#1005) Role permissions can now be displayed in a matrix view using the Sonata\UserBundle\Form\Type\RolesMatrixType --- docs/images/roles_matrix.png | Bin 0 -> 173223 bytes docs/index.rst | 1 + docs/reference/roles_matrix.rst | 57 ++++ .../Compiler/RolesMatrixCompilerPass.php | 37 ++ src/Form/Type/RolesMatrixType.php | 103 ++++++ src/Resources/config/admin.xml | 24 +- src/Resources/config/twig.xml | 6 +- .../views/Form/form_admin_fields.html.twig | 9 + .../views/Form/roles_matrix.html.twig | 41 +++ .../views/Form/roles_matrix_list.html.twig | 21 ++ .../RolesBuilder/AdminRolesBuilder.php | 118 +++++++ .../AdminRolesBuilderInterface.php | 21 ++ .../ExpandableRolesBuilderInterface.php | 22 ++ .../RolesBuilder/MatrixRolesBuilder.php | 76 +++++ .../MatrixRolesBuilderInterface.php | 21 ++ .../PermissionLabelsBuilderInterface.php | 25 ++ .../RolesBuilder/RolesBuilderInterface.php | 22 ++ .../RolesBuilder/SecurityRolesBuilder.php | 146 ++++++++ src/SonataUserBundle.php | 2 + src/Twig/RolesMatrixExtension.php | 99 ++++++ .../Compiler/RolesMatrixCompilerPassTest.php | 60 ++++ tests/Form/Type/RolesMatrixTypeTest.php | 115 +++++++ .../RolesBuilder/AdminRolesBuilderTest.php | 178 ++++++++++ .../RolesBuilder/MatrixRolesBuilderTest.php | 110 ++++++ .../RolesBuilder/SecurityRolesBuilderTest.php | 207 ++++++++++++ tests/Twig/RolesMatrixExtensionTest.php | 315 ++++++++++++++++++ 26 files changed, 1833 insertions(+), 3 deletions(-) create mode 100644 docs/images/roles_matrix.png create mode 100644 docs/reference/roles_matrix.rst create mode 100644 src/DependencyInjection/Compiler/RolesMatrixCompilerPass.php create mode 100644 src/Form/Type/RolesMatrixType.php create mode 100644 src/Resources/views/Form/roles_matrix.html.twig create mode 100644 src/Resources/views/Form/roles_matrix_list.html.twig create mode 100644 src/Security/RolesBuilder/AdminRolesBuilder.php create mode 100644 src/Security/RolesBuilder/AdminRolesBuilderInterface.php create mode 100644 src/Security/RolesBuilder/ExpandableRolesBuilderInterface.php create mode 100644 src/Security/RolesBuilder/MatrixRolesBuilder.php create mode 100644 src/Security/RolesBuilder/MatrixRolesBuilderInterface.php create mode 100644 src/Security/RolesBuilder/PermissionLabelsBuilderInterface.php create mode 100644 src/Security/RolesBuilder/RolesBuilderInterface.php create mode 100644 src/Security/RolesBuilder/SecurityRolesBuilder.php create mode 100644 src/Twig/RolesMatrixExtension.php create mode 100644 tests/DependencyInjection/Compiler/RolesMatrixCompilerPassTest.php create mode 100755 tests/Form/Type/RolesMatrixTypeTest.php create mode 100644 tests/Security/RolesBuilder/AdminRolesBuilderTest.php create mode 100644 tests/Security/RolesBuilder/MatrixRolesBuilderTest.php create mode 100644 tests/Security/RolesBuilder/SecurityRolesBuilderTest.php create mode 100644 tests/Twig/RolesMatrixExtensionTest.php diff --git a/docs/images/roles_matrix.png b/docs/images/roles_matrix.png new file mode 100644 index 0000000000000000000000000000000000000000..701d0715765bdf1d226d005b86fa68d95268fbf8 GIT binary patch literal 173223 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 + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Sonata\UserBundle\DependencyInjection\Compiler; + +use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; +use Symfony\Component\DependencyInjection\ContainerBuilder; + +/** + * @author Christian Gripp + * @author Cengizhan Çalışkan + * @author Silas Joisten + */ +final class RolesMatrixCompilerPass implements CompilerPassInterface +{ + public function process(ContainerBuilder $container): void + { + foreach ($container->findTaggedServiceIds('sonata.admin') as $name => $items) { + foreach ($items as $item) { + if (($item['show_in_roles_matrix'] ?? true) === false) { + $container->getDefinition('sonata.user.admin_roles_builder') + ->addMethodCall('addExcludeAdmin', [$name]); + } + } + } + } +} diff --git a/src/Form/Type/RolesMatrixType.php b/src/Form/Type/RolesMatrixType.php new file mode 100644 index 000000000..6dc9fd40a --- /dev/null +++ b/src/Form/Type/RolesMatrixType.php @@ -0,0 +1,103 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Sonata\UserBundle\Form\Type; + +use Sonata\UserBundle\Security\RolesBuilder\ExpandableRolesBuilderInterface; +use Symfony\Component\Form\AbstractType; +use Symfony\Component\Form\Extension\Core\Type\ChoiceType; +use Symfony\Component\Form\FormTypeInterface; +use Symfony\Component\OptionsResolver\Options; +use Symfony\Component\OptionsResolver\OptionsResolver; + +/** + * @author Silas Joisten + */ +final class RolesMatrixType extends AbstractType +{ + /** + * @var ExpandableRolesBuilderInterface + */ + private $rolesBuilder; + + public function __construct(ExpandableRolesBuilderInterface $rolesBuilder) + { + $this->rolesBuilder = $rolesBuilder; + } + + /** + * {@inheritdoc} + */ + public function configureOptions(OptionsResolver $resolver): void + { + $resolver->setDefaults([ + 'expanded' => true, + 'choices' => function (Options $options, $parentChoices): array { + if (!empty($parentChoices)) { + return []; + } + + $roles = $this->rolesBuilder->getRoles( + $options['choice_translation_domain'], + $options['expanded'] + ); + $roles = array_keys($roles); + + return array_combine($roles, $roles); + }, + 'choice_translation_domain' => function (Options $options, $value): ?string { + // if choice_translation_domain is true, then it's the same as translation_domain + if (true === $value) { + $value = $options['translation_domain']; + } + if (null === $value) { + // no translation domain yet, try to ask sonata admin + $admin = null; + if (isset($options['sonata_admin'])) { + $admin = $options['sonata_admin']; + } + if (null === $admin && isset($options['sonata_field_description'])) { + $admin = $options['sonata_field_description']->getAdmin(); + } + if (null !== $admin) { + $value = $admin->getTranslationDomain(); + } + } + + return $value; + }, + + 'data_class' => null, + ]); + + // Symfony 2.8 BC + if (method_exists(FormTypeInterface::class, 'setDefaultOptions')) { + $resolver->setDefault('choices_as_values', true); + } + } + + public function getParent(): string + { + return ChoiceType::class; + } + + public function getBlockPrefix(): string + { + return 'sonata_roles_matrix'; + } + + public function getName(): string + { + return $this->getBlockPrefix(); + } +} diff --git a/src/Resources/config/admin.xml b/src/Resources/config/admin.xml index cfd1e8d7e..3b943032c 100644 --- a/src/Resources/config/admin.xml +++ b/src/Resources/config/admin.xml @@ -1,7 +1,7 @@ - + @@ -10,9 +10,29 @@ - + + + + + + + + + + + + + + + + %security.role_hierarchy.roles% + + + + + diff --git a/src/Resources/config/twig.xml b/src/Resources/config/twig.xml index a787a00dc..3715bba5d 100644 --- a/src/Resources/config/twig.xml +++ b/src/Resources/config/twig.xml @@ -1,8 +1,12 @@ - + + + + + diff --git a/src/Resources/views/Form/form_admin_fields.html.twig b/src/Resources/views/Form/form_admin_fields.html.twig index a0ad8d91c..de1738dc8 100644 --- a/src/Resources/views/Form/form_admin_fields.html.twig +++ b/src/Resources/views/Form/form_admin_fields.html.twig @@ -27,3 +27,12 @@ file that was distributed with this source code. {% endif %} {% endspaceless %} {% endblock sonata_security_roles_widget %} + +{% block sonata_roles_matrix_widget %} +{% spaceless %} + {{ renderMatrix(form)|raw }} +
    + {{ renderRolesList(form)|raw }} +
+{% endspaceless %} +{% endblock sonata_roles_matrix_widget %} diff --git a/src/Resources/views/Form/roles_matrix.html.twig b/src/Resources/views/Form/roles_matrix.html.twig new file mode 100644 index 000000000..7dcfd3cde --- /dev/null +++ b/src/Resources/views/Form/roles_matrix.html.twig @@ -0,0 +1,41 @@ +{# + +This file is part of the Sonata package. + +(c) Thomas Rabaix + +For the full copyright and license information, please view the LICENSE +file that was distributed with this source code. + +#} + + + + + {% for label in permission_labels|sort %} + + {% endfor %} + + + + {% for admin_label, roles in grouped_roles %} + + + {% for role, attributes in roles|sort %} + + {% endfor %} + + {% endfor %} + +
{{ label }}
{{ admin_label }} + {{ form_widget(attributes.form, { label: false }) }} + {% if not attributes.is_granted %} + + {% endif %} +
+ diff --git a/src/Resources/views/Form/roles_matrix_list.html.twig b/src/Resources/views/Form/roles_matrix_list.html.twig new file mode 100644 index 000000000..f8ddd8f82 --- /dev/null +++ b/src/Resources/views/Form/roles_matrix_list.html.twig @@ -0,0 +1,21 @@ +{# + +This file is part of the Sonata package. + +(c) Thomas Rabaix + +For the full copyright and license information, please view the LICENSE +file that was distributed with this source code. + +#} +{% for role, attributes in roles|sort %} +
  • {{ form_widget(attributes.form, {label: attributes.role_translated, value: attributes.role}) }}
  • + {% if not attributes.is_granted %} + + {% endif %} +{% endfor %} diff --git a/src/Security/RolesBuilder/AdminRolesBuilder.php b/src/Security/RolesBuilder/AdminRolesBuilder.php new file mode 100644 index 000000000..b0bb8fee9 --- /dev/null +++ b/src/Security/RolesBuilder/AdminRolesBuilder.php @@ -0,0 +1,118 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Sonata\UserBundle\Security\RolesBuilder; + +use Sonata\AdminBundle\Admin\AdminInterface; +use Sonata\AdminBundle\Admin\Pool; +use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface; +use Symfony\Component\Translation\TranslatorInterface; + +/** + * @author Silas Joisten + */ +final class AdminRolesBuilder implements AdminRolesBuilderInterface +{ + /** + * @var AuthorizationCheckerInterface + */ + private $authorizationChecker; + + /** + * @var Pool + */ + private $pool; + + /** + * @var TranslatorInterface + */ + private $translator; + + /** + * @var string [] + */ + private $excludeAdmins = []; + + public function __construct( + AuthorizationCheckerInterface $authorizationChecker, + Pool $pool, + TranslatorInterface $translator + ) { + $this->authorizationChecker = $authorizationChecker; + $this->pool = $pool; + $this->translator = $translator; + } + + public function getPermissionLabels(): array + { + $permissionLabels = []; + foreach ($this->getRoles() as $attributes) { + if (isset($attributes['label'])) { + $permissionLabels[$attributes['label']] = $attributes['label']; + } + } + + return $permissionLabels; + } + + public function getExcludeAdmins(): array + { + return $this->excludeAdmins; + } + + public function addExcludeAdmin(string $exclude): void + { + $this->excludeAdmins[] = $exclude; + } + + public function getRoles(string $domain = null): array + { + $adminRoles = []; + foreach ($this->pool->getAdminServiceIds() as $id) { + if (in_array($id, $this->excludeAdmins)) { + continue; + } + + $admin = $this->pool->getInstance($id); + $securityHandler = $admin->getSecurityHandler(); + $baseRole = $securityHandler->getBaseRole($admin); + foreach (array_keys($admin->getSecurityInformation()) as $key) { + $role = sprintf($baseRole, $key); + $adminRoles[$role] = [ + 'role' => $role, + 'label' => $key, + 'role_translated' => $this->translateRole($role, $domain), + 'is_granted' => $this->isMaster($admin) || $this->authorizationChecker->isGranted($role), + 'admin_label' => $admin->getTranslator()->trans($admin->getLabel()), + ]; + } + } + + return $adminRoles; + } + + private function isMaster(AdminInterface $admin): bool + { + return $admin->isGranted('MASTER') || $admin->isGranted('OPERATOR') + || $this->authorizationChecker->isGranted($this->pool->getOption('role_super_admin')); + } + + private function translateRole(string $role, $domain): string + { + if ($domain) { + return $this->translator->trans($role, [], $domain); + } + + return $role; + } +} diff --git a/src/Security/RolesBuilder/AdminRolesBuilderInterface.php b/src/Security/RolesBuilder/AdminRolesBuilderInterface.php new file mode 100644 index 000000000..ab2914fa2 --- /dev/null +++ b/src/Security/RolesBuilder/AdminRolesBuilderInterface.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Sonata\UserBundle\Security\RolesBuilder; + +/** + * @author Silas Joisten + */ +interface AdminRolesBuilderInterface extends RolesBuilderInterface, PermissionLabelsBuilderInterface +{ +} diff --git a/src/Security/RolesBuilder/ExpandableRolesBuilderInterface.php b/src/Security/RolesBuilder/ExpandableRolesBuilderInterface.php new file mode 100644 index 000000000..43979d60a --- /dev/null +++ b/src/Security/RolesBuilder/ExpandableRolesBuilderInterface.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Sonata\UserBundle\Security\RolesBuilder; + +/** + * @author Silas Joisten + */ +interface ExpandableRolesBuilderInterface extends RolesBuilderInterface +{ + public function getExpandedRoles(?string $domain = null): array; +} diff --git a/src/Security/RolesBuilder/MatrixRolesBuilder.php b/src/Security/RolesBuilder/MatrixRolesBuilder.php new file mode 100644 index 000000000..c9b300bf9 --- /dev/null +++ b/src/Security/RolesBuilder/MatrixRolesBuilder.php @@ -0,0 +1,76 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Sonata\UserBundle\Security\RolesBuilder; + +use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; + +/** + * @author Silas Joisten + */ +final class MatrixRolesBuilder implements MatrixRolesBuilderInterface +{ + /** + * @var TokenStorageInterface + */ + private $tokenStorage; + + /** + * @var AdminRolesBuilderInterface + */ + private $adminRolesBuilder; + + /** + * @var ExpandableRolesBuilderInterface + */ + private $securityRolesBuilder; + + public function __construct( + TokenStorageInterface $tokenStorage, + AdminRolesBuilderInterface $adminRolesBuilder, + ExpandableRolesBuilderInterface $securityRolesBuilder + ) { + $this->tokenStorage = $tokenStorage; + $this->adminRolesBuilder = $adminRolesBuilder; + $this->securityRolesBuilder = $securityRolesBuilder; + } + + public function getRoles(?string $domain = null): array + { + if (!$this->tokenStorage->getToken()) { + return []; + } + + return array_merge( + $this->securityRolesBuilder->getRoles($domain), + $this->adminRolesBuilder->getRoles($domain) + ); + } + + public function getExpandedRoles(?string $domain = null): array + { + if (!$this->tokenStorage->getToken()) { + return []; + } + + return array_merge( + $this->securityRolesBuilder->getExpandedRoles($domain), + $this->adminRolesBuilder->getRoles($domain) + ); + } + + public function getPermissionLabels(): array + { + return $this->adminRolesBuilder->getPermissionLabels(); + } +} diff --git a/src/Security/RolesBuilder/MatrixRolesBuilderInterface.php b/src/Security/RolesBuilder/MatrixRolesBuilderInterface.php new file mode 100644 index 000000000..1734138b9 --- /dev/null +++ b/src/Security/RolesBuilder/MatrixRolesBuilderInterface.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Sonata\UserBundle\Security\RolesBuilder; + +/** + * @author Silas Joisten + */ +interface MatrixRolesBuilderInterface extends ExpandableRolesBuilderInterface, PermissionLabelsBuilderInterface +{ +} diff --git a/src/Security/RolesBuilder/PermissionLabelsBuilderInterface.php b/src/Security/RolesBuilder/PermissionLabelsBuilderInterface.php new file mode 100644 index 000000000..88f50055d --- /dev/null +++ b/src/Security/RolesBuilder/PermissionLabelsBuilderInterface.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Sonata\UserBundle\Security\RolesBuilder; + +/** + * @author Silas Joisten + */ +interface PermissionLabelsBuilderInterface +{ + /** + * @return string[] + */ + public function getPermissionLabels(): array; +} diff --git a/src/Security/RolesBuilder/RolesBuilderInterface.php b/src/Security/RolesBuilder/RolesBuilderInterface.php new file mode 100644 index 000000000..9a71d8fb5 --- /dev/null +++ b/src/Security/RolesBuilder/RolesBuilderInterface.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Sonata\UserBundle\Security\RolesBuilder; + +/** + * @author Silas Joisten + */ +interface RolesBuilderInterface +{ + public function getRoles(?string $domain = null): array; +} diff --git a/src/Security/RolesBuilder/SecurityRolesBuilder.php b/src/Security/RolesBuilder/SecurityRolesBuilder.php new file mode 100644 index 000000000..52f9445dd --- /dev/null +++ b/src/Security/RolesBuilder/SecurityRolesBuilder.php @@ -0,0 +1,146 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Sonata\UserBundle\Security\RolesBuilder; + +use Sonata\AdminBundle\Admin\Pool; +use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface; +use Symfony\Component\Translation\TranslatorInterface; + +/** + * @author Silas Joisten + */ +final class SecurityRolesBuilder implements ExpandableRolesBuilderInterface +{ + /** + * @var AuthorizationCheckerInterface + */ + private $authorizationChecker; + + /** + * @var Pool + */ + private $pool; + + /** + * @var TranslatorInterface + */ + private $translator; + + /** + * @var string [] + */ + private $rolesHierarchy; + + public function __construct( + AuthorizationCheckerInterface $authorizationChecker, + Pool $pool, + TranslatorInterface $translator, + array $rolesHierarchy = [] + ) { + $this->authorizationChecker = $authorizationChecker; + $this->pool = $pool; + $this->translator = $translator; + $this->rolesHierarchy = $rolesHierarchy; + } + + public function getExpandedRoles(?string $domain = null): array + { + $securityRoles = []; + foreach ($hierarchy = $this->getHierarchy() as $role => $childRoles) { + $translatedRoles = array_map( + [$this, 'translateRole'], + $childRoles, + array_fill(0, count($childRoles), $domain) + ); + + $translatedRoles = count($translatedRoles) > 0 ? ': '.implode(', ', $translatedRoles) : ''; + $securityRoles[$role] = [ + 'role' => $role, + 'role_translated' => $role.$translatedRoles, + 'is_granted' => $this->authorizationChecker->isGranted($role), + ]; + + $securityRoles = array_merge( + $securityRoles, + $this->getSecurityRoles($hierarchy, $childRoles, $domain) + ); + } + + return $securityRoles; + } + + public function getRoles(?string $domain = null): array + { + $securityRoles = []; + foreach ($hierarchy = $this->getHierarchy() as $role => $childRoles) { + $securityRoles[$role] = $this->getSecurityRole($role, $domain); + $securityRoles = array_merge( + $securityRoles, + $this->getSecurityRoles($hierarchy, $childRoles, $domain) + ); + } + + return $securityRoles; + } + + private function getHierarchy(): array + { + return array_merge([ + $this->pool->getOption('role_super_admin') => [], + $this->pool->getOption('role_admin') => [], + ], $this->rolesHierarchy); + } + + private function getSecurityRole(string $role, ?string $domain): array + { + return [ + 'role' => $role, + 'role_translated' => $this->translateRole($role, $domain), + 'is_granted' => $this->authorizationChecker->isGranted($role), + ]; + } + + private function getSecurityRoles(array $hierarchy, array $roles, ?string $domain): array + { + $securityRoles = []; + foreach ($roles as $role) { + if (!array_key_exists($role, $hierarchy) && !isset($securityRoles[$role]) + && !$this->recursiveArraySearch($role, $securityRoles)) { + $securityRoles[$role] = $this->getSecurityRole($role, $domain); + } + } + + return $securityRoles; + } + + private function translateRole(string $role, $domain): string + { + if ($domain) { + return $this->translator->trans($role, [], $domain); + } + + return $role; + } + + private function recursiveArraySearch(string $role, array $roles): bool + { + foreach ($roles as $key => $value) { + if ($role === $key || (is_array($value) && true === $this->recursiveArraySearch($role, $value))) { + return true; + } + } + + return false; + } +} diff --git a/src/SonataUserBundle.php b/src/SonataUserBundle.php index a5567ea2c..63494c92b 100644 --- a/src/SonataUserBundle.php +++ b/src/SonataUserBundle.php @@ -15,6 +15,7 @@ use Sonata\CoreBundle\Form\FormHelper; use Sonata\UserBundle\DependencyInjection\Compiler\GlobalVariablesCompilerPass; +use Sonata\UserBundle\DependencyInjection\Compiler\RolesMatrixCompilerPass; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\HttpKernel\Bundle\Bundle; @@ -26,6 +27,7 @@ class SonataUserBundle extends Bundle public function build(ContainerBuilder $container): void { $container->addCompilerPass(new GlobalVariablesCompilerPass()); + $container->addCompilerPass(new RolesMatrixCompilerPass()); $this->registerFormMapping(); } diff --git a/src/Twig/RolesMatrixExtension.php b/src/Twig/RolesMatrixExtension.php new file mode 100644 index 000000000..444624298 --- /dev/null +++ b/src/Twig/RolesMatrixExtension.php @@ -0,0 +1,99 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Sonata\UserBundle\Twig; + +use Sonata\UserBundle\Security\RolesBuilder\MatrixRolesBuilderInterface; +use Symfony\Component\Form\FormView; +use Twig\Environment; +use Twig\Extension\AbstractExtension; +use Twig\TwigFunction; + +/** + * @author Christian Gripp + * @author Cengizhan Çalışkan + * @author Silas Joisten + */ +final class RolesMatrixExtension extends AbstractExtension +{ + /** + * @var MatrixRolesBuilderInterface + */ + private $rolesBuilder; + + public function __construct(MatrixRolesBuilderInterface $rolesBuilder) + { + $this->rolesBuilder = $rolesBuilder; + } + + public function getFunctions(): array + { + return [ + new TwigFunction('renderMatrix', [$this, 'renderMatrix'], ['needs_environment' => true]), + new TwigFunction( + 'renderRolesList', + [$this, 'renderRolesList'], + ['needs_environment' => true] + ), + ]; + } + + public function getName(): string + { + return self::class; + } + + public function renderRolesList(Environment $environment, FormView $form): string + { + $roles = $this->rolesBuilder->getRoles(); + foreach ($roles as $role => $attributes) { + if (isset($attributes['admin_label'])) { + unset($roles[$role]); + continue; + } + + $roles[$role] = $attributes; + foreach ($form->getIterator() as $child) { + if ($child->vars['value'] == $role) { + $roles[$role]['form'] = $child; + } + } + } + + return $environment->render('@SonataUser/Form/roles_matrix_list.html.twig', [ + 'roles' => $roles, + ]); + } + + public function renderMatrix(Environment $environment, FormView $form): string + { + $groupedRoles = []; + foreach ($this->rolesBuilder->getRoles() as $role => $attributes) { + if (!isset($attributes['admin_label'])) { + continue; + } + + $groupedRoles[$attributes['admin_label']][$role] = $attributes; + foreach ($form->getIterator() as $child) { + if ($child->vars['value'] == $role) { + $groupedRoles[$attributes['admin_label']][$role]['form'] = $child; + } + } + } + + return $environment->render('@SonataUser/Form/roles_matrix.html.twig', [ + 'grouped_roles' => $groupedRoles, + 'permission_labels' => $this->rolesBuilder->getPermissionLabels(), + ]); + } +} diff --git a/tests/DependencyInjection/Compiler/RolesMatrixCompilerPassTest.php b/tests/DependencyInjection/Compiler/RolesMatrixCompilerPassTest.php new file mode 100644 index 000000000..25d83e69a --- /dev/null +++ b/tests/DependencyInjection/Compiler/RolesMatrixCompilerPassTest.php @@ -0,0 +1,60 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Sonata\UserBundle\Tests\DependencyInjection; + +use PHPUnit\Framework\TestCase; +use Sonata\UserBundle\DependencyInjection\Compiler\RolesMatrixCompilerPass; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Definition; + +/** + * @author Silas Joisten + */ +final class RolesMatrixCompilerPassTest extends TestCase +{ + /** + * @test + */ + public function process(): void + { + $definition = $this->createMock(Definition::class); + + $container = $this->createMock(ContainerBuilder::class); + $container + ->expects($this->once()) + ->method('getDefinition') + ->with('sonata.user.admin_roles_builder') + ->willReturn($definition); + + $taggedServices = [ + 'sonata.admin.foo' => [0 => ['show_in_roles_matrix' => true]], + 'sonata.admin.bar' => [0 => ['show_in_roles_matrix' => false]], + 'sonata.admin.test' => [], + ]; + + $container + ->expects($this->once()) + ->method('findTaggedServiceIds') + ->with('sonata.admin') + ->willReturn($taggedServices); + + $definition + ->expects($this->once()) + ->method('addMethodCall') + ->with('addExcludeAdmin', ['sonata.admin.bar']); + + $compilerPass = new RolesMatrixCompilerPass(); + $compilerPass->process($container); + } +} diff --git a/tests/Form/Type/RolesMatrixTypeTest.php b/tests/Form/Type/RolesMatrixTypeTest.php new file mode 100755 index 000000000..75bc2a969 --- /dev/null +++ b/tests/Form/Type/RolesMatrixTypeTest.php @@ -0,0 +1,115 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Sonata\UserBundle\Tests\Form\Type; + +use Sonata\UserBundle\Form\Type\RolesMatrixType; +use Sonata\UserBundle\Security\RolesBuilder\ExpandableRolesBuilderInterface; +use Symfony\Component\Form\Extension\Core\Type\ChoiceType; +use Symfony\Component\Form\FormTypeInterface; +use Symfony\Component\Form\PreloadedExtension; +use Symfony\Component\Form\Test\TypeTestCase; +use Symfony\Component\OptionsResolver\OptionsResolver; + +/** + * @author Silas Joisten + */ +final class RolesMatrixTypeTest extends TypeTestCase +{ + private $roleBuilder; + + public function testGetDefaultOptions(): void + { + $type = new RolesMatrixType($this->roleBuilder); + + $optionResolver = new OptionsResolver(); + $type->configureOptions($optionResolver); + + $options = $optionResolver->resolve(); + $this->assertCount(3, $options['choices']); + + if (method_exists(FormTypeInterface::class, 'setDefaultOptions')) { + $this->assertTrue($options['choices_as_values']); + } + } + + public function testGetParent(): void + { + $type = new RolesMatrixType($this->roleBuilder); + + $this->assertEquals(ChoiceType::class, $type->getParent()); + } + + public function testSubmitValidData(): void + { + $form = $this->factory->create(RolesMatrixType::class, null, [ + 'multiple' => true, + 'expanded' => true, + 'required' => false, + ]); + + $form->submit([0 => 'ROLE_FOO']); + + $this->assertTrue($form->isSynchronized()); + $this->assertCount(1, $form->getData()); + $this->assertTrue(in_array('ROLE_FOO', $form->getData())); + } + + public function testSubmitInvalidData(): void + { + $form = $this->factory->create(RolesMatrixType::class, null, [ + 'multiple' => true, + 'expanded' => true, + 'required' => false, + ]); + + $form->submit([0 => 'ROLE_NOT_EXISTS']); + + $this->assertFalse($form->isSynchronized()); + $this->assertNull($form->getData()); + } + + public function testChoicesAsValues(): void + { + $resolver = new OptionsResolver(); + $type = new RolesMatrixType($this->roleBuilder); + + // If 'choices_as_values' option is not defined (Symfony >= 3.0), default value should not be set. + $type->configureOptions($resolver); + + // If 'choices_as_values' option is defined (Symfony 2.8), default value should be set to true. + $resolver->setDefault('choices_as_values', true); + $type->configureOptions($resolver); + $options = $resolver->resolve(); + + $this->assertTrue($resolver->hasDefault('choices_as_values')); + $this->assertTrue($options['choices_as_values']); + } + + protected function getExtensions() + { + $this->roleBuilder = $this->createMock(ExpandableRolesBuilderInterface::class); + + $this->roleBuilder->expects($this->any())->method('getRoles')->will($this->returnValue([ + 'ROLE_FOO' => 'ROLE_FOO', + 'ROLE_USER' => 'ROLE_USER', + 'ROLE_ADMIN' => 'ROLE_ADMIN: ROLE_USER', + ])); + + $childType = new RolesMatrixType($this->roleBuilder); + + return [new PreloadedExtension([ + $childType->getName() => $childType, + ], [])]; + } +} diff --git a/tests/Security/RolesBuilder/AdminRolesBuilderTest.php b/tests/Security/RolesBuilder/AdminRolesBuilderTest.php new file mode 100644 index 000000000..75ff10d90 --- /dev/null +++ b/tests/Security/RolesBuilder/AdminRolesBuilderTest.php @@ -0,0 +1,178 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Sonata\UserBundle\Tests\Security\RolesBuilder; + +use PHPUnit\Framework\TestCase; +use Sonata\AdminBundle\Admin\AdminInterface; +use Sonata\AdminBundle\Admin\Pool; +use Sonata\AdminBundle\Security\Handler\SecurityHandlerInterface; +use Sonata\UserBundle\Security\RolesBuilder\AdminRolesBuilder; +use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; +use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; +use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface; +use Symfony\Component\Translation\TranslatorInterface; + +/** + * @author Silas Joisten + */ +final class AdminRolesBuilderTest extends TestCase +{ + private $securityHandler; + private $authorizationChecker; + private $admin; + private $tokenStorage; + private $token; + private $pool; + private $translator; + + private $securityInformation = [ + 'GUEST' => [0 => 'VIEW', 1 => 'LIST'], + 'STAFF' => [0 => 'EDIT', 1 => 'LIST', 2 => 'CREATE'], + 'EDITOR' => [0 => 'OPERATOR', 1 => 'EXPORT'], + 'ADMIN' => [0 => 'MASTER'], + ]; + + public function setUp(): void + { + $this->securityHandler = $this->createMock(SecurityHandlerInterface::class); + $this->authorizationChecker = $this->createMock(AuthorizationCheckerInterface::class); + $this->admin = $this->createMock(AdminInterface::class); + $this->tokenStorage = $this->createMock(TokenStorageInterface::class); + $this->token = $this->createMock(TokenInterface::class); + $this->pool = $this->createMock(Pool::class); + $this->translator = $this->createMock(TranslatorInterface::class); + } + + public function testGetPermissionLabels(): void + { + $this->translator->method('trans'); + + $this->securityHandler->method('getBaseRole') + ->willReturn('ROLE_SONATA_FOO_%s'); + + $this->admin->method('getSecurityHandler') + ->willReturn($this->securityHandler); + + $this->admin->method('getTranslator') + ->willReturn($this->translator); + + $this->admin->method('getSecurityInformation') + ->willReturn($this->securityInformation); + + $this->pool->expects($this->once()) + ->method('getAdminServiceIds') + ->willReturn(['sonata.admin.bar']); + + $this->pool->expects($this->once()) + ->method('getInstance') + ->with('sonata.admin.bar') + ->willReturn($this->admin); + + $rolesBuilder = new AdminRolesBuilder( + $this->authorizationChecker, + $this->pool, + $this->translator + ); + + $expected = [ + 'GUEST' => 'GUEST', + 'STAFF' => 'STAFF', + 'EDITOR' => 'EDITOR', + 'ADMIN' => 'ADMIN', + ]; + + $this->assertSame($expected, $rolesBuilder->getPermissionLabels()); + } + + public function testGetRoles(): void + { + $this->translator->method('trans') + ->willReturn('Foo'); + + $this->securityHandler->method('getBaseRole') + ->willReturn('ROLE_SONATA_FOO_%s'); + + $this->admin->method('getSecurityHandler') + ->willReturn($this->securityHandler); + + $this->admin->method('getTranslator') + ->willReturn($this->translator); + + $this->admin->method('getSecurityInformation') + ->willReturn($this->securityInformation); + + $this->admin->method('getLabel') + ->willReturn('Foo'); + + $this->pool->expects($this->once()) + ->method('getAdminServiceIds') + ->willReturn(['sonata.admin.bar']); + + $this->pool->expects($this->once()) + ->method('getInstance') + ->with('sonata.admin.bar') + ->willReturn($this->admin); + + $rolesBuilder = new AdminRolesBuilder( + $this->authorizationChecker, + $this->pool, + $this->translator + ); + + $expected = [ + 'ROLE_SONATA_FOO_GUEST' => [ + 'role' => 'ROLE_SONATA_FOO_GUEST', + 'label' => 'GUEST', + 'role_translated' => 'ROLE_SONATA_FOO_GUEST', + 'is_granted' => false, + 'admin_label' => 'Foo', + ], + 'ROLE_SONATA_FOO_STAFF' => [ + 'role' => 'ROLE_SONATA_FOO_STAFF', + 'label' => 'STAFF', + 'role_translated' => 'ROLE_SONATA_FOO_STAFF', + 'is_granted' => false, + 'admin_label' => 'Foo', + ], + 'ROLE_SONATA_FOO_EDITOR' => [ + 'role' => 'ROLE_SONATA_FOO_EDITOR', + 'label' => 'EDITOR', + 'role_translated' => 'ROLE_SONATA_FOO_EDITOR', + 'is_granted' => false, + 'admin_label' => 'Foo', + ], + 'ROLE_SONATA_FOO_ADMIN' => [ + 'role' => 'ROLE_SONATA_FOO_ADMIN', + 'label' => 'ADMIN', + 'role_translated' => 'ROLE_SONATA_FOO_ADMIN', + 'is_granted' => false, + 'admin_label' => 'Foo', + ], + ]; + + $this->assertSame($expected, $rolesBuilder->getRoles()); + } + + public function testGetAddExcludeAdmins(): void + { + $rolesBuilder = new AdminRolesBuilder( + $this->authorizationChecker, + $this->pool, + $this->translator + ); + $rolesBuilder->addExcludeAdmin('sonata.admin.bar'); + + $this->assertSame(['sonata.admin.bar'], $rolesBuilder->getExcludeAdmins()); + } +} diff --git a/tests/Security/RolesBuilder/MatrixRolesBuilderTest.php b/tests/Security/RolesBuilder/MatrixRolesBuilderTest.php new file mode 100644 index 000000000..393cca762 --- /dev/null +++ b/tests/Security/RolesBuilder/MatrixRolesBuilderTest.php @@ -0,0 +1,110 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Sonata\UserBundle\Tests\Security\RolesBuilder; + +use PHPUnit\Framework\TestCase; +use Sonata\UserBundle\Security\RolesBuilder\AdminRolesBuilderInterface; +use Sonata\UserBundle\Security\RolesBuilder\ExpandableRolesBuilderInterface; +use Sonata\UserBundle\Security\RolesBuilder\MatrixRolesBuilder; +use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; +use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; + +/** + * @author Silas Joisten + */ +final class MatrixRolesBuilderTest extends TestCase +{ + private $tokenStorage; + private $token; + private $adminRolesBuilder; + private $securityRolesBuilder; + + public function setUp(): void + { + $this->tokenStorage = $this->createMock(TokenStorageInterface::class); + $this->token = $this->createMock(TokenInterface::class); + $this->adminRolesBuilder = $this->createMock(AdminRolesBuilderInterface::class); + $this->securityRolesBuilder = $this->createMock(ExpandableRolesBuilderInterface::class); + } + + public function testGetPermissionLabels(): void + { + $expected = ['EDIT' => 'EDIT', 'LIST' => 'LIST', 'CREATE' => 'CREATE']; + + $this->adminRolesBuilder->method('getPermissionLabels') + ->willReturn($expected); + + $matrixRolesBuilder = new MatrixRolesBuilder( + $this->tokenStorage, + $this->adminRolesBuilder, + $this->securityRolesBuilder + ); + + $this->assertSame($expected, $matrixRolesBuilder->getPermissionLabels()); + } + + public function testGetRoles(): void + { + $this->tokenStorage->method('getToken') + ->willReturn($this->token); + + $adminRoles = [ + 'ROLE_SONATA_FOO_GUEST' => [ + 'role' => 'ROLE_SONATA_FOO_GUEST', + 'label' => 'GUEST', + 'role_translated' => 'ROLE_SONATA_FOO_GUEST', + 'is_granted' => false, + 'admin_label' => 'Foo', + ], + ]; + + $this->adminRolesBuilder->method('getRoles') + ->willReturn($adminRoles); + + $securityRoles = [ + 'ROLE_FOO' => [ + 'role' => 'ROLE_FOO', + 'role_translated' => 'ROLE_FOO: ROLE_BAR, ROLE_ADMIN', + 'is_granted' => true, + ], + ]; + + $this->securityRolesBuilder->method('getRoles') + ->willReturn($securityRoles); + + $matrixRolesBuilder = new MatrixRolesBuilder( + $this->tokenStorage, + $this->adminRolesBuilder, + $this->securityRolesBuilder + ); + + $expected = array_merge($securityRoles, $adminRoles); + + $this->assertSame($expected, $matrixRolesBuilder->getRoles()); + } + + public function testGetRolesNoToken(): void + { + $this->tokenStorage->method('getToken') + ->willReturn(null); + + $matrixRolesBuilder = new MatrixRolesBuilder( + $this->tokenStorage, + $this->adminRolesBuilder, + $this->securityRolesBuilder + ); + + $this->assertEmpty($matrixRolesBuilder->getRoles()); + } +} diff --git a/tests/Security/RolesBuilder/SecurityRolesBuilderTest.php b/tests/Security/RolesBuilder/SecurityRolesBuilderTest.php new file mode 100644 index 000000000..6c677fd8c --- /dev/null +++ b/tests/Security/RolesBuilder/SecurityRolesBuilderTest.php @@ -0,0 +1,207 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Sonata\UserBundle\Tests\Security\RolesBuilder; + +use PHPUnit\Framework\TestCase; +use Sonata\AdminBundle\Admin\AdminInterface; +use Sonata\AdminBundle\Admin\Pool; +use Sonata\UserBundle\Security\RolesBuilder\SecurityRolesBuilder; +use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface; +use Symfony\Component\Translation\TranslatorInterface; + +/** + * @author Silas Joisten + */ +final class SecurityRolesBuilderTest extends TestCase +{ + private $authorizationChecker; + private $admin; + private $pool; + private $translator; + private $rolesHierarchy = ['ROLE_FOO' => ['ROLE_BAR', 'ROLE_ADMIN']]; + + public function setUp(): void + { + $this->authorizationChecker = $this->createMock(AuthorizationCheckerInterface::class); + $this->admin = $this->createMock(AdminInterface::class); + $this->pool = $this->createMock(Pool::class); + $this->translator = $this->createMock(TranslatorInterface::class); + } + + public function testGetRoles(): void + { + $this->pool->expects($this->at(0)) + ->method('getOption') + ->with('role_super_admin') + ->willReturn('ROLE_SUPER_ADMIN'); + + $this->pool->expects($this->at(1)) + ->method('getOption') + ->with('role_admin') + ->willReturn('ROLE_SONATA_ADMIN'); + + $securityRolesBuilder = new SecurityRolesBuilder( + $this->authorizationChecker, + $this->pool, + $this->translator, + $this->rolesHierarchy + ); + + $this->authorizationChecker->method('isGranted') + ->willReturn(true); + + $expected = [ + 'ROLE_SUPER_ADMIN' => [ + 'role' => 'ROLE_SUPER_ADMIN', + 'role_translated' => 'ROLE_SUPER_ADMIN', + 'is_granted' => true, + ], + 'ROLE_SONATA_ADMIN' => [ + 'role' => 'ROLE_SONATA_ADMIN', + 'role_translated' => 'ROLE_SONATA_ADMIN', + 'is_granted' => true, + ], + 'ROLE_FOO' => [ + 'role' => 'ROLE_FOO', + 'role_translated' => 'ROLE_FOO: ROLE_BAR, ROLE_ADMIN', + 'is_granted' => true, + ], + 'ROLE_BAR' => [ + 'role' => 'ROLE_BAR', + 'role_translated' => 'ROLE_BAR', + 'is_granted' => true, + ], + 'ROLE_ADMIN' => [ + 'role' => 'ROLE_ADMIN', + 'role_translated' => 'ROLE_ADMIN', + 'is_granted' => true, + ], + ]; + + $this->assertEquals($expected, $securityRolesBuilder->getExpandedRoles()); + } + + public function testGetRolesNotExpanded(): void + { + $this->pool->expects($this->at(0)) + ->method('getOption') + ->with('role_super_admin') + ->willReturn('ROLE_SUPER_ADMIN'); + + $this->pool->expects($this->at(1)) + ->method('getOption') + ->with('role_admin') + ->willReturn('ROLE_SONATA_ADMIN'); + + $securityRolesBuilder = new SecurityRolesBuilder( + $this->authorizationChecker, + $this->pool, + $this->translator, + $this->rolesHierarchy + ); + + $this->authorizationChecker->method('isGranted') + ->willReturn(true); + + $expected = [ + 'ROLE_SUPER_ADMIN' => [ + 'role' => 'ROLE_SUPER_ADMIN', + 'role_translated' => 'ROLE_SUPER_ADMIN', + 'is_granted' => true, + ], + 'ROLE_SONATA_ADMIN' => [ + 'role' => 'ROLE_SONATA_ADMIN', + 'role_translated' => 'ROLE_SONATA_ADMIN', + 'is_granted' => true, + ], + 'ROLE_FOO' => [ + 'role' => 'ROLE_FOO', + 'role_translated' => 'ROLE_FOO', + 'is_granted' => true, + ], + 'ROLE_BAR' => [ + 'role' => 'ROLE_BAR', + 'role_translated' => 'ROLE_BAR', + 'is_granted' => true, + ], + 'ROLE_ADMIN' => [ + 'role' => 'ROLE_ADMIN', + 'role_translated' => 'ROLE_ADMIN', + 'is_granted' => true, + ], + ]; + + $this->assertEquals($expected, $securityRolesBuilder->getRoles(null, false)); + } + + public function testGetRolesWithExistingRole(): void + { + $this->pool->expects($this->at(0)) + ->method('getOption') + ->with('role_super_admin') + ->willReturn('ROLE_SUPER_ADMIN'); + + $this->pool->expects($this->at(1)) + ->method('getOption') + ->with('role_admin') + ->willReturn('ROLE_SONATA_ADMIN'); + + $this->rolesHierarchy['ROLE_STAFF'] = ['ROLE_SUPER_ADMIN', 'ROLE_SUPER_ADMIN']; + + $securityRolesBuilder = new SecurityRolesBuilder( + $this->authorizationChecker, + $this->pool, + $this->translator, + $this->rolesHierarchy + ); + + $this->authorizationChecker->method('isGranted') + ->willReturn(true); + + $expected = [ + 'ROLE_SUPER_ADMIN' => [ + 'role' => 'ROLE_SUPER_ADMIN', + 'role_translated' => 'ROLE_SUPER_ADMIN', + 'is_granted' => true, + ], + 'ROLE_SONATA_ADMIN' => [ + 'role' => 'ROLE_SONATA_ADMIN', + 'role_translated' => 'ROLE_SONATA_ADMIN', + 'is_granted' => true, + ], + 'ROLE_FOO' => [ + 'role' => 'ROLE_FOO', + 'role_translated' => 'ROLE_FOO: ROLE_BAR, ROLE_ADMIN', + 'is_granted' => true, + ], + 'ROLE_BAR' => [ + 'role' => 'ROLE_BAR', + 'role_translated' => 'ROLE_BAR', + 'is_granted' => true, + ], + 'ROLE_ADMIN' => [ + 'role' => 'ROLE_ADMIN', + 'role_translated' => 'ROLE_ADMIN', + 'is_granted' => true, + ], + 'ROLE_STAFF' => [ + 'role' => 'ROLE_STAFF', + 'role_translated' => 'ROLE_STAFF: ROLE_SUPER_ADMIN, ROLE_SUPER_ADMIN', + 'is_granted' => true, + ], + ]; + + $this->assertEquals($expected, $securityRolesBuilder->getExpandedRoles()); + } +} diff --git a/tests/Twig/RolesMatrixExtensionTest.php b/tests/Twig/RolesMatrixExtensionTest.php new file mode 100644 index 000000000..290c5fbca --- /dev/null +++ b/tests/Twig/RolesMatrixExtensionTest.php @@ -0,0 +1,315 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Sonata\UserBundle\Tests\Twig; + +use PHPUnit\Framework\TestCase; +use Sonata\UserBundle\Security\RolesBuilder\MatrixRolesBuilderInterface; +use Sonata\UserBundle\Twig\RolesMatrixExtension; +use Symfony\Component\Form\FormView; +use Twig\Environment; + +/** + * @author Silas Joisten + */ +final class RolesMatrixExtensionTest extends TestCase +{ + private $rolesBuilder; + private $environment; + private $formView; + + /** + * {@inheritdoc} + */ + public function setUp(): void + { + $this->rolesBuilder = $this->createMock(MatrixRolesBuilderInterface::class); + $this->environment = $this->createMock(Environment::class); + $this->formView = $this->createMock(FormView::class); + } + + public function testGetName(): void + { + $rolesMatrixExtension = new RolesMatrixExtension($this->rolesBuilder); + $this->assertSame(RolesMatrixExtension::class, $rolesMatrixExtension->getName()); + } + + /** + * @test + */ + public function renderRolesListWithAdminLabel(): void + { + $roles = [ + 'SUPER_TEST_ROLE' => [ + 'role' => 'SUPER_TEST_ROLE', + 'role_translated' => 'SUPER TEST ROLE TRANSLATED', + 'is_granted' => true, + 'admin_label' => 'admin_name', + ], + ]; + $this->rolesBuilder + ->expects($this->once()) + ->method('getRoles') + ->willReturn($roles); + + $this->formView + ->expects($this->never()) + ->method('getIterator'); + + $this->environment + ->expects($this->once()) + ->method('render') + ->with('@SonataUser/Form/roles_matrix_list.html.twig', ['roles' => []]) + ->willReturn('') + ; + + $rolesMatrixExtension = new RolesMatrixExtension($this->rolesBuilder); + $rolesMatrixExtension->renderRolesList($this->environment, $this->formView); + } + + /** + * @test + */ + public function renderRolesList(): void + { + $roles = [ + 'SUPER_TEST_ROLE' => [ + 'role' => 'SUPER_TEST_ROLE', + 'role_translated' => 'SUPER TEST ROLE TRANSLATED', + 'is_granted' => true, + ], + ]; + $this->rolesBuilder + ->expects($this->once()) + ->method('getRoles') + ->willReturn($roles); + + $form = new FormView(); + $form->vars['value'] = 'SUPER_TEST_ROLE'; + + $this->formView + ->method('getIterator') + ->willReturn([$form]); + + $this->environment + ->expects($this->once()) + ->method('render') + ->with('@SonataUser/Form/roles_matrix_list.html.twig', [ + 'roles' => [ + 'SUPER_TEST_ROLE' => [ + 'role' => 'SUPER_TEST_ROLE', + 'role_translated' => 'SUPER TEST ROLE TRANSLATED', + 'is_granted' => true, + 'form' => $form, + ], + ], + ]) + ->willReturn(''); + + $rolesMatrixExtension = new RolesMatrixExtension($this->rolesBuilder); + $rolesMatrixExtension->renderRolesList($this->environment, $this->formView); + } + + /** + * @test + */ + public function renderRolesListWithoutFormValue(): void + { + $roles = [ + 'SUPER_TEST_ROLE' => [ + 'role' => 'SUPER_TEST_ROLE', + 'role_translated' => 'SUPER TEST ROLE TRANSLATED', + 'is_granted' => true, + ], + ]; + $this->rolesBuilder + ->expects($this->once()) + ->method('getRoles') + ->willReturn($roles); + + $form = new FormView(); + $form->vars['value'] = 'WRONG_VALUE'; + + $this->formView + ->method('getIterator') + ->willReturn([$form]); + + $this->environment + ->expects($this->once()) + ->method('render') + ->with('@SonataUser/Form/roles_matrix_list.html.twig', [ + 'roles' => [ + 'SUPER_TEST_ROLE' => [ + 'role' => 'SUPER_TEST_ROLE', + 'role_translated' => 'SUPER TEST ROLE TRANSLATED', + 'is_granted' => true, + ], + ], + ]) + ->willReturn(''); + + $rolesMatrixExtension = new RolesMatrixExtension($this->rolesBuilder); + $rolesMatrixExtension->renderRolesList($this->environment, $this->formView); + } + + /** + * @test + */ + public function renderMatrixWithoutAdminLabels(): void + { + $roles = [ + 'BASE_ROLE_FOO_%s' => [ + 'role' => 'BASE_ROLE_FOO_EDIT', + 'label' => 'EDIT', + 'role_translated' => 'ROLE FOO TRANSLATED', + 'is_granted' => true, + ], + ]; + $this->rolesBuilder + ->expects($this->once()) + ->method('getRoles') + ->willReturn($roles); + + $this->rolesBuilder + ->expects($this->once()) + ->method('getPermissionLabels') + ->willReturn(['EDIT', 'CREATE']); + + $this->formView + ->expects($this->never()) + ->method('getIterator'); + + $this->environment + ->expects($this->once()) + ->method('render') + ->with('@SonataUser/Form/roles_matrix.html.twig', [ + 'grouped_roles' => [], + 'permission_labels' => ['EDIT', 'CREATE'], + ]) + ->willReturn(''); + + $rolesMatrixExtension = new RolesMatrixExtension($this->rolesBuilder); + $rolesMatrixExtension->renderMatrix($this->environment, $this->formView); + } + + /** + * @test + */ + public function renderMatrix(): void + { + $roles = [ + 'BASE_ROLE_FOO_EDIT' => [ + 'role' => 'BASE_ROLE_FOO_EDIT', + 'label' => 'EDIT', + 'role_translated' => 'ROLE FOO TRANSLATED', + 'admin_label' => 'fooadmin', + 'is_granted' => true, + ], + ]; + $this->rolesBuilder + ->expects($this->once()) + ->method('getRoles') + ->willReturn($roles); + + $this->rolesBuilder + ->expects($this->once()) + ->method('getPermissionLabels') + ->willReturn(['EDIT', 'CREATE']); + + $form = new FormView(); + $form->vars['value'] = 'BASE_ROLE_FOO_EDIT'; + + $this->formView + ->expects($this->once()) + ->method('getIterator') + ->willReturn([$form]); + + $this->environment + ->expects($this->once()) + ->method('render') + ->with('@SonataUser/Form/roles_matrix.html.twig', [ + 'grouped_roles' => [ + 'fooadmin' => [ + 'BASE_ROLE_FOO_EDIT' => [ + 'role' => 'BASE_ROLE_FOO_EDIT', + 'label' => 'EDIT', + 'role_translated' => 'ROLE FOO TRANSLATED', + 'admin_label' => 'fooadmin', + 'is_granted' => true, + 'form' => $form, + ], + ], + ], + 'permission_labels' => ['EDIT', 'CREATE'], + ]) + ->willReturn(''); + + $rolesMatrixExtension = new RolesMatrixExtension($this->rolesBuilder); + $rolesMatrixExtension->renderMatrix($this->environment, $this->formView); + } + + /** + * @test + */ + public function renderMatrixFormVarsNotSet(): void + { + $roles = [ + 'BASE_ROLE_FOO_%s' => [ + 'role' => 'BASE_ROLE_FOO_EDIT', + 'label' => 'EDIT', + 'role_translated' => 'ROLE FOO TRANSLATED', + 'admin_label' => 'fooadmin', + 'is_granted' => true, + ], + ]; + $this->rolesBuilder + ->expects($this->once()) + ->method('getRoles') + ->willReturn($roles); + + $this->rolesBuilder + ->expects($this->once()) + ->method('getPermissionLabels') + ->willReturn(['EDIT', 'CREATE']); + + $form = new FormView(); + $form->vars['value'] = 'WRONG_VALUE'; + + $this->formView + ->expects($this->once()) + ->method('getIterator') + ->willReturn([$form]); + + $this->environment + ->expects($this->once()) + ->method('render') + ->with('@SonataUser/Form/roles_matrix.html.twig', [ + 'grouped_roles' => [ + 'fooadmin' => [ + 'BASE_ROLE_FOO_%s' => [ + 'role' => 'BASE_ROLE_FOO_EDIT', + 'label' => 'EDIT', + 'role_translated' => 'ROLE FOO TRANSLATED', + 'admin_label' => 'fooadmin', + 'is_granted' => true, + ], + ], + ], + 'permission_labels' => ['EDIT', 'CREATE'], + ]) + ->willReturn(''); + + $rolesMatrixExtension = new RolesMatrixExtension($this->rolesBuilder); + $rolesMatrixExtension->renderMatrix($this->environment, $this->formView); + } +}