mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-11-08 05:08:25 +00:00
Improve DX of ScopePickerType and adjust it's implementations
This commit is contained in:
@@ -18,7 +18,6 @@ use Chill\ActivityBundle\Security\Authorization\ActivityVoter;
|
||||
use Chill\DocStoreBundle\Form\CollectionStoredObjectType;
|
||||
use Chill\MainBundle\Entity\Center;
|
||||
use Chill\MainBundle\Entity\Location;
|
||||
use Chill\MainBundle\Entity\Scope;
|
||||
use Chill\MainBundle\Entity\User;
|
||||
use Chill\MainBundle\Form\Type\ChillDateType;
|
||||
use Chill\MainBundle\Form\Type\CommentType;
|
||||
@@ -48,7 +47,6 @@ use Symfony\Component\Form\FormEvent;
|
||||
use Symfony\Component\Form\FormEvents;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
|
||||
use Symfony\Component\Security\Core\Security;
|
||||
|
||||
class ActivityType extends AbstractType
|
||||
{
|
||||
@@ -62,7 +60,6 @@ class ActivityType extends AbstractType
|
||||
protected array $timeChoices,
|
||||
protected SocialIssueRender $socialIssueRender,
|
||||
protected SocialActionRender $socialActionRender,
|
||||
private readonly Security $security,
|
||||
) {
|
||||
if (!$tokenStorage->getToken()->getUser() instanceof User) {
|
||||
throw new \RuntimeException('you should have a valid user');
|
||||
@@ -90,22 +87,10 @@ class ActivityType extends AbstractType
|
||||
$activityType = $options['activityType'];
|
||||
|
||||
if (null !== $options['data']->getPerson()) {
|
||||
|
||||
$reachableScopes = array_values(
|
||||
array_filter(
|
||||
$this->authorizationHelper->getReachableScopes(
|
||||
$this->security->getUser(),
|
||||
ActivityVoter::CREATE === (string) $options['role'] ? ActivityVoter::CREATE_PERSON : (string) $options['role'],
|
||||
$options['center']
|
||||
),
|
||||
static fn (Scope $s) => $s->isActive()
|
||||
)
|
||||
);
|
||||
|
||||
$builder->add('scope', ScopePickerType::class, [
|
||||
'reachable_scopes' => $reachableScopes,
|
||||
'role' => ActivityVoter::CREATE === (string) $options['role'] ? ActivityVoter::CREATE_PERSON : (string) $options['role'],
|
||||
'center' => $options['center'],
|
||||
'required' => true,
|
||||
'label' => count($reachableScopes) > 1 ? 'Scope' : false,
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,6 @@ namespace Chill\DocStoreBundle\Form;
|
||||
use Chill\DocStoreBundle\Entity\Document;
|
||||
use Chill\DocStoreBundle\Entity\DocumentCategory;
|
||||
use Chill\DocStoreBundle\Entity\PersonDocument;
|
||||
use Chill\MainBundle\Entity\Scope;
|
||||
use Chill\MainBundle\Form\Type\ChillDateType;
|
||||
use Chill\MainBundle\Form\Type\ChillTextareaType;
|
||||
use Chill\MainBundle\Form\Type\ScopePickerType;
|
||||
@@ -59,19 +58,9 @@ class PersonDocumentType extends AbstractType
|
||||
]);
|
||||
|
||||
if ($isScopeConcerned && $this->parameterBag->get('chill_main')['acl']['form_show_scopes']) {
|
||||
$reachableScopes = array_values(
|
||||
array_filter(
|
||||
$this->authorizationHelper->getReachableScopes(
|
||||
$this->security->getUser(),
|
||||
$options['role'],
|
||||
$this->centerResolverDispatcher->resolveCenter($document)
|
||||
),
|
||||
static fn (Scope $s) => $s->isActive()
|
||||
)
|
||||
);
|
||||
$builder->add('scope', ScopePickerType::class, [
|
||||
'reachable_scopes' => $reachableScopes,
|
||||
'label' => count($reachableScopes) > 1 ? 'Scope' : false,
|
||||
'role' => $options['role'],
|
||||
'subject' => $document,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ use Chill\MainBundle\Entity\Scope;
|
||||
use Chill\MainBundle\Entity\User;
|
||||
use Chill\MainBundle\Form\DataMapper\ScopePickerDataMapper;
|
||||
use Chill\MainBundle\Security\Authorization\AuthorizationHelperInterface;
|
||||
use Chill\MainBundle\Security\Resolver\CenterResolverManagerInterface;
|
||||
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
|
||||
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
@@ -32,65 +33,84 @@ use Symfony\Component\Security\Core\Security;
|
||||
* Allow to pick amongst available scope for the current
|
||||
* user.
|
||||
*
|
||||
* options :
|
||||
*
|
||||
* - `center`: the center of the entity
|
||||
* - `role` : the role of the user
|
||||
* Options:
|
||||
* - `role`: string, the role to check permissions for
|
||||
* - Either `subject`: object, entity to resolve centers from
|
||||
* - Or `center`: Center|array|null, the center(s) to check
|
||||
*/
|
||||
class ScopePickerType extends AbstractType
|
||||
{
|
||||
public function __construct(
|
||||
private readonly TranslatableStringHelperInterface $translatableStringHelper,
|
||||
private readonly AuthorizationHelperInterface $authorizationHelper,
|
||||
private readonly Security $security,
|
||||
private readonly CenterResolverManagerInterface $centerResolverManager,
|
||||
) {}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||
{
|
||||
/* $items = array_values(
|
||||
array_filter(
|
||||
$this->authorizationHelper->getReachableScopes(
|
||||
$this->security->getUser(),
|
||||
$options['role'],
|
||||
$options['center']
|
||||
),
|
||||
static fn (Scope $s) => $s->isActive()
|
||||
)
|
||||
);*/
|
||||
|
||||
if (0 === \count($options['reachable_scopes'])) {
|
||||
throw new \RuntimeException('no scopes are reachable. This form should not be shown to user');
|
||||
// Compute centers from subject
|
||||
$centers = $options['center'] ?? null;
|
||||
if (null === $centers && isset($options['subject'])) {
|
||||
$centers = $this->centerResolverManager->resolveCenters($options['subject']);
|
||||
}
|
||||
|
||||
if (1 !== \count($options['reachable_scopes'])) {
|
||||
if (null === $centers) {
|
||||
throw new \RuntimeException('Either "center" or "subject" must be provided');
|
||||
}
|
||||
|
||||
$reachableScopes = array_values(
|
||||
array_filter(
|
||||
$this->authorizationHelper->getReachableScopes(
|
||||
$this->security->getUser(),
|
||||
$options['role'],
|
||||
$centers
|
||||
),
|
||||
static fn (Scope $s) => $s->isActive()
|
||||
)
|
||||
);
|
||||
|
||||
$builder->setAttribute('reachable_scopes_count', count($reachableScopes));
|
||||
|
||||
if (0 === count($reachableScopes)) {
|
||||
$builder->setAttribute('has_scopes', false);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$builder->setAttribute('has_scopes', true);
|
||||
|
||||
if (1 !== count($reachableScopes)) {
|
||||
$builder->add('scope', EntityType::class, [
|
||||
'class' => Scope::class,
|
||||
'placeholder' => 'Choose the circle',
|
||||
'choice_label' => fn (Scope $c) => $this->translatableStringHelper->localize($c->getName()),
|
||||
'choices' => $options['reachable_scopes'],
|
||||
'choices' => $reachableScopes,
|
||||
]);
|
||||
$builder->setDataMapper(new ScopePickerDataMapper());
|
||||
} else {
|
||||
$builder->add('scope', HiddenType::class, [
|
||||
'data' => $options['reachable_scopes'][0]->getId(),
|
||||
'data' => $reachableScopes[0]->getId(),
|
||||
]);
|
||||
$builder->setDataMapper(new ScopePickerDataMapper($options['reachable_scopes'][0]));
|
||||
$builder->setDataMapper(new ScopePickerDataMapper($reachableScopes[0]));
|
||||
}
|
||||
}
|
||||
|
||||
public function buildView(FormView $view, FormInterface $form, array $options)
|
||||
{
|
||||
$view->vars['fullWidth'] = true;
|
||||
// display of label is handled by the EntityType
|
||||
$view->vars['label'] = false;
|
||||
}
|
||||
|
||||
public function configureOptions(OptionsResolver $resolver)
|
||||
{
|
||||
$resolver
|
||||
->setRequired('reachable_scopes')
|
||||
->setAllowedTypes('reachable_scopes', ['array']);
|
||||
// create `center` option
|
||||
// ->setRequired('center')
|
||||
// ->setAllowedTypes('center', [Center::class, 'array', 'null'])
|
||||
// create ``role` option
|
||||
// ->setRequired('role')
|
||||
// ->setAllowedTypes('role', ['string']);
|
||||
->setRequired('role')
|
||||
->setAllowedTypes('role', ['string'])
|
||||
->setDefined('subject')
|
||||
->setAllowedTypes('subject', ['object'])
|
||||
->setDefined('center')
|
||||
->setAllowedTypes('center', [Center::class, 'array', 'null']);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ use Chill\MainBundle\Entity\Scope;
|
||||
use Chill\MainBundle\Entity\User;
|
||||
use Chill\MainBundle\Form\Type\ScopePickerType;
|
||||
use Chill\MainBundle\Security\Authorization\AuthorizationHelperInterface;
|
||||
use Chill\MainBundle\Security\Resolver\CenterResolverManagerInterface;
|
||||
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\Mapping\Builder\ClassMetadataBuilder;
|
||||
@@ -38,10 +39,11 @@ final class ScopePickerTypeTest extends TypeTestCase
|
||||
{
|
||||
use ProphecyTrait;
|
||||
|
||||
public function estBuildOneScopeIsSuccessful()
|
||||
public function testBuildOneScopeIsSuccessful()
|
||||
{
|
||||
$form = $this->factory->create(ScopePickerType::class, null, [
|
||||
'reachable_scopes' => [new Scope()],
|
||||
'role' => 'ONE_SCOPE',
|
||||
'center' => [],
|
||||
]);
|
||||
|
||||
$view = $form->createView();
|
||||
@@ -52,7 +54,8 @@ final class ScopePickerTypeTest extends TypeTestCase
|
||||
public function testBuildThreeScopesIsSuccessful()
|
||||
{
|
||||
$form = $this->factory->create(ScopePickerType::class, null, [
|
||||
'reachable_scopes' => [new Scope(), new Scope(), new Scope()],
|
||||
'role' => 'THREE_SCOPE',
|
||||
'center' => [],
|
||||
]);
|
||||
|
||||
$view = $form->createView();
|
||||
@@ -63,7 +66,8 @@ final class ScopePickerTypeTest extends TypeTestCase
|
||||
public function testBuildTwoScopesIsSuccessful()
|
||||
{
|
||||
$form = $this->factory->create(ScopePickerType::class, null, [
|
||||
'reachable_scopes' => [new Scope(), new Scope()],
|
||||
'role' => 'TWO_SCOPE',
|
||||
'center' => [],
|
||||
]);
|
||||
|
||||
$view = $form->createView();
|
||||
@@ -97,10 +101,13 @@ final class ScopePickerTypeTest extends TypeTestCase
|
||||
static fn ($args) => $args[0]['fr']
|
||||
);
|
||||
|
||||
$centerResolverManager = $this->prophesize(CenterResolverManagerInterface::class);
|
||||
|
||||
$type = new ScopePickerType(
|
||||
$translatableStringHelper->reveal(),
|
||||
$authorizationHelper->reveal(),
|
||||
$security->reveal(),
|
||||
$translatableStringHelper->reveal()
|
||||
$centerResolverManager->reveal()
|
||||
);
|
||||
|
||||
// add the mocks for creating EntityType
|
||||
|
||||
@@ -167,20 +167,9 @@ final readonly class PersonContext implements PersonContextInterface
|
||||
}
|
||||
|
||||
if ($this->isScopeNecessary($entity)) {
|
||||
$reachableScopes = array_values(
|
||||
array_filter(
|
||||
$this->authorizationHelper->getReachableScopes(
|
||||
$this->security->getUser(),
|
||||
PersonDocumentVoter::CREATE,
|
||||
$this->centerResolverManager->resolveCenters($entity)
|
||||
),
|
||||
static fn (Scope $s) => $s->isActive()
|
||||
)
|
||||
);
|
||||
|
||||
$builder->add('scope', ScopePickerType::class, [
|
||||
'reachable_scopes' => $reachableScopes,
|
||||
'label' => count($reachableScopes) > 1 ? 'Scope' : false,
|
||||
'role' => PersonDocumentVoter::CREATE,
|
||||
'subject' => $entity,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,6 @@ declare(strict_types=1);
|
||||
|
||||
namespace Chill\TaskBundle\Form;
|
||||
|
||||
use Chill\MainBundle\Entity\Scope;
|
||||
use Chill\MainBundle\Form\Type\ChillDateType;
|
||||
use Chill\MainBundle\Form\Type\ChillTextareaType;
|
||||
use Chill\MainBundle\Form\Type\DateIntervalType;
|
||||
@@ -27,7 +26,6 @@ use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
use Symfony\Component\Security\Core\Security;
|
||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
|
||||
class SingleTaskType extends AbstractType
|
||||
{
|
||||
@@ -72,22 +70,11 @@ class SingleTaskType extends AbstractType
|
||||
]);
|
||||
|
||||
if ($isScopeConcerned && $this->parameterBag->get('chill_main')['acl']['form_show_scopes']) {
|
||||
$reachableScopes = array_values(
|
||||
array_filter(
|
||||
$this->authorizationHelper->getReachableScopes(
|
||||
$this->security->getUser(),
|
||||
$options['role'],
|
||||
$center
|
||||
),
|
||||
static fn (Scope $s) => $s->isActive()
|
||||
)
|
||||
);
|
||||
|
||||
$builder
|
||||
->add('circle', ScopePickerType::class, [
|
||||
'reachable_scopes' => $reachableScopes,
|
||||
'role' => $options['role'],
|
||||
'subject' => $task,
|
||||
'required' => true,
|
||||
'label' => count($reachableScopes) > 1 ? 'Scope' : false,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
{% block title 'Tasks for {{ name }}'|trans({ '{{ name }}' : person|chill_entity_render_string }) %}
|
||||
|
||||
{% block content %}
|
||||
<div class="col-md-10 col-xxl">
|
||||
<div class="task-list"">
|
||||
|
||||
<h1>{{ block('title') }}</h1>
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
{% endblock %}
|
||||
{% else %}
|
||||
{% block content %}
|
||||
<div class="col-md-10 col-xxl tasks">
|
||||
<div class="col-md-9 col-xxl tasks">
|
||||
{% include '@ChillTask/SingleTask/AccompanyingCourse/list.html.twig' %}
|
||||
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user