WIP: render entities

This commit is contained in:
2026-02-13 19:22:08 +01:00
parent 32c5f21438
commit 22ace0c66e
20 changed files with 337 additions and 0 deletions

View File

@@ -0,0 +1,20 @@
<?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\MainBundle\Audit\Exception;
class DisplaySubjectException extends \LogicException
{
public function __construct(array $subject)
{
parent::__construct(sprintf('Subject "%s" could not be displayed', json_encode($subject['subject'], JSON_THROW_ON_ERROR, 5)));
}
}

View File

@@ -26,6 +26,15 @@ class Subject
return [...$this->identifiers, 't' => $this->type];
}
public static function fromArray(array $subject): self
{
return new self($subject['t'], array_filter(
$subject,
static fn (string $key) => 't' !== $key,
ARRAY_FILTER_USE_KEY
));
}
public function isEqual(Subject $subject): bool
{
if ($subject->type !== $this->type) {

View File

@@ -12,6 +12,7 @@ declare(strict_types=1);
namespace Chill\MainBundle\Audit;
use Chill\MainBundle\Audit\Exception\ConvertSubjectException;
use Chill\MainBundle\Audit\Exception\DisplaySubjectException;
final readonly class SubjectConverterManager implements SubjectConverterManagerInterface
{
@@ -20,6 +21,11 @@ final readonly class SubjectConverterManager implements SubjectConverterManagerI
* @var iterable<SubjectConverterInterface>
*/
private iterable $converters,
/**
* @var iterable<SubjectDisplayerInterface>
*/
private iterable $displayers,
) {}
public function getSubjectsForEntity(mixed $subject, bool $includeAssociated = false): SubjectBag
@@ -36,4 +42,15 @@ final readonly class SubjectConverterManager implements SubjectConverterManagerI
throw new ConvertSubjectException($subject);
}
public function display(Subject $subject, array $options = []): string
{
foreach ($this->displayers as $displayer) {
if ($displayer->supportsDisplay($subject, $options = [])) {
return $displayer->display($subject, $options = []);
}
}
throw new DisplaySubjectException($subject->asArray());
}
}

View File

@@ -14,4 +14,6 @@ namespace Chill\MainBundle\Audit;
interface SubjectConverterManagerInterface
{
public function getSubjectsForEntity(object $subject, bool $includeAssociated = false): SubjectBag;
public function display(Subject $subject): string;
}

View File

@@ -0,0 +1,27 @@
<?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\MainBundle\Audit;
/**
* Interface for displaying a given Subject instance as html with optional configurations.
*/
interface SubjectDisplayerInterface
{
public function supportsDisplay(Subject $subject, array $optons = []): bool;
/**
* Render a Subject as an HTML string.
*
* @return string an html string
*/
public function display(Subject $subject, array $options = []): string;
}

View File

@@ -0,0 +1,29 @@
<?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\MainBundle\Audit\Twig;
use Chill\MainBundle\Audit\Subject;
use Chill\MainBundle\Audit\SubjectConverterManagerInterface;
use Twig\Extension\RuntimeExtensionInterface;
final readonly class SubjectRenderRuntimeTwig implements RuntimeExtensionInterface
{
public function __construct(private SubjectConverterManagerInterface $subjectConverterManager) {}
public function renderAuditSubject(array|Subject $subject, array $options = []): string
{
return $this->subjectConverterManager->display(
$subject instanceof Subject ? $subject : Subject::fromArray($subject),
$options
);
}
}

View File

@@ -0,0 +1,25 @@
<?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\MainBundle\Audit\Twig;
use Twig\Extension\AbstractExtension;
use Twig\TwigFilter;
final class SubjectRenderTwig extends AbstractExtension
{
public function getFilters(): array
{
return [
new TwigFilter('chill_render_audit_subject', [SubjectRenderRuntimeTwig::class, 'renderAuditSubject'], ['is_safe' => ['html']]),
];
}
}