diff --git a/src/Controller/Admin/Feedback/ProvideController.php b/src/Controller/Admin/Feedback/ProvideController.php
index 1616bc7..6523b0b 100644
--- a/src/Controller/Admin/Feedback/ProvideController.php
+++ b/src/Controller/Admin/Feedback/ProvideController.php
@@ -37,8 +37,8 @@ class ProvideController extends AbstractController
// Feedback provided by admins is published instantly
$feedback->setStatus(Feedback::STATUS_PUBLISHED);
- if (null !== $form->get('authorOverride')->getData()) {
- $feedback->setAuthor($form->get('authorOverride')->getData());
+ if (null !== $author = $form->get('authorOverride')->getData()) {
+ $feedback->setAuthor($author->getFullName());
}
$this->entityManager->persist($feedback);
diff --git a/src/Controller/Administrative/Feedback/ProvideController.php b/src/Controller/Administrative/Feedback/ProvideController.php
index b6027a7..bb95a6d 100644
--- a/src/Controller/Administrative/Feedback/ProvideController.php
+++ b/src/Controller/Administrative/Feedback/ProvideController.php
@@ -56,6 +56,12 @@ class ProvideController extends AbstractController
$feedback->setStatus(Feedback::STATUS_PUBLISHED);
}
+ if (true === $form->has('author')) {
+ /** @var User $author */
+ $author = $form->get('author')->getData();
+ $feedback->setAuthor($author->getFullName());
+ }
+
$teamer = $disposition->getTeamer();
$teamer->addFeedback($feedback);
$disposition->setFeedback($feedback);
diff --git a/src/Form/AbstractFeedbackType.php b/src/Form/AbstractFeedbackType.php
new file mode 100644
index 0000000..6cfddf3
--- /dev/null
+++ b/src/Form/AbstractFeedbackType.php
@@ -0,0 +1,51 @@
+add('ratings', FeedbackRatingsType::class, [
+ 'label' => false,
+ 'feedback_set' => $feedbackSet,
+ ])
+ ->add('comment', TextareaType::class, [
+ 'label' => 'Kommentar (öffentlich)',
+ 'required' => false,
+ 'attr' => [
+ 'rows' => 5,
+ ],
+ 'help' => 'Bitte formuliere deinen Kommentar so, dass er an das Team weitergegeben werden kann',
+ ])
+ ->add('commentInternal', TextareaType::class, [
+ 'label' => 'Kommentar (intern)',
+ 'required' => false,
+ 'attr' => [
+ 'rows' => 5,
+ ],
+ ])
+ ;
+ }
+
+ public function configureOptions(OptionsResolver $resolver): void
+ {
+ $resolver->setDefaults([
+ 'data_class' => Feedback::class,
+ ]);
+ }
+}
diff --git a/src/Form/AdminFeedbackType.php b/src/Form/AdminFeedbackType.php
index a972248..bed15e9 100644
--- a/src/Form/AdminFeedbackType.php
+++ b/src/Form/AdminFeedbackType.php
@@ -2,21 +2,17 @@
namespace App\Form;
-use App\Entity\Feedback;
use App\Entity\FeedbackSet;
use App\Entity\Teamer;
use App\Entity\User;
use App\Repository\FeedbackSetRepository;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
-use Symfony\Component\Form\AbstractType;
-use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
-use Symfony\Component\Form\FormInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
-class AdminFeedbackType extends AbstractType
+class AdminFeedbackType extends AbstractFeedbackType
{
public function __construct(private readonly FeedbackSetRepository $feedbackSetRepository)
{
@@ -34,7 +30,7 @@ class AdminFeedbackType extends AbstractType
])
->add('authorOverride', AutocompleteEntityType::class, [
'mapped' => false,
- 'label' => 'abweichender Absender',
+ 'label' => 'Feedbackgeber:in',
'class' => User::class,
'label_property' => 'lastName',
'label_function' => fn (User $user) => (string) $user,
@@ -57,7 +53,7 @@ class AdminFeedbackType extends AbstractType
return;
}
- $this->addDynamicForm($feedbackSet, $form);
+ $this->addFeedbackFields($form, $feedbackSet);
})
->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event) {
$data = $event->getData();
@@ -67,47 +63,26 @@ class AdminFeedbackType extends AbstractType
return;
}
- $feedbackSet = $this->feedbackSetRepository->find($data['feedbackSet']);
- $this->addDynamicForm($feedbackSet, $form);
- })
- ;
- }
+ if (null === $feedbackSet = $this->feedbackSetRepository->find($data['feedbackSet'])) {
+ return;
+ }
- private function addDynamicForm(FeedbackSet $feedbackSet, FormInterface $form): void
- {
- $form
- ->add('ratings', FeedbackRatingsType::class, [
- 'label' => false,
- 'feedback_set' => $feedbackSet,
- ])
- ->add('comment', TextareaType::class, [
- 'label' => 'Kommentar (öffentlich)',
- 'required' => false,
- 'attr' => [
- 'rows' => 5,
- ],
- 'help' => 'Bitte formuliere deinen Kommentar so, dass er an das Team weitergegeben werden kann',
- ])
- ->add('commentInternal', TextareaType::class, [
- 'label' => 'Kommentar (intern)',
- 'required' => false,
- 'attr' => [
- 'rows' => 5,
- ],
- ])
+ $this->addFeedbackFields($form, $feedbackSet);
+ })
;
}
public function configureOptions(OptionsResolver $resolver): void
{
- $resolver
- ->setDefaults([
- 'data_class' => Feedback::class,
- 'validation_groups' => [
- 'Default',
- 'admin',
- ],
- ])
- ;
+ parent::configureOptions($resolver);
+
+ $resolver->setDefaults([
+ // the disposition-driven flow guarantees teamer and feedback set structurally, here
+ // they are picked by hand and must be validated
+ 'validation_groups' => [
+ 'Default',
+ 'admin',
+ ],
+ ]);
}
}
diff --git a/src/Form/FeedbackType.php b/src/Form/FeedbackType.php
index 63f4e99..32bf093 100644
--- a/src/Form/FeedbackType.php
+++ b/src/Form/FeedbackType.php
@@ -2,46 +2,70 @@
namespace App\Form;
-use App\Entity\Feedback;
use App\Entity\FeedbackSet;
-use Symfony\Component\Form\AbstractType;
-use Symfony\Component\Form\Extension\Core\Type\TextareaType;
+use App\Entity\User;
+use App\Repository\UserRepository;
+use Symfony\Bridge\Doctrine\Form\Type\EntityType;
+use Symfony\Bundle\SecurityBundle\Security;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
+use Symfony\Component\Validator\Constraints as Assert;
-class FeedbackType extends AbstractType
+class FeedbackType extends AbstractFeedbackType
{
+ public function __construct(
+ private readonly Security $security,
+ private readonly UserRepository $userRepository,
+ ) {
+ }
+
public function buildForm(FormBuilderInterface $builder, array $options): void
{
- $builder
- ->add('ratings', FeedbackRatingsType::class, [
- 'label' => false,
- 'feedback_set' => $options['feedback_set'],
- ])
- ->add('comment', TextareaType::class, [
- 'label' => 'Kommentar (öffentlich)',
- 'required' => false,
- 'attr' => [
- 'rows' => 5,
- ],
- 'help' => 'Bitte formuliere deinen Kommentar so, dass er an das Team weitergegeben werden kann',
- ])
- ->add('commentInternal', TextareaType::class, [
- 'label' => 'Kommentar (intern)',
- 'required' => false,
- 'attr' => [
- 'rows' => 5,
- ],
- ])
- ;
+ if (true === $this->security->isGranted('ROLE_ADMINISTRATIVE')) {
+ $this->addAuthorField($builder);
+ }
+
+ $this->addFeedbackFields($builder, $options['feedback_set']);
+ }
+
+ /**
+ * Feedback::$author is a name snapshot rather than a relation, so the field stays unmapped and
+ * the controller writes the chosen user's full name.
+ */
+ private function addAuthorField(FormBuilderInterface $builder): void
+ {
+ $roles = array_diff(array_keys(User::ROLES), ['ROLE_TEAMER']);
+
+ $choices = $this->userRepository->getUsersByRoles($roles);
+
+ /** @var User $user */
+ $user = $this->security->getUser();
+
+ // a user granted the role by the hierarchy alone would not be among the choices
+ $choiceIds = array_map(fn (User $choice) => $choice->getId(), $choices);
+
+ if (false === in_array($user->getId(), $choiceIds, true)) {
+ array_unshift($choices, $user);
+ }
+
+ $builder->add('author', EntityType::class, [
+ 'label' => 'Feedbackgeber:in',
+ 'mapped' => false,
+ 'class' => User::class,
+ 'choices' => $choices,
+ 'choice_label' => 'fullName',
+ 'data' => $user,
+ 'constraints' => [
+ new Assert\NotNull(message: 'Bitte wähle eine:n Feedbackgeber:in'),
+ ],
+ ]);
}
public function configureOptions(OptionsResolver $resolver): void
{
+ parent::configureOptions($resolver);
+
$resolver
- ->setDefaults([
- 'data_class' => Feedback::class,
- ])
->setRequired(['feedback_set'])
->setAllowedTypes('feedback_set', FeedbackSet::class)
;
diff --git a/src/Repository/UserRepository.php b/src/Repository/UserRepository.php
index 954f977..bfa60b4 100644
--- a/src/Repository/UserRepository.php
+++ b/src/Repository/UserRepository.php
@@ -61,6 +61,35 @@ class UserRepository extends ServiceEntityRepository
;
}
+ /**
+ * Active users holding at least one of the given roles.
+ *
+ * @param string[] $roles
+ *
+ * @return User[]
+ */
+ public function getUsersByRoles(array $roles): array
+ {
+ $qb = $this->createQueryBuilder('user');
+
+ $roleMatches = $qb->expr()->orX();
+
+ foreach ($roles as $index => $role) {
+ $roleMatches->add('JSON_CONTAINS(user.roles, :role_'.$index.') = 1');
+ $qb->setParameter('role_'.$index, json_encode($role));
+ }
+
+ return $qb
+ ->andWhere($roleMatches)
+ ->andWhere($qb->expr()->isNull('user.deletedAt'))
+ ->andWhere($qb->expr()->isNull('user.disabledAt'))
+ ->orderBy('user.lastName', 'ASC')
+ ->addOrderBy('user.firstName', 'ASC')
+ ->getQuery()
+ ->getResult()
+ ;
+ }
+
/**
* @param string[]|string $hotelCode
*
diff --git a/templates/_partials/_feedback_rating_scale.html.twig b/templates/_partials/_feedback_rating_scale.html.twig
new file mode 100644
index 0000000..3d4657c
--- /dev/null
+++ b/templates/_partials/_feedback_rating_scale.html.twig
@@ -0,0 +1,53 @@
+
+ Bewertungsskala
+
+
+
+ |
+ 5 Punkte
+ |
+
+ Der/die Wochenteamer:in hat hervorragende Arbeit geleistet und ist beim Team und den Gästen
+ sehr gut angekommen, es gibt nichts auszusetzen.
+ |
+
+
+ |
+ 4 Punkte
+ |
+
+ Der/die Wochenteamer:in hat einen sehr guten Job geleistet. Wenn es etwas zu beanstanden oder
+ Ideen zur Verbesserung gibt, dann sind es nur Kleinigkeiten (diese gerne in den Kommentar
+ schreiben).
+ |
+
+
+ |
+ 3 Punkte
+ |
+
+ Der/die Wochenteamer:in hat einen ganz guten Job erledigt. Es gibt einige Dinge, die
+ verbesserungswürdig sind (diese gerne in den Kommentaren vermerken). Der/die Wochenteamer:in
+ ist aber nicht negativ aufgefallen.
+ |
+
+
+ |
+ 2 Punkte
+ |
+
+ Der/die Wocheteamer:in hat keinen guten Job geleistet. Der Einsatz hat das Team eher belastet,
+ als es zu unterstützen. Der/die Wochenteamer:in bekommt noch eine Chance sich zu beweisen
+ (hierfür gerne ein schriftliches Feedback im Kommentarfeld hinterlassen).
+ |
+
+
+ |
+ 1 Punkt
+ |
+
+ Der/die Wochenteamer:in hat einen schlechten Job erledigt, ist Team und/oder Gästen negativ
+ aufgefallen und soll keine weiteren Einsätze erhalten.
+ |
+
+
diff --git a/templates/admin/feedback/provide.html.twig b/templates/admin/feedback/provide.html.twig
index 305795e..5de51a2 100644
--- a/templates/admin/feedback/provide.html.twig
+++ b/templates/admin/feedback/provide.html.twig
@@ -51,59 +51,7 @@
{{ form_end(form) }}
-
- Bewertungsskala
-
-
-
- |
- 5 Punkte
- |
-
- Der/die Wochenteamer:in hat hervorragende Arbeit geleistet und ist beim Team und den Gästen
- sehr gut angekommen, es gibt nichts auszusetzen.
- |
-
-
- |
- 4 Punkte
- |
-
- Der/die Wochenteamer:in hat einen sehr guten Job geleistet. Wenn es etwas zu beanstanden oder
- Ideen zur Verbesserung gibt, dann sind es nur Kleinigkeiten (diese gerne in den Kommentar
- schreiben).
- |
-
-
- |
- 3 Punkte
- |
-
- Der/die Wochenteamer:in hat einen ganz guten Job erledigt. Es gibt einige Dinge, die
- verbesserungswürdig sind (diese gerne in den Kommentaren vermerken). Der/die Wochenteamer:in
- ist aber nicht negativ aufgefallen.
- |
-
-
- |
- 2 Punkte
- |
-
- Der/die Wocheteamer:in hat keinen guten Job geleistet. Der Einsatz hat das Team eher belastet,
- als es zu unterstützen. Der/die Wochenteamer:in bekommt noch eine Chance sich zu beweisen
- (hierfür gerne ein schriftliches Feedback im Kommentarfeld hinterlassen).
- |
-
-
- |
- 1 Punkt
- |
-
- Der/die Wochenteamer:in hat einen schlechten Job erledigt, ist Team und/oder Gästen negativ
- aufgefallen und soll keine weiteren Einsätze erhalten.
- |
-
-
+ {% include '_partials/_feedback_rating_scale.html.twig' %}
{% endblock %}
\ No newline at end of file
diff --git a/templates/administrative/feedback/provide.html.twig b/templates/administrative/feedback/provide.html.twig
index 63bd6c3..2b85d63 100644
--- a/templates/administrative/feedback/provide.html.twig
+++ b/templates/administrative/feedback/provide.html.twig
@@ -13,6 +13,11 @@
{{ form_start(form) }}
+ {% if form.author is defined %}
+
+ {{ form_row(form.author) }}
+
+ {% endif %}
{% for child in form.ratings.children %}
@@ -35,59 +40,7 @@
{{ form_end(form) }}
-
- Bewertungsskala
-
-
-
- |
- 5 Punkte
- |
-
- Der/die Wochenteamer:in hat hervorragende Arbeit geleistet und ist beim Team und den Gästen
- sehr gut angekommen, es gibt nichts auszusetzen.
- |
-
-
- |
- 4 Punkte
- |
-
- Der/die Wochenteamer:in hat einen sehr guten Job geleistet. Wenn es etwas zu beanstanden oder
- Ideen zur Verbesserung gibt, dann sind es nur Kleinigkeiten (diese gerne in den Kommentar
- schreiben).
- |
-
-
- |
- 3 Punkte
- |
-
- Der/die Wochenteamer:in hat einen ganz guten Job erledigt. Es gibt einige Dinge, die
- verbesserungswürdig sind (diese gerne in den Kommentaren vermerken). Der/die Wochenteamer:in
- ist aber nicht negativ aufgefallen.
- |
-
-
- |
- 2 Punkte
- |
-
- Der/die Wocheteamer:in hat keinen guten Job geleistet. Der Einsatz hat das Team eher belastet,
- als es zu unterstützen. Der/die Wochenteamer:in bekommt noch eine Chance sich zu beweisen
- (hierfür gerne ein schriftliches Feedback im Kommentarfeld hinterlassen).
- |
-
-
- |
- 1 Punkt
- |
-
- Der/die Wochenteamer:in hat einen schlechten Job erledigt, ist Team und/oder Gästen negativ
- aufgefallen und soll keine weiteren Einsätze erhalten.
- |
-
-
+ {% include '_partials/_feedback_rating_scale.html.twig' %}
{% endblock %}
\ No newline at end of file