Refactored TwigExtensions Part 1

This commit is contained in:
Jan Böhmer 2022-09-18 16:45:12 +02:00
parent 8e6300079a
commit b078389381
21 changed files with 301 additions and 89 deletions

View file

@ -96,12 +96,12 @@ class EntityURLGenerator
* @param mixed $entity The element for which the page should be generated * @param mixed $entity The element for which the page should be generated
* @param string $type The page type. Currently supported: 'info', 'edit', 'create', 'clone', 'list'/'list_parts' * @param string $type The page type. Currently supported: 'info', 'edit', 'create', 'clone', 'list'/'list_parts'
* *
* @return string|null the link to the desired page * @return string the link to the desired page
* *
* @throws EntityNotSupportedException thrown if the entity is not supported for the given type * @throws EntityNotSupportedException thrown if the entity is not supported for the given type
* @throws InvalidArgumentException thrown if the givent type is not existing * @throws InvalidArgumentException thrown if the givent type is not existing
*/ */
public function getURL($entity, string $type): ?string public function getURL($entity, string $type): string
{ {
switch ($type) { switch ($type) {
case 'info': case 'info':

View file

@ -77,7 +77,6 @@ use function get_class;
class AppExtension extends AbstractExtension class AppExtension extends AbstractExtension
{ {
protected $entityURLGenerator;
protected $markdownParser; protected $markdownParser;
protected $serializer; protected $serializer;
protected $treeBuilder; protected $treeBuilder;
@ -88,16 +87,13 @@ class AppExtension extends AbstractExtension
protected $FAIconGenerator; protected $FAIconGenerator;
protected $translator; protected $translator;
protected $objectNormalizer; public function __construct(MarkdownParser $markdownParser,
public function __construct(EntityURLGenerator $entityURLGenerator, MarkdownParser $markdownParser,
SerializerInterface $serializer, TreeViewGenerator $treeBuilder, SerializerInterface $serializer, TreeViewGenerator $treeBuilder,
MoneyFormatter $moneyFormatter, MoneyFormatter $moneyFormatter,
SIFormatter $SIFormatter, AmountFormatter $amountFormatter, SIFormatter $SIFormatter, AmountFormatter $amountFormatter,
AttachmentURLGenerator $attachmentURLGenerator, AttachmentURLGenerator $attachmentURLGenerator,
FAIconGenerator $FAIconGenerator, TranslatorInterface $translator, ObjectNormalizer $objectNormalizer) FAIconGenerator $FAIconGenerator, TranslatorInterface $translator)
{ {
$this->entityURLGenerator = $entityURLGenerator;
$this->markdownParser = $markdownParser; $this->markdownParser = $markdownParser;
$this->serializer = $serializer; $this->serializer = $serializer;
$this->treeBuilder = $treeBuilder; $this->treeBuilder = $treeBuilder;
@ -107,14 +103,11 @@ class AppExtension extends AbstractExtension
$this->attachmentURLGenerator = $attachmentURLGenerator; $this->attachmentURLGenerator = $attachmentURLGenerator;
$this->FAIconGenerator = $FAIconGenerator; $this->FAIconGenerator = $FAIconGenerator;
$this->translator = $translator; $this->translator = $translator;
$this->objectNormalizer = $objectNormalizer;
} }
public function getFilters(): array public function getFilters(): array
{ {
return [ return [
new TwigFilter('entityURL', [$this, 'generateEntityURL']),
new TwigFilter('markdown', [$this->markdownParser, 'markForRendering'], [ new TwigFilter('markdown', [$this->markdownParser, 'markForRendering'], [
'pre_escape' => 'html', 'pre_escape' => 'html',
'is_safe' => ['html'], 'is_safe' => ['html'],
@ -123,25 +116,10 @@ class AppExtension extends AbstractExtension
new TwigFilter('siFormat', [$this, 'siFormat']), new TwigFilter('siFormat', [$this, 'siFormat']),
new TwigFilter('amountFormat', [$this, 'amountFormat']), new TwigFilter('amountFormat', [$this, 'amountFormat']),
new TwigFilter('loginPath', [$this, 'loginPath']), new TwigFilter('loginPath', [$this, 'loginPath']),
new TwigFilter('toArray', [$this, 'toArray'])
]; ];
} }
public function getTests(): array
{
return [
new TwigTest('instanceof', static function ($var, $instance) {
return $var instanceof $instance;
}),
new TwigTest('entity', static function ($var) {
return $var instanceof AbstractDBElement;
}),
new TwigTest('object', static function ($var) {
return is_object($var);
}),
];
}
public function getFunctions(): array public function getFunctions(): array
{ {
@ -149,31 +127,9 @@ class AppExtension extends AbstractExtension
new TwigFunction('generateTreeData', [$this, 'treeData']), new TwigFunction('generateTreeData', [$this, 'treeData']),
new TwigFunction('attachment_thumbnail', [$this->attachmentURLGenerator, 'getThumbnailURL']), new TwigFunction('attachment_thumbnail', [$this->attachmentURLGenerator, 'getThumbnailURL']),
new TwigFunction('ext_to_fa_icon', [$this->FAIconGenerator, 'fileExtensionToFAType']), new TwigFunction('ext_to_fa_icon', [$this->FAIconGenerator, 'fileExtensionToFAType']),
new TwigFunction('entity_type', [$this, 'getEntityType']),
]; ];
} }
public function getEntityType($entity): ?string
{
$map = [
Part::class => 'part',
Footprint::class => 'footprint',
Storelocation::class => 'storelocation',
Manufacturer::class => 'manufacturer',
Category::class => 'category',
Device::class => 'device',
Attachment::class => 'attachment',
Supplier::class => 'supplier',
User::class => 'user',
Group::class => 'group',
Currency::class => 'currency',
MeasurementUnit::class => 'measurement_unit',
LabelProfile::class => 'label_profile',
];
return $map[get_class($entity)] ?? null;
}
public function treeData(AbstractDBElement $element, string $type = 'newEdit'): string public function treeData(AbstractDBElement $element, string $type = 'newEdit'): string
{ {
$tree = $this->treeBuilder->getTreeView(get_class($element), null, $type, $element); $tree = $this->treeBuilder->getTreeView(get_class($element), null, $type, $element);
@ -181,10 +137,7 @@ class AppExtension extends AbstractExtension
return json_encode($tree, JSON_THROW_ON_ERROR); return json_encode($tree, JSON_THROW_ON_ERROR);
} }
public function toArray($object): array
{
return $this->objectNormalizer->normalize($object, null);
}
/** /**
* This function/filter generates an path. * This function/filter generates an path.
@ -198,10 +151,7 @@ class AppExtension extends AbstractExtension
return implode('/', $parts); return implode('/', $parts);
} }
public function generateEntityURL(AbstractDBElement $entity, string $method = 'info'): string
{
return $this->entityURLGenerator->getURL($entity, $method);
}
public function formatCurrency($amount, ?Currency $currency = null, int $decimals = 5): string public function formatCurrency($amount, ?Currency $currency = null, int $decimals = 5): string
{ {

View file

@ -0,0 +1,91 @@
<?php
namespace App\Twig;
use App\Entity\Attachments\Attachment;
use App\Entity\Base\AbstractDBElement;
use App\Entity\Devices\Device;
use App\Entity\LabelSystem\LabelProfile;
use App\Entity\Parts\Category;
use App\Entity\Parts\Footprint;
use App\Entity\Parts\Manufacturer;
use App\Entity\Parts\MeasurementUnit;
use App\Entity\Parts\Part;
use App\Entity\Parts\Storelocation;
use App\Entity\Parts\Supplier;
use App\Entity\PriceInformations\Currency;
use App\Entity\UserSystem\Group;
use App\Entity\UserSystem\User;
use App\Services\EntityURLGenerator;
use Twig\Extension\AbstractExtension;
use Twig\TwigFilter;
use Twig\TwigFunction;
use Twig\TwigTest;
class EntityExtension extends AbstractExtension
{
protected $entityURLGenerator;
public function __construct(EntityURLGenerator $entityURLGenerator)
{
$this->entityURLGenerator = $entityURLGenerator;
}
public function getFilters(): array
{
return [
];
}
public function getTests(): array
{
return [
/* Checks if the given variable is an entitity (instance of AbstractDBElement) */
new TwigTest('entity', static function ($var) {
return $var instanceof AbstractDBElement;
}),
];
}
public function getFunctions(): array
{
return [
/* Returns a string representation of the given entity */
new TwigFunction('entity_type', [$this, 'getEntityType']),
new TwigFunction('entity_url', [$this, 'generateEntityURL']),
];
}
public function generateEntityURL(AbstractDBElement $entity, string $method = 'info'): string
{
return $this->entityURLGenerator->getURL($entity, $method);
}
public function getEntityType(object $entity): ?string
{
$map = [
Part::class => 'part',
Footprint::class => 'footprint',
Storelocation::class => 'storelocation',
Manufacturer::class => 'manufacturer',
Category::class => 'category',
Device::class => 'device',
Attachment::class => 'attachment',
Supplier::class => 'supplier',
User::class => 'user',
Group::class => 'group',
Currency::class => 'currency',
MeasurementUnit::class => 'measurement_unit',
LabelProfile::class => 'label_profile',
];
foreach ($map as $class => $type) {
if ($entity instanceof $class) {
return $type;
}
}
return false;
}
}

View file

@ -0,0 +1,60 @@
<?php
namespace App\Twig;
use App\Entity\Base\AbstractDBElement;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
use Twig\Extension\AbstractExtension;
use Twig\TwigFilter;
use Twig\TwigTest;
/**
* The functionalities here extend the Twig with some core functions, which are independently of Part-DB.
*/
class TwigCoreExtension extends AbstractExtension
{
protected $objectNormalizer;
public function __construct(ObjectNormalizer $objectNormalizer)
{
$this->objectNormalizer = $objectNormalizer;
}
public function getTests(): array
{
return [
/*
* Checks if a given variable is an instance of a given class. E.g. ` x is instanceof('App\Entity\Parts\Part')`
*/
new TwigTest('instanceof', static function ($var, $instance) {
return $var instanceof $instance;
}),
/* Checks if a given variable is an object. E.g. `x is object` */
new TwigTest('object', static function ($var) {
return is_object($var);
}),
];
}
public function getFilters()
{
return [
/* Converts the given object to an array representation of the public/accessible properties */
new TwigFilter('to_array', [$this, 'toArray']),
];
}
public function toArray($object)
{
if(! is_object($object) && ! is_array($object)) {
throw new \InvalidArgumentException('The given variable is not an object or array!');
}
//If it is already an array, we can just return it
if(is_array($object)) {
return $object;
}
return $this->objectNormalizer->normalize($object, null);
}
}

View file

@ -29,7 +29,7 @@ use Doctrine\ORM\EntityManagerInterface;
use Twig\Extension\AbstractExtension; use Twig\Extension\AbstractExtension;
use Twig\TwigFunction; use Twig\TwigFunction;
class LastUserExtension extends AbstractExtension class UserExtension extends AbstractExtension
{ {
/** @var LogEntryRepository */ /** @var LogEntryRepository */
private $repo; private $repo;
@ -42,8 +42,10 @@ class LastUserExtension extends AbstractExtension
public function getFunctions(): array public function getFunctions(): array
{ {
return [ return [
new TwigFunction('getLastEditingUser', [$this->repo, 'getLastEditingUser']), /* Returns the user which has edited the given entity the last time. */
new TwigFunction('getCreatingUser', [$this->repo, 'getCreatingUser']), new TwigFunction('last_editing_user', [$this->repo, 'getLastEditingUser']),
/* Returns the user which has created the given entity. */
new TwigFunction('creating_user', [$this->repo, 'getCreatingUser']),
]; ];
} }
} }

View file

@ -1,4 +1,4 @@
<form method="post" class="" action="{{ entity|entityURL('delete') }}" {{ stimulus_controller('elements/delete_btn') }} {{ stimulus_action('elements/delete_btn', "submit", "submit") }} <form method="post" class="" action="{{ entity_url(entity, 'delete') }}" {{ stimulus_controller('elements/delete_btn') }} {{ stimulus_action('elements/delete_btn', "submit", "submit") }}
data-delete-title="{% trans with {'%name%': entity.name }%}entity.delete.confirm_title{% endtrans %}" data-delete-title="{% trans with {'%name%': entity.name }%}entity.delete.confirm_title{% endtrans %}"
data-delete-message="{% trans %}entity.delete.message{% endtrans %}"> data-delete-message="{% trans %}entity.delete.message{% endtrans %}">
<input type="hidden" name="_method" value="DELETE"> <input type="hidden" name="_method" value="DELETE">

View file

@ -1,5 +1,5 @@
<div class="row mb-2"> <div class="row mb-2">
<div class="offset-3 col"> <div class="offset-3 col">
<a class="btn btn-info {% if not is_granted('create', entity) %}disabled{% endif %}" href="{{ entity | entityURL('clone') }}">{% trans %}entity.duplicate{% endtrans %}</a> <a class="btn btn-info {% if not is_granted('create', entity) %}disabled{% endif %}" href="{{ entity_url(entity, 'clone') }}">{% trans %}entity.duplicate{% endtrans %}</a>
</div> </div>
</div> </div>

View file

@ -60,7 +60,7 @@
<div class="col-sm-9"> <div class="col-sm-9">
<span class="form-control-plaintext">{{ profile.name ?? '-' }} <span class="form-control-plaintext">{{ profile.name ?? '-' }}
{% if profile %} {% if profile %}
<a href="{{ profile | entityURL('edit') }}" title="{% trans %}label_generator.edit_profile{% endtrans %}" <a href="{{ entity_url(profile, 'edit') }}" title="{% trans %}label_generator.edit_profile{% endtrans %}"
><i class="fas fa-edit"></i></a> ><i class="fas fa-edit"></i></a>
{% endif %} {% endif %}
</span> </span>

View file

@ -143,11 +143,11 @@
{% if attach.secure and not is_granted('show_private', attach) %} {% if attach.secure and not is_granted('show_private', attach) %}
{# Leave blank #} {# Leave blank #}
{% elseif attach.picture %} {% elseif attach.picture %}
<a href="{{ attach | entityURL('file_view') }}" rel="noopener" target="_blank" data-turbo="false"> <a href="{{ entity_url(attach, 'file_view') }}" rel="noopener" target="_blank" data-turbo="false">
<img class="img-fluid img-thumbnail thumbnail-sm" src="{{ attachment_thumbnail(attach, 'thumbnail_md') }}" alt="{% trans %}attachment.preview.alt{% endtrans %}" /> <img class="img-fluid img-thumbnail thumbnail-sm" src="{{ attachment_thumbnail(attach, 'thumbnail_md') }}" alt="{% trans %}attachment.preview.alt{% endtrans %}" />
</a> </a>
{% else %} {% else %}
<a href="{{ attach | entityURL('file_view') }}" rel="noopener" target="_blank" data-turbo="false" class="link-external">{% trans %}attachment.view{% endtrans %}</a> <a href="{{ entity_url(attach, 'file_view') }}" rel="noopener" target="_blank" data-turbo="false" class="link-external">{% trans %}attachment.view{% endtrans %}</a>
{% endif %} {% endif %}
{% else %} {% else %}
<br><br> <br><br>

View file

@ -7,7 +7,7 @@
{% block card_title %} {% block card_title %}
<i class="fas fa-edit fa-fw" aria-hidden="true"></i> <i class="fas fa-edit fa-fw" aria-hidden="true"></i>
{% trans with {'%name%': part.name} %}part.edit.card_title{% endtrans %} {% trans with {'%name%': part.name} %}part.edit.card_title{% endtrans %}
<b><a href="{{ part|entityURL('info') }}" class="text-white">{{ part.name }}</a></b> <b><a href="{{ entity_url(part, 'info') }}" class="text-white">{{ part.name }}</a></b>
<div class="float-end"> <div class="float-end">
{% trans %}id.label{% endtrans %}: {{ part.id }} {% trans %}id.label{% endtrans %}: {{ part.id }}
</div> </div>

View file

@ -57,12 +57,12 @@
</td> </td>
<td><div class="btn-group" role="group" aria-label=""> <td><div class="btn-group" role="group" aria-label="">
<a {% if attachment_manager.fileExisting(attachment) %}href="{{ attachment|entityURL('file_view') }}"{% endif %} target="_blank" <a {% if attachment_manager.fileExisting(attachment) %}href="{{ entity_url(attachment, 'file_view') }}"{% endif %} target="_blank"
class="btn btn-secondary {% if not attachment_manager.fileExisting(attachment) or (attachment.secure and not is_granted("show_secure", attachment)) %}disabled{% endif %}" class="btn btn-secondary {% if not attachment_manager.fileExisting(attachment) or (attachment.secure and not is_granted("show_secure", attachment)) %}disabled{% endif %}"
data-turbo="false" title="{% trans %}attachment.view{% endtrans %}" rel="noopener"> data-turbo="false" title="{% trans %}attachment.view{% endtrans %}" rel="noopener">
<i class="fas fa-eye fa-fw"></i> <i class="fas fa-eye fa-fw"></i>
</a> </a>
<a {% if attachment_manager.fileExisting(attachment) %}href="{{ attachment|entityURL('file_download') }}"{% endif %} data-turbo="false" <a {% if attachment_manager.fileExisting(attachment) %}href="{{ entity_url(attachment, 'file_download') }}"{% endif %} data-turbo="false"
class="btn btn-secondary {% if not attachment_manager.fileExisting(attachment) or (attachment.secure and not is_granted("show_secure", attachment)) %}disabled{% endif %}" class="btn btn-secondary {% if not attachment_manager.fileExisting(attachment) or (attachment.secure and not is_granted("show_secure", attachment)) %}disabled{% endif %}"
title="{% trans %}attachment.download{% endtrans %}"> title="{% trans %}attachment.download{% endtrans %}">
<i class="fas fa-download fa-fw"></i> <i class="fas fa-download fa-fw"></i>

View file

@ -10,7 +10,7 @@
<tr> <tr>
<td>{% trans %}user.creating_user{% endtrans %}</td> <td>{% trans %}user.creating_user{% endtrans %}</td>
<td>{% if is_granted('show_users', part) %} <td>{% if is_granted('show_users', part) %}
{{ getCreatingUser(part).fullName(true) ?? 'Unknown'|trans }} {{ creating_user(part).fullName(true) ?? 'Unknown'|trans }}
{% else %} {% else %}
{% trans %}accessDenied{% endtrans %} {% trans %}accessDenied{% endtrans %}
{% endif %} {% endif %}
@ -25,7 +25,7 @@
<tr> <tr>
<td>{% trans %}user.last_editing_user{% endtrans %}</td> <td>{% trans %}user.last_editing_user{% endtrans %}</td>
<td>{% if is_granted('show_users', part) %} <td>{% if is_granted('show_users', part) %}
{{ getLastEditingUser(part).fullName(true) ?? 'Unknown'|trans }} {{ last_editing_user(part).fullName(true) ?? 'Unknown'|trans }}
{% else %} {% else %}
{% trans %}accessDenied{% endtrans %} {% trans %}accessDenied{% endtrans %}
{% endif %} {% endif %}

View file

@ -8,7 +8,7 @@
<h5 class="text-muted pt-2" title="{% trans %}manufacturer.label{% endtrans %}"> <h5 class="text-muted pt-2" title="{% trans %}manufacturer.label{% endtrans %}">
{% if part.manufacturer %} {% if part.manufacturer %}
{% if part.manufacturer.id is not null %} {% if part.manufacturer.id is not null %}
<a href="{{ part.manufacturer | entityURL('list_parts') }}">{{ part.manufacturer.name}}</a> <a href="{{ entity_url(part.manufacturer, 'list_parts') }}">{{ part.manufacturer.name}}</a>
{% else %} {% else %}
{{ part.manufacturer.name }} {{ part.manufacturer.name }}
{% endif %} {% endif %}
@ -24,9 +24,9 @@
<h3 class="w-fit" title="{% trans %}name.label{% endtrans %}">{{ part.name }} <h3 class="w-fit" title="{% trans %}name.label{% endtrans %}">{{ part.name }}
{# You need edit permission to use the edit button #} {# You need edit permission to use the edit button #}
{% if timeTravel is not null %} {% if timeTravel is not null %}
<a href="{{ part|entityURL('info') }}"><i title="{% trans %}part.back_to_info{% endtrans %}" class="fas fa-fw fa-arrow-circle-left"></i></a> <a href="{{ entity_url(part, 'info') }}"><i title="{% trans %}part.back_to_info{% endtrans %}" class="fas fa-fw fa-arrow-circle-left"></i></a>
{% elseif is_granted('edit', part) %} {% elseif is_granted('edit', part) %}
<a href="{{ part|entityURL('edit') }}"><i class="fas fa-fw fa-sm fa-edit"></i></a> <a href="{{ entity_url(part, 'edit') }}"><i class="fas fa-fw fa-sm fa-edit"></i></a>
{% endif %} {% endif %}
</h3> </h3>
<h6 class="text-muted w-fit" title="{% trans %}description.label{% endtrans %}"><span>{{ part.description|markdown(true) }}</span></h6> <h6 class="text-muted w-fit" title="{% trans %}description.label{% endtrans %}"><span>{{ part.description|markdown(true) }}</span></h6>

View file

@ -12,7 +12,7 @@
{% for order in part.orderdetails %} {% for order in part.orderdetails %}
<tr class="{% if order.obsolete %}table-danger{% endif %}"> <tr class="{% if order.obsolete %}table-danger{% endif %}">
<td> <td>
<a href="{{ order.supplier | entityURL('list_parts') }}">{{ order.supplier.name }}</a> <a href="{{ entity_url(order.supplier, 'list_parts') }}">{{ order.supplier.name }}</a>
</td> </td>
<td>{% if order.supplierProductUrl is not empty %} <td>{% if order.supplierProductUrl is not empty %}
<a href="{{ order.supplierProductUrl }}" rel="noopener" target="_blank" class="link-external">{{ order.supplierPartNr }}</a> <a href="{{ order.supplierProductUrl }}" rel="noopener" target="_blank" class="link-external">{{ order.supplierPartNr }}</a>

View file

@ -11,8 +11,8 @@
{% for pic in pictures %} {% for pic in pictures %}
{# @var pic App\Entity\Attachments\Attachment #} {# @var pic App\Entity\Attachments\Attachment #}
<div class="carousel-item {% if loop.first %}active{% endif %}"> <div class="carousel-item {% if loop.first %}active{% endif %}">
<a href="{{ pic | entityURL('file_view') }}" data-turbo="false" target="_blank" rel="noopener"> <a href="{{ entity_url(pic, 'file_view') }}" data-turbo="false" target="_blank" rel="noopener">
<img class="d-block w-100 img-fluid img-thumbnail bg-light" src="{{ pic | entityURL('file_view') }}" alt=""> <img class="d-block w-100 img-fluid img-thumbnail bg-light" src="{{ entity_url(pic, 'file_view') }}" alt="">
<div class="mask"></div> <div class="mask"></div>
<div class="carousel-caption-hover"> <div class="carousel-caption-hover">
<div class="carousel-caption"> <div class="carousel-caption">

View file

@ -1,7 +1,7 @@
{% import "LabelSystem/dropdown_macro.html.twig" as dropdown %} {% import "LabelSystem/dropdown_macro.html.twig" as dropdown %}
{% if is_granted('edit', part) %} {% if is_granted('edit', part) %}
<a href="{{ part|entityURL('edit') }}" class="btn btn-primary mt-3"> <a href="{{ entity_url(part, 'edit') }}" class="btn btn-primary mt-3">
<i class="fas fa-fw fa-edit"></i> <i class="fas fa-fw fa-edit"></i>
{% trans %}part.edit.btn{% endtrans %} {% trans %}part.edit.btn{% endtrans %}
</a> </a>
@ -11,7 +11,7 @@
{% if is_granted('create', part) %} {% if is_granted('create', part) %}
<br> <br>
<div class="btn-group mt-2"> <div class="btn-group mt-2">
<a class="btn btn-primary" href="{{ part|entityURL('clone') }}"> <a class="btn btn-primary" href="{{ entity_url(part, 'clone') }}">
<i class="fas fa-clone"></i> <i class="fas fa-clone"></i>
{% trans %}part.clone.btn{% endtrans %} {% trans %}part.clone.btn{% endtrans %}
</a> </a>
@ -19,7 +19,7 @@
<span class="caret"></span> <span class="caret"></span>
</button> </button>
<div class="dropdown-menu" role="menu"> <div class="dropdown-menu" role="menu">
<a class="dropdown-item" href="{{ part|entityURL('create') }}"> <a class="dropdown-item" href="{{ entity_url(part, 'create') }}">
<i class="fas fa-plus-square"></i> <i class="fas fa-plus-square"></i>
{% trans %}part.create.btn{% endtrans %} {% trans %}part.create.btn{% endtrans %}
</a> </a>
@ -27,7 +27,7 @@
</div> </div>
{% endif %} {% endif %}
<form method="post" class="mt-2" action="{{ part|entityURL('delete') }}" <form method="post" class="mt-2" action="{{ entity_url(part, 'delete') }}"
{{ stimulus_controller('elements/delete_btn') }} {{ stimulus_action('elements/delete_btn', "submit", "submit") }} {{ stimulus_controller('elements/delete_btn') }} {{ stimulus_action('elements/delete_btn', "submit", "submit") }}
data-delete-title="{% trans with {'%name%': part.name }%}part.delete.confirm_title{% endtrans %}" data-delete-title="{% trans with {'%name%': part.name }%}part.delete.confirm_title{% endtrans %}"
data-delete-message="{% trans %}part.delete.message{% endtrans %}"> data-delete-message="{% trans %}part.delete.message{% endtrans %}">

View file

@ -125,7 +125,7 @@
{# Retain the query parameters of the search form if it is existing #} {# Retain the query parameters of the search form if it is existing #}
{% if searchFilter is defined %} {% if searchFilter is defined %}
{% for property, value in searchFilter|toArray %} {% for property, value in searchFilter|to_array %}
<input type="hidden" name="{{ property }}" data-no-clear="true" value="{{ value }}"> <input type="hidden" name="{{ property }}" data-no-clear="true" value="{{ value }}">
{% endfor %} {% endfor %}

View file

@ -8,7 +8,7 @@
<div class="accordion-header"> <div class="accordion-header">
<button class="accordion-button collapsed py-2" data-bs-toggle="collapse" data-bs-target="#entityInfo"> <button class="accordion-button collapsed py-2" data-bs-toggle="collapse" data-bs-target="#entityInfo">
{% if entity.masterPictureAttachment is not null and attachment_manager.isFileExisting(entity.masterPictureAttachment) %} {% if entity.masterPictureAttachment is not null and attachment_manager.isFileExisting(entity.masterPictureAttachment) %}
<img class="hoverpic ms-0 me-1 d-inline" {{ stimulus_controller('elements/hoverpic') }} data-thumbnail="{{ entity.masterPictureAttachment | entityURL('file_view') }}" src="{{ attachment_thumbnail(entity.masterPictureAttachment, 'thumbnail_sm') }}"> <img class="hoverpic ms-0 me-1 d-inline" {{ stimulus_controller('elements/hoverpic') }} data-thumbnail="{{ entity_url(entity.masterPictureAttachment, 'file_view') }}" src="{{ attachment_thumbnail(entity.masterPictureAttachment, 'thumbnail_sm') }}">
{% else %} {% else %}
{{ helper.entity_icon(entity, "me-1") }} {{ helper.entity_icon(entity, "me-1") }}
{% endif %} {% endif %}
@ -71,7 +71,7 @@
<div class="col-sm-3"> <div class="col-sm-3">
{% block quick_links %}{% endblock %} {% block quick_links %}{% endblock %}
<a class="btn btn-secondary w-100 mb-2" href="{{ entity | entityURL('edit') }}"> <a class="btn btn-secondary w-100 mb-2" href="{{ entity_url(entity, 'edit') }}">
<i class="fas fa-edit"></i> {% trans %}entity.edit.btn{% endtrans %} <i class="fas fa-edit"></i> {% trans %}entity.edit.btn{% endtrans %}
</a> </a>
<div class=""> <div class="">

View file

@ -10,10 +10,10 @@
{% set disabled = attachment.secure and not is_granted("show_secure", attachment) %} {% set disabled = attachment.secure and not is_granted("show_secure", attachment) %}
{% if not attachment_helper or attachment_helper.fileExisting(attachment) %} {% if not attachment_helper or attachment_helper.fileExisting(attachment) %}
{% if link and not disabled %} {% if link and not disabled %}
<a target="_blank" data-turbo="false" rel="noopener" href="{{ attachment|entityURL('file_view') }}"> <a target="_blank" data-turbo="false" rel="noopener" href="{{ entity_url(attachment, 'file_view') }}">
{% endif %} {% endif %}
{% if attachment.picture %} {% if attachment.picture %}
<img class="hoverpic" {{ stimulus_controller('elements/hoverpic') }} data-thumbnail="{{ attachment|entityURL('file_view') }}" src="{{ attachment|entityURL('file_view') }}"> <img class="hoverpic" {{ stimulus_controller('elements/hoverpic') }} data-thumbnail="{{ entity_url(attachment, 'file_view') }}" src="{{ entity_url(attachment, 'file_view') }}">
{% else %} {% else %}
<i class="text-dark {{ class }} {{ ext_to_fa_icon(attachment.extension) }}"></i> <i class="text-dark {{ class }} {{ ext_to_fa_icon(attachment.extension) }}"></i>
{% endif %} {% endif %}
@ -59,7 +59,7 @@
{% for e in entity.pathArray %} {% for e in entity.pathArray %}
<li> <li>
{% if link_type is not empty and e.id is not null %} {% if link_type is not empty and e.id is not null %}
<a href="{{ e | entityURL(link_type) }}">{{ e.name }}</a> <a href="{{ entity_url(e, link_type) }}">{{ e.name }}</a>
{% else %} {% else %}
{{ e.name }} {{ e.name }}
{% endif %} {% endif %}
@ -115,7 +115,7 @@
{% for e in entity.pathArray %} {% for e in entity.pathArray %}
<li class="breadcrumb-item {% if loop.last %}active{% endif %}"> <li class="breadcrumb-item {% if loop.last %}active{% endif %}">
{% if link_type is not empty and not loop.last and e.id is not null %} {% if link_type is not empty and not loop.last and e.id is not null %}
<a href="{{ e | entityURL(link_type) }}">{{ e.name }}</a> <a href="{{ entity_url(e, link_type) }}">{{ e.name }}</a>
{% else %} {% else %}
{{ e.name }} {{ e.name }}
{% endif %} {% endif %}
@ -141,9 +141,9 @@
{% endif %} {% endif %}
{% if is_granted('show_users', entity) %} {% if is_granted('show_users', entity) %}
{% if lastModified == true %} {% if lastModified == true %}
{% set user = getLastEditingUser(entity) %} {% set user = last_editing_user(entity) %}
{% else %} {% else %}
{% set user = getCreatingUser(entity) %} {% set user = creating_user(entity) %}
{% endif %} {% endif %}
{% if user is not null %} {% if user is not null %}

View file

@ -0,0 +1,53 @@
<?php
namespace App\Tests\Twig;
use App\Entity\Attachments\Attachment;
use App\Entity\Attachments\PartAttachment;
use App\Entity\Devices\Device;
use App\Entity\LabelSystem\LabelProfile;
use App\Entity\Parts\Category;
use App\Entity\Parts\Footprint;
use App\Entity\Parts\Manufacturer;
use App\Entity\Parts\MeasurementUnit;
use App\Entity\Parts\Part;
use App\Entity\Parts\Storelocation;
use App\Entity\Parts\Supplier;
use App\Entity\PriceInformations\Currency;
use App\Entity\UserSystem\Group;
use App\Entity\UserSystem\User;
use App\Twig\EntityExtension;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
class EntityExtensionTest extends WebTestCase
{
/** @var EntityExtension */
protected $service;
protected function setUp(): void
{
parent::setUp(); // TODO: Change the autogenerated stub
//Get an service instance.
self::bootKernel();
$this->service = self::getContainer()->get(EntityExtension::class);
}
public function testGetEntityType()
{
$this->assertEquals('part', $this->service->getEntityType(new Part()));
$this->assertEquals('footprint', $this->service->getEntityType(new Footprint()));
$this->assertEquals('storelocation', $this->service->getEntityType(new Storelocation()));
$this->assertEquals('manufacturer', $this->service->getEntityType(new Manufacturer()));
$this->assertEquals('category', $this->service->getEntityType(new Category()));
$this->assertEquals('device', $this->service->getEntityType(new Device()));
$this->assertEquals('attachment', $this->service->getEntityType(new PartAttachment()));
$this->assertEquals('supplier', $this->service->getEntityType(new Supplier()));
$this->assertEquals('user', $this->service->getEntityType(new User()));
$this->assertEquals('group', $this->service->getEntityType(new Group()));
$this->assertEquals('currency', $this->service->getEntityType(new Currency()));
$this->assertEquals('measurement_unit', $this->service->getEntityType(new MeasurementUnit()));
$this->assertEquals('label_profile', $this->service->getEntityType(new LabelProfile()));
}
}

View file

@ -0,0 +1,56 @@
<?php
namespace App\Tests\Twig;
use App\Twig\TwigCoreExtension;
use PHPUnit\Framework\TestCase;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
class TwigCoreExtensionTest extends WebTestCase
{
/** @var TwigCoreExtension */
protected $service;
protected function setUp(): void
{
parent::setUp(); // TODO: Change the autogenerated stub
//Get an service instance.
self::bootKernel();
$this->service = self::getContainer()->get(TwigCoreExtension::class);
}
public function testToArray(): void
{
//Check for simple arrays
$this->assertSame([], $this->service->toArray([]));
$this->assertSame([1, 2, 3], $this->service->toArray([1, 2, 3]));
//Check for simple objects
$this->assertSame([], $this->service->toArray(new \stdClass()));
$this->assertSame(['test' => 1], $this->service->toArray((object)['test' => 1]));
//Only test and test4 should be available
$obj = new class {
public $test = 1;
protected $test2 = 3;
private $test3 = 5;
private $test4 = 7;
public function getTest4()
{
return $this->test4;
}
};
$this->assertEqualsCanonicalizing(['test' => 1, 'test4' => 7], $this->service->toArray($obj));
}
public function testToArrayException(): void
{
//When passing a simple scalar value a exception should be thrown.
$this->expectException(\InvalidArgumentException::class);
$this->service->toArray(1);
}
}