From 2c252fa79a84c64788a99abf487453a586377fc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Mon, 2 Mar 2026 13:31:16 +0100 Subject: [PATCH] Add audit functionality for `AccompanyingCourseDocument` and integrate subject converter and displayer - Introduced `AccompanyingCourseDocumentSubjectConverter` for audit conversion logic. - Added `AccompanyingCourseDocumentSubjectDisplayer` for handling audit display logic, including a Twig template. - Created unit tests to verify proper behavior of the converter and displayer. --- ...mpanyingCourseDocumentSubjectDisplayer.php | 49 ++++++++++ ...mpanyingCourseDocumentSubjectConverter.php | 53 +++++++++++ .../accompanying_course_document.html.twig | 1 + ...yingCourseDocumentSubjectDisplayerTest.php | 94 +++++++++++++++++++ ...yingCourseDocumentSubjectConverterTest.php | 72 ++++++++++++++ .../translations/messages.fr.yml | 5 + 6 files changed, 274 insertions(+) create mode 100644 src/Bundle/ChillDocStoreBundle/Audit/Displayer/AccompanyingCourseDocumentSubjectDisplayer.php create mode 100644 src/Bundle/ChillDocStoreBundle/Audit/SubjectConverter/AccompanyingCourseDocumentSubjectConverter.php create mode 100644 src/Bundle/ChillDocStoreBundle/Resources/views/Audit/accompanying_course_document.html.twig create mode 100644 src/Bundle/ChillDocStoreBundle/tests/Audit/Displayer/AccompanyingCourseDocumentSubjectDisplayerTest.php create mode 100644 src/Bundle/ChillDocStoreBundle/tests/Audit/SubjectConverter/AccompanyingCourseDocumentSubjectConverterTest.php diff --git a/src/Bundle/ChillDocStoreBundle/Audit/Displayer/AccompanyingCourseDocumentSubjectDisplayer.php b/src/Bundle/ChillDocStoreBundle/Audit/Displayer/AccompanyingCourseDocumentSubjectDisplayer.php new file mode 100644 index 000000000..7b668dc54 --- /dev/null +++ b/src/Bundle/ChillDocStoreBundle/Audit/Displayer/AccompanyingCourseDocumentSubjectDisplayer.php @@ -0,0 +1,49 @@ +type; + } + + public function display(Subject $subject, string $format = 'html', array $options = []): string + { + $id = $subject->identifiers['id']; + $document = $this->repository->find($id); + + if ('html' === $format) { + return $this->twig->render('@ChillDocStore/Audit/accompanying_course_document.html.twig', [ + 'id' => $id, + 'document' => $document, + ]); + } + + if (null === $document) { + return (string) $id; + } + + return $document->getTitle(); + } +} diff --git a/src/Bundle/ChillDocStoreBundle/Audit/SubjectConverter/AccompanyingCourseDocumentSubjectConverter.php b/src/Bundle/ChillDocStoreBundle/Audit/SubjectConverter/AccompanyingCourseDocumentSubjectConverter.php new file mode 100644 index 000000000..b534f0aac --- /dev/null +++ b/src/Bundle/ChillDocStoreBundle/Audit/SubjectConverter/AccompanyingCourseDocumentSubjectConverter.php @@ -0,0 +1,53 @@ + + */ +final class AccompanyingCourseDocumentSubjectConverter implements SubjectConverterInterface, SubjectConverterManagerAwareInterface +{ + use SubjectConverterManagerAwareTrait; + + public function supportsConvert(mixed $subject): bool + { + return $subject instanceof AccompanyingCourseDocument; + } + + public function convert(mixed $subject, bool $includeAssociated = false): SubjectBag + { + $main = new SubjectBag( + new Subject( + type: 'accompanying_course_document', + identifiers: ['id' => $subject->getId()], + ) + ); + + if (null !== $subject->getCourse()) { + $main->append($this->subjectConverterManager->getSubjectsForEntity($subject->getCourse(), $includeAssociated)); + } + + return $main; + } + + public static function getDefaultPriority(): int + { + return 0; + } +} diff --git a/src/Bundle/ChillDocStoreBundle/Resources/views/Audit/accompanying_course_document.html.twig b/src/Bundle/ChillDocStoreBundle/Resources/views/Audit/accompanying_course_document.html.twig new file mode 100644 index 000000000..56c4eaf19 --- /dev/null +++ b/src/Bundle/ChillDocStoreBundle/Resources/views/Audit/accompanying_course_document.html.twig @@ -0,0 +1 @@ +{{ 'audit.accompanying_course_document.display'|trans({'{id}': id }) }}{% if document is not null %} - {{ document.title }}{% endif %} diff --git a/src/Bundle/ChillDocStoreBundle/tests/Audit/Displayer/AccompanyingCourseDocumentSubjectDisplayerTest.php b/src/Bundle/ChillDocStoreBundle/tests/Audit/Displayer/AccompanyingCourseDocumentSubjectDisplayerTest.php new file mode 100644 index 000000000..db5f4d612 --- /dev/null +++ b/src/Bundle/ChillDocStoreBundle/tests/Audit/Displayer/AccompanyingCourseDocumentSubjectDisplayerTest.php @@ -0,0 +1,94 @@ +prophesize(AccompanyingCourseDocumentRepository::class); + $twig = $this->prophesize(Environment::class); + $displayer = new AccompanyingCourseDocumentSubjectDisplayer($repository->reveal(), $twig->reveal()); + $this->assertTrue($displayer->supportsDisplay(new Subject('accompanying_course_document', ['id' => 123]))); + $this->assertFalse($displayer->supportsDisplay(new Subject('other', ['id' => 123]))); + } + + public function testDisplayHtml(): void + { + $repository = $this->prophesize(AccompanyingCourseDocumentRepository::class); + $twig = $this->prophesize(Environment::class); + $document = $this->prophesize(AccompanyingCourseDocument::class); + + $id = 123; + $subject = new Subject('accompanying_course_document', ['id' => $id]); + + $repository->find($id)->willReturn($document->reveal()); + $twig->render('@ChillDocStore/Audit/accompanying_course_document.html.twig', [ + 'id' => $id, + 'document' => $document->reveal(), + ])->willReturn('Document Title'); + + $displayer = new AccompanyingCourseDocumentSubjectDisplayer($repository->reveal(), $twig->reveal()); + + $result = $displayer->display($subject, 'html'); + $this->assertSame('Document Title', $result); + } + + public function testDisplayString(): void + { + $repository = $this->prophesize(AccompanyingCourseDocumentRepository::class); + $twig = $this->prophesize(Environment::class); + $document = $this->prophesize(AccompanyingCourseDocument::class); + + $id = 123; + $subject = new Subject('accompanying_course_document', ['id' => $id]); + + $document->getTitle()->willReturn('Document Title'); + $repository->find($id)->willReturn($document->reveal()); + + $displayer = new AccompanyingCourseDocumentSubjectDisplayer($repository->reveal(), $twig->reveal()); + + $result = $displayer->display($subject, 'string'); + $this->assertSame('Document Title', $result); + } + + public function testDisplayWithIdFallback(): void + { + $repository = $this->prophesize(AccompanyingCourseDocumentRepository::class); + $twig = $this->prophesize(Environment::class); + + $id = 123; + $subject = new Subject('accompanying_course_document', ['id' => $id]); + + $repository->find($id)->willReturn(null); + + $displayer = new AccompanyingCourseDocumentSubjectDisplayer($repository->reveal(), $twig->reveal()); + + $result = $displayer->display($subject, 'string'); + $this->assertSame('123', $result); + } +} diff --git a/src/Bundle/ChillDocStoreBundle/tests/Audit/SubjectConverter/AccompanyingCourseDocumentSubjectConverterTest.php b/src/Bundle/ChillDocStoreBundle/tests/Audit/SubjectConverter/AccompanyingCourseDocumentSubjectConverterTest.php new file mode 100644 index 000000000..31941060b --- /dev/null +++ b/src/Bundle/ChillDocStoreBundle/tests/Audit/SubjectConverter/AccompanyingCourseDocumentSubjectConverterTest.php @@ -0,0 +1,72 @@ +assertTrue($converter->supportsConvert($this->createMock(AccompanyingCourseDocument::class))); + $this->assertFalse($converter->supportsConvert(new \stdClass())); + } + + public function testConvert(): void + { + $storedObject = new StoredObject(); + $storedObject->setTitle('Document Title'); + + $document = new AccompanyingCourseDocument(); + $document->setObject($storedObject); + $reflection = new \ReflectionClass($document); + $idProp = $reflection->getProperty('id'); + $idProp->setValue($document, 123); + + $course = new AccompanyingPeriod(); + $reflection = new \ReflectionClass($course); + $idProp = $reflection->getProperty('id'); + $idProp->setValue($course, 456); + $document->setCourse($course); + + $subjectConverterManager = $this->prophesize(SubjectConverterManagerInterface::class); + $subjectConverterManager->getSubjectsForEntity($course, true)->willReturn( + new SubjectBag($s = new Subject('accompanying_period', ['id' => 456])) + ); + + $converter = new AccompanyingCourseDocumentSubjectConverter(); + $converter->setSubjectConverterManager($subjectConverterManager->reveal()); + + $subjectBag = $converter->convert($document, true); + + $this->assertSame('accompanying_course_document', $subjectBag->subject->type); + $this->assertSame(['id' => 123], $subjectBag->subject->identifiers); + $this->assertCount(1, $subjectBag->associatedSubjects); + $this->assertSame($s, $subjectBag->associatedSubjects[0]); + } +} diff --git a/src/Bundle/ChillDocStoreBundle/translations/messages.fr.yml b/src/Bundle/ChillDocStoreBundle/translations/messages.fr.yml index 7979fdad3..ad3b2906d 100644 --- a/src/Bundle/ChillDocStoreBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillDocStoreBundle/translations/messages.fr.yml @@ -133,3 +133,8 @@ audit: stored_object: display: Document n°{id} display_with_title: Document n°{id} - {title} + generic-doc: + list_for_accompanying_period: Liste des documents d'un parcours d'accompagnement + list_for_person: Liste des documents de l'usager + accompanying_course_document: + display: Document d'un parcours d'accompagnement n°{id}