Applied rector with PHP8.1 migration rules

This commit is contained in:
Jan Böhmer 2023-06-11 14:15:46 +02:00
parent dc6a67c2f0
commit 7ee01d9a05
303 changed files with 1228 additions and 3465 deletions

View file

@ -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, [

View file

@ -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;

View file

@ -38,7 +38,6 @@ class LocaleDateTimeColumn extends AbstractColumn
{
/**
* @param $value
* @return string
* @throws Exception
*/
public function normalize($value): string

View file

@ -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;
}
/**

View file

@ -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;
}
/**

View file

@ -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;
}
/**

View file

@ -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) {

View file

@ -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

View file

@ -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>';
}
}

View file

@ -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

View file

@ -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)
);
}

View file

@ -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,
])
;

View file

@ -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;

View file

@ -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
{

View file

@ -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);
}
}

View file

@ -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
{

View file

@ -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;

View file

@ -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;

View file

@ -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);

View file

@ -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

View file

@ -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

View file

@ -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;

View file

@ -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');
}

View file

@ -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
{

View file

@ -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 . '%';
}

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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 '';
}

View file

@ -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}");
}

View file

@ -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'),
])

View file

@ -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