mirror of
https://github.com/Part-DB/Part-DB-server.git
synced 2025-06-24 10:49:00 +02:00
Applied rector with PHP8.1 migration rules
This commit is contained in:
parent
dc6a67c2f0
commit
7ee01d9a05
303 changed files with 1228 additions and 3465 deletions
|
@ -42,27 +42,14 @@ use Symfony\Contracts\Translation\TranslatorInterface;
|
|||
|
||||
final class AttachmentDataTable implements DataTableTypeInterface
|
||||
{
|
||||
private TranslatorInterface $translator;
|
||||
private EntityURLGenerator $entityURLGenerator;
|
||||
private AttachmentManager $attachmentHelper;
|
||||
private ElementTypeNameGenerator $elementTypeNameGenerator;
|
||||
private AttachmentURLGenerator $attachmentURLGenerator;
|
||||
|
||||
public function __construct(TranslatorInterface $translator, EntityURLGenerator $entityURLGenerator,
|
||||
AttachmentManager $attachmentHelper, AttachmentURLGenerator $attachmentURLGenerator,
|
||||
ElementTypeNameGenerator $elementTypeNameGenerator)
|
||||
public function __construct(private readonly TranslatorInterface $translator, private readonly EntityURLGenerator $entityURLGenerator, private readonly AttachmentManager $attachmentHelper, private readonly AttachmentURLGenerator $attachmentURLGenerator, private readonly ElementTypeNameGenerator $elementTypeNameGenerator)
|
||||
{
|
||||
$this->translator = $translator;
|
||||
$this->entityURLGenerator = $entityURLGenerator;
|
||||
$this->attachmentHelper = $attachmentHelper;
|
||||
$this->elementTypeNameGenerator = $elementTypeNameGenerator;
|
||||
$this->attachmentURLGenerator = $attachmentURLGenerator;
|
||||
}
|
||||
|
||||
public function configure(DataTable $dataTable, array $options): void
|
||||
{
|
||||
$dataTable->add('dont_matter', RowClassColumn::class, [
|
||||
'render' => function ($value, Attachment $context) {
|
||||
'render' => function ($value, Attachment $context): string {
|
||||
//Mark attachments with missing files yellow
|
||||
if(!$this->attachmentHelper->isFileExisting($context)){
|
||||
return 'table-warning';
|
||||
|
@ -75,7 +62,7 @@ final class AttachmentDataTable implements DataTableTypeInterface
|
|||
$dataTable->add('picture', TextColumn::class, [
|
||||
'label' => '',
|
||||
'className' => 'no-colvis',
|
||||
'render' => function ($value, Attachment $context) {
|
||||
'render' => function ($value, Attachment $context): string {
|
||||
if ($context->isPicture()
|
||||
&& !$context->isExternal()
|
||||
&& $this->attachmentHelper->isFileExisting($context)) {
|
||||
|
@ -125,25 +112,21 @@ final class AttachmentDataTable implements DataTableTypeInterface
|
|||
$dataTable->add('attachment_type', TextColumn::class, [
|
||||
'label' => 'attachment.table.type',
|
||||
'field' => 'attachment_type.name',
|
||||
'render' => function ($value, Attachment $context) {
|
||||
return sprintf(
|
||||
'<a href="%s">%s</a>',
|
||||
$this->entityURLGenerator->editURL($context->getAttachmentType()),
|
||||
htmlspecialchars($value)
|
||||
);
|
||||
},
|
||||
'render' => fn($value, Attachment $context): string => sprintf(
|
||||
'<a href="%s">%s</a>',
|
||||
$this->entityURLGenerator->editURL($context->getAttachmentType()),
|
||||
htmlspecialchars((string) $value)
|
||||
),
|
||||
]);
|
||||
|
||||
$dataTable->add('element', TextColumn::class, [
|
||||
'label' => 'attachment.table.element',
|
||||
//'propertyPath' => 'element.name',
|
||||
'render' => function ($value, Attachment $context) {
|
||||
return sprintf(
|
||||
'<a href="%s">%s</a>',
|
||||
$this->entityURLGenerator->infoURL($context->getElement()),
|
||||
$this->elementTypeNameGenerator->getTypeNameCombination($context->getElement(), true)
|
||||
);
|
||||
},
|
||||
'render' => fn($value, Attachment $context): string => sprintf(
|
||||
'<a href="%s">%s</a>',
|
||||
$this->entityURLGenerator->infoURL($context->getElement()),
|
||||
$this->elementTypeNameGenerator->getTypeNameCombination($context->getElement(), true)
|
||||
),
|
||||
]);
|
||||
|
||||
$dataTable->add('filename', TextColumn::class, [
|
||||
|
|
|
@ -31,13 +31,8 @@ use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
|
|||
|
||||
class EntityColumn extends AbstractColumn
|
||||
{
|
||||
protected EntityURLGenerator $urlGenerator;
|
||||
protected PropertyAccessorInterface $accessor;
|
||||
|
||||
public function __construct(EntityURLGenerator $URLGenerator, PropertyAccessorInterface $accessor)
|
||||
public function __construct(protected EntityURLGenerator $urlGenerator, protected PropertyAccessorInterface $accessor)
|
||||
{
|
||||
$this->urlGenerator = $URLGenerator;
|
||||
$this->accessor = $accessor;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -58,34 +53,30 @@ class EntityColumn extends AbstractColumn
|
|||
|
||||
$resolver->setRequired('property');
|
||||
|
||||
$resolver->setDefault('field', static function (Options $option) {
|
||||
return $option['property'].'.name';
|
||||
});
|
||||
$resolver->setDefault('field', static fn(Options $option): string => $option['property'].'.name');
|
||||
|
||||
$resolver->setDefault('render', function (Options $options) {
|
||||
return function ($value, $context) use ($options) {
|
||||
if ($this->accessor->isReadable($context, $options['property'])) {
|
||||
$entity = $this->accessor->getValue($context, $options['property']);
|
||||
} else {
|
||||
$entity = null;
|
||||
$resolver->setDefault('render', fn(Options $options) => function ($value, $context) use ($options): string {
|
||||
if ($this->accessor->isReadable($context, $options['property'])) {
|
||||
$entity = $this->accessor->getValue($context, $options['property']);
|
||||
} else {
|
||||
$entity = null;
|
||||
}
|
||||
|
||||
/** @var AbstractNamedDBElement|null $entity */
|
||||
|
||||
if ($entity instanceof \App\Entity\Base\AbstractNamedDBElement) {
|
||||
if (null !== $entity->getID()) {
|
||||
return sprintf(
|
||||
'<a href="%s">%s</a>',
|
||||
$this->urlGenerator->listPartsURL($entity),
|
||||
htmlspecialchars($entity->getName())
|
||||
);
|
||||
}
|
||||
|
||||
/** @var AbstractNamedDBElement|null $entity */
|
||||
return sprintf('<i>%s</i>', $value);
|
||||
}
|
||||
|
||||
if (null !== $entity) {
|
||||
if (null !== $entity->getID()) {
|
||||
return sprintf(
|
||||
'<a href="%s">%s</a>',
|
||||
$this->urlGenerator->listPartsURL($entity),
|
||||
htmlspecialchars($entity->getName())
|
||||
);
|
||||
}
|
||||
|
||||
return sprintf('<i>%s</i>', $value);
|
||||
}
|
||||
|
||||
return '';
|
||||
};
|
||||
return '';
|
||||
});
|
||||
|
||||
return $this;
|
||||
|
|
|
@ -38,7 +38,6 @@ class LocaleDateTimeColumn extends AbstractColumn
|
|||
{
|
||||
/**
|
||||
* @param $value
|
||||
* @return string
|
||||
* @throws Exception
|
||||
*/
|
||||
public function normalize($value): string
|
||||
|
|
|
@ -28,13 +28,8 @@ use Symfony\Contracts\Translation\TranslatorInterface;
|
|||
|
||||
class LogEntryExtraColumn extends AbstractColumn
|
||||
{
|
||||
protected TranslatorInterface $translator;
|
||||
protected LogEntryExtraFormatter $formatter;
|
||||
|
||||
public function __construct(TranslatorInterface $translator, LogEntryExtraFormatter $formatter)
|
||||
public function __construct(protected TranslatorInterface $translator, protected LogEntryExtraFormatter $formatter)
|
||||
{
|
||||
$this->translator = $translator;
|
||||
$this->formatter = $formatter;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -44,11 +44,8 @@ use Symfony\Contracts\Translation\TranslatorInterface;
|
|||
|
||||
class LogEntryTargetColumn extends AbstractColumn
|
||||
{
|
||||
private LogTargetHelper $logTargetHelper;
|
||||
|
||||
public function __construct(LogTargetHelper $logTargetHelper)
|
||||
public function __construct(private readonly LogTargetHelper $logTargetHelper)
|
||||
{
|
||||
$this->logTargetHelper = $logTargetHelper;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -27,11 +27,8 @@ use Omines\DataTablesBundle\Column\AbstractColumn;
|
|||
|
||||
class MarkdownColumn extends AbstractColumn
|
||||
{
|
||||
protected MarkdownParser $markdown;
|
||||
|
||||
public function __construct(MarkdownParser $markdown)
|
||||
public function __construct(protected MarkdownParser $markdown)
|
||||
{
|
||||
$this->markdown = $markdown;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -33,15 +33,8 @@ use Symfony\Component\OptionsResolver\OptionsResolver;
|
|||
|
||||
class PartAttachmentsColumn extends AbstractColumn
|
||||
{
|
||||
protected FAIconGenerator $FAIconGenerator;
|
||||
protected EntityURLGenerator $urlGenerator;
|
||||
protected AttachmentManager $attachmentManager;
|
||||
|
||||
public function __construct(FAIconGenerator $FAIconGenerator, EntityURLGenerator $urlGenerator, AttachmentManager $attachmentManager)
|
||||
public function __construct(protected FAIconGenerator $FAIconGenerator, protected EntityURLGenerator $urlGenerator, protected AttachmentManager $attachmentManager)
|
||||
{
|
||||
$this->FAIconGenerator = $FAIconGenerator;
|
||||
$this->urlGenerator = $urlGenerator;
|
||||
$this->attachmentManager = $attachmentManager;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -61,9 +54,7 @@ class PartAttachmentsColumn extends AbstractColumn
|
|||
throw new RuntimeException('$context must be a Part object!');
|
||||
}
|
||||
$tmp = '';
|
||||
$attachments = $context->getAttachments()->filter(function (Attachment $attachment) {
|
||||
return $attachment->getShowInTable() && $this->attachmentManager->isFileExisting($attachment);
|
||||
});
|
||||
$attachments = $context->getAttachments()->filter(fn(Attachment $attachment) => $attachment->getShowInTable() && $this->attachmentManager->isFileExisting($attachment));
|
||||
|
||||
$count = 5;
|
||||
foreach ($attachments as $attachment) {
|
||||
|
|
|
@ -25,11 +25,8 @@ use Symfony\Contracts\Translation\TranslatorInterface;
|
|||
|
||||
class PrettyBoolColumn extends AbstractColumn
|
||||
{
|
||||
protected TranslatorInterface $translator;
|
||||
|
||||
public function __construct(TranslatorInterface $translator)
|
||||
public function __construct(protected TranslatorInterface $translator)
|
||||
{
|
||||
$this->translator = $translator;
|
||||
}
|
||||
|
||||
public function normalize($value): ?bool
|
||||
|
|
|
@ -51,13 +51,8 @@ use Symfony\Contracts\Translation\TranslatorInterface;
|
|||
|
||||
class RevertLogColumn extends AbstractColumn
|
||||
{
|
||||
protected TranslatorInterface $translator;
|
||||
protected \Symfony\Bundle\SecurityBundle\Security $security;
|
||||
|
||||
public function __construct(TranslatorInterface $translator, \Symfony\Bundle\SecurityBundle\Security $security)
|
||||
public function __construct(protected TranslatorInterface $translator, protected \Symfony\Bundle\SecurityBundle\Security $security)
|
||||
{
|
||||
$this->translator = $translator;
|
||||
$this->security = $security;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -105,8 +100,6 @@ class RevertLogColumn extends AbstractColumn
|
|||
$this->translator->trans('log.undo.revert')
|
||||
);
|
||||
|
||||
$tmp .= '</div>';
|
||||
|
||||
return $tmp;
|
||||
return $tmp . '</div>';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,11 +26,8 @@ use Symfony\Component\OptionsResolver\OptionsResolver;
|
|||
|
||||
class SIUnitNumberColumn extends AbstractColumn
|
||||
{
|
||||
protected SIFormatter $formatter;
|
||||
|
||||
public function __construct(SIFormatter $formatter)
|
||||
public function __construct(protected SIFormatter $formatter)
|
||||
{
|
||||
$this->formatter = $formatter;
|
||||
}
|
||||
|
||||
public function configureOptions(OptionsResolver $resolver): self
|
||||
|
|
|
@ -27,11 +27,8 @@ use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
|||
|
||||
class TagsColumn extends AbstractColumn
|
||||
{
|
||||
protected UrlGeneratorInterface $urlGenerator;
|
||||
|
||||
public function __construct(UrlGeneratorInterface $urlGenerator)
|
||||
public function __construct(protected UrlGeneratorInterface $urlGenerator)
|
||||
{
|
||||
$this->urlGenerator = $urlGenerator;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -46,7 +43,7 @@ class TagsColumn extends AbstractColumn
|
|||
return [];
|
||||
}
|
||||
|
||||
return explode(',', $value);
|
||||
return explode(',', (string) $value);
|
||||
}
|
||||
|
||||
public function render($tags, $context): string
|
||||
|
@ -61,7 +58,7 @@ class TagsColumn extends AbstractColumn
|
|||
$html .= sprintf(
|
||||
'<a href="%s" class="badge bg-primary badge-table">%s</a>',
|
||||
$this->urlGenerator->generate('part_list_tags', ['tag' => $tag]),
|
||||
htmlspecialchars($tag)
|
||||
htmlspecialchars((string) $tag)
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -54,16 +54,12 @@ class ErrorDataTable implements DataTableTypeInterface
|
|||
|
||||
$dataTable
|
||||
->add('dont_matter_we_only_set_color', RowClassColumn::class, [
|
||||
'render' => function ($value, $context) {
|
||||
return 'table-warning';
|
||||
},
|
||||
'render' => fn($value, $context): string => 'table-warning',
|
||||
])
|
||||
|
||||
->add('error', TextColumn::class, [
|
||||
'label' => 'error_table.error',
|
||||
'render' => function ($value, $context) {
|
||||
return '<i class="fa-solid fa-triangle-exclamation fa-fw"></i> ' . $value;
|
||||
},
|
||||
'render' => fn($value, $context): string => '<i class="fa-solid fa-triangle-exclamation fa-fw"></i> ' . $value,
|
||||
])
|
||||
;
|
||||
|
||||
|
|
|
@ -60,59 +60,38 @@ class AttachmentFilter implements FilterInterface
|
|||
$this->applyAllChildFilters($queryBuilder);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return NumberConstraint
|
||||
*/
|
||||
public function getDbId(): NumberConstraint
|
||||
{
|
||||
return $this->dbId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return TextConstraint
|
||||
*/
|
||||
public function getName(): TextConstraint
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return DateTimeConstraint
|
||||
*/
|
||||
public function getLastModified(): DateTimeConstraint
|
||||
{
|
||||
return $this->lastModified;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return DateTimeConstraint
|
||||
*/
|
||||
public function getAddedDate(): DateTimeConstraint
|
||||
{
|
||||
return $this->addedDate;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return BooleanConstraint
|
||||
*/
|
||||
public function getShowInTable(): BooleanConstraint
|
||||
{
|
||||
return $this->showInTable;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return EntityConstraint
|
||||
*/
|
||||
public function getAttachmentType(): EntityConstraint
|
||||
{
|
||||
return $this->attachmentType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return InstanceOfConstraint
|
||||
*/
|
||||
public function getTargetType(): InstanceOfConstraint
|
||||
{
|
||||
return $this->targetType;
|
||||
|
|
|
@ -60,8 +60,6 @@ trait CompoundFilterTrait
|
|||
|
||||
/**
|
||||
* Applies all children filters that are declared as property of this filter using reflection.
|
||||
* @param QueryBuilder $queryBuilder
|
||||
* @return void
|
||||
*/
|
||||
protected function applyAllChildFilters(QueryBuilder $queryBuilder): void
|
||||
{
|
||||
|
|
|
@ -26,11 +26,6 @@ abstract class AbstractConstraint implements FilterInterface
|
|||
{
|
||||
use FilterTrait;
|
||||
|
||||
/**
|
||||
* @var string The property where this BooleanConstraint should apply to
|
||||
*/
|
||||
protected string $property;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
|
@ -43,9 +38,11 @@ abstract class AbstractConstraint implements FilterInterface
|
|||
*/
|
||||
abstract public function isEnabled(): bool;
|
||||
|
||||
public function __construct(string $property, string $identifier = null)
|
||||
public function __construct(/**
|
||||
* @var string The property where this BooleanConstraint should apply to
|
||||
*/
|
||||
protected string $property, string $identifier = null)
|
||||
{
|
||||
$this->property = $property;
|
||||
$this->identifier = $identifier ?? $this->generateParameterIdentifier($property);
|
||||
}
|
||||
}
|
|
@ -24,19 +24,14 @@ use Doctrine\ORM\QueryBuilder;
|
|||
|
||||
class BooleanConstraint extends AbstractConstraint
|
||||
{
|
||||
/** @var bool|null The value of our constraint */
|
||||
protected ?bool $value;
|
||||
|
||||
|
||||
public function __construct(string $property, string $identifier = null, ?bool $default_value = null)
|
||||
public function __construct(string $property, string $identifier = null, /** @var bool|null The value of our constraint */
|
||||
protected ?bool $value = null)
|
||||
{
|
||||
parent::__construct($property, $identifier);
|
||||
$this->value = $default_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of this constraint. Null means "don't filter", true means "filter for true", false means "filter for false".
|
||||
* @return bool|null
|
||||
*/
|
||||
public function getValue(): ?bool
|
||||
{
|
||||
|
@ -45,7 +40,6 @@ class BooleanConstraint extends AbstractConstraint
|
|||
|
||||
/**
|
||||
* Sets the value of this constraint. Null means "don't filter", true means "filter for true", false means "filter for false".
|
||||
* @param bool|null $value
|
||||
*/
|
||||
public function setValue(?bool $value): void
|
||||
{
|
||||
|
|
|
@ -24,7 +24,7 @@ use Doctrine\ORM\QueryBuilder;
|
|||
|
||||
class ChoiceConstraint extends AbstractConstraint
|
||||
{
|
||||
public const ALLOWED_OPERATOR_VALUES = ['ANY', 'NONE'];
|
||||
final public const ALLOWED_OPERATOR_VALUES = ['ANY', 'NONE'];
|
||||
|
||||
/**
|
||||
* @var string[]|int[] The values to compare to
|
||||
|
@ -46,7 +46,6 @@ class ChoiceConstraint extends AbstractConstraint
|
|||
|
||||
/**
|
||||
* @param string[]|int[] $value
|
||||
* @return ChoiceConstraint
|
||||
*/
|
||||
public function setValue(array $value): ChoiceConstraint
|
||||
{
|
||||
|
@ -54,18 +53,11 @@ class ChoiceConstraint extends AbstractConstraint
|
|||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getOperator(): string
|
||||
{
|
||||
return $this->operator;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $operator
|
||||
* @return ChoiceConstraint
|
||||
*/
|
||||
public function setOperator(string $operator): ChoiceConstraint
|
||||
{
|
||||
$this->operator = $operator;
|
||||
|
|
|
@ -33,26 +33,6 @@ class EntityConstraint extends AbstractConstraint
|
|||
private const ALLOWED_OPERATOR_VALUES_BASE = ['=', '!='];
|
||||
private const ALLOWED_OPERATOR_VALUES_STRUCTURAL = ['INCLUDING_CHILDREN', 'EXCLUDING_CHILDREN'];
|
||||
|
||||
/**
|
||||
* @var NodesListBuilder
|
||||
*/
|
||||
protected ?NodesListBuilder $nodesListBuilder;
|
||||
|
||||
/**
|
||||
* @var class-string<T> The class to use for the comparison
|
||||
*/
|
||||
protected string $class;
|
||||
|
||||
/**
|
||||
* @var string|null The operator to use
|
||||
*/
|
||||
protected ?string $operator;
|
||||
|
||||
/**
|
||||
* @var T The value to compare to
|
||||
*/
|
||||
protected $value;
|
||||
|
||||
/**
|
||||
* @param NodesListBuilder|null $nodesListBuilder
|
||||
* @param class-string<T> $class
|
||||
|
@ -61,18 +41,13 @@ class EntityConstraint extends AbstractConstraint
|
|||
* @param null $value
|
||||
* @param string $operator
|
||||
*/
|
||||
public function __construct(?NodesListBuilder $nodesListBuilder, string $class, string $property, string $identifier = null, $value = null, string $operator = '')
|
||||
public function __construct(protected ?\App\Services\Trees\NodesListBuilder $nodesListBuilder, protected string $class, string $property, string $identifier = null, protected $value = null, protected ?string $operator = '')
|
||||
{
|
||||
$this->nodesListBuilder = $nodesListBuilder;
|
||||
$this->class = $class;
|
||||
|
||||
if ($nodesListBuilder === null && $this->isStructural()) {
|
||||
if (!$nodesListBuilder instanceof \App\Services\Trees\NodesListBuilder && $this->isStructural()) {
|
||||
throw new \InvalidArgumentException('NodesListBuilder must be provided for structural entities');
|
||||
}
|
||||
|
||||
parent::__construct($property, $identifier);
|
||||
$this->value = $value;
|
||||
$this->operator = $operator;
|
||||
}
|
||||
|
||||
public function getClass(): string
|
||||
|
@ -80,17 +55,11 @@ class EntityConstraint extends AbstractConstraint
|
|||
return $this->class;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string|null
|
||||
*/
|
||||
public function getOperator(): ?string
|
||||
{
|
||||
return $this->operator;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|null $operator
|
||||
*/
|
||||
public function setOperator(?string $operator): self
|
||||
{
|
||||
$this->operator = $operator;
|
||||
|
@ -119,7 +88,6 @@ class EntityConstraint extends AbstractConstraint
|
|||
|
||||
/**
|
||||
* Checks whether the constraints apply to a structural type or not
|
||||
* @return bool
|
||||
*/
|
||||
public function isStructural(): bool
|
||||
{
|
||||
|
@ -136,7 +104,7 @@ class EntityConstraint extends AbstractConstraint
|
|||
$tmp = self::ALLOWED_OPERATOR_VALUES_BASE;
|
||||
|
||||
if ($this->isStructural()) {
|
||||
$tmp = array_merge($tmp, self::ALLOWED_OPERATOR_VALUES_STRUCTURAL);
|
||||
$tmp = [...$tmp, ...self::ALLOWED_OPERATOR_VALUES_STRUCTURAL];
|
||||
}
|
||||
|
||||
return $tmp;
|
||||
|
@ -160,7 +128,7 @@ class EntityConstraint extends AbstractConstraint
|
|||
}
|
||||
|
||||
//We need to handle null values differently, as they can not be compared with == or !=
|
||||
if ($this->value === null) {
|
||||
if (!$this->value instanceof \App\Entity\Base\AbstractDBElement) {
|
||||
if($this->operator === '=' || $this->operator === 'INCLUDING_CHILDREN') {
|
||||
$queryBuilder->andWhere(sprintf("%s IS NULL", $this->property));
|
||||
return;
|
||||
|
|
|
@ -35,7 +35,6 @@ trait FilterTrait
|
|||
|
||||
/**
|
||||
* Checks if the given input is an aggregateFunction like COUNT(part.partsLot) or so
|
||||
* @return bool
|
||||
*/
|
||||
protected function isAggregateFunctionString(string $input): bool
|
||||
{
|
||||
|
@ -44,8 +43,6 @@ trait FilterTrait
|
|||
|
||||
/**
|
||||
* Generates a parameter identifier that can be used for the given property. It gives random results, to be unique, so you have to cache it.
|
||||
* @param string $property
|
||||
* @return string
|
||||
*/
|
||||
protected function generateParameterIdentifier(string $property): string
|
||||
{
|
||||
|
@ -57,13 +54,8 @@ trait FilterTrait
|
|||
|
||||
/**
|
||||
* Adds a simple constraint in the form of (property OPERATOR value) (e.g. "part.name = :name") to the given query builder.
|
||||
* @param QueryBuilder $queryBuilder
|
||||
* @param string $property
|
||||
* @param string $comparison_operator
|
||||
* @param mixed $value
|
||||
* @return void
|
||||
*/
|
||||
protected function addSimpleAndConstraint(QueryBuilder $queryBuilder, string $property, string $parameterIdentifier, string $comparison_operator, $value): void
|
||||
protected function addSimpleAndConstraint(QueryBuilder $queryBuilder, string $property, string $parameterIdentifier, string $comparison_operator, mixed $value): void
|
||||
{
|
||||
if ($comparison_operator === 'IN' || $comparison_operator === 'NOT IN') {
|
||||
$expression = sprintf("%s %s (:%s)", $property, $comparison_operator, $parameterIdentifier);
|
||||
|
|
|
@ -27,7 +27,7 @@ use Doctrine\ORM\QueryBuilder;
|
|||
*/
|
||||
class InstanceOfConstraint extends AbstractConstraint
|
||||
{
|
||||
public const ALLOWED_OPERATOR_VALUES = ['ANY', 'NONE'];
|
||||
final public const ALLOWED_OPERATOR_VALUES = ['ANY', 'NONE'];
|
||||
|
||||
/**
|
||||
* @var string[] The values to compare to (fully qualified class names)
|
||||
|
@ -57,16 +57,12 @@ class InstanceOfConstraint extends AbstractConstraint
|
|||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getOperator(): string
|
||||
{
|
||||
return $this->operator;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $operator
|
||||
* @return $this
|
||||
*/
|
||||
public function setOperator(string $operator): self
|
||||
|
|
|
@ -25,61 +25,28 @@ use RuntimeException;
|
|||
|
||||
class NumberConstraint extends AbstractConstraint
|
||||
{
|
||||
public const ALLOWED_OPERATOR_VALUES = ['=', '!=', '<', '>', '<=', '>=', 'BETWEEN'];
|
||||
final public const ALLOWED_OPERATOR_VALUES = ['=', '!=', '<', '>', '<=', '>=', 'BETWEEN'];
|
||||
|
||||
|
||||
/**
|
||||
* The value1 used for comparison (this is the main one used for all mono-value comparisons)
|
||||
* @var float|null|int|\DateTimeInterface
|
||||
*/
|
||||
protected $value1;
|
||||
|
||||
/**
|
||||
* The second value used when operator is RANGE; this is the upper bound of the range
|
||||
* @var float|null|int|\DateTimeInterface
|
||||
*/
|
||||
protected $value2;
|
||||
|
||||
/**
|
||||
* @var string|null The operator to use
|
||||
*/
|
||||
protected ?string $operator;
|
||||
|
||||
/**
|
||||
* @return float|int|null|\DateTimeInterface
|
||||
*/
|
||||
public function getValue1()
|
||||
public function getValue1(): float|int|null|\DateTimeInterface
|
||||
{
|
||||
return $this->value1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param float|int|\DateTimeInterface|null $value1
|
||||
*/
|
||||
public function setValue1($value1): void
|
||||
public function setValue1(float|int|\DateTimeInterface|null $value1): void
|
||||
{
|
||||
$this->value1 = $value1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return float|int|null
|
||||
*/
|
||||
public function getValue2()
|
||||
public function getValue2(): float|int|null
|
||||
{
|
||||
return $this->value2;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param float|int|null $value2
|
||||
*/
|
||||
public function setValue2($value2): void
|
||||
public function setValue2(float|int|null $value2): void
|
||||
{
|
||||
$this->value2 = $value2;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getOperator(): string
|
||||
{
|
||||
return $this->operator;
|
||||
|
@ -94,12 +61,22 @@ class NumberConstraint extends AbstractConstraint
|
|||
}
|
||||
|
||||
|
||||
public function __construct(string $property, string $identifier = null, $value1 = null, string $operator = null, $value2 = null)
|
||||
/**
|
||||
* @param float|null|int|\DateTimeInterface $value1
|
||||
* @param float|null|int|\DateTimeInterface $value2
|
||||
*/
|
||||
public function __construct(string $property, string $identifier = null, /**
|
||||
* The value1 used for comparison (this is the main one used for all mono-value comparisons)
|
||||
*/
|
||||
protected float|int|\DateTimeInterface|null $value1 = null, /**
|
||||
* @var string|null The operator to use
|
||||
*/
|
||||
protected ?string $operator = null, /**
|
||||
* The second value used when operator is RANGE; this is the upper bound of the range
|
||||
*/
|
||||
protected float|int|\DateTimeInterface|null $value2 = null)
|
||||
{
|
||||
parent::__construct($property, $identifier);
|
||||
$this->value1 = $value1;
|
||||
$this->value2 = $value2;
|
||||
$this->operator = $operator;
|
||||
}
|
||||
|
||||
public function isEnabled(): bool
|
||||
|
|
|
@ -103,71 +103,44 @@ class ParameterConstraint extends AbstractConstraint
|
|||
$queryBuilder->andWhere('(' . $subqb->getDQL() . ') > 0');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @return ParameterConstraint
|
||||
*/
|
||||
public function setName(string $name): ParameterConstraint
|
||||
{
|
||||
$this->name = $name;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getSymbol(): string
|
||||
{
|
||||
return $this->symbol;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $symbol
|
||||
* @return ParameterConstraint
|
||||
*/
|
||||
public function setSymbol(string $symbol): ParameterConstraint
|
||||
{
|
||||
$this->symbol = $symbol;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getUnit(): string
|
||||
{
|
||||
return $this->unit;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $unit
|
||||
* @return ParameterConstraint
|
||||
*/
|
||||
public function setUnit(string $unit): ParameterConstraint
|
||||
{
|
||||
$this->unit = $unit;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return TextConstraint
|
||||
*/
|
||||
public function getValueText(): TextConstraint
|
||||
{
|
||||
return $this->value_text;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ParameterValueConstraint
|
||||
*/
|
||||
public function getValue(): ParameterValueConstraint
|
||||
{
|
||||
return $this->value;
|
||||
|
|
|
@ -25,18 +25,14 @@ use Doctrine\ORM\QueryBuilder;
|
|||
|
||||
class ParameterValueConstraint extends NumberConstraint
|
||||
{
|
||||
protected string $alias;
|
||||
|
||||
public const ALLOWED_OPERATOR_VALUES = ['=', '!=', '<', '>', '<=', '>=', 'BETWEEN',
|
||||
final public const ALLOWED_OPERATOR_VALUES = ['=', '!=', '<', '>', '<=', '>=', 'BETWEEN',
|
||||
//Additional operators
|
||||
'IN_RANGE', 'NOT_IN_RANGE', 'GREATER_THAN_RANGE', 'GREATER_EQUAL_RANGE', 'LESS_THAN_RANGE', 'LESS_EQUAL_RANGE', 'RANGE_IN_RANGE', 'RANGE_INTERSECT_RANGE'];
|
||||
|
||||
/**
|
||||
* @param string $alias The alias which is used in the sub query of ParameterConstraint
|
||||
*/
|
||||
public function __construct(string $alias) {
|
||||
$this->alias = $alias;
|
||||
|
||||
public function __construct(protected string $alias) {
|
||||
parent::__construct($alias . '.value_typical');
|
||||
}
|
||||
|
||||
|
|
|
@ -26,23 +26,20 @@ use Doctrine\ORM\QueryBuilder;
|
|||
|
||||
class TagsConstraint extends AbstractConstraint
|
||||
{
|
||||
public const ALLOWED_OPERATOR_VALUES = ['ANY', 'ALL', 'NONE'];
|
||||
final public const ALLOWED_OPERATOR_VALUES = ['ANY', 'ALL', 'NONE'];
|
||||
|
||||
/**
|
||||
* @var string|null The operator to use
|
||||
* @param string $value
|
||||
*/
|
||||
protected ?string $operator;
|
||||
|
||||
/**
|
||||
public function __construct(string $property, string $identifier = null, /**
|
||||
* @var string The value to compare to
|
||||
*/
|
||||
protected $value;
|
||||
|
||||
public function __construct(string $property, string $identifier = null, $value = null, string $operator = '')
|
||||
protected $value = null, /**
|
||||
* @var string|null The operator to use
|
||||
*/
|
||||
protected ?string $operator = '')
|
||||
{
|
||||
parent::__construct($property, $identifier);
|
||||
$this->value = $value;
|
||||
$this->operator = $operator;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -62,17 +59,11 @@ class TagsConstraint extends AbstractConstraint
|
|||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getValue(): string
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $value
|
||||
*/
|
||||
public function setValue(string $value): self
|
||||
{
|
||||
$this->value = $value;
|
||||
|
@ -96,9 +87,6 @@ class TagsConstraint extends AbstractConstraint
|
|||
|
||||
/**
|
||||
* Builds an expression to query for a single tag
|
||||
* @param QueryBuilder $queryBuilder
|
||||
* @param string $tag
|
||||
* @return Expr\Orx
|
||||
*/
|
||||
protected function getExpressionForTag(QueryBuilder $queryBuilder, string $tag): Expr\Orx
|
||||
{
|
||||
|
|
|
@ -25,23 +25,20 @@ use Doctrine\ORM\QueryBuilder;
|
|||
class TextConstraint extends AbstractConstraint
|
||||
{
|
||||
|
||||
public const ALLOWED_OPERATOR_VALUES = ['=', '!=', 'STARTS', 'ENDS', 'CONTAINS', 'LIKE', 'REGEX'];
|
||||
final public const ALLOWED_OPERATOR_VALUES = ['=', '!=', 'STARTS', 'ENDS', 'CONTAINS', 'LIKE', 'REGEX'];
|
||||
|
||||
/**
|
||||
* @var string|null The operator to use
|
||||
* @param string $value
|
||||
*/
|
||||
protected ?string $operator;
|
||||
|
||||
/**
|
||||
public function __construct(string $property, string $identifier = null, /**
|
||||
* @var string The value to compare to
|
||||
*/
|
||||
protected $value;
|
||||
|
||||
public function __construct(string $property, string $identifier = null, $value = null, string $operator = '')
|
||||
protected $value = null, /**
|
||||
* @var string|null The operator to use
|
||||
*/
|
||||
protected ?string $operator = '')
|
||||
{
|
||||
parent::__construct($property, $identifier);
|
||||
$this->value = $value;
|
||||
$this->operator = $operator;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -61,17 +58,11 @@ class TextConstraint extends AbstractConstraint
|
|||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getValue(): string
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $value
|
||||
*/
|
||||
public function setValue(string $value): self
|
||||
{
|
||||
$this->value = $value;
|
||||
|
@ -105,11 +96,11 @@ class TextConstraint extends AbstractConstraint
|
|||
$like_value = null;
|
||||
if ($this->operator === 'LIKE') {
|
||||
$like_value = $this->value;
|
||||
} else if ($this->operator === 'STARTS') {
|
||||
} elseif ($this->operator === 'STARTS') {
|
||||
$like_value = $this->value . '%';
|
||||
} else if ($this->operator === 'ENDS') {
|
||||
} elseif ($this->operator === 'ENDS') {
|
||||
$like_value = '%' . $this->value;
|
||||
} else if ($this->operator === 'CONTAINS') {
|
||||
} elseif ($this->operator === 'CONTAINS') {
|
||||
$like_value = '%' . $this->value . '%';
|
||||
}
|
||||
|
||||
|
|
|
@ -58,9 +58,6 @@ class LogFilter implements FilterInterface
|
|||
$this->applyAllChildFilters($queryBuilder);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return DateTimeConstraint
|
||||
*/
|
||||
public function getTimestamp(): DateTimeConstraint
|
||||
{
|
||||
return $this->timestamp;
|
||||
|
@ -69,38 +66,26 @@ class LogFilter implements FilterInterface
|
|||
/**
|
||||
* @return IntConstraint|NumberConstraint
|
||||
*/
|
||||
public function getDbId()
|
||||
public function getDbId(): \App\DataTables\Filters\Constraints\IntConstraint|\App\DataTables\Filters\Constraints\NumberConstraint
|
||||
{
|
||||
return $this->dbId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ChoiceConstraint
|
||||
*/
|
||||
public function getLevel(): ChoiceConstraint
|
||||
{
|
||||
return $this->level;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return InstanceOfConstraint
|
||||
*/
|
||||
public function getEventType(): InstanceOfConstraint
|
||||
{
|
||||
return $this->eventType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ChoiceConstraint
|
||||
*/
|
||||
public function getTargetType(): ChoiceConstraint
|
||||
{
|
||||
return $this->targetType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return IntConstraint
|
||||
*/
|
||||
public function getTargetId(): IntConstraint
|
||||
{
|
||||
return $this->targetId;
|
||||
|
|
|
@ -145,17 +145,11 @@ class PartFilter implements FilterInterface
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return BooleanConstraint
|
||||
*/
|
||||
public function getFavorite(): BooleanConstraint
|
||||
{
|
||||
return $this->favorite;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return BooleanConstraint
|
||||
*/
|
||||
public function getNeedsReview(): BooleanConstraint
|
||||
{
|
||||
return $this->needsReview;
|
||||
|
@ -176,17 +170,11 @@ class PartFilter implements FilterInterface
|
|||
return $this->description;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return DateTimeConstraint
|
||||
*/
|
||||
public function getLastModified(): DateTimeConstraint
|
||||
{
|
||||
return $this->lastModified;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return DateTimeConstraint
|
||||
*/
|
||||
public function getAddedDate(): DateTimeConstraint
|
||||
{
|
||||
return $this->addedDate;
|
||||
|
@ -197,49 +185,31 @@ class PartFilter implements FilterInterface
|
|||
return $this->category;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return EntityConstraint
|
||||
*/
|
||||
public function getFootprint(): EntityConstraint
|
||||
{
|
||||
return $this->footprint;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return EntityConstraint
|
||||
*/
|
||||
public function getManufacturer(): EntityConstraint
|
||||
{
|
||||
return $this->manufacturer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return EntityConstraint
|
||||
*/
|
||||
public function getSupplier(): EntityConstraint
|
||||
{
|
||||
return $this->supplier;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return EntityConstraint
|
||||
*/
|
||||
public function getStorelocation(): EntityConstraint
|
||||
{
|
||||
return $this->storelocation;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return EntityConstraint
|
||||
*/
|
||||
public function getMeasurementUnit(): EntityConstraint
|
||||
{
|
||||
return $this->measurementUnit;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return NumberConstraint
|
||||
*/
|
||||
public function getDbId(): NumberConstraint
|
||||
{
|
||||
return $this->dbId;
|
||||
|
@ -250,33 +220,21 @@ class PartFilter implements FilterInterface
|
|||
return $this->ipn;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return TextConstraint
|
||||
*/
|
||||
public function getComment(): TextConstraint
|
||||
{
|
||||
return $this->comment;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return NumberConstraint
|
||||
*/
|
||||
public function getMinAmount(): NumberConstraint
|
||||
{
|
||||
return $this->minAmount;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return TextConstraint
|
||||
*/
|
||||
public function getManufacturerProductUrl(): TextConstraint
|
||||
{
|
||||
return $this->manufacturer_product_url;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return TextConstraint
|
||||
*/
|
||||
public function getManufacturerProductNumber(): TextConstraint
|
||||
{
|
||||
return $this->manufacturer_product_number;
|
||||
|
@ -287,73 +245,46 @@ class PartFilter implements FilterInterface
|
|||
return $this->lotCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return EntityConstraint
|
||||
*/
|
||||
public function getLotOwner(): EntityConstraint
|
||||
{
|
||||
return $this->lotOwner;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return TagsConstraint
|
||||
*/
|
||||
public function getTags(): TagsConstraint
|
||||
{
|
||||
return $this->tags;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return IntConstraint
|
||||
*/
|
||||
public function getOrderdetailsCount(): IntConstraint
|
||||
{
|
||||
return $this->orderdetailsCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return IntConstraint
|
||||
*/
|
||||
public function getAttachmentsCount(): IntConstraint
|
||||
{
|
||||
return $this->attachmentsCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return BooleanConstraint
|
||||
*/
|
||||
public function getLotNeedsRefill(): BooleanConstraint
|
||||
{
|
||||
return $this->lotNeedsRefill;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return BooleanConstraint
|
||||
*/
|
||||
public function getLotUnknownAmount(): BooleanConstraint
|
||||
{
|
||||
return $this->lotUnknownAmount;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return DateTimeConstraint
|
||||
*/
|
||||
public function getLotExpirationDate(): DateTimeConstraint
|
||||
{
|
||||
return $this->lotExpirationDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return EntityConstraint
|
||||
*/
|
||||
public function getAttachmentType(): EntityConstraint
|
||||
{
|
||||
return $this->attachmentType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return TextConstraint
|
||||
*/
|
||||
public function getAttachmentName(): TextConstraint
|
||||
{
|
||||
return $this->attachmentName;
|
||||
|
@ -369,9 +300,6 @@ class PartFilter implements FilterInterface
|
|||
return $this->amountSum;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ArrayCollection
|
||||
*/
|
||||
public function getParameters(): ArrayCollection
|
||||
{
|
||||
return $this->parameters;
|
||||
|
@ -382,25 +310,16 @@ class PartFilter implements FilterInterface
|
|||
return $this->parametersCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return TextConstraint
|
||||
*/
|
||||
public function getLotDescription(): TextConstraint
|
||||
{
|
||||
return $this->lotDescription;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return BooleanConstraint
|
||||
*/
|
||||
public function getObsolete(): BooleanConstraint
|
||||
{
|
||||
return $this->obsolete;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return LessThanDesiredConstraint
|
||||
*/
|
||||
public function getLessThanDesired(): LessThanDesiredConstraint
|
||||
{
|
||||
return $this->lessThanDesired;
|
||||
|
|
|
@ -26,9 +26,6 @@ use Doctrine\ORM\QueryBuilder;
|
|||
class PartSearchFilter implements FilterInterface
|
||||
{
|
||||
|
||||
/** @var string The string to query for */
|
||||
protected string $keyword;
|
||||
|
||||
/** @var boolean Whether to use regex for searching */
|
||||
protected bool $regex = false;
|
||||
|
||||
|
@ -68,9 +65,11 @@ class PartSearchFilter implements FilterInterface
|
|||
/** @var bool Use Internal Part number for searching */
|
||||
protected bool $ipn = true;
|
||||
|
||||
public function __construct(string $query)
|
||||
public function __construct(
|
||||
/** @var string The string to query for */
|
||||
protected string $keyword
|
||||
)
|
||||
{
|
||||
$this->keyword = $query;
|
||||
}
|
||||
|
||||
protected function getFieldsToSearch(): array
|
||||
|
@ -122,12 +121,12 @@ class PartSearchFilter implements FilterInterface
|
|||
$fields_to_search = $this->getFieldsToSearch();
|
||||
|
||||
//If we have nothing to search for, do nothing
|
||||
if (empty($fields_to_search) || empty($this->keyword)) {
|
||||
if ($fields_to_search === [] || empty($this->keyword)) {
|
||||
return;
|
||||
}
|
||||
|
||||
//Convert the fields to search to a list of expressions
|
||||
$expressions = array_map(function (string $field) {
|
||||
$expressions = array_map(function (string $field): string {
|
||||
if ($this->regex) {
|
||||
return sprintf("REGEXP(%s, :search_query) = 1", $field);
|
||||
}
|
||||
|
@ -148,162 +147,99 @@ class PartSearchFilter implements FilterInterface
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getKeyword(): string
|
||||
{
|
||||
return $this->keyword;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $keyword
|
||||
* @return PartSearchFilter
|
||||
*/
|
||||
public function setKeyword(string $keyword): PartSearchFilter
|
||||
{
|
||||
$this->keyword = $keyword;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isRegex(): bool
|
||||
{
|
||||
return $this->regex;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $regex
|
||||
* @return PartSearchFilter
|
||||
*/
|
||||
public function setRegex(bool $regex): PartSearchFilter
|
||||
{
|
||||
$this->regex = $regex;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isName(): bool
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $name
|
||||
* @return PartSearchFilter
|
||||
*/
|
||||
public function setName(bool $name): PartSearchFilter
|
||||
{
|
||||
$this->name = $name;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isCategory(): bool
|
||||
{
|
||||
return $this->category;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $category
|
||||
* @return PartSearchFilter
|
||||
*/
|
||||
public function setCategory(bool $category): PartSearchFilter
|
||||
{
|
||||
$this->category = $category;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isDescription(): bool
|
||||
{
|
||||
return $this->description;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $description
|
||||
* @return PartSearchFilter
|
||||
*/
|
||||
public function setDescription(bool $description): PartSearchFilter
|
||||
{
|
||||
$this->description = $description;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isTags(): bool
|
||||
{
|
||||
return $this->tags;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $tags
|
||||
* @return PartSearchFilter
|
||||
*/
|
||||
public function setTags(bool $tags): PartSearchFilter
|
||||
{
|
||||
$this->tags = $tags;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isStorelocation(): bool
|
||||
{
|
||||
return $this->storelocation;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $storelocation
|
||||
* @return PartSearchFilter
|
||||
*/
|
||||
public function setStorelocation(bool $storelocation): PartSearchFilter
|
||||
{
|
||||
$this->storelocation = $storelocation;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isOrdernr(): bool
|
||||
{
|
||||
return $this->ordernr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $ordernr
|
||||
* @return PartSearchFilter
|
||||
*/
|
||||
public function setOrdernr(bool $ordernr): PartSearchFilter
|
||||
{
|
||||
$this->ordernr = $ordernr;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isMpn(): bool
|
||||
{
|
||||
return $this->mpn;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $mpn
|
||||
* @return PartSearchFilter
|
||||
*/
|
||||
public function setMpn(bool $mpn): PartSearchFilter
|
||||
{
|
||||
$this->mpn = $mpn;
|
||||
|
@ -321,72 +257,44 @@ class PartSearchFilter implements FilterInterface
|
|||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isSupplier(): bool
|
||||
{
|
||||
return $this->supplier;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $supplier
|
||||
* @return PartSearchFilter
|
||||
*/
|
||||
public function setSupplier(bool $supplier): PartSearchFilter
|
||||
{
|
||||
$this->supplier = $supplier;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isManufacturer(): bool
|
||||
{
|
||||
return $this->manufacturer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $manufacturer
|
||||
* @return PartSearchFilter
|
||||
*/
|
||||
public function setManufacturer(bool $manufacturer): PartSearchFilter
|
||||
{
|
||||
$this->manufacturer = $manufacturer;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isFootprint(): bool
|
||||
{
|
||||
return $this->footprint;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $footprint
|
||||
* @return PartSearchFilter
|
||||
*/
|
||||
public function setFootprint(bool $footprint): PartSearchFilter
|
||||
{
|
||||
$this->footprint = $footprint;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isComment(): bool
|
||||
{
|
||||
return $this->comment;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $comment
|
||||
* @return PartSearchFilter
|
||||
*/
|
||||
public function setComment(bool $comment): PartSearchFilter
|
||||
{
|
||||
$this->comment = $comment;
|
||||
|
|
|
@ -31,19 +31,8 @@ use Symfony\Contracts\Translation\TranslatorInterface;
|
|||
*/
|
||||
class PartDataTableHelper
|
||||
{
|
||||
private PartPreviewGenerator $previewGenerator;
|
||||
private AttachmentURLGenerator $attachmentURLGenerator;
|
||||
|
||||
private TranslatorInterface $translator;
|
||||
private EntityURLGenerator $entityURLGenerator;
|
||||
|
||||
public function __construct(PartPreviewGenerator $previewGenerator, AttachmentURLGenerator $attachmentURLGenerator,
|
||||
EntityURLGenerator $entityURLGenerator, TranslatorInterface $translator)
|
||||
public function __construct(private readonly PartPreviewGenerator $previewGenerator, private readonly AttachmentURLGenerator $attachmentURLGenerator, private readonly EntityURLGenerator $entityURLGenerator, private readonly TranslatorInterface $translator)
|
||||
{
|
||||
$this->previewGenerator = $previewGenerator;
|
||||
$this->attachmentURLGenerator = $attachmentURLGenerator;
|
||||
$this->translator = $translator;
|
||||
$this->entityURLGenerator = $entityURLGenerator;
|
||||
}
|
||||
|
||||
public function renderName(Part $context): string
|
||||
|
@ -57,7 +46,7 @@ class PartDataTableHelper
|
|||
if ($context->isNeedsReview()) {
|
||||
$icon = sprintf('<i class="fa-solid fa-ambulance fa-fw me-1" title="%s"></i>', $this->translator->trans('part.needs_review.badge'));
|
||||
}
|
||||
if ($context->getBuiltProject() !== null) {
|
||||
if ($context->getBuiltProject() instanceof \App\Entity\ProjectSystem\Project) {
|
||||
$icon = sprintf('<i class="fa-solid fa-box-archive fa-fw me-1" title="%s"></i>',
|
||||
$this->translator->trans('part.info.projectBuildPart.hint') . ': ' . $context->getBuiltProject()->getName());
|
||||
}
|
||||
|
@ -74,7 +63,7 @@ class PartDataTableHelper
|
|||
public function renderPicture(Part $context): string
|
||||
{
|
||||
$preview_attachment = $this->previewGenerator->getTablePreviewAttachment($context);
|
||||
if (null === $preview_attachment) {
|
||||
if (!$preview_attachment instanceof \App\Entity\Attachments\Attachment) {
|
||||
return '';
|
||||
}
|
||||
|
||||
|
|
|
@ -61,27 +61,13 @@ use Symfony\Contracts\Translation\TranslatorInterface;
|
|||
|
||||
class LogDataTable implements DataTableTypeInterface
|
||||
{
|
||||
protected ElementTypeNameGenerator $elementTypeNameGenerator;
|
||||
protected TranslatorInterface $translator;
|
||||
protected UrlGeneratorInterface $urlGenerator;
|
||||
protected EntityURLGenerator $entityURLGenerator;
|
||||
protected LogEntryRepository $logRepo;
|
||||
protected \Symfony\Bundle\SecurityBundle\Security $security;
|
||||
protected UserAvatarHelper $userAvatarHelper;
|
||||
protected LogLevelHelper $logLevelHelper;
|
||||
|
||||
public function __construct(ElementTypeNameGenerator $elementTypeNameGenerator, TranslatorInterface $translator,
|
||||
UrlGeneratorInterface $urlGenerator, EntityURLGenerator $entityURLGenerator, EntityManagerInterface $entityManager,
|
||||
\Symfony\Bundle\SecurityBundle\Security $security, UserAvatarHelper $userAvatarHelper, LogLevelHelper $logLevelHelper)
|
||||
public function __construct(protected ElementTypeNameGenerator $elementTypeNameGenerator, protected TranslatorInterface $translator,
|
||||
protected UrlGeneratorInterface $urlGenerator, protected EntityURLGenerator $entityURLGenerator, EntityManagerInterface $entityManager,
|
||||
protected \Symfony\Bundle\SecurityBundle\Security $security, protected UserAvatarHelper $userAvatarHelper, protected LogLevelHelper $logLevelHelper)
|
||||
{
|
||||
$this->elementTypeNameGenerator = $elementTypeNameGenerator;
|
||||
$this->translator = $translator;
|
||||
$this->urlGenerator = $urlGenerator;
|
||||
$this->entityURLGenerator = $entityURLGenerator;
|
||||
$this->logRepo = $entityManager->getRepository(AbstractLogEntry::class);
|
||||
$this->security = $security;
|
||||
$this->userAvatarHelper = $userAvatarHelper;
|
||||
$this->logLevelHelper = $logLevelHelper;
|
||||
}
|
||||
|
||||
public function configureOptions(OptionsResolver $optionsResolver): void
|
||||
|
@ -115,21 +101,17 @@ class LogDataTable implements DataTableTypeInterface
|
|||
|
||||
//This special $$rowClass column is used to set the row class depending on the log level. The class gets set by the frontend controller
|
||||
$dataTable->add('dont_matter', RowClassColumn::class, [
|
||||
'render' => function ($value, AbstractLogEntry $context) {
|
||||
return $this->logLevelHelper->logLevelToTableColorClass($context->getLevelString());
|
||||
},
|
||||
'render' => fn($value, AbstractLogEntry $context) => $this->logLevelHelper->logLevelToTableColorClass($context->getLevelString()),
|
||||
]);
|
||||
|
||||
$dataTable->add('symbol', TextColumn::class, [
|
||||
'label' => '',
|
||||
'className' => 'no-colvis',
|
||||
'render' => function ($value, AbstractLogEntry $context) {
|
||||
return sprintf(
|
||||
'<i class="fas fa-fw %s" title="%s"></i>',
|
||||
$this->logLevelHelper->logLevelToIconClass($context->getLevelString()),
|
||||
$context->getLevelString()
|
||||
);
|
||||
},
|
||||
'render' => fn($value, AbstractLogEntry $context): string => sprintf(
|
||||
'<i class="fas fa-fw %s" title="%s"></i>',
|
||||
$this->logLevelHelper->logLevelToIconClass($context->getLevelString()),
|
||||
$context->getLevelString()
|
||||
),
|
||||
]);
|
||||
|
||||
$dataTable->add('id', TextColumn::class, [
|
||||
|
@ -140,12 +122,10 @@ class LogDataTable implements DataTableTypeInterface
|
|||
$dataTable->add('timestamp', LocaleDateTimeColumn::class, [
|
||||
'label' => 'log.timestamp',
|
||||
'timeFormat' => 'medium',
|
||||
'render' => function (string $value, AbstractLogEntry $context) {
|
||||
return sprintf('<a href="%s">%s</a>',
|
||||
$this->urlGenerator->generate('log_details', ['id' => $context->getId()]),
|
||||
$value
|
||||
);
|
||||
}
|
||||
'render' => fn(string $value, AbstractLogEntry $context): string => sprintf('<a href="%s">%s</a>',
|
||||
$this->urlGenerator->generate('log_details', ['id' => $context->getId()]),
|
||||
$value
|
||||
)
|
||||
]);
|
||||
|
||||
$dataTable->add('type', TextColumn::class, [
|
||||
|
@ -169,18 +149,16 @@ class LogDataTable implements DataTableTypeInterface
|
|||
'label' => 'log.level',
|
||||
'visible' => 'system_log' === $options['mode'],
|
||||
'propertyPath' => 'levelString',
|
||||
'render' => function (string $value, AbstractLogEntry $context) {
|
||||
return $this->translator->trans('log.level.'.$value);
|
||||
},
|
||||
'render' => fn(string $value, AbstractLogEntry $context) => $this->translator->trans('log.level.'.$value),
|
||||
]);
|
||||
|
||||
$dataTable->add('user', TextColumn::class, [
|
||||
'label' => 'log.user',
|
||||
'render' => function ($value, AbstractLogEntry $context) {
|
||||
'render' => function ($value, AbstractLogEntry $context): string {
|
||||
$user = $context->getUser();
|
||||
|
||||
//If user was deleted, show the info from the username field
|
||||
if ($user === null) {
|
||||
if (!$user instanceof \App\Entity\UserSystem\User) {
|
||||
if ($context->isCLIEntry()) {
|
||||
return sprintf('%s [%s]',
|
||||
htmlentities($context->getCLIUsername()),
|
||||
|
@ -241,19 +219,17 @@ class LogDataTable implements DataTableTypeInterface
|
|||
) {
|
||||
try {
|
||||
$target = $this->logRepo->getTargetElement($context);
|
||||
if (null !== $target) {
|
||||
if ($target instanceof \App\Entity\Base\AbstractDBElement) {
|
||||
return $this->entityURLGenerator->timeTravelURL($target, $context->getTimestamp());
|
||||
}
|
||||
} catch (EntityNotSupportedException $exception) {
|
||||
} catch (EntityNotSupportedException) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
'disabled' => function ($value, AbstractLogEntry $context) {
|
||||
return !$this->security->isGranted('show_history', $context->getTargetClass());
|
||||
},
|
||||
'disabled' => fn($value, AbstractLogEntry $context) => !$this->security->isGranted('show_history', $context->getTargetClass()),
|
||||
]);
|
||||
|
||||
$dataTable->add('actionRevert', RevertLogColumn::class, [
|
||||
|
@ -310,7 +286,7 @@ class LogDataTable implements DataTableTypeInterface
|
|||
foreach ($options['filter_elements'] as $element) {
|
||||
/** @var AbstractDBElement $element */
|
||||
|
||||
$target_type = AbstractLogEntry::targetTypeClassToID(get_class($element));
|
||||
$target_type = AbstractLogEntry::targetTypeClassToID($element::class);
|
||||
$target_id = $element->getID();
|
||||
$builder->orWhere("log.target_type = ${target_type} AND log.target_id = ${target_id}");
|
||||
}
|
||||
|
|
|
@ -54,22 +54,8 @@ use Symfony\Contracts\Translation\TranslatorInterface;
|
|||
|
||||
final class PartsDataTable implements DataTableTypeInterface
|
||||
{
|
||||
private TranslatorInterface $translator;
|
||||
private AmountFormatter $amountFormatter;
|
||||
private \Symfony\Bundle\SecurityBundle\Security $security;
|
||||
|
||||
private PartDataTableHelper $partDataTableHelper;
|
||||
|
||||
private EntityURLGenerator $urlGenerator;
|
||||
|
||||
public function __construct(EntityURLGenerator $urlGenerator, TranslatorInterface $translator,
|
||||
AmountFormatter $amountFormatter,PartDataTableHelper $partDataTableHelper, \Symfony\Bundle\SecurityBundle\Security $security)
|
||||
public function __construct(private readonly EntityURLGenerator $urlGenerator, private readonly TranslatorInterface $translator, private readonly AmountFormatter $amountFormatter, private readonly PartDataTableHelper $partDataTableHelper, private readonly \Symfony\Bundle\SecurityBundle\Security $security)
|
||||
{
|
||||
$this->urlGenerator = $urlGenerator;
|
||||
$this->translator = $translator;
|
||||
$this->amountFormatter = $amountFormatter;
|
||||
$this->security = $security;
|
||||
$this->partDataTableHelper = $partDataTableHelper;
|
||||
}
|
||||
|
||||
public function configureOptions(OptionsResolver $optionsResolver): void
|
||||
|
@ -92,7 +78,7 @@ final class PartsDataTable implements DataTableTypeInterface
|
|||
$dataTable
|
||||
//Color the table rows depending on the review and favorite status
|
||||
->add('dont_matter', RowClassColumn::class, [
|
||||
'render' => function ($value, Part $context) {
|
||||
'render' => function ($value, Part $context): string {
|
||||
if ($context->isNeedsReview()) {
|
||||
return 'table-secondary';
|
||||
}
|
||||
|
@ -108,15 +94,11 @@ final class PartsDataTable implements DataTableTypeInterface
|
|||
->add('picture', TextColumn::class, [
|
||||
'label' => '',
|
||||
'className' => 'no-colvis',
|
||||
'render' => function ($value, Part $context) {
|
||||
return $this->partDataTableHelper->renderPicture($context);
|
||||
},
|
||||
'render' => fn($value, Part $context) => $this->partDataTableHelper->renderPicture($context),
|
||||
])
|
||||
->add('name', TextColumn::class, [
|
||||
'label' => $this->translator->trans('part.table.name'),
|
||||
'render' => function ($value, Part $context) {
|
||||
return $this->partDataTableHelper->renderName($context);
|
||||
},
|
||||
'render' => fn($value, Part $context) => $this->partDataTableHelper->renderName($context),
|
||||
])
|
||||
->add('id', TextColumn::class, [
|
||||
'label' => $this->translator->trans('part.table.id'),
|
||||
|
@ -153,11 +135,11 @@ final class PartsDataTable implements DataTableTypeInterface
|
|||
$dataTable->add('storelocation', TextColumn::class, [
|
||||
'label' => $this->translator->trans('part.table.storeLocations'),
|
||||
'orderField' => 'storelocations.name',
|
||||
'render' => function ($value, Part $context) {
|
||||
'render' => function ($value, Part $context): string {
|
||||
$tmp = [];
|
||||
foreach ($context->getPartLots() as $lot) {
|
||||
//Ignore lots without storelocation
|
||||
if (null === $lot->getStorageLocation()) {
|
||||
if (!$lot->getStorageLocation() instanceof \App\Entity\Parts\Storelocation) {
|
||||
continue;
|
||||
}
|
||||
$tmp[] = sprintf(
|
||||
|
@ -216,9 +198,7 @@ final class PartsDataTable implements DataTableTypeInterface
|
|||
->add('minamount', TextColumn::class, [
|
||||
'label' => $this->translator->trans('part.table.minamount'),
|
||||
'visible' => false,
|
||||
'render' => function ($value, Part $context) {
|
||||
return htmlspecialchars($this->amountFormatter->format($value, $context->getPartUnit()));
|
||||
},
|
||||
'render' => fn($value, Part $context): string => htmlspecialchars($this->amountFormatter->format($value, $context->getPartUnit())),
|
||||
]);
|
||||
|
||||
if ($this->security->isGranted('@footprints.read')) {
|
||||
|
@ -278,12 +258,8 @@ final class PartsDataTable implements DataTableTypeInterface
|
|||
->add('edit', IconLinkColumn::class, [
|
||||
'label' => $this->translator->trans('part.table.edit'),
|
||||
'visible' => false,
|
||||
'href' => function ($value, Part $context) {
|
||||
return $this->urlGenerator->editURL($context);
|
||||
},
|
||||
'disabled' => function ($value, Part $context) {
|
||||
return !$this->security->isGranted('edit', $context);
|
||||
},
|
||||
'href' => fn($value, Part $context) => $this->urlGenerator->editURL($context),
|
||||
'disabled' => fn($value, Part $context) => !$this->security->isGranted('edit', $context),
|
||||
'title' => $this->translator->trans('part.table.edit.title'),
|
||||
])
|
||||
|
||||
|
|
|
@ -40,18 +40,8 @@ use Symfony\Contracts\Translation\TranslatorInterface;
|
|||
|
||||
class ProjectBomEntriesDataTable implements DataTableTypeInterface
|
||||
{
|
||||
protected TranslatorInterface $translator;
|
||||
protected PartDataTableHelper $partDataTableHelper;
|
||||
protected EntityURLGenerator $entityURLGenerator;
|
||||
protected AmountFormatter $amountFormatter;
|
||||
|
||||
public function __construct(TranslatorInterface $translator, PartDataTableHelper $partDataTableHelper,
|
||||
EntityURLGenerator $entityURLGenerator, AmountFormatter $amountFormatter)
|
||||
public function __construct(protected TranslatorInterface $translator, protected PartDataTableHelper $partDataTableHelper, protected EntityURLGenerator $entityURLGenerator, protected AmountFormatter $amountFormatter)
|
||||
{
|
||||
$this->translator = $translator;
|
||||
$this->partDataTableHelper = $partDataTableHelper;
|
||||
$this->entityURLGenerator = $entityURLGenerator;
|
||||
$this->amountFormatter = $amountFormatter;
|
||||
}
|
||||
|
||||
|
||||
|
@ -63,7 +53,7 @@ class ProjectBomEntriesDataTable implements DataTableTypeInterface
|
|||
'label' => '',
|
||||
'className' => 'no-colvis',
|
||||
'render' => function ($value, ProjectBOMEntry $context) {
|
||||
if($context->getPart() === null) {
|
||||
if(!$context->getPart() instanceof \App\Entity\Parts\Part) {
|
||||
return '';
|
||||
}
|
||||
return $this->partDataTableHelper->renderPicture($context->getPart());
|
||||
|
@ -79,9 +69,9 @@ class ProjectBomEntriesDataTable implements DataTableTypeInterface
|
|||
'label' => $this->translator->trans('project.bom.quantity'),
|
||||
'className' => 'text-center',
|
||||
'orderField' => 'bom_entry.quantity',
|
||||
'render' => function ($value, ProjectBOMEntry $context) {
|
||||
'render' => function ($value, ProjectBOMEntry $context): float|string {
|
||||
//If we have a non-part entry, only show the rounded quantity
|
||||
if ($context->getPart() === null) {
|
||||
if (!$context->getPart() instanceof \App\Entity\Parts\Part) {
|
||||
return round($context->getQuantity());
|
||||
}
|
||||
//Otherwise use the unit of the part to format the quantity
|
||||
|
@ -93,10 +83,10 @@ class ProjectBomEntriesDataTable implements DataTableTypeInterface
|
|||
'label' => $this->translator->trans('part.table.name'),
|
||||
'orderField' => 'part.name',
|
||||
'render' => function ($value, ProjectBOMEntry $context) {
|
||||
if($context->getPart() === null) {
|
||||
if(!$context->getPart() instanceof \App\Entity\Parts\Part) {
|
||||
return htmlspecialchars($context->getName());
|
||||
}
|
||||
if($context->getPart() !== null) {
|
||||
if($context->getPart() instanceof \App\Entity\Parts\Part) {
|
||||
$tmp = $this->partDataTableHelper->renderName($context->getPart());
|
||||
if(!empty($context->getName())) {
|
||||
$tmp .= '<br><b>'.htmlspecialchars($context->getName()).'</b>';
|
||||
|
@ -110,7 +100,7 @@ class ProjectBomEntriesDataTable implements DataTableTypeInterface
|
|||
->add('description', MarkdownColumn::class, [
|
||||
'label' => $this->translator->trans('part.table.description'),
|
||||
'data' => function (ProjectBOMEntry $context) {
|
||||
if($context->getPart() !== null) {
|
||||
if($context->getPart() instanceof \App\Entity\Parts\Part) {
|
||||
return $context->getPart()->getDescription();
|
||||
}
|
||||
//For non-part BOM entries show the comment field
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue