mirror of
https://github.com/Part-DB/Part-DB-server.git
synced 2025-07-13 20:04:34 +02:00
Refactored TwigExtensions Part 1
This commit is contained in:
parent
8e6300079a
commit
b078389381
21 changed files with 301 additions and 89 deletions
|
@ -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':
|
||||||
|
|
|
@ -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
|
||||||
{
|
{
|
||||||
|
|
91
src/Twig/EntityExtension.php
Normal file
91
src/Twig/EntityExtension.php
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
60
src/Twig/TwigCoreExtension.php
Normal file
60
src/Twig/TwigCoreExtension.php
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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']),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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">
|
||||||
|
|
|
@ -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>
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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 %}
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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">
|
||||||
|
|
|
@ -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 %}">
|
||||||
|
|
|
@ -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 %}
|
||||||
|
|
||||||
|
|
|
@ -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="">
|
||||||
|
|
|
@ -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 %}
|
||||||
|
|
53
tests/Twig/EntityExtensionTest.php
Normal file
53
tests/Twig/EntityExtensionTest.php
Normal 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()));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
56
tests/Twig/TwigCoreExtensionTest.php
Normal file
56
tests/Twig/TwigCoreExtensionTest.php
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue