From b055a64ff5575c5a3e9211bdc8e6a62c3fc115db Mon Sep 17 00:00:00 2001 From: David Molineus Date: Wed, 17 Mar 2021 10:20:41 +0100 Subject: [PATCH 1/6] Submit an event when a new record is stored --- composer.json | 2 ++ src/Controller/SurveyFragment.php | 13 +++++-- src/Event/SurveyRecordStoredEvent.php | 51 +++++++++++++++++++++++++++ src/Resources/config/services.yaml | 1 + 4 files changed, 64 insertions(+), 3 deletions(-) create mode 100644 src/Event/SurveyRecordStoredEvent.php diff --git a/composer.json b/composer.json index c306f2f..b86acd8 100644 --- a/composer.json +++ b/composer.json @@ -27,6 +27,8 @@ "symfony/translation-contracts": "^2.3", "symfony/twig-bundle": "^4.4|^5.0", "symfony/dependency-injection": "^4.4|^5.0", + "symfony/event-dispatcher": "^4.4|^5.0", + "symfony/event-dispatcher-contracts": "^1.1|^2.0", "symfony/expression-language": "^4.4|^5.0", "symfony/form": "^4.4|^5.0", "symfony/http-kernel": "^4.4|^5.0", diff --git a/src/Controller/SurveyFragment.php b/src/Controller/SurveyFragment.php index e1943fa..4af99f8 100644 --- a/src/Controller/SurveyFragment.php +++ b/src/Controller/SurveyFragment.php @@ -17,12 +17,14 @@ use Doctrine\ORM\EntityManager; use Mvo\ContaoSurvey\Entity\Record; use Mvo\ContaoSurvey\Entity\Survey; +use Mvo\ContaoSurvey\Event\SurveyRecordStoredEvent; use Mvo\ContaoSurvey\Form\SurveyManager; use Mvo\ContaoSurvey\Form\SurveyManagerFactory; use Mvo\ContaoSurvey\Registry; use Mvo\ContaoSurvey\Repository\SurveyRepository; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; /** * @ContentElement(category="includes") @@ -34,15 +36,17 @@ class SurveyFragment extends AbstractContentElementController private ScopeMatcher $scopeMatcher; private EntityManager $entityManager; private Registry $registry; + private EventDispatcherInterface $eventDispatcher; private bool $protectEditing; - public function __construct(SurveyRepository $surveyRepository, SurveyManagerFactory $managerFactory, ScopeMatcher $scopeMatcher, EntityManager $entityManager, Registry $registry, bool $protectEditing) + public function __construct(SurveyRepository $surveyRepository, SurveyManagerFactory $managerFactory, ScopeMatcher $scopeMatcher, EntityManager $entityManager, Registry $registry, EventDispatcherInterface $eventDispatcher, bool $protectEditing) { $this->surveyRepository = $surveyRepository; $this->managerFactory = $managerFactory; $this->scopeMatcher = $scopeMatcher; $this->entityManager = $entityManager; $this->registry = $registry; + $this->eventDispatcher = $eventDispatcher; $this->protectEditing = $protectEditing; } @@ -78,8 +82,9 @@ protected function getResponse(Template $template, ContentModel $model, Request $manager->form->handleRequest($request); if ($this->proceedUntilCompleted($manager)) { - $this->storeRecord($survey, $manager->getAnswers()); + $record = $this->storeRecord($survey, $manager->getAnswers()); $manager->reset(); + $this->eventDispatcher->dispatch(new SurveyRecordStoredEvent($survey, $record, $model)); return $this->render('@MvoContaoSurvey/_thanks.html.twig', [ 'headline' => $headline, @@ -144,7 +149,7 @@ private function proceedUntilCompleted(SurveyManager $manager): bool return false; } - private function storeRecord(Survey $survey, array $answers): void + private function storeRecord(Survey $survey, array $answers): Record { $record = new Record($survey, $answers); @@ -152,5 +157,7 @@ private function storeRecord(Survey $survey, array $answers): void $this->entityManager->persist($record); $this->entityManager->flush(); + + return $record; } } diff --git a/src/Event/SurveyRecordStoredEvent.php b/src/Event/SurveyRecordStoredEvent.php new file mode 100644 index 0000000..7bc59f2 --- /dev/null +++ b/src/Event/SurveyRecordStoredEvent.php @@ -0,0 +1,51 @@ +survey = $survey; + $this->record = $record; + $this->context = $context; + } + + public function getSurvey(): Survey + { + return $this->survey; + } + + public function getRecord(): Record + { + return $this->record; + } + + /** + * Get the context where the survey was stored. Usually a content element or module model. + */ + public function getContext(): Model + { + return $this->context; + } +} diff --git a/src/Resources/config/services.yaml b/src/Resources/config/services.yaml index 5dcbc76..f4c7367 100644 --- a/src/Resources/config/services.yaml +++ b/src/Resources/config/services.yaml @@ -156,6 +156,7 @@ services: - '@contao.routing.scope_matcher' - '@doctrine.orm.entity_manager' - '@mvo.survey.registry' + - '@event_dispatcher' - '%mvo_survey.protect_editing%' tags: - { name: 'terminal42_service_annotation' } From fe46fa3fa0e0590039a6b70f512e086529d50860 Mon Sep 17 00:00:00 2001 From: David Molineus Date: Thu, 18 Mar 2021 10:35:30 +0100 Subject: [PATCH 2/6] Rename event and store the record using an event listener --- src/Controller/SurveyFragment.php | 22 +++------------ ...oredEvent.php => SurveySubmittedEvent.php} | 2 +- src/EventListener/StoreRecordListener.php | 28 +++++++++++++++++++ src/Resources/config/services.yaml | 8 +++++- 4 files changed, 40 insertions(+), 20 deletions(-) rename src/Event/{SurveyRecordStoredEvent.php => SurveySubmittedEvent.php} (96%) create mode 100644 src/EventListener/StoreRecordListener.php diff --git a/src/Controller/SurveyFragment.php b/src/Controller/SurveyFragment.php index 4af99f8..3278056 100644 --- a/src/Controller/SurveyFragment.php +++ b/src/Controller/SurveyFragment.php @@ -17,7 +17,7 @@ use Doctrine\ORM\EntityManager; use Mvo\ContaoSurvey\Entity\Record; use Mvo\ContaoSurvey\Entity\Survey; -use Mvo\ContaoSurvey\Event\SurveyRecordStoredEvent; +use Mvo\ContaoSurvey\Event\SurveySubmittedEvent; use Mvo\ContaoSurvey\Form\SurveyManager; use Mvo\ContaoSurvey\Form\SurveyManagerFactory; use Mvo\ContaoSurvey\Registry; @@ -34,17 +34,15 @@ class SurveyFragment extends AbstractContentElementController private SurveyRepository $surveyRepository; private SurveyManagerFactory $managerFactory; private ScopeMatcher $scopeMatcher; - private EntityManager $entityManager; private Registry $registry; private EventDispatcherInterface $eventDispatcher; private bool $protectEditing; - public function __construct(SurveyRepository $surveyRepository, SurveyManagerFactory $managerFactory, ScopeMatcher $scopeMatcher, EntityManager $entityManager, Registry $registry, EventDispatcherInterface $eventDispatcher, bool $protectEditing) + public function __construct(SurveyRepository $surveyRepository, SurveyManagerFactory $managerFactory, ScopeMatcher $scopeMatcher, Registry $registry, EventDispatcherInterface $eventDispatcher, bool $protectEditing) { $this->surveyRepository = $surveyRepository; $this->managerFactory = $managerFactory; $this->scopeMatcher = $scopeMatcher; - $this->entityManager = $entityManager; $this->registry = $registry; $this->eventDispatcher = $eventDispatcher; $this->protectEditing = $protectEditing; @@ -82,9 +80,9 @@ protected function getResponse(Template $template, ContentModel $model, Request $manager->form->handleRequest($request); if ($this->proceedUntilCompleted($manager)) { - $record = $this->storeRecord($survey, $manager->getAnswers()); + $record = new Record($survey, $manager->getAnswers()); $manager->reset(); - $this->eventDispatcher->dispatch(new SurveyRecordStoredEvent($survey, $record, $model)); + $this->eventDispatcher->dispatch(new SurveySubmittedEvent($survey, $record, $model)); return $this->render('@MvoContaoSurvey/_thanks.html.twig', [ 'headline' => $headline, @@ -148,16 +146,4 @@ private function proceedUntilCompleted(SurveyManager $manager): bool // form contains errors return false; } - - private function storeRecord(Survey $survey, array $answers): Record - { - $record = new Record($survey, $answers); - - // todo validate - - $this->entityManager->persist($record); - $this->entityManager->flush(); - - return $record; - } } diff --git a/src/Event/SurveyRecordStoredEvent.php b/src/Event/SurveySubmittedEvent.php similarity index 96% rename from src/Event/SurveyRecordStoredEvent.php rename to src/Event/SurveySubmittedEvent.php index 7bc59f2..89ede98 100644 --- a/src/Event/SurveyRecordStoredEvent.php +++ b/src/Event/SurveySubmittedEvent.php @@ -16,7 +16,7 @@ /** * @psalm-immutable */ -final class SurveyRecordStoredEvent +final class SurveySubmittedEvent { private Survey $survey; diff --git a/src/EventListener/StoreRecordListener.php b/src/EventListener/StoreRecordListener.php new file mode 100644 index 0000000..e934dbf --- /dev/null +++ b/src/EventListener/StoreRecordListener.php @@ -0,0 +1,28 @@ +entityManager = $entityManager; + } + + /** + * @ServiceTag(name="kernel_event_listener", event="Mvo\ContaoSurvey\Event\SurveySubmittedEvent", priority="128") + */ + public function __invoke(SurveySubmittedEvent $event): void + { + $this->entityManager->persist($event->getRecord()); + $this->entityManager->flush(); + } +} diff --git a/src/Resources/config/services.yaml b/src/Resources/config/services.yaml index f4c7367..f6a1ac3 100644 --- a/src/Resources/config/services.yaml +++ b/src/Resources/config/services.yaml @@ -62,6 +62,13 @@ services: tags: - { name: 'kernel.event_listener', event: 'kernel.request', priority: -800 } + mvo.survey.listener.store_record: + class: Mvo\ContaoSurvey\EventListener\StoreRecordListener + arguments: + - '@doctrine.orm.entity_manager' + tags: + - { name: 'kernel.event_listener', event: 'Mvo\ContaoSurvey\Event\SurveySubmittedEvent', priority: 128 } + mvo.survey.form.manager_factory: class: Mvo\ContaoSurvey\Form\SurveyManagerFactory arguments: @@ -154,7 +161,6 @@ services: - '@mvo.survey.repository.survey' - '@mvo.survey.form.manager_factory' - '@contao.routing.scope_matcher' - - '@doctrine.orm.entity_manager' - '@mvo.survey.registry' - '@event_dispatcher' - '%mvo_survey.protect_editing%' From d5a664ff89f61aca453b30fdcb3d54759d1d9ba5 Mon Sep 17 00:00:00 2001 From: David Molineus Date: Thu, 18 Mar 2021 10:45:29 +0100 Subject: [PATCH 3/6] Add option to disable storing records --- src/Entity/Survey.php | 10 ++++++++++ src/EventListener/DataContainer/Survey.php | 1 + src/Resources/contao/dca/tl_survey.php | 13 ++++++++++++- src/Resources/contao/languages/de/tl_survey.php | 1 + src/Resources/contao/languages/en/tl_survey.php | 1 + src/Resources/views/Backend/survey_record.html.twig | 2 ++ 6 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/Entity/Survey.php b/src/Entity/Survey.php index e7a660e..cf7c591 100644 --- a/src/Entity/Survey.php +++ b/src/Entity/Survey.php @@ -39,6 +39,11 @@ class Survey extends DcaDefault */ private string $buttonLabel = ''; + /** + * @ORM\Column(name="store_records", type="boolean", options={"default": true}) + */ + private bool $storeRecords = true; + /** * @ORM\OneToMany(targetEntity="Section", mappedBy="survey") * @@ -132,6 +137,11 @@ public function isFrozen(): bool return $this->frozen; } + public function isStoreRecords(): bool + { + return $this->storeRecords; + } + public function clearRecords(): void { $this->records->clear(); diff --git a/src/EventListener/DataContainer/Survey.php b/src/EventListener/DataContainer/Survey.php index 8999009..80b115c 100644 --- a/src/EventListener/DataContainer/Survey.php +++ b/src/EventListener/DataContainer/Survey.php @@ -98,6 +98,7 @@ public function listSurveys(array $row, string $label): string 'count' => $submittedRecordsCount, 'frozen' => (bool) $row['frozen'], 'protect_editing' => $this->protectEditing, + 'store_records' => (bool) $row['store_records'], ] ); } diff --git a/src/Resources/contao/dca/tl_survey.php b/src/Resources/contao/dca/tl_survey.php index 5f29a26..d6ad325 100644 --- a/src/Resources/contao/dca/tl_survey.php +++ b/src/Resources/contao/dca/tl_survey.php @@ -42,7 +42,7 @@ ], 'palettes' => [ '__selector__' => [], - 'default' => 'title,frozen;{details_legend},note_submission,button_label,button_href', + 'default' => 'title,frozen,store_records;{details_legend},note_submission,button_label,button_href', ], 'subpalettes' => [ ], @@ -93,5 +93,16 @@ // Keep this for MySQL Strict mode. Otherwise Contao would save an empty string 'sql' => ['type' => 'boolean', 'default' => false], ], + 'store_records' => [ + 'inputType' => 'checkbox', + 'filter' => true, + 'eval' => [ + 'tl_class' => 'w50 m12', + ], + 'default' => true, + 'save_callback' => [static fn ($v) => '1' === $v], + // Keep this for MySQL Strict mode. Otherwise Contao would save an empty string + 'sql' => ['type' => 'boolean', 'default' => false], + ], ], ]; diff --git a/src/Resources/contao/languages/de/tl_survey.php b/src/Resources/contao/languages/de/tl_survey.php index 3fd0497..90d8eeb 100644 --- a/src/Resources/contao/languages/de/tl_survey.php +++ b/src/Resources/contao/languages/de/tl_survey.php @@ -11,6 +11,7 @@ $GLOBALS['TL_LANG']['tl_survey']['title'] = ['Titel', 'Geben Sie den Titel dieser Umfrage ein.']; $GLOBALS['TL_LANG']['tl_survey']['frozen'] = ['Umfrage einfrieren', 'Bearbeitung dieser Umfrage sperren. Nur eingefrorene Umfragen werden im Frontend ausgegeben.']; +$GLOBALS['TL_LANG']['tl_survey']['store_records'] = ['Ergebnisse speichern', 'Ergebnisse werden in der Datenbank gespeichert.']; $GLOBALS['TL_LANG']['tl_survey']['details_legend'] = 'Details zur Danke-Seite'; $GLOBALS['TL_LANG']['tl_survey']['note_submission'] = ['Nachricht', 'Fügen Sie eine "Danke"-Nachricht hinzu, die nach erfolgreichem Absenden angezeigt wird.']; $GLOBALS['TL_LANG']['tl_survey']['button_label'] = ['Button Bezeichner', 'Fügen Sie einen optionalen Button hinzu.']; diff --git a/src/Resources/contao/languages/en/tl_survey.php b/src/Resources/contao/languages/en/tl_survey.php index 5da1cbb..53d65b1 100644 --- a/src/Resources/contao/languages/en/tl_survey.php +++ b/src/Resources/contao/languages/en/tl_survey.php @@ -11,6 +11,7 @@ $GLOBALS['TL_LANG']['tl_survey']['title'] = ['Title', 'Enter the title of this survey.']; $GLOBALS['TL_LANG']['tl_survey']['frozen'] = ['Freeze survey', 'Lock editing of this survey. Only frozen surveys will be output in the frontend.']; +$GLOBALS['TL_LANG']['tl_survey']['store_records'] = ['Store records', 'Store submitted records in the database.']; $GLOBALS['TL_LANG']['tl_survey']['details_legend'] = 'Submission details'; $GLOBALS['TL_LANG']['tl_survey']['note_submission'] = ['Submission note', 'Add a "thank you" message that will be shown after successful submission.']; $GLOBALS['TL_LANG']['tl_survey']['button_label'] = ['Button label', 'Add an optional button.']; diff --git a/src/Resources/views/Backend/survey_record.html.twig b/src/Resources/views/Backend/survey_record.html.twig index 6874d4a..baafa5c 100644 --- a/src/Resources/views/Backend/survey_record.html.twig +++ b/src/Resources/views/Backend/survey_record.html.twig @@ -27,6 +27,7 @@ {% endif %}
{{ name }}
+ {% if store_records or count > 0 %}
{{ 'records.count'|trans({'%count%': count}) }} @@ -45,5 +46,6 @@
+ {% endif %}
From db5abe197edcde7399dd61805506d35fc846a48f Mon Sep 17 00:00:00 2001 From: David Molineus Date: Thu, 18 Mar 2021 10:48:51 +0100 Subject: [PATCH 4/6] Recognize store records option and fix cs issues --- src/Controller/SurveyFragment.php | 1 - src/Event/SurveySubmittedEvent.php | 2 +- src/EventListener/StoreRecordListener.php | 9 +++++++++ 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/Controller/SurveyFragment.php b/src/Controller/SurveyFragment.php index 3278056..b1f7114 100644 --- a/src/Controller/SurveyFragment.php +++ b/src/Controller/SurveyFragment.php @@ -14,7 +14,6 @@ use Contao\CoreBundle\Routing\ScopeMatcher; use Contao\CoreBundle\ServiceAnnotation\ContentElement; use Contao\Template; -use Doctrine\ORM\EntityManager; use Mvo\ContaoSurvey\Entity\Record; use Mvo\ContaoSurvey\Entity\Survey; use Mvo\ContaoSurvey\Event\SurveySubmittedEvent; diff --git a/src/Event/SurveySubmittedEvent.php b/src/Event/SurveySubmittedEvent.php index 89ede98..df16603 100644 --- a/src/Event/SurveySubmittedEvent.php +++ b/src/Event/SurveySubmittedEvent.php @@ -16,7 +16,7 @@ /** * @psalm-immutable */ -final class SurveySubmittedEvent +class SurveySubmittedEvent { private Survey $survey; diff --git a/src/EventListener/StoreRecordListener.php b/src/EventListener/StoreRecordListener.php index e934dbf..47a4321 100644 --- a/src/EventListener/StoreRecordListener.php +++ b/src/EventListener/StoreRecordListener.php @@ -2,6 +2,11 @@ declare(strict_types=1); +/* + * @author Moritz Vondano + * @license MIT + */ + namespace Mvo\ContaoSurvey\EventListener; use Doctrine\ORM\EntityManagerInterface; @@ -22,6 +27,10 @@ public function __construct(EntityManagerInterface $entityManager) */ public function __invoke(SurveySubmittedEvent $event): void { + if (!$event->getSurvey()->isStoreRecords()) { + return; + } + $this->entityManager->persist($event->getRecord()); $this->entityManager->flush(); } From 572695063d67a87dab629b645b81d948b022f303 Mon Sep 17 00:00:00 2001 From: David Molineus Date: Thu, 18 Mar 2021 11:30:09 +0100 Subject: [PATCH 5/6] Correctly set sql default value Co-authored-by: M. Vondano --- src/Resources/contao/dca/tl_survey.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Resources/contao/dca/tl_survey.php b/src/Resources/contao/dca/tl_survey.php index d6ad325..4c29692 100644 --- a/src/Resources/contao/dca/tl_survey.php +++ b/src/Resources/contao/dca/tl_survey.php @@ -102,7 +102,7 @@ 'default' => true, 'save_callback' => [static fn ($v) => '1' === $v], // Keep this for MySQL Strict mode. Otherwise Contao would save an empty string - 'sql' => ['type' => 'boolean', 'default' => false], + 'sql' => ['type' => 'boolean', 'default' => true], ], ], ]; From 4ef804e029d21f6c0cc9624738e568a251f920c3 Mon Sep 17 00:00:00 2001 From: David Molineus Date: Thu, 18 Mar 2021 11:33:24 +0100 Subject: [PATCH 6/6] Add clr class Co-authored-by: M. Vondano --- src/Resources/contao/dca/tl_survey.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Resources/contao/dca/tl_survey.php b/src/Resources/contao/dca/tl_survey.php index 4c29692..85bd190 100644 --- a/src/Resources/contao/dca/tl_survey.php +++ b/src/Resources/contao/dca/tl_survey.php @@ -97,7 +97,7 @@ 'inputType' => 'checkbox', 'filter' => true, 'eval' => [ - 'tl_class' => 'w50 m12', + 'tl_class' => 'clr w50 m12', ], 'default' => true, 'save_callback' => [static fn ($v) => '1' === $v],