mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2026-03-03 04:29:40 +00:00
Add audit functionality for StoredObject actions and integrate StoredObjectSubjectConverter and StoredObjectSubjectDisplayer
- Introduced `StoredObjectSubjectConverter` for audit conversion logic and `StoredObjectSubjectDisplayer` for display logic. - Added corresponding Twig template and French translations for audit messages. - Created unit tests to ensure proper functionality of the converter and displayer.
This commit is contained in:
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Chill\DocStoreBundle\Audit\Displayer;
|
||||
|
||||
use Chill\DocStoreBundle\Repository\StoredObjectRepositoryInterface;
|
||||
use Chill\MainBundle\Audit\Subject;
|
||||
use Chill\MainBundle\Audit\SubjectDisplayerInterface;
|
||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
use Twig\Environment;
|
||||
|
||||
final readonly class StoredObjectSubjectDisplayer implements SubjectDisplayerInterface
|
||||
{
|
||||
public function __construct(
|
||||
private StoredObjectRepositoryInterface $storedObjectRepository,
|
||||
private Environment $twig,
|
||||
private TranslatorInterface $translator,
|
||||
) {}
|
||||
|
||||
public function supportsDisplay(Subject $subject, array $options = []): bool
|
||||
{
|
||||
return 'stored_object' === $subject->type;
|
||||
}
|
||||
|
||||
public function display(Subject $subject, string $format = 'html', array $options = []): string
|
||||
{
|
||||
$id = $subject->identifiers['id'];
|
||||
$storedObject = $this->storedObjectRepository->find($id);
|
||||
|
||||
if ('html' === $format) {
|
||||
return $this->twig->render('@ChillDocStore/Audit/stored_object.html.twig', [
|
||||
'id' => $id,
|
||||
'storedObject' => $storedObject,
|
||||
]);
|
||||
}
|
||||
|
||||
if (null !== $storedObject) {
|
||||
return $this->translator->trans('audit.stored_object.display_with_title', ['{id}' => $id, '{title}' => $storedObject->getTitle()]);
|
||||
}
|
||||
|
||||
return $this->translator->trans('audit.stored_object.display', ['{id}' => $id]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Chill\DocStoreBundle\Audit\SubjectConverter;
|
||||
|
||||
use Chill\DocStoreBundle\Entity\StoredObject;
|
||||
use Chill\DocStoreBundle\Repository\AssociatedEntityToStoredObjectRepository;
|
||||
use Chill\MainBundle\Audit\Subject;
|
||||
use Chill\MainBundle\Audit\SubjectBag;
|
||||
use Chill\MainBundle\Audit\SubjectConverterInterface;
|
||||
use Chill\MainBundle\Audit\SubjectConverterManagerAwareInterface;
|
||||
use Chill\MainBundle\Audit\SubjectConverterManagerAwareTrait;
|
||||
|
||||
/**
|
||||
* @implements SubjectConverterInterface<StoredObject>
|
||||
*/
|
||||
final class StoredObjectSubjectConverter implements SubjectConverterInterface, SubjectConverterManagerAwareInterface
|
||||
{
|
||||
use SubjectConverterManagerAwareTrait;
|
||||
|
||||
public function __construct(private readonly AssociatedEntityToStoredObjectRepository $associatedEntityToStoredObjectRepository) {}
|
||||
|
||||
public function convert(mixed $subject, bool $includeAssociated = false): SubjectBag
|
||||
{
|
||||
$main = new SubjectBag(new Subject('stored_object', ['id' => $subject->getId()]));
|
||||
$associated = $this->associatedEntityToStoredObjectRepository->findAssociatedEntityToStoredObject($subject);
|
||||
|
||||
if (null !== $associated) {
|
||||
$main->append(
|
||||
$this->subjectConverterManager->getSubjectsForEntity($associated, $includeAssociated)
|
||||
);
|
||||
}
|
||||
|
||||
return $main;
|
||||
}
|
||||
|
||||
public function supportsConvert(mixed $subject): bool
|
||||
{
|
||||
return $subject instanceof StoredObject;
|
||||
}
|
||||
|
||||
public static function getDefaultPriority(): int
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
<span>{{ 'audit.stored_object.display'|trans({'{{id}': id }) }}{% if storedObject is not null %} - {{ storedObject.title}}{% endif %}</span>
|
||||
@@ -0,0 +1,104 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Chill\DocStoreBundle\Tests\Audit\Displayer;
|
||||
|
||||
use Chill\DocStoreBundle\Audit\Displayer\StoredObjectSubjectDisplayer;
|
||||
use Chill\DocStoreBundle\Entity\StoredObject;
|
||||
use Chill\DocStoreBundle\Repository\StoredObjectRepositoryInterface;
|
||||
use Chill\MainBundle\Audit\Subject;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
use Twig\Environment;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @coversNothing
|
||||
*/
|
||||
class StoredObjectSubjectDisplayerTest extends TestCase
|
||||
{
|
||||
private StoredObjectRepositoryInterface $repository;
|
||||
private Environment $twig;
|
||||
private StoredObjectSubjectDisplayer $displayer;
|
||||
|
||||
private TranslatorInterface $translator;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->repository = $this->createMock(StoredObjectRepositoryInterface::class);
|
||||
$this->twig = $this->createMock(Environment::class);
|
||||
$this->translator = $this->createMock(TranslatorInterface::class);
|
||||
|
||||
$this->displayer = new StoredObjectSubjectDisplayer($this->repository, $this->twig, $this->translator);
|
||||
}
|
||||
|
||||
public function testSupportsDisplay(): void
|
||||
{
|
||||
$this->assertTrue($this->displayer->supportsDisplay(new Subject('stored_object', ['id' => 1])));
|
||||
$this->assertFalse($this->displayer->supportsDisplay(new Subject('person', ['id' => 1])));
|
||||
}
|
||||
|
||||
public function testDisplayHtml(): void
|
||||
{
|
||||
$subject = new Subject('stored_object', ['id' => 123]);
|
||||
$storedObject = $this->createMock(StoredObject::class);
|
||||
|
||||
$this->repository->expects($this->once())
|
||||
->method('find')
|
||||
->with(123)
|
||||
->willReturn($storedObject);
|
||||
|
||||
$this->twig->expects($this->once())
|
||||
->method('render')
|
||||
->with('@ChillDocStore/Audit/stored_object.html.twig', [
|
||||
'id' => 123,
|
||||
'storedObject' => $storedObject,
|
||||
])
|
||||
->willReturn('Rendered HTML');
|
||||
|
||||
$result = $this->displayer->display($subject, 'html');
|
||||
$this->assertSame('Rendered HTML', $result);
|
||||
}
|
||||
|
||||
public function testDisplayString(): void
|
||||
{
|
||||
$subject = new Subject('stored_object', ['id' => 123]);
|
||||
$storedObject = $this->createMock(StoredObject::class);
|
||||
$storedObject->method('getTitle')->willReturn('Document Title');
|
||||
$this->translator->method('trans')->with('audit.stored_object.display_with_title', ['{id}' => 123, '{title}' => 'Document Title'])
|
||||
->willReturn('translated');
|
||||
|
||||
$this->repository->expects($this->once())
|
||||
->method('find')
|
||||
->with(123)
|
||||
->willReturn($storedObject);
|
||||
|
||||
$result = $this->displayer->display($subject, 'string');
|
||||
$this->assertSame('translated', $result);
|
||||
}
|
||||
|
||||
public function testDisplayStringWithNotFoundObject(): void
|
||||
{
|
||||
$this->translator->method('trans')->with('audit.stored_object.display', ['{id}' => 123])
|
||||
->willReturn('translated');
|
||||
|
||||
$subject = new Subject('stored_object', ['id' => 123]);
|
||||
|
||||
$this->repository->expects($this->once())
|
||||
->method('find')
|
||||
->with(123)
|
||||
->willReturn(null);
|
||||
|
||||
$result = $this->displayer->display($subject, 'string');
|
||||
$this->assertSame('translated', $result);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Chill\DocStoreBundle\Tests\Audit\SubjectConverter;
|
||||
|
||||
use Chill\DocStoreBundle\Audit\SubjectConverter\StoredObjectSubjectConverter;
|
||||
use Chill\DocStoreBundle\Entity\StoredObject;
|
||||
use Chill\DocStoreBundle\Repository\AssociatedEntityToStoredObjectRepository;
|
||||
use Chill\MainBundle\Audit\Subject;
|
||||
use Chill\MainBundle\Audit\SubjectBag;
|
||||
use Chill\MainBundle\Audit\SubjectConverterManagerInterface;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Prophecy\PhpUnit\ProphecyTrait;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @coversNothing
|
||||
*/
|
||||
class StoredObjectSubjectConverterTest extends TestCase
|
||||
{
|
||||
use ProphecyTrait;
|
||||
|
||||
public function testSupportsConvert(): void
|
||||
{
|
||||
$associatedEntity = $this->prophesize(AssociatedEntityToStoredObjectRepository::class);
|
||||
$subjectConverterManager = $this->prophesize(SubjectConverterManagerInterface::class);
|
||||
$converter = new StoredObjectSubjectConverter($associatedEntity->reveal());
|
||||
$converter->setSubjectConverterManager($subjectConverterManager->reveal());
|
||||
|
||||
$this->assertTrue($converter->supportsConvert($this->createMock(StoredObject::class)));
|
||||
$this->assertFalse($converter->supportsConvert(new \stdClass()));
|
||||
}
|
||||
|
||||
public function testConvertWithoutAssociated(): void
|
||||
{
|
||||
$storedObject = new StoredObject();
|
||||
$reflection = new \ReflectionClass($storedObject);
|
||||
$id = $reflection->getProperty('id');
|
||||
$id->setValue($storedObject, 123);
|
||||
|
||||
$associatedEntity = $this->prophesize(AssociatedEntityToStoredObjectRepository::class);
|
||||
$subjectConverterManager = $this->prophesize(SubjectConverterManagerInterface::class);
|
||||
$associatedEntity->findAssociatedEntityToStoredObject($storedObject)->willReturn(null)->shouldBeCalled();
|
||||
|
||||
$converter = new StoredObjectSubjectConverter($associatedEntity->reveal());
|
||||
$converter->setSubjectConverterManager($subjectConverterManager->reveal());
|
||||
|
||||
$subjectBag = $converter->convert($storedObject);
|
||||
|
||||
$this->assertSame('stored_object', $subjectBag->subject->type);
|
||||
$this->assertSame(['id' => 123], $subjectBag->subject->identifiers);
|
||||
}
|
||||
|
||||
public function testConvertWithAssociated(): void
|
||||
{
|
||||
$storedObject = new StoredObject();
|
||||
$reflection = new \ReflectionClass($storedObject);
|
||||
$id = $reflection->getProperty('id');
|
||||
$id->setValue($storedObject, 123);
|
||||
|
||||
$associatedEntity = $this->prophesize(AssociatedEntityToStoredObjectRepository::class);
|
||||
$subjectConverterManager = $this->prophesize(SubjectConverterManagerInterface::class);
|
||||
$associatedEntity->findAssociatedEntityToStoredObject($storedObject)->willReturn($associated = new \stdClass());
|
||||
$subjectConverterManager->getSubjectsForEntity($associated, true)->willReturn(new SubjectBag($s = new Subject('associated', ['id' => 456])));
|
||||
|
||||
$converter = new StoredObjectSubjectConverter($associatedEntity->reveal());
|
||||
$converter->setSubjectConverterManager($subjectConverterManager->reveal());
|
||||
|
||||
$subjectBag = $converter->convert($storedObject, true);
|
||||
|
||||
$this->assertSame('stored_object', $subjectBag->subject->type);
|
||||
$this->assertSame(['id' => 123], $subjectBag->subject->identifiers);
|
||||
$this->assertCount(1, $subjectBag->associatedSubjects);
|
||||
$this->assertSame($s, $subjectBag->associatedSubjects[0]);
|
||||
}
|
||||
}
|
||||
@@ -128,3 +128,8 @@ signatures:
|
||||
see_all_pages: Voir toutes les pages
|
||||
all_pages: Toutes les pages
|
||||
go_to_signature_unique: Aller à la zone de signature
|
||||
|
||||
audit:
|
||||
stored_object:
|
||||
display: Document n°{id}
|
||||
display_with_title: Document n°{id} - {title}
|
||||
|
||||
Reference in New Issue
Block a user