WIP: Implement feedback functionality

This commit is contained in:
Björn Fromme
2023-11-02 18:01:12 +01:00
parent 2689f93683
commit 2599fd69dc
28 changed files with 640 additions and 43 deletions
@@ -7,6 +7,7 @@ class CrmAttributesResponse
private ?array $attributeGroups = null;
private bool $admin = false;
private bool $manager = false;
private bool $houseManager = false;
private bool $teamer = false;
public function getAttributeGroups(): ?array
@@ -56,6 +57,18 @@ class CrmAttributesResponse
return $this;
}
public function isHouseManager(): bool
{
return $this->houseManager;
}
public function setHouseManager(bool $houseManager): static
{
$this->houseManager = $houseManager;
return $this;
}
public function toArray(): array
{
$crmSelections = [];
+4 -2
View File
@@ -133,7 +133,7 @@ class ResponseParser
public function createCrmAttributesResponse(\SimpleXMLElement $xml): CrmAttributesResponse
{
$groups = [];
$isAdmin = $isManager = $isTeamer = false;
$isAdmin = $isManager = $isHouseManager = $isTeamer = false;
foreach ($xml->xpath('selektionsmerkmale/selektionsgruppe') as $item) {
$group = new CrmAttributeGroup();
@@ -169,6 +169,7 @@ class ResponseParser
->setAdmin($isAdmin)
->setManager($isManager)
->setTeamer($isTeamer)
->setHouseManager($isHouseManager)
;
return $response;
@@ -242,9 +243,10 @@ class ResponseParser
private function resolveOptions(array $options): array
{
$optionsResolver = new OptionsResolver();
$optionsResolver->setRequired(['bpn_crm_id_admin', 'bpn_crm_id_manager', 'bpn_crm_id_teamer']);
$optionsResolver->setRequired(['bpn_crm_id_admin', 'bpn_crm_id_manager', 'bpn_crm_id_house_manager', 'bpn_crm_id_teamer']);
$optionsResolver->setAllowedTypes('bpn_crm_id_admin', 'int');
$optionsResolver->setAllowedTypes('bpn_crm_id_manager', 'int');
$optionsResolver->setAllowedTypes('bpn_crm_id_house_manager', 'int');
$optionsResolver->setAllowedTypes('bpn_crm_id_teamer', 'int');
return $optionsResolver->resolve($options);
+3
View File
@@ -30,6 +30,9 @@ class UserDataHandler
if ($crmAttributes->isManager()) {
$roles[] = 'ROLE_MANAGER';
}
if ($crmAttributes->isHouseManager()) {
$roles[] = 'ROLE_HOUSE_MANAGER';
}
if ($crmAttributes->isTeamer()) {
$roles[] = 'ROLE_TEAMER';
}
@@ -0,0 +1,48 @@
<?php
namespace App\Controller\Admin\System\FeedbackSet;
use App\Entity\FeedbackSet;
use App\Form\FeedbackSetType;
use Doctrine\ORM\EntityManagerInterface;
use Psr\Log\LoggerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Http\Attribute\IsGranted;
class CreateController extends AbstractController
{
public function __construct(
private readonly EntityManagerInterface $entityManager,
private readonly LoggerInterface $logger
) {
}
#[Route('/admin/system/feedback-set/create', name: 'app_admin_system_feedback_set_create')]
#[IsGranted('ROLE_ADMIN')]
public function index(Request $request): Response
{
$feedbackSet = new FeedbackSet();
$form = $this->createForm(FeedbackSetType::class, $feedbackSet);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$this->entityManager->persist($feedbackSet);
$this->entityManager->flush();
$this->addFlash('success', 'Die Feedback-Vorlage wurde angelegt');
$this->logger->info('Create feedback set', [
'feedback_set_id' => $feedbackSet->getId(),
'feedback_set_name' => $feedbackSet->getName(),
]);
return $this->redirectToRoute('app_admin_system_feedback_set_index');
}
return $this->render('admin/system/feedback_set/create.html.twig', [
'form' => $form
]);
}
}
@@ -0,0 +1,36 @@
<?php
namespace App\Controller\Admin\System\FeedbackSet;
use App\Entity\FeedbackSet;
use Doctrine\ORM\EntityManagerInterface;
use Psr\Log\LoggerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Http\Attribute\IsGranted;
class DeleteController extends AbstractController
{
public function __construct(
private readonly EntityManagerInterface $entityManager,
private readonly LoggerInterface $logger
) {
}
#[Route('/admin/system/feedback-set/delete/{id}', name: 'app_admin_system_feedback_set_delete', methods: ['POST'])]
#[IsGranted('ROLE_ADMIN')]
public function index(FeedbackSet $feedbackSet): Response
{
$this->entityManager->remove($feedbackSet);
$this->entityManager->flush();
$this->addFlash('success', 'Die Feedback-Vorlage wurde gelöscht');
$this->logger->info('Delete feedback set', [
'feedback_set_id' => $feedbackSet->getId(),
'feedback_set_name' => $feedbackSet->getName(),
]);
return $this->redirectToRoute('app_admin_system_feedback_set_index');
}
}
@@ -0,0 +1,46 @@
<?php
namespace App\Controller\Admin\System\FeedbackSet;
use App\Entity\FeedbackSet;
use App\Form\FeedbackSetType;
use Doctrine\ORM\EntityManagerInterface;
use Psr\Log\LoggerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Http\Attribute\IsGranted;
class EditController extends AbstractController
{
public function __construct(
private readonly EntityManagerInterface $entityManager,
private readonly LoggerInterface $logger
) {
}
#[Route('/admin/system/feedback-set/edit/{id}', name: 'app_admin_system_feedback_set_edit')]
#[IsGranted('ROLE_ADMIN')]
public function index(FeedbackSet $feedbackSet, Request $request): Response
{
$form = $this->createForm(FeedbackSetType::class, $feedbackSet);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$this->entityManager->flush();
$this->addFlash('success', 'Die Feedback-Vorlage wurde aktualisiert');
$this->logger->info('Edit feedback set', [
'feedback_set_id' => $feedbackSet->getId(),
'feedback_set_name' => $feedbackSet->getName(),
]);
return $this->redirectToRoute('app_admin_system_feedback_set_index');
}
return $this->render('admin/system/feedback_set/edit.html.twig', [
'form' => $form
]);
}
}
@@ -0,0 +1,29 @@
<?php
namespace App\Controller\Admin\System\FeedbackSet;
use App\Repository\FeedbackSetRepository;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Http\Attribute\IsGranted;
class IndexController extends AbstractController
{
public function __construct(private readonly FeedbackSetRepository $feedbackSetRepository)
{}
#[Route('/admin/system/feedback-set', name: 'app_admin_system_feedback_set_index')]
#[IsGranted('ROLE_ADMIN')]
public function index(): Response
{
$feedbackSets = $this
->feedbackSetRepository
->findAll()
;
return $this->render('admin/system/feedback_set/index.html.twig', [
'feedbackSets' => $feedbackSets,
]);
}
}
@@ -0,0 +1,16 @@
<?php
namespace App\Controller\HouseManager;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
class IndexController extends AbstractController
{
#[Route('/house-manager', name: 'app_house_manager_index')]
public function index(): Response
{
return $this->render('');
}
}
+34
View File
@@ -84,6 +84,9 @@ class Assignment implements BlameableEntityInterface, TimestampableEntityInterfa
#[ORM\ManyToOne]
private ?User $owner = null;
#[ORM\OneToMany(mappedBy: 'assignment', targetEntity: Feedback::class)]
private Collection $feedbacks;
public function __construct()
{
$this->uuid = Uuid::v4();
@@ -93,6 +96,7 @@ class Assignment implements BlameableEntityInterface, TimestampableEntityInterfa
$this->teamers = new ArrayCollection();
$this->benefits = "Anreise im E&P Reisebus\nUnterkunft\nVerpflegung\nSkipass\n";
$this->documents = new ArrayCollection();
$this->feedbacks = new ArrayCollection();
}
public static function duplicate(Assignment $assignment): static
@@ -436,4 +440,34 @@ class Assignment implements BlameableEntityInterface, TimestampableEntityInterfa
return $this;
}
/**
* @return Collection<int, Feedback>
*/
public function getFeedbacks(): Collection
{
return $this->feedbacks;
}
public function addFeedback(Feedback $feedback): static
{
if (!$this->feedbacks->contains($feedback)) {
$this->feedbacks->add($feedback);
$feedback->setAssignment($this);
}
return $this;
}
public function removeFeedback(Feedback $feedback): static
{
if ($this->feedbacks->removeElement($feedback)) {
// set the owning side to null (unless already changed)
if ($feedback->getAssignment() === $this) {
$feedback->setAssignment(null);
}
}
return $this;
}
}
+13 -27
View File
@@ -26,8 +26,9 @@ class Feedback implements BlameableEntityInterface, TimestampableEntityInterface
#[ORM\ManyToOne(inversedBy: 'feedback')]
private ?Teamer $teamer = null;
#[ORM\Column(type: Types::TEXT)]
private ?string $body = null;
#[ORM\ManyToOne(inversedBy: 'feedbacks')]
#[ORM\JoinColumn(onDelete: 'SET NULL')]
private ?Assignment $assignment = null;
#[ORM\Column(length: 255)]
private ?string $assignmentDestination = null;
@@ -35,11 +36,8 @@ class Feedback implements BlameableEntityInterface, TimestampableEntityInterface
#[ORM\Column(type: Types::DATE_IMMUTABLE)]
private ?\DateTimeImmutable $assignmentDate = null;
#[ORM\Column(length: 255)]
private ?string $authorName = null;
#[ORM\Column(length: 255)]
private ?string $authorEmail = null;
#[ORM\Column]
private array $ratings = [];
public function __construct()
{
@@ -68,14 +66,14 @@ class Feedback implements BlameableEntityInterface, TimestampableEntityInterface
return $this;
}
public function getBody(): ?string
public function getAssignment(): ?Assignment
{
return $this->body;
return $this->assignment;
}
public function setBody(string $body): static
public function setAssignment(?Assignment $assignment): static
{
$this->body = $body;
$this->assignment = $assignment;
return $this;
}
@@ -104,26 +102,14 @@ class Feedback implements BlameableEntityInterface, TimestampableEntityInterface
return $this;
}
public function getAuthorName(): ?string
public function getRatings(): array
{
return $this->authorName;
return $this->ratings;
}
public function setAuthorName(string $authorName): static
public function setRatings(array $ratings): static
{
$this->authorName = $authorName;
return $this;
}
public function getAuthorEmail(): ?string
{
return $this->authorEmail;
}
public function setAuthorEmail(string $authorEmail): static
{
$this->authorEmail = $authorEmail;
$this->ratings = $ratings;
return $this;
}
+56
View File
@@ -0,0 +1,56 @@
<?php
namespace App\Entity;
use App\Entity\Traits\TimestampableEntity;
use App\Repository\FeedbackSetRepository;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
#[ORM\Entity(repositoryClass: FeedbackSetRepository::class)]
class FeedbackSet implements TimestampableEntityInterface
{
use TimestampableEntity;
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
private ?int $id = null;
#[ORM\Column(length: 255)]
#[Assert\NotBlank(message: 'Bitte gib die Bezeichnung ein')]
private ?string $name = null;
#[ORM\Column]
#[Assert\Count(min: 1, minMessage: 'Bitte füge mindestens eine Bewertung hinzu')]
private array $items = [];
public function getId(): ?int
{
return $this->id;
}
public function getName(): ?string
{
return $this->name;
}
public function setName(string $name): static
{
$this->name = $name;
return $this;
}
public function getItems(): array
{
return $this->items;
}
public function setItems(array $items): static
{
$this->items = $items;
return $this;
}
}
+16
View File
@@ -38,6 +38,10 @@ class JobProfile implements BlameableEntityInterface, TimestampableEntityInterfa
#[ORM\ManyToMany(targetEntity: Training::class)]
private Collection $requiredTrainings;
#[ORM\ManyToOne]
#[ORM\JoinColumn(onDelete: 'SET NULL')]
private ?FeedbackSet $feedbackSet = null;
public function __construct()
{
$this->uuid = Uuid::v4();
@@ -101,4 +105,16 @@ class JobProfile implements BlameableEntityInterface, TimestampableEntityInterfa
return $this;
}
public function getFeedbackSet(): ?FeedbackSet
{
return $this->feedbackSet;
}
public function setFeedbackSet(?FeedbackSet $feedbackSet): static
{
$this->feedbackSet = $feedbackSet;
return $this;
}
}
+17
View File
@@ -48,6 +48,9 @@ class User implements UserInterface, TimestampableEntityInterface
#[ORM\OneToOne(inversedBy: 'user', cascade: ['persist', 'remove'])]
private ?Contact $contact = null;
#[ORM\Column(nullable: true)]
private ?int $hotelBusProId = null;
public function __construct()
{
$this->uuid = Uuid::v4();
@@ -178,6 +181,8 @@ class User implements UserInterface, TimestampableEntityInterface
return 'app_admin_index';
} elseif ($this->hasRole('ROLE_MANAGER')) {
return 'app_manager_index';
} elseif ($this->hasRole('ROLE_HOUSE_MANAGER')) {
return 'app_house_manager_index';
} else {
return 'app_teamer_index';
}
@@ -215,4 +220,16 @@ class User implements UserInterface, TimestampableEntityInterface
return $this;
}
public function getHotelBusProId(): ?int
{
return $this->hotelBusProId;
}
public function setHotelBusProId(?int $hotelBusProId): static
{
$this->hotelBusProId = $hotelBusProId;
return $this;
}
}
+2
View File
@@ -3,8 +3,10 @@
namespace App\EventListener;
use Psr\Log\LoggerInterface;
use Symfony\Component\EventDispatcher\Attribute\AsEventListener;
use Symfony\Component\Security\Http\Event\LogoutEvent;
#[AsEventListener(event: LogoutEvent::class, method: 'onLogout')]
class LogoutListener
{
public function __construct(private readonly LoggerInterface $logger)
+36
View File
@@ -0,0 +1,36 @@
<?php
namespace App\Form;
use App\Entity\FeedbackSet;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class FeedbackSetType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('name', TextType::class, [
'label' => 'Bezeichnung',
])
->add('items', CollectionType::class, [
'label' => 'Bewertungen',
'entry_type' => TextType::class,
'allow_add' => true,
'allow_delete' => true,
'error_bubbling' => false,
])
;
}
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'data_class' => FeedbackSet::class,
]);
}
}
+7
View File
@@ -2,6 +2,7 @@
namespace App\Form;
use App\Entity\FeedbackSet;
use App\Entity\JobProfile;
use App\Entity\License;
use App\Entity\Training;
@@ -45,6 +46,12 @@ class JobProfileType extends AbstractType
'Snowboardlehrer*in' => License::TYPE_SNOWBOARD,
],
])
->add('feedbackSet', EntityType::class, [
'label' => 'Feedback-Vorlage',
'class' => FeedbackSet::class,
'choice_label' => 'name',
'placeholder' => 'Kein Feedback',
])
;
}
+15
View File
@@ -76,6 +76,21 @@ class AdminMenuBuilder extends AbstractMenuBuilder
],
],
],
[
'route' => 'app_admin_system_feedback_set_index',
'title' => 'Feedback-Vorlagen',
'children' => [
[
'route' => 'app_admin_system_feedback_set_create',
'title' => 'Feedback-Vorlage anlegen',
],
[
'route' => 'app_admin_system_feedback_set_edit',
'routeParameters' => $this->getDefaultRouteParameters(),
'title' => 'Feedback-Vorlage bearbeiten',
],
],
],
[
'route' => 'app_admin_system_faq_index',
'title' => 'FAQ',
+23
View File
@@ -0,0 +1,23 @@
<?php
namespace App\Repository;
use App\Entity\FeedbackSet;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
/**
* @extends ServiceEntityRepository<FeedbackSet>
*
* @method FeedbackSet|null find($id, $lockMode = null, $lockVersion = null)
* @method FeedbackSet|null findOneBy(array $criteria, array $orderBy = null)
* @method FeedbackSet[] findAll()
* @method FeedbackSet[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
*/
class FeedbackSetRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, FeedbackSet::class);
}
}