Fixed some inspection issues

This commit is contained in:
Jan Böhmer 2024-03-03 19:57:31 +01:00
parent 33475dca66
commit 42e604245c
85 changed files with 272 additions and 291 deletions

View file

@ -22,6 +22,7 @@ declare(strict_types=1);
namespace App\Entity\Attachments;
use ApiPlatform\Doctrine\Common\Filter\DateFilterInterface;
use ApiPlatform\Doctrine\Orm\Filter\DateFilter;
use ApiPlatform\Doctrine\Orm\Filter\OrderFilter;
use ApiPlatform\Metadata\ApiFilter;
@ -61,10 +62,10 @@ use LogicException;
#[ORM\DiscriminatorMap(self::ORM_DISCRIMINATOR_MAP)]
#[ORM\EntityListeners([AttachmentDeleteListener::class])]
#[ORM\Table(name: '`attachments`')]
#[ORM\Index(name: 'attachments_idx_id_element_id_class_name', columns: ['id', 'element_id', 'class_name'])]
#[ORM\Index(name: 'attachments_idx_class_name_id', columns: ['class_name', 'id'])]
#[ORM\Index(name: 'attachment_name_idx', columns: ['name'])]
#[ORM\Index(name: 'attachment_element_idx', columns: ['class_name', 'element_id'])]
#[ORM\Index(columns: ['id', 'element_id', 'class_name'], name: 'attachments_idx_id_element_id_class_name')]
#[ORM\Index(columns: ['class_name', 'id'], name: 'attachments_idx_class_name_id')]
#[ORM\Index(columns: ['name'], name: 'attachment_name_idx')]
#[ORM\Index(columns: ['class_name', 'element_id'], name: 'attachment_element_idx')]
#[ApiResource(
operations: [
new Get(security: 'is_granted("read", object)'),
@ -84,7 +85,7 @@ use LogicException;
description: 'The URL to a thumbnail version of this file. This only exists for internal picture attachments.')]
#[ApiFilter(LikeFilter::class, properties: ["name"])]
#[ApiFilter(EntityFilter::class, properties: ["attachment_type"])]
#[ApiFilter(DateFilter::class, strategy: DateFilter::EXCLUDE_NULL)]
#[ApiFilter(DateFilter::class, strategy: DateFilterInterface::EXCLUDE_NULL)]
#[ApiFilter(OrderFilter::class, properties: ['name', 'id', 'addedDate', 'lastModified'])]
//This discriminator map is required for API platform to know which class to use for deserialization, when creating a new attachment.
#[DiscriminatorMap(typeProperty: '_type', mapping: self::API_DISCRIMINATOR_MAP)]
@ -151,7 +152,7 @@ abstract class Attachment extends AbstractNamedDBElement
/**
* @var string The path to the file relative to a placeholder path like %MEDIA%
*/
#[ORM\Column(type: Types::STRING, name: 'path')]
#[ORM\Column(name: 'path', type: Types::STRING)]
protected string $path = '';
/**
@ -176,7 +177,7 @@ abstract class Attachment extends AbstractNamedDBElement
#[Assert\NotNull(message: 'validator.attachment.must_not_be_null')]
#[ORM\ManyToOne(targetEntity: AttachmentType::class, inversedBy: 'attachments_with_type')]
#[ORM\JoinColumn(name: 'type_id', nullable: false)]
#[Selectable()]
#[Selectable]
#[Groups(['attachment:read', 'attachment:write'])]
protected ?AttachmentType $attachment_type = null;
@ -246,12 +247,7 @@ abstract class Attachment extends AbstractNamedDBElement
$extension = pathinfo(parse_url($this->path, PHP_URL_PATH) ?? '', PATHINFO_EXTENSION);
//If no extension is found or it is known picture extension, we assume that this is a picture extension
if ($extension === '' || in_array(strtolower($extension), static::PICTURE_EXTS, true)) {
return true;
}
//Otherwise we assume that the file is not a picture
return false;
return $extension === '' || in_array(strtolower($extension), static::PICTURE_EXTS, true);
}
$extension = pathinfo($this->getPath(), PATHINFO_EXTENSION);
@ -521,6 +517,11 @@ abstract class Attachment extends AbstractNamedDBElement
#[SerializedName('url')]
public function setURL(?string $url): self
{
//Do nothing if the URL is empty
if ($url === null || $url === '') {
return $this;
}
$url = trim($url);
//Escape spaces in URL
$url = str_replace(' ', '%20', $url);

View file

@ -22,6 +22,7 @@ declare(strict_types=1);
namespace App\Entity\Attachments;
use ApiPlatform\Doctrine\Common\Filter\DateFilterInterface;
use ApiPlatform\Doctrine\Orm\Filter\DateFilter;
use ApiPlatform\Doctrine\Orm\Filter\OrderFilter;
use ApiPlatform\Metadata\ApiFilter;
@ -55,8 +56,8 @@ use Symfony\Component\Validator\Constraints as Assert;
*/
#[ORM\Entity(repositoryClass: StructuralDBElementRepository::class)]
#[ORM\Table(name: '`attachment_types`')]
#[ORM\Index(name: 'attachment_types_idx_name', columns: ['name'])]
#[ORM\Index(name: 'attachment_types_idx_parent_name', columns: ['parent_id', 'name'])]
#[ORM\Index(columns: ['name'], name: 'attachment_types_idx_name')]
#[ORM\Index(columns: ['parent_id', 'name'], name: 'attachment_types_idx_parent_name')]
#[ApiResource(
operations: [
new Get(security: 'is_granted("read", object)'),
@ -81,11 +82,11 @@ use Symfony\Component\Validator\Constraints as Assert;
)]
#[ApiFilter(PropertyFilter::class)]
#[ApiFilter(LikeFilter::class, properties: ["name", "comment"])]
#[ApiFilter(DateFilter::class, strategy: DateFilter::EXCLUDE_NULL)]
#[ApiFilter(DateFilter::class, strategy: DateFilterInterface::EXCLUDE_NULL)]
#[ApiFilter(OrderFilter::class, properties: ['name', 'id', 'addedDate', 'lastModified'])]
class AttachmentType extends AbstractStructuralDBElement
{
#[ORM\OneToMany(targetEntity: AttachmentType::class, mappedBy: 'parent', cascade: ['persist'])]
#[ORM\OneToMany(mappedBy: 'parent', targetEntity: AttachmentType::class, cascade: ['persist'])]
#[ORM\OrderBy(['name' => 'ASC'])]
protected Collection $children;
@ -109,7 +110,7 @@ class AttachmentType extends AbstractStructuralDBElement
* @var Collection<int, AttachmentTypeAttachment>
*/
#[Assert\Valid]
#[ORM\OneToMany(targetEntity: AttachmentTypeAttachment::class, mappedBy: 'element', cascade: ['persist', 'remove'], orphanRemoval: true)]
#[ORM\OneToMany(mappedBy: 'element', targetEntity: AttachmentTypeAttachment::class, cascade: ['persist', 'remove'], orphanRemoval: true)]
#[ORM\OrderBy(['name' => 'ASC'])]
#[Groups(['attachment_type:read', 'attachment_type:write'])]
protected Collection $attachments;
@ -122,7 +123,7 @@ class AttachmentType extends AbstractStructuralDBElement
/** @var Collection<int, AttachmentTypeParameter>
*/
#[Assert\Valid]
#[ORM\OneToMany(targetEntity: AttachmentTypeParameter::class, mappedBy: 'element', cascade: ['persist', 'remove'], orphanRemoval: true)]
#[ORM\OneToMany(mappedBy: 'element', targetEntity: AttachmentTypeParameter::class, cascade: ['persist', 'remove'], orphanRemoval: true)]
#[ORM\OrderBy(['group' => 'ASC', 'name' => 'ASC'])]
#[Groups(['attachment_type:read', 'attachment_type:write'])]
protected Collection $parameters;
@ -130,7 +131,7 @@ class AttachmentType extends AbstractStructuralDBElement
/**
* @var Collection<Attachment>
*/
#[ORM\OneToMany(targetEntity: Attachment::class, mappedBy: 'attachment_type')]
#[ORM\OneToMany(mappedBy: 'attachment_type', targetEntity: Attachment::class)]
protected Collection $attachments_with_type;
#[Groups(['attachment_type:read'])]

View file

@ -62,7 +62,7 @@ use Symfony\Component\Serializer\Annotation\Groups;
* @extends AttachmentContainingDBElement<AT>
* @uses ParametersTrait<PT>
*/
#[UniqueEntity(fields: ['name', 'parent'], ignoreNull: false, message: 'structural.entity.unique_name')]
#[UniqueEntity(fields: ['name', 'parent'], message: 'structural.entity.unique_name', ignoreNull: false)]
#[ORM\MappedSuperclass(repositoryClass: StructuralDBElementRepository::class)]
#[ORM\EntityListeners([TreeCacheInvalidationListener::class])]
abstract class AbstractStructuralDBElement extends AttachmentContainingDBElement
@ -118,7 +118,7 @@ abstract class AbstractStructuralDBElement extends AttachmentContainingDBElement
* @var Collection<int, AbstractParameter>
* @phpstan-var Collection<int, PT>
*/
#[Assert\Valid()]
#[Assert\Valid]
protected Collection $parameters;
/** @var string[] all names of all parent elements as an array of strings,
@ -176,7 +176,7 @@ abstract class AbstractStructuralDBElement extends AttachmentContainingDBElement
throw new InvalidArgumentException('isChildOf() only works for objects of the same type!');
}
if (!$this->getParent() instanceof \App\Entity\Base\AbstractStructuralDBElement) { // this is the root node
if (!$this->getParent() instanceof self) { // this is the root node
return false;
}
@ -244,9 +244,9 @@ abstract class AbstractStructuralDBElement extends AttachmentContainingDBElement
/*
* Only check for nodes that have a parent. In the other cases zero is correct.
*/
if (0 === $this->level && $this->parent instanceof \App\Entity\Base\AbstractStructuralDBElement) {
if (0 === $this->level && $this->parent instanceof self) {
$element = $this->parent;
while ($element instanceof \App\Entity\Base\AbstractStructuralDBElement) {
while ($element instanceof self) {
/** @var AbstractStructuralDBElement $element */
$element = $element->parent;
++$this->level;
@ -274,7 +274,7 @@ abstract class AbstractStructuralDBElement extends AttachmentContainingDBElement
$overflow = 20; //We only allow 20 levels depth
while ($element->parent instanceof \App\Entity\Base\AbstractStructuralDBElement && $overflow >= 0) {
while ($element->parent instanceof self && $overflow >= 0) {
$element = $element->parent;
$this->full_path_strings[] = $element->getName();
//Decrement to prevent mem overflow.
@ -360,7 +360,7 @@ abstract class AbstractStructuralDBElement extends AttachmentContainingDBElement
$this->parent = $new_parent;
//Add this element as child to the new parent
if ($new_parent instanceof \App\Entity\Base\AbstractStructuralDBElement) {
if ($new_parent instanceof self) {
$new_parent->getChildren()->add($this);
}
@ -445,7 +445,7 @@ abstract class AbstractStructuralDBElement extends AttachmentContainingDBElement
public function setAlternativeNames(?string $new_value): self
{
//Add a trailing comma, if not already there (makes it easier to find in the database)
if (is_string($new_value) && substr($new_value, -1) !== ',') {
if (is_string($new_value) && !str_ends_with($new_value, ',')) {
$new_value .= ',';
}

View file

@ -85,7 +85,7 @@ class LabelOptions
/** @var LabelProcessMode The mode that will be used to interpret the lines
*/
#[ORM\Column(type: Types::STRING, enumType: LabelProcessMode::class, name: 'lines_mode')]
#[ORM\Column(name: 'lines_mode', type: Types::STRING, enumType: LabelProcessMode::class)]
protected LabelProcessMode $process_mode = LabelProcessMode::PLACEHOLDER;
/**

View file

@ -66,7 +66,7 @@ class LabelProfile extends AttachmentContainingDBElement
/**
* @var Collection<int, LabelAttachment>
*/
#[ORM\OneToMany(targetEntity: LabelAttachment::class, mappedBy: 'element', cascade: ['persist', 'remove'], orphanRemoval: true)]
#[ORM\OneToMany(mappedBy: 'element', targetEntity: LabelAttachment::class, cascade: ['persist', 'remove'], orphanRemoval: true)]
#[ORM\OrderBy(['name' => 'ASC'])]
protected Collection $attachments;

View file

@ -147,65 +147,38 @@ class CollectionElementDeleted extends AbstractLogEntry implements LogWithEventU
private function resolveAbstractClassToInstantiableClass(string $abstract_class): string
{
if (is_a($abstract_class, AbstractParameter::class, true)) {
switch ($this->getTargetClass()) {
case AttachmentType::class:
return AttachmentTypeParameter::class;
case Category::class:
return CategoryParameter::class;
case Currency::class:
return CurrencyParameter::class;
case Project::class:
return ProjectParameter::class;
case Footprint::class:
return FootprintParameter::class;
case Group::class:
return GroupParameter::class;
case Manufacturer::class:
return ManufacturerParameter::class;
case MeasurementUnit::class:
return MeasurementUnitParameter::class;
case Part::class:
return PartParameter::class;
case StorageLocation::class:
return StorageLocationParameter::class;
case Supplier::class:
return SupplierParameter::class;
default:
throw new \RuntimeException('Unknown target class for parameter: '.$this->getTargetClass());
}
return match ($this->getTargetClass()) {
AttachmentType::class => AttachmentTypeParameter::class,
Category::class => CategoryParameter::class,
Currency::class => CurrencyParameter::class,
Project::class => ProjectParameter::class,
Footprint::class => FootprintParameter::class,
Group::class => GroupParameter::class,
Manufacturer::class => ManufacturerParameter::class,
MeasurementUnit::class => MeasurementUnitParameter::class,
Part::class => PartParameter::class,
StorageLocation::class => StorageLocationParameter::class,
Supplier::class => SupplierParameter::class,
default => throw new \RuntimeException('Unknown target class for parameter: '.$this->getTargetClass()),
};
}
if (is_a($abstract_class, Attachment::class, true)) {
switch ($this->getTargetClass()) {
case AttachmentType::class:
return AttachmentTypeAttachment::class;
case Category::class:
return CategoryAttachment::class;
case Currency::class:
return CurrencyAttachment::class;
case Project::class:
return ProjectAttachment::class;
case Footprint::class:
return FootprintAttachment::class;
case Group::class:
return GroupAttachment::class;
case Manufacturer::class:
return ManufacturerAttachment::class;
case MeasurementUnit::class:
return MeasurementUnitAttachment::class;
case Part::class:
return PartAttachment::class;
case StorageLocation::class:
return StorageLocationAttachment::class;
case Supplier::class:
return SupplierAttachment::class;
case User::class:
return UserAttachment::class;
default:
throw new \RuntimeException('Unknown target class for parameter: '.$this->getTargetClass());
}
return match ($this->getTargetClass()) {
AttachmentType::class => AttachmentTypeAttachment::class,
Category::class => CategoryAttachment::class,
Currency::class => CurrencyAttachment::class,
Project::class => ProjectAttachment::class,
Footprint::class => FootprintAttachment::class,
Group::class => GroupAttachment::class,
Manufacturer::class => ManufacturerAttachment::class,
MeasurementUnit::class => MeasurementUnitAttachment::class,
Part::class => PartAttachment::class,
StorageLocation::class => StorageLocationAttachment::class,
Supplier::class => SupplierAttachment::class,
User::class => UserAttachment::class,
default => throw new \RuntimeException('Unknown target class for parameter: '.$this->getTargetClass()),
};
}
throw new \RuntimeException('The class '.$abstract_class.' is abstract and no explicit resolving to an concrete type is defined!');

View file

@ -20,7 +20,7 @@
namespace App\Entity\LogSystem;
use \Psr\Log\LogLevel as PSRLogLevel;
use Psr\Log\LogLevel as PSRLogLevel;
enum LogLevel: int
{

View file

@ -32,7 +32,7 @@ use League\OAuth2\Client\Token\AccessTokenInterface;
/**
* This entity represents a OAuth token pair (access and refresh token), for an application
*/
#[ORM\Entity()]
#[ORM\Entity]
#[ORM\Table(name: 'oauth_tokens')]
#[ORM\UniqueConstraint(name: 'oauth_tokens_unique_name', columns: ['name'])]
#[ORM\Index(columns: ['name'], name: 'oauth_tokens_name_idx')]

View file

@ -41,6 +41,7 @@ declare(strict_types=1);
namespace App\Entity\Parameters;
use ApiPlatform\Doctrine\Common\Filter\DateFilterInterface;
use ApiPlatform\Doctrine\Orm\Filter\DateFilter;
use ApiPlatform\Doctrine\Orm\Filter\OrderFilter;
use ApiPlatform\Doctrine\Orm\Filter\RangeFilter;
@ -76,9 +77,9 @@ use function sprintf;
6 => MeasurementUnitParameter::class, 7 => PartParameter::class, 8 => StorageLocationParameter::class,
9 => SupplierParameter::class, 10 => AttachmentTypeParameter::class])]
#[ORM\Table('parameters')]
#[ORM\Index(name: 'parameter_name_idx', columns: ['name'])]
#[ORM\Index(name: 'parameter_group_idx', columns: ['param_group'])]
#[ORM\Index(name: 'parameter_type_element_idx', columns: ['type', 'element_id'])]
#[ORM\Index(columns: ['name'], name: 'parameter_name_idx')]
#[ORM\Index(columns: ['param_group'], name: 'parameter_group_idx')]
#[ORM\Index(columns: ['type', 'element_id'], name: 'parameter_type_element_idx')]
#[ApiResource(
shortName: 'Parameter',
operations: [
@ -91,7 +92,7 @@ use function sprintf;
denormalizationContext: ['groups' => ['parameter:write', 'parameter:write:standalone', 'api:basic:write'], 'openapi_definition_name' => 'Write'],
)]
#[ApiFilter(LikeFilter::class, properties: ["name", "symbol", "unit", "group", "value_text"])]
#[ApiFilter(DateFilter::class, strategy: DateFilter::EXCLUDE_NULL)]
#[ApiFilter(DateFilter::class, strategy: DateFilterInterface::EXCLUDE_NULL)]
#[ApiFilter(RangeFilter::class, properties: ["value_min", "value_typical", "value_max"])]
#[ApiFilter(OrderFilter::class, properties: ['name', 'id', 'addedDate', 'lastModified'])]
//This discriminator map is required for API platform to know which class to use for deserialization, when creating a new parameter.
@ -166,7 +167,7 @@ abstract class AbstractParameter extends AbstractNamedDBElement
* @var string the group this parameter belongs to
*/
#[Groups(['full', 'parameter:read', 'parameter:write'])]
#[ORM\Column(type: Types::STRING, name: 'param_group')]
#[ORM\Column(name: 'param_group', type: Types::STRING)]
protected string $group = '';
/**

View file

@ -22,6 +22,7 @@ declare(strict_types=1);
namespace App\Entity\Parts;
use ApiPlatform\Doctrine\Common\Filter\DateFilterInterface;
use ApiPlatform\Doctrine\Orm\Filter\DateFilter;
use ApiPlatform\Doctrine\Orm\Filter\OrderFilter;
use ApiPlatform\Doctrine\Orm\Filter\SearchFilter;
@ -60,8 +61,8 @@ use Symfony\Component\Validator\Constraints as Assert;
*/
#[ORM\Entity(repositoryClass: CategoryRepository::class)]
#[ORM\Table(name: '`categories`')]
#[ORM\Index(name: 'category_idx_name', columns: ['name'])]
#[ORM\Index(name: 'category_idx_parent_name', columns: ['parent_id', 'name'])]
#[ORM\Index(columns: ['name'], name: 'category_idx_name')]
#[ORM\Index(columns: ['parent_id', 'name'], name: 'category_idx_parent_name')]
#[ApiResource(
operations: [
new Get(security: 'is_granted("read", object)'),
@ -88,11 +89,11 @@ use Symfony\Component\Validator\Constraints as Assert;
)]
#[ApiFilter(PropertyFilter::class)]
#[ApiFilter(LikeFilter::class, properties: ["name", "comment"])]
#[ApiFilter(DateFilter::class, strategy: DateFilter::EXCLUDE_NULL)]
#[ApiFilter(DateFilter::class, strategy: DateFilterInterface::EXCLUDE_NULL)]
#[ApiFilter(OrderFilter::class, properties: ['name', 'id', 'addedDate', 'lastModified'])]
class Category extends AbstractPartsContainingDBElement
{
#[ORM\OneToMany(targetEntity: self::class, mappedBy: 'parent')]
#[ORM\OneToMany(mappedBy: 'parent', targetEntity: self::class)]
#[ORM\OrderBy(['name' => 'ASC'])]
protected Collection $children;
@ -166,7 +167,7 @@ class Category extends AbstractPartsContainingDBElement
*/
#[Assert\Valid]
#[Groups(['full', 'category:read', 'category:write'])]
#[ORM\OneToMany(targetEntity: CategoryAttachment::class, mappedBy: 'element', cascade: ['persist', 'remove'], orphanRemoval: true)]
#[ORM\OneToMany(mappedBy: 'element', targetEntity: CategoryAttachment::class, cascade: ['persist', 'remove'], orphanRemoval: true)]
#[ORM\OrderBy(['name' => 'ASC'])]
protected Collection $attachments;
@ -179,7 +180,7 @@ class Category extends AbstractPartsContainingDBElement
*/
#[Assert\Valid]
#[Groups(['full', 'category:read', 'category:write'])]
#[ORM\OneToMany(targetEntity: CategoryParameter::class, mappedBy: 'element', cascade: ['persist', 'remove'], orphanRemoval: true)]
#[ORM\OneToMany(mappedBy: 'element', targetEntity: CategoryParameter::class, cascade: ['persist', 'remove'], orphanRemoval: true)]
#[ORM\OrderBy(['group' => 'ASC', 'name' => 'ASC'])]
protected Collection $parameters;

View file

@ -22,6 +22,7 @@ declare(strict_types=1);
namespace App\Entity\Parts;
use ApiPlatform\Doctrine\Common\Filter\DateFilterInterface;
use ApiPlatform\Doctrine\Orm\Filter\DateFilter;
use ApiPlatform\Doctrine\Orm\Filter\OrderFilter;
use ApiPlatform\Doctrine\Orm\Filter\SearchFilter;
@ -61,8 +62,8 @@ use Symfony\Component\Validator\Constraints as Assert;
*/
#[ORM\Entity(repositoryClass: FootprintRepository::class)]
#[ORM\Table('`footprints`')]
#[ORM\Index(name: 'footprint_idx_name', columns: ['name'])]
#[ORM\Index(name: 'footprint_idx_parent_name', columns: ['parent_id', 'name'])]
#[ORM\Index(columns: ['name'], name: 'footprint_idx_name')]
#[ORM\Index(columns: ['parent_id', 'name'], name: 'footprint_idx_parent_name')]
#[ApiResource(
operations: [
new Get(security: 'is_granted("read", object)'),
@ -89,7 +90,7 @@ use Symfony\Component\Validator\Constraints as Assert;
)]
#[ApiFilter(PropertyFilter::class)]
#[ApiFilter(LikeFilter::class, properties: ["name", "comment"])]
#[ApiFilter(DateFilter::class, strategy: DateFilter::EXCLUDE_NULL)]
#[ApiFilter(DateFilter::class, strategy: DateFilterInterface::EXCLUDE_NULL)]
#[ApiFilter(OrderFilter::class, properties: ['name', 'id', 'addedDate', 'lastModified'])]
class Footprint extends AbstractPartsContainingDBElement
{
@ -99,7 +100,7 @@ class Footprint extends AbstractPartsContainingDBElement
#[ApiProperty(readableLink: false, writableLink: false)]
protected ?AbstractStructuralDBElement $parent = null;
#[ORM\OneToMany(targetEntity: self::class, mappedBy: 'parent')]
#[ORM\OneToMany(mappedBy: 'parent', targetEntity: self::class)]
#[ORM\OrderBy(['name' => 'ASC'])]
protected Collection $children;
@ -110,7 +111,7 @@ class Footprint extends AbstractPartsContainingDBElement
* @var Collection<int, FootprintAttachment>
*/
#[Assert\Valid]
#[ORM\OneToMany(targetEntity: FootprintAttachment::class, mappedBy: 'element', cascade: ['persist', 'remove'], orphanRemoval: true)]
#[ORM\OneToMany(mappedBy: 'element', targetEntity: FootprintAttachment::class, cascade: ['persist', 'remove'], orphanRemoval: true)]
#[ORM\OrderBy(['name' => 'ASC'])]
#[Groups(['footprint:read', 'footprint:write'])]
protected Collection $attachments;
@ -131,7 +132,7 @@ class Footprint extends AbstractPartsContainingDBElement
/** @var Collection<int, FootprintParameter>
*/
#[Assert\Valid]
#[ORM\OneToMany(targetEntity: FootprintParameter::class, mappedBy: 'element', cascade: ['persist', 'remove'], orphanRemoval: true)]
#[ORM\OneToMany(mappedBy: 'element', targetEntity: FootprintParameter::class, cascade: ['persist', 'remove'], orphanRemoval: true)]
#[ORM\OrderBy(['group' => 'ASC', 'name' => 'ASC'])]
#[Groups(['footprint:read', 'footprint:write'])]
protected Collection $parameters;

View file

@ -22,6 +22,7 @@ declare(strict_types=1);
namespace App\Entity\Parts;
use ApiPlatform\Doctrine\Common\Filter\DateFilterInterface;
use ApiPlatform\Doctrine\Orm\Filter\DateFilter;
use ApiPlatform\Doctrine\Orm\Filter\OrderFilter;
use ApiPlatform\Metadata\ApiFilter;
@ -56,8 +57,8 @@ use Symfony\Component\Validator\Constraints as Assert;
*/
#[ORM\Entity(repositoryClass: ManufacturerRepository::class)]
#[ORM\Table('`manufacturers`')]
#[ORM\Index(name: 'manufacturer_name', columns: ['name'])]
#[ORM\Index(name: 'manufacturer_idx_parent_name', columns: ['parent_id', 'name'])]
#[ORM\Index(columns: ['name'], name: 'manufacturer_name')]
#[ORM\Index(columns: ['parent_id', 'name'], name: 'manufacturer_idx_parent_name')]
#[ApiResource(
operations: [
new Get(security: 'is_granted("read", object)'),
@ -84,7 +85,7 @@ use Symfony\Component\Validator\Constraints as Assert;
)]
#[ApiFilter(PropertyFilter::class)]
#[ApiFilter(LikeFilter::class, properties: ["name", "comment"])]
#[ApiFilter(DateFilter::class, strategy: DateFilter::EXCLUDE_NULL)]
#[ApiFilter(DateFilter::class, strategy: DateFilterInterface::EXCLUDE_NULL)]
#[ApiFilter(OrderFilter::class, properties: ['name', 'id', 'addedDate', 'lastModified'])]
class Manufacturer extends AbstractCompany
{
@ -94,7 +95,7 @@ class Manufacturer extends AbstractCompany
#[ApiProperty(readableLink: false, writableLink: false)]
protected ?AbstractStructuralDBElement $parent = null;
#[ORM\OneToMany(targetEntity: self::class, mappedBy: 'parent')]
#[ORM\OneToMany(mappedBy: 'parent', targetEntity: self::class)]
#[ORM\OrderBy(['name' => 'ASC'])]
protected Collection $children;
@ -102,7 +103,7 @@ class Manufacturer extends AbstractCompany
* @var Collection<int, ManufacturerAttachment>
*/
#[Assert\Valid]
#[ORM\OneToMany(targetEntity: ManufacturerAttachment::class, mappedBy: 'element', cascade: ['persist', 'remove'], orphanRemoval: true)]
#[ORM\OneToMany(mappedBy: 'element', targetEntity: ManufacturerAttachment::class, cascade: ['persist', 'remove'], orphanRemoval: true)]
#[ORM\OrderBy(['name' => 'ASC'])]
#[Groups(['manufacturer:read', 'manufacturer:write'])]
#[ApiProperty(readableLink: false, writableLink: true)]
@ -117,7 +118,7 @@ class Manufacturer extends AbstractCompany
/** @var Collection<int, ManufacturerParameter>
*/
#[Assert\Valid]
#[ORM\OneToMany(targetEntity: ManufacturerParameter::class, mappedBy: 'element', cascade: ['persist', 'remove'], orphanRemoval: true)]
#[ORM\OneToMany(mappedBy: 'element', targetEntity: ManufacturerParameter::class, cascade: ['persist', 'remove'], orphanRemoval: true)]
#[ORM\OrderBy(['group' => 'ASC', 'name' => 'ASC'])]
#[Groups(['manufacturer:read', 'manufacturer:write'])]
#[ApiProperty(readableLink: false, writableLink: true)]

View file

@ -22,6 +22,7 @@ declare(strict_types=1);
namespace App\Entity\Parts;
use ApiPlatform\Doctrine\Common\Filter\DateFilterInterface;
use ApiPlatform\Doctrine\Orm\Filter\DateFilter;
use ApiPlatform\Doctrine\Orm\Filter\OrderFilter;
use ApiPlatform\Metadata\ApiFilter;
@ -60,8 +61,8 @@ use Symfony\Component\Validator\Constraints as Assert;
#[UniqueEntity('unit')]
#[ORM\Entity(repositoryClass: MeasurementUnitRepository::class)]
#[ORM\Table(name: '`measurement_units`')]
#[ORM\Index(name: 'unit_idx_name', columns: ['name'])]
#[ORM\Index(name: 'unit_idx_parent_name', columns: ['parent_id', 'name'])]
#[ORM\Index(columns: ['name'], name: 'unit_idx_name')]
#[ORM\Index(columns: ['parent_id', 'name'], name: 'unit_idx_parent_name')]
#[ApiResource(
operations: [
new Get(security: 'is_granted("read", object)'),
@ -88,7 +89,7 @@ use Symfony\Component\Validator\Constraints as Assert;
)]
#[ApiFilter(PropertyFilter::class)]
#[ApiFilter(LikeFilter::class, properties: ["name", "comment", "unit"])]
#[ApiFilter(DateFilter::class, strategy: DateFilter::EXCLUDE_NULL)]
#[ApiFilter(DateFilter::class, strategy: DateFilterInterface::EXCLUDE_NULL)]
#[ApiFilter(OrderFilter::class, properties: ['name', 'id', 'addedDate', 'lastModified'])]
class MeasurementUnit extends AbstractPartsContainingDBElement
{
@ -98,7 +99,7 @@ class MeasurementUnit extends AbstractPartsContainingDBElement
*/
#[Assert\Length(max: 10)]
#[Groups(['extended', 'full', 'import', 'measurement_unit:read', 'measurement_unit:write'])]
#[ORM\Column(type: Types::STRING, name: 'unit', nullable: true)]
#[ORM\Column(name: 'unit', type: Types::STRING, nullable: true)]
protected ?string $unit = null;
#[Groups(['measurement_unit:read', 'measurement_unit:write'])]
@ -109,7 +110,7 @@ class MeasurementUnit extends AbstractPartsContainingDBElement
* Set to false, to measure continuous sizes likes masses or lengths.
*/
#[Groups(['extended', 'full', 'import', 'measurement_unit:read', 'measurement_unit:write'])]
#[ORM\Column(type: Types::BOOLEAN, name: 'is_integer')]
#[ORM\Column(name: 'is_integer', type: Types::BOOLEAN)]
protected bool $is_integer = false;
/**
@ -118,10 +119,10 @@ class MeasurementUnit extends AbstractPartsContainingDBElement
*/
#[Assert\Expression('this.isUseSIPrefix() == false or this.getUnit() != null', message: 'validator.measurement_unit.use_si_prefix_needs_unit')]
#[Groups(['full', 'import', 'measurement_unit:read', 'measurement_unit:write'])]
#[ORM\Column(type: Types::BOOLEAN, name: 'use_si_prefix')]
#[ORM\Column(name: 'use_si_prefix', type: Types::BOOLEAN)]
protected bool $use_si_prefix = false;
#[ORM\OneToMany(targetEntity: self::class, mappedBy: 'parent', cascade: ['persist'])]
#[ORM\OneToMany(mappedBy: 'parent', targetEntity: self::class, cascade: ['persist'])]
#[ORM\OrderBy(['name' => 'ASC'])]
protected Collection $children;
@ -135,7 +136,7 @@ class MeasurementUnit extends AbstractPartsContainingDBElement
* @var Collection<int, MeasurementUnitAttachment>
*/
#[Assert\Valid]
#[ORM\OneToMany(targetEntity: MeasurementUnitAttachment::class, mappedBy: 'element', cascade: ['persist', 'remove'], orphanRemoval: true)]
#[ORM\OneToMany(mappedBy: 'element', targetEntity: MeasurementUnitAttachment::class, cascade: ['persist', 'remove'], orphanRemoval: true)]
#[ORM\OrderBy(['name' => 'ASC'])]
#[Groups(['measurement_unit:read', 'measurement_unit:write'])]
protected Collection $attachments;
@ -148,7 +149,7 @@ class MeasurementUnit extends AbstractPartsContainingDBElement
/** @var Collection<int, MeasurementUnitParameter>
*/
#[Assert\Valid]
#[ORM\OneToMany(targetEntity: MeasurementUnitParameter::class, mappedBy: 'element', cascade: ['persist', 'remove'], orphanRemoval: true)]
#[ORM\OneToMany(mappedBy: 'element', targetEntity: MeasurementUnitParameter::class, cascade: ['persist', 'remove'], orphanRemoval: true)]
#[ORM\OrderBy(['group' => 'ASC', 'name' => 'ASC'])]
#[Groups(['measurement_unit:read', 'measurement_unit:write'])]
protected Collection $parameters;

View file

@ -22,6 +22,7 @@ declare(strict_types=1);
namespace App\Entity\Parts;
use ApiPlatform\Doctrine\Common\Filter\DateFilterInterface;
use ApiPlatform\Doctrine\Orm\Filter\BooleanFilter;
use ApiPlatform\Doctrine\Orm\Filter\DateFilter;
use ApiPlatform\Doctrine\Orm\Filter\OrderFilter;
@ -74,9 +75,9 @@ use Symfony\Component\Validator\Context\ExecutionContextInterface;
#[ORM\Entity(repositoryClass: PartRepository::class)]
#[ORM\EntityListeners([TreeCacheInvalidationListener::class])]
#[ORM\Table('`parts`')]
#[ORM\Index(name: 'parts_idx_datet_name_last_id_needs', columns: ['datetime_added', 'name', 'last_modified', 'id', 'needs_review'])]
#[ORM\Index(name: 'parts_idx_name', columns: ['name'])]
#[ORM\Index(name: 'parts_idx_ipn', columns: ['ipn'])]
#[ORM\Index(columns: ['datetime_added', 'name', 'last_modified', 'id', 'needs_review'], name: 'parts_idx_datet_name_last_id_needs')]
#[ORM\Index(columns: ['name'], name: 'parts_idx_name')]
#[ORM\Index(columns: ['ipn'], name: 'parts_idx_ipn')]
#[ApiResource(
operations: [
new Get(normalizationContext: ['groups' => ['part:read', 'provider_reference:read', 'api:basic:read', 'part_lot:read',
@ -97,7 +98,7 @@ use Symfony\Component\Validator\Context\ExecutionContextInterface;
#[ApiFilter(LikeFilter::class, properties: ["name", "comment", "description", "ipn", "tags", "manufacturer_product_number"])]
#[ApiFilter(BooleanFilter::class, properties: ["favorite" , "needs_review"])]
#[ApiFilter(RangeFilter::class, properties: ["mass", "minamount"])]
#[ApiFilter(DateFilter::class, strategy: DateFilter::EXCLUDE_NULL)]
#[ApiFilter(DateFilter::class, strategy: DateFilterInterface::EXCLUDE_NULL)]
#[ApiFilter(OrderFilter::class, properties: ['name', 'id', 'addedDate', 'lastModified'])]
class Part extends AttachmentContainingDBElement
{
@ -116,7 +117,7 @@ class Part extends AttachmentContainingDBElement
*/
#[Assert\Valid]
#[Groups(['full', 'part:read', 'part:write'])]
#[ORM\OneToMany(targetEntity: PartParameter::class, mappedBy: 'element', cascade: ['persist', 'remove'], orphanRemoval: true)]
#[ORM\OneToMany(mappedBy: 'element', targetEntity: PartParameter::class, cascade: ['persist', 'remove'], orphanRemoval: true)]
#[ORM\OrderBy(['group' => 'ASC', 'name' => 'ASC'])]
protected Collection $parameters;
@ -136,7 +137,7 @@ class Part extends AttachmentContainingDBElement
*/
#[Assert\Valid]
#[Groups(['full', 'part:read', 'part:write'])]
#[ORM\OneToMany(targetEntity: PartAttachment::class, mappedBy: 'element', cascade: ['persist', 'remove'], orphanRemoval: true)]
#[ORM\OneToMany(mappedBy: 'element', targetEntity: PartAttachment::class, cascade: ['persist', 'remove'], orphanRemoval: true)]
#[ORM\OrderBy(['name' => 'ASC'])]
protected Collection $attachments;

View file

@ -23,6 +23,7 @@ declare(strict_types=1);
namespace App\Entity\Parts;
use ApiPlatform\Doctrine\Common\Filter\DateFilterInterface;
use ApiPlatform\Doctrine\Orm\Filter\BooleanFilter;
use ApiPlatform\Doctrine\Orm\Filter\DateFilter;
use ApiPlatform\Doctrine\Orm\Filter\OrderFilter;
@ -67,7 +68,7 @@ use Symfony\Component\Validator\Constraints as Assert;
)]
#[ApiFilter(PropertyFilter::class)]
#[ApiFilter(LikeFilter::class, properties: ["other_type", "comment"])]
#[ApiFilter(DateFilter::class, strategy: DateFilter::EXCLUDE_NULL)]
#[ApiFilter(DateFilter::class, strategy: DateFilterInterface::EXCLUDE_NULL)]
#[ApiFilter(OrderFilter::class, properties: ['comment', 'addedDate', 'lastModified'])]
class PartAssociation extends AbstractDBElement implements TimeStampableInterface
{

View file

@ -22,6 +22,7 @@ declare(strict_types=1);
namespace App\Entity\Parts;
use ApiPlatform\Doctrine\Common\Filter\DateFilterInterface;
use ApiPlatform\Doctrine\Orm\Filter\BooleanFilter;
use ApiPlatform\Doctrine\Orm\Filter\DateFilter;
use ApiPlatform\Doctrine\Orm\Filter\OrderFilter;
@ -80,7 +81,7 @@ use Symfony\Component\Validator\Context\ExecutionContextInterface;
)]
#[ApiFilter(PropertyFilter::class)]
#[ApiFilter(LikeFilter::class, properties: ["description", "comment"])]
#[ApiFilter(DateFilter::class, strategy: DateFilter::EXCLUDE_NULL)]
#[ApiFilter(DateFilter::class, strategy: DateFilterInterface::EXCLUDE_NULL)]
#[ApiFilter(BooleanFilter::class, properties: ['instock_unknown', 'needs_refill'])]
#[ApiFilter(RangeFilter::class, properties: ['amount'])]
#[ApiFilter(OrderFilter::class, properties: ['description', 'comment', 'addedDate', 'lastModified'])]
@ -107,7 +108,7 @@ class PartLot extends AbstractDBElement implements TimeStampableInterface, Named
* Set to null, if the lot can be used indefinitely.
*/
#[Groups(['extended', 'full', 'import', 'part_lot:read', 'part_lot:write'])]
#[ORM\Column(type: Types::DATETIME_MUTABLE, name: 'expiration_date', nullable: true)]
#[ORM\Column(name: 'expiration_date', type: Types::DATETIME_MUTABLE, nullable: true)]
protected ?\DateTimeInterface $expiration_date = null;
/**
@ -116,7 +117,7 @@ class PartLot extends AbstractDBElement implements TimeStampableInterface, Named
#[Groups(['simple', 'extended', 'full', 'import', 'part_lot:read', 'part_lot:write'])]
#[ORM\ManyToOne(targetEntity: StorageLocation::class, fetch: 'EAGER')]
#[ORM\JoinColumn(name: 'id_store_location')]
#[Selectable()]
#[Selectable]
protected ?StorageLocation $storage_location = null;
/**

View file

@ -64,7 +64,7 @@ trait BasicPropertyTrait
* Every part must have a category.
*/
#[Assert\NotNull(message: 'validator.select_valid_category')]
#[Selectable()]
#[Selectable]
#[Groups(['simple', 'extended', 'full', 'import', "part:read", "part:write"])]
#[ORM\ManyToOne(targetEntity: Category::class)]
#[ORM\JoinColumn(name: 'id_category', nullable: false)]
@ -76,7 +76,7 @@ trait BasicPropertyTrait
#[Groups(['simple', 'extended', 'full', 'import', 'part:read', 'part:write'])]
#[ORM\ManyToOne(targetEntity: Footprint::class)]
#[ORM\JoinColumn(name: 'id_footprint')]
#[Selectable()]
#[Selectable]
protected ?Footprint $footprint = null;
/**

View file

@ -41,7 +41,7 @@ trait InstockTrait
*/
#[Assert\Valid]
#[Groups(['extended', 'full', 'import', 'part:read', 'part:write'])]
#[ORM\OneToMany(targetEntity: PartLot::class, mappedBy: 'part', cascade: ['persist', 'remove'], orphanRemoval: true)]
#[ORM\OneToMany(mappedBy: 'part', targetEntity: PartLot::class, cascade: ['persist', 'remove'], orphanRemoval: true)]
#[ORM\OrderBy(['amount' => 'DESC'])]
protected Collection $partLots;

View file

@ -42,7 +42,7 @@ trait ManufacturerTrait
#[Groups(['simple', 'extended', 'full', 'import', 'part:read', 'part:write'])]
#[ORM\ManyToOne(targetEntity: Manufacturer::class)]
#[ORM\JoinColumn(name: 'id_manufacturer')]
#[Selectable()]
#[Selectable]
protected ?Manufacturer $manufacturer = null;
/**

View file

@ -40,7 +40,7 @@ trait OrderTrait
*/
#[Assert\Valid]
#[Groups(['extended', 'full', 'import', 'part:read', 'part:write'])]
#[ORM\OneToMany(targetEntity: Orderdetail::class, mappedBy: 'part', cascade: ['persist', 'remove'], orphanRemoval: true)]
#[ORM\OneToMany(mappedBy: 'part', targetEntity: Orderdetail::class, cascade: ['persist', 'remove'], orphanRemoval: true)]
#[ORM\OrderBy(['supplierpartnr' => 'ASC'])]
protected Collection $orderdetails;

View file

@ -16,13 +16,13 @@ trait ProjectTrait
/**
* @var Collection<ProjectBOMEntry> $project_bom_entries
*/
#[ORM\OneToMany(targetEntity: ProjectBOMEntry::class, mappedBy: 'part', cascade: ['remove'], orphanRemoval: true)]
#[ORM\OneToMany(mappedBy: 'part', targetEntity: ProjectBOMEntry::class, cascade: ['remove'], orphanRemoval: true)]
protected Collection $project_bom_entries;
/**
* @var Project|null If a project is set here, then this part is special and represents the builds of a project.
*/
#[ORM\OneToOne(targetEntity: Project::class, inversedBy: 'build_part')]
#[ORM\OneToOne(inversedBy: 'build_part', targetEntity: Project::class)]
#[ORM\JoinColumn]
protected ?Project $built_project = null;

View file

@ -22,6 +22,7 @@ declare(strict_types=1);
namespace App\Entity\Parts;
use ApiPlatform\Doctrine\Common\Filter\DateFilterInterface;
use ApiPlatform\Doctrine\Orm\Filter\DateFilter;
use ApiPlatform\Doctrine\Orm\Filter\OrderFilter;
use ApiPlatform\Metadata\ApiFilter;
@ -56,8 +57,8 @@ use Symfony\Component\Validator\Constraints as Assert;
*/
#[ORM\Entity(repositoryClass: StorelocationRepository::class)]
#[ORM\Table('`storelocations`')]
#[ORM\Index(name: 'location_idx_name', columns: ['name'])]
#[ORM\Index(name: 'location_idx_parent_name', columns: ['parent_id', 'name'])]
#[ORM\Index(columns: ['name'], name: 'location_idx_name')]
#[ORM\Index(columns: ['parent_id', 'name'], name: 'location_idx_parent_name')]
#[ApiResource(
operations: [
new Get(security: 'is_granted("read", object)'),
@ -84,11 +85,11 @@ use Symfony\Component\Validator\Constraints as Assert;
)]
#[ApiFilter(PropertyFilter::class)]
#[ApiFilter(LikeFilter::class, properties: ["name", "comment"])]
#[ApiFilter(DateFilter::class, strategy: DateFilter::EXCLUDE_NULL)]
#[ApiFilter(DateFilter::class, strategy: DateFilterInterface::EXCLUDE_NULL)]
#[ApiFilter(OrderFilter::class, properties: ['name', 'id', 'addedDate', 'lastModified'])]
class StorageLocation extends AbstractPartsContainingDBElement
{
#[ORM\OneToMany(targetEntity: self::class, mappedBy: 'parent')]
#[ORM\OneToMany(mappedBy: 'parent', targetEntity: self::class)]
#[ORM\OrderBy(['name' => 'ASC'])]
protected Collection $children;
@ -112,7 +113,7 @@ class StorageLocation extends AbstractPartsContainingDBElement
/** @var Collection<int, StorageLocationParameter>
*/
#[Assert\Valid]
#[ORM\OneToMany(targetEntity: StorageLocationParameter::class, mappedBy: 'element', cascade: ['persist', 'remove'], orphanRemoval: true)]
#[ORM\OneToMany(mappedBy: 'element', targetEntity: StorageLocationParameter::class, cascade: ['persist', 'remove'], orphanRemoval: true)]
#[ORM\OrderBy(['group' => 'ASC', 'name' => 'ASC'])]
#[Groups(['location:read', 'location:write'])]
protected Collection $parameters;
@ -158,7 +159,7 @@ class StorageLocation extends AbstractPartsContainingDBElement
* @var Collection<int, StorageLocationAttachment>
*/
#[Assert\Valid]
#[ORM\OneToMany(targetEntity: StorageLocationAttachment::class, mappedBy: 'element', cascade: ['persist', 'remove'], orphanRemoval: true)]
#[ORM\OneToMany(mappedBy: 'element', targetEntity: StorageLocationAttachment::class, cascade: ['persist', 'remove'], orphanRemoval: true)]
#[Groups(['location:read', 'location:write'])]
protected Collection $attachments;

View file

@ -22,6 +22,7 @@ declare(strict_types=1);
namespace App\Entity\Parts;
use ApiPlatform\Doctrine\Common\Filter\DateFilterInterface;
use ApiPlatform\Doctrine\Orm\Filter\DateFilter;
use ApiPlatform\Doctrine\Orm\Filter\OrderFilter;
use ApiPlatform\Metadata\ApiFilter;
@ -61,8 +62,8 @@ use Symfony\Component\Validator\Constraints as Assert;
*/
#[ORM\Entity(repositoryClass: SupplierRepository::class)]
#[ORM\Table('`suppliers`')]
#[ORM\Index(name: 'supplier_idx_name', columns: ['name'])]
#[ORM\Index(name: 'supplier_idx_parent_name', columns: ['parent_id', 'name'])]
#[ORM\Index(columns: ['name'], name: 'supplier_idx_name')]
#[ORM\Index(columns: ['parent_id', 'name'], name: 'supplier_idx_parent_name')]
#[ApiResource(
operations: [
new Get(security: 'is_granted("read", object)'),
@ -81,17 +82,17 @@ use Symfony\Component\Validator\Constraints as Assert;
security: 'is_granted("@manufacturers.read")'
)],
uriVariables: [
'id' => new Link(fromClass: Supplier::class, fromProperty: 'children')
'id' => new Link(fromProperty: 'children', fromClass: Supplier::class)
],
normalizationContext: ['groups' => ['supplier:read', 'company:read', 'api:basic:read'], 'openapi_definition_name' => 'Read']
)]
#[ApiFilter(PropertyFilter::class)]
#[ApiFilter(LikeFilter::class, properties: ["name", "comment"])]
#[ApiFilter(DateFilter::class, strategy: DateFilter::EXCLUDE_NULL)]
#[ApiFilter(DateFilter::class, strategy: DateFilterInterface::EXCLUDE_NULL)]
#[ApiFilter(OrderFilter::class, properties: ['name', 'id', 'addedDate', 'lastModified'])]
class Supplier extends AbstractCompany
{
#[ORM\OneToMany(targetEntity: self::class, mappedBy: 'parent')]
#[ORM\OneToMany(mappedBy: 'parent', targetEntity: self::class)]
#[ORM\OrderBy(['name' => 'ASC'])]
protected Collection $children;
@ -104,7 +105,7 @@ class Supplier extends AbstractCompany
/**
* @var Collection<int, Orderdetail>|Orderdetail[]
*/
#[ORM\OneToMany(targetEntity: Orderdetail::class, mappedBy: 'supplier')]
#[ORM\OneToMany(mappedBy: 'supplier', targetEntity: Orderdetail::class)]
protected Collection $orderdetails;
/**
@ -113,22 +114,22 @@ class Supplier extends AbstractCompany
*/
#[ORM\ManyToOne(targetEntity: Currency::class)]
#[ORM\JoinColumn(name: 'default_currency_id')]
#[Selectable()]
#[Selectable]
protected ?Currency $default_currency = null;
/**
* @var BigDecimal|null The shipping costs that have to be paid, when ordering via this supplier
*/
#[Groups(['extended', 'full', 'import'])]
#[ORM\Column(name: 'shipping_costs', nullable: true, type: 'big_decimal', precision: 11, scale: 5)]
#[BigDecimalPositiveOrZero()]
#[ORM\Column(name: 'shipping_costs', type: 'big_decimal', precision: 11, scale: 5, nullable: true)]
#[BigDecimalPositiveOrZero]
protected ?BigDecimal $shipping_costs = null;
/**
* @var Collection<int, SupplierAttachment>
*/
#[Assert\Valid]
#[ORM\OneToMany(targetEntity: SupplierAttachment::class, mappedBy: 'element', cascade: ['persist', 'remove'], orphanRemoval: true)]
#[ORM\OneToMany(mappedBy: 'element', targetEntity: SupplierAttachment::class, cascade: ['persist', 'remove'], orphanRemoval: true)]
#[ORM\OrderBy(['name' => 'ASC'])]
#[Groups(['supplier:read', 'supplier:write'])]
#[ApiProperty(readableLink: false, writableLink: true)]
@ -143,7 +144,7 @@ class Supplier extends AbstractCompany
/** @var Collection<int, SupplierParameter>
*/
#[Assert\Valid]
#[ORM\OneToMany(targetEntity: SupplierParameter::class, mappedBy: 'element', cascade: ['persist', 'remove'], orphanRemoval: true)]
#[ORM\OneToMany(mappedBy: 'element', targetEntity: SupplierParameter::class, cascade: ['persist', 'remove'], orphanRemoval: true)]
#[ORM\OrderBy(['group' => 'ASC', 'name' => 'ASC'])]
#[Groups(['supplier:read', 'supplier:write'])]
#[ApiProperty(readableLink: false, writableLink: true)]

View file

@ -22,6 +22,7 @@ declare(strict_types=1);
namespace App\Entity\PriceInformations;
use ApiPlatform\Doctrine\Common\Filter\DateFilterInterface;
use ApiPlatform\Doctrine\Orm\Filter\DateFilter;
use ApiPlatform\Doctrine\Orm\Filter\OrderFilter;
use ApiPlatform\Metadata\ApiFilter;
@ -60,8 +61,8 @@ use Symfony\Component\Validator\Constraints as Assert;
#[UniqueEntity('iso_code')]
#[ORM\Entity(repositoryClass: CurrencyRepository::class)]
#[ORM\Table(name: 'currencies')]
#[ORM\Index(name: 'currency_idx_name', columns: ['name'])]
#[ORM\Index(name: 'currency_idx_parent_name', columns: ['parent_id', 'name'])]
#[ORM\Index(columns: ['name'], name: 'currency_idx_name')]
#[ORM\Index(columns: ['parent_id', 'name'], name: 'currency_idx_parent_name')]
#[ApiResource(
operations: [
new Get(security: 'is_granted("read", object)'),
@ -88,7 +89,7 @@ use Symfony\Component\Validator\Constraints as Assert;
)]
#[ApiFilter(PropertyFilter::class)]
#[ApiFilter(LikeFilter::class, properties: ["name", "comment", "iso_code"])]
#[ApiFilter(DateFilter::class, strategy: DateFilter::EXCLUDE_NULL)]
#[ApiFilter(DateFilter::class, strategy: DateFilterInterface::EXCLUDE_NULL)]
#[ApiFilter(OrderFilter::class, properties: ['name', 'id', 'addedDate', 'lastModified'])]
class Currency extends AbstractStructuralDBElement
{
@ -99,7 +100,7 @@ class Currency extends AbstractStructuralDBElement
* (how many base units the current currency is worth)
*/
#[ORM\Column(type: 'big_decimal', precision: 11, scale: 5, nullable: true)]
#[BigDecimalPositive()]
#[BigDecimalPositive]
#[Groups(['currency:read', 'currency:write'])]
#[ApiProperty(readableLink: false, writableLink: false)]
protected ?BigDecimal $exchange_rate = null;
@ -116,7 +117,7 @@ class Currency extends AbstractStructuralDBElement
#[ORM\Column(type: Types::STRING)]
protected string $iso_code = "";
#[ORM\OneToMany(targetEntity: self::class, mappedBy: 'parent', cascade: ['persist'])]
#[ORM\OneToMany(mappedBy: 'parent', targetEntity: self::class, cascade: ['persist'])]
#[ORM\OrderBy(['name' => 'ASC'])]
protected Collection $children;
@ -130,7 +131,7 @@ class Currency extends AbstractStructuralDBElement
* @var Collection<int, CurrencyAttachment>
*/
#[Assert\Valid]
#[ORM\OneToMany(targetEntity: CurrencyAttachment::class, mappedBy: 'element', cascade: ['persist', 'remove'], orphanRemoval: true)]
#[ORM\OneToMany(mappedBy: 'element', targetEntity: CurrencyAttachment::class, cascade: ['persist', 'remove'], orphanRemoval: true)]
#[ORM\OrderBy(['name' => 'ASC'])]
#[Groups(['currency:read', 'currency:write'])]
protected Collection $attachments;
@ -143,14 +144,14 @@ class Currency extends AbstractStructuralDBElement
/** @var Collection<int, CurrencyParameter>
*/
#[Assert\Valid]
#[ORM\OneToMany(targetEntity: CurrencyParameter::class, mappedBy: 'element', cascade: ['persist', 'remove'], orphanRemoval: true)]
#[ORM\OneToMany(mappedBy: 'element', targetEntity: CurrencyParameter::class, cascade: ['persist', 'remove'], orphanRemoval: true)]
#[ORM\OrderBy(['group' => 'ASC', 'name' => 'ASC'])]
#[Groups(['currency:read', 'currency:write'])]
protected Collection $parameters;
/** @var Collection<int, Pricedetail>
*/
#[ORM\OneToMany(targetEntity: Pricedetail::class, mappedBy: 'currency')]
#[ORM\OneToMany(mappedBy: 'currency', targetEntity: Pricedetail::class)]
protected Collection $pricedetails;
#[Groups(['currency:read'])]

View file

@ -23,6 +23,7 @@ declare(strict_types=1);
namespace App\Entity\PriceInformations;
use ApiPlatform\Doctrine\Common\Filter\DateFilterInterface;
use ApiPlatform\Doctrine\Orm\Filter\BooleanFilter;
use ApiPlatform\Doctrine\Orm\Filter\DateFilter;
use ApiPlatform\Doctrine\Orm\Filter\OrderFilter;
@ -59,7 +60,7 @@ use Symfony\Component\Validator\Constraints as Assert;
#[ORM\Entity]
#[ORM\HasLifecycleCallbacks]
#[ORM\Table('`orderdetails`')]
#[ORM\Index(name: 'orderdetails_supplier_part_nr', columns: ['supplierpartnr'])]
#[ORM\Index(columns: ['supplierpartnr'], name: 'orderdetails_supplier_part_nr')]
#[ApiResource(
operations: [
new Get(security: 'is_granted("read", object)'),
@ -88,7 +89,7 @@ use Symfony\Component\Validator\Constraints as Assert;
#[ApiFilter(PropertyFilter::class)]
#[ApiFilter(LikeFilter::class, properties: ["supplierpartnr", "supplier_product_url"])]
#[ApiFilter(BooleanFilter::class, properties: ["obsolete"])]
#[ApiFilter(DateFilter::class, strategy: DateFilter::EXCLUDE_NULL)]
#[ApiFilter(DateFilter::class, strategy: DateFilterInterface::EXCLUDE_NULL)]
#[ApiFilter(OrderFilter::class, properties: ['supplierpartnr', 'id', 'addedDate', 'lastModified'])]
class Orderdetail extends AbstractDBElement implements TimeStampableInterface, NamedElementInterface
{
@ -96,7 +97,7 @@ class Orderdetail extends AbstractDBElement implements TimeStampableInterface, N
#[Assert\Valid]
#[Groups(['extended', 'full', 'import', 'orderdetail:read', 'orderdetail:write'])]
#[ORM\OneToMany(targetEntity: Pricedetail::class, mappedBy: 'orderdetail', cascade: ['persist', 'remove'], orphanRemoval: true)]
#[ORM\OneToMany(mappedBy: 'orderdetail', targetEntity: Pricedetail::class, cascade: ['persist', 'remove'], orphanRemoval: true)]
#[ORM\OrderBy(['min_discount_quantity' => 'ASC'])]
protected Collection $pricedetails;

View file

@ -55,8 +55,8 @@ use Symfony\Component\Validator\Constraints as Assert;
#[ORM\Entity]
#[ORM\HasLifecycleCallbacks]
#[ORM\Table('`pricedetails`')]
#[ORM\Index(name: 'pricedetails_idx_min_discount', columns: ['min_discount_quantity'])]
#[ORM\Index(name: 'pricedetails_idx_min_discount_price_qty', columns: ['min_discount_quantity', 'price_related_quantity'])]
#[ORM\Index(columns: ['min_discount_quantity'], name: 'pricedetails_idx_min_discount')]
#[ORM\Index(columns: ['min_discount_quantity', 'price_related_quantity'], name: 'pricedetails_idx_min_discount_price_qty')]
#[ApiResource(
operations: [
new Get(security: 'is_granted("read", object)'),
@ -80,7 +80,7 @@ class Pricedetail extends AbstractDBElement implements TimeStampableInterface
*/
#[Groups(['extended', 'full', 'pricedetail:read', 'pricedetail:write'])]
#[ORM\Column(type: 'big_decimal', precision: 11, scale: 5)]
#[BigDecimalPositive()]
#[BigDecimalPositive]
protected BigDecimal $price;
/**
@ -90,7 +90,7 @@ class Pricedetail extends AbstractDBElement implements TimeStampableInterface
#[Groups(['extended', 'full', 'import', 'pricedetail:read', 'pricedetail:write'])]
#[ORM\ManyToOne(targetEntity: Currency::class, inversedBy: 'pricedetails')]
#[ORM\JoinColumn(name: 'id_currency')]
#[Selectable()]
#[Selectable]
protected ?Currency $currency = null;
/**

View file

@ -90,7 +90,7 @@ use Symfony\Component\Validator\Context\ExecutionContextInterface;
#[ApiFilter(OrderFilter::class, properties: ['name', 'id', 'addedDate', 'lastModified'])]
class Project extends AbstractStructuralDBElement
{
#[ORM\OneToMany(targetEntity: self::class, mappedBy: 'parent')]
#[ORM\OneToMany(mappedBy: 'parent', targetEntity: self::class)]
#[ORM\OrderBy(['name' => 'ASC'])]
protected Collection $children;
@ -105,9 +105,9 @@ class Project extends AbstractStructuralDBElement
#[Assert\Valid]
#[Groups(['extended', 'full'])]
#[ORM\OneToMany(targetEntity: ProjectBOMEntry::class, mappedBy: 'project', cascade: ['persist', 'remove'], orphanRemoval: true)]
#[UniqueObjectCollection(fields: ['part'], message: 'project.bom_entry.part_already_in_bom')]
#[UniqueObjectCollection(fields: ['name'], message: 'project.bom_entry.name_already_in_bom')]
#[ORM\OneToMany(mappedBy: 'project', targetEntity: ProjectBOMEntry::class, cascade: ['persist', 'remove'], orphanRemoval: true)]
#[UniqueObjectCollection(message: 'project.bom_entry.part_already_in_bom', fields: ['part'])]
#[UniqueObjectCollection(message: 'project.bom_entry.name_already_in_bom', fields: ['name'])]
protected Collection $bom_entries;
#[ORM\Column(type: Types::INTEGER)]
@ -125,7 +125,7 @@ class Project extends AbstractStructuralDBElement
/**
* @var Part|null The (optional) part that represents the builds of this project in the stock
*/
#[ORM\OneToOne(targetEntity: Part::class, mappedBy: 'built_project', cascade: ['persist'], orphanRemoval: true)]
#[ORM\OneToOne(mappedBy: 'built_project', targetEntity: Part::class, cascade: ['persist'], orphanRemoval: true)]
#[Groups(['project:read', 'project:write'])]
protected ?Part $build_part = null;
@ -139,7 +139,7 @@ class Project extends AbstractStructuralDBElement
/**
* @var Collection<int, ProjectAttachment>
*/
#[ORM\OneToMany(targetEntity: ProjectAttachment::class, mappedBy: 'element', cascade: ['persist', 'remove'], orphanRemoval: true)]
#[ORM\OneToMany(mappedBy: 'element', targetEntity: ProjectAttachment::class, cascade: ['persist', 'remove'], orphanRemoval: true)]
#[ORM\OrderBy(['name' => 'ASC'])]
#[Groups(['project:read', 'project:write'])]
protected Collection $attachments;
@ -151,7 +151,7 @@ class Project extends AbstractStructuralDBElement
/** @var Collection<int, ProjectParameter>
*/
#[ORM\OneToMany(targetEntity: ProjectParameter::class, mappedBy: 'element', cascade: ['persist', 'remove'], orphanRemoval: true)]
#[ORM\OneToMany(mappedBy: 'element', targetEntity: ProjectParameter::class, cascade: ['persist', 'remove'], orphanRemoval: true)]
#[ORM\OrderBy(['group' => 'ASC', 'name' => 'ASC'])]
#[Groups(['project:read', 'project:write'])]
protected Collection $parameters;

View file

@ -59,11 +59,11 @@ use Symfony\Component\Validator\Context\ExecutionContextInterface;
#[ORM\Table('project_bom_entries')]
#[ApiResource(
operations: [
new Get(security: 'is_granted("read", object)', uriTemplate: '/project_bom_entries/{id}.{_format}',),
new GetCollection(security: 'is_granted("@projects.read")', uriTemplate: '/project_bom_entries.{_format}',),
new Post(securityPostDenormalize: 'is_granted("create", object)', uriTemplate: '/project_bom_entries.{_format}',),
new Patch(security: 'is_granted("edit", object)', uriTemplate: '/project_bom_entries/{id}.{_format}',),
new Delete(security: 'is_granted("delete", object)', uriTemplate: '/project_bom_entries/{id}.{_format}',),
new Get(uriTemplate: '/project_bom_entries/{id}.{_format}', security: 'is_granted("read", object)',),
new GetCollection(uriTemplate: '/project_bom_entries.{_format}', security: 'is_granted("@projects.read")',),
new Post(uriTemplate: '/project_bom_entries.{_format}', securityPostDenormalize: 'is_granted("create", object)',),
new Patch(uriTemplate: '/project_bom_entries/{id}.{_format}', security: 'is_granted("edit", object)',),
new Delete(uriTemplate: '/project_bom_entries/{id}.{_format}', security: 'is_granted("delete", object)',),
],
normalizationContext: ['groups' => ['bom_entry:read', 'api:basic:read'], 'openapi_definition_name' => 'Read'],
denormalizationContext: ['groups' => ['bom_entry:write', 'api:basic:write'], 'openapi_definition_name' => 'Write'],
@ -90,14 +90,14 @@ class ProjectBOMEntry extends AbstractDBElement implements UniqueValidatableInte
use TimestampTrait;
#[Assert\Positive]
#[ORM\Column(type: Types::FLOAT, name: 'quantity')]
#[ORM\Column(name: 'quantity', type: Types::FLOAT)]
#[Groups(['bom_entry:read', 'bom_entry:write'])]
protected float $quantity = 1.0;
/**
* @var string A comma separated list of the names, where this parts should be placed
*/
#[ORM\Column(type: Types::TEXT, name: 'mountnames')]
#[ORM\Column(name: 'mountnames', type: Types::TEXT)]
#[Groups(['bom_entry:read', 'bom_entry:write'])]
protected string $mountnames = '';

View file

@ -45,12 +45,12 @@ use Symfony\Component\Validator\Constraints as Assert;
*/
#[ORM\Entity]
#[ORM\Table('`groups`')]
#[ORM\Index(name: 'group_idx_name', columns: ['name'])]
#[ORM\Index(name: 'group_idx_parent_name', columns: ['parent_id', 'name'])]
#[NoLockout()]
#[ORM\Index(columns: ['name'], name: 'group_idx_name')]
#[ORM\Index(columns: ['parent_id', 'name'], name: 'group_idx_parent_name')]
#[NoLockout]
class Group extends AbstractStructuralDBElement implements HasPermissionsInterface
{
#[ORM\OneToMany(targetEntity: self::class, mappedBy: 'parent')]
#[ORM\OneToMany(mappedBy: 'parent', targetEntity: self::class)]
#[ORM\OrderBy(['name' => 'ASC'])]
protected Collection $children;
@ -61,21 +61,21 @@ class Group extends AbstractStructuralDBElement implements HasPermissionsInterfa
/**
* @var Collection<int, User>
*/
#[ORM\OneToMany(targetEntity: User::class, mappedBy: 'group')]
#[ORM\OneToMany(mappedBy: 'group', targetEntity: User::class)]
protected Collection $users;
/**
* @var bool If true all users associated with this group must have enabled some kind of two-factor authentication
*/
#[Groups(['extended', 'full', 'import'])]
#[ORM\Column(type: Types::BOOLEAN, name: 'enforce_2fa')]
#[ORM\Column(name: 'enforce_2fa', type: Types::BOOLEAN)]
protected bool $enforce2FA = false;
/**
* @var Collection<int, GroupAttachment>
*/
#[Assert\Valid]
#[ORM\OneToMany(targetEntity: GroupAttachment::class, mappedBy: 'element', cascade: ['persist', 'remove'], orphanRemoval: true)]
#[ORM\OneToMany(mappedBy: 'element', targetEntity: GroupAttachment::class, cascade: ['persist', 'remove'], orphanRemoval: true)]
#[ORM\OrderBy(['name' => 'ASC'])]
protected Collection $attachments;
@ -85,14 +85,14 @@ class Group extends AbstractStructuralDBElement implements HasPermissionsInterfa
#[Groups(['full'])]
#[ORM\Embedded(class: PermissionData::class, columnPrefix: 'permissions_')]
#[ValidPermission()]
#[ValidPermission]
protected ?PermissionData $permissions = null;
/**
* @var Collection<int, GroupParameter>
*/
#[Assert\Valid]
#[ORM\OneToMany(targetEntity: GroupParameter::class, mappedBy: 'element', cascade: ['persist', 'remove'], orphanRemoval: true)]
#[ORM\OneToMany(mappedBy: 'element', targetEntity: GroupParameter::class, cascade: ['persist', 'remove'], orphanRemoval: true)]
#[ORM\OrderBy(['group' => 'ASC', 'name' => 'ASC'])]
protected Collection $parameters;

View file

@ -57,7 +57,7 @@ final class PermissionData implements \JsonSerializable
* operation => value,
* ]
*/
#[ORM\Column(type: Types::JSON, name: 'data')]
#[ORM\Column(name: 'data', type: Types::JSON)]
protected array $data = []
)
{

View file

@ -22,6 +22,7 @@ declare(strict_types=1);
namespace App\Entity\UserSystem;
use ApiPlatform\Doctrine\Common\Filter\DateFilterInterface;
use ApiPlatform\Doctrine\Orm\Filter\DateFilter;
use ApiPlatform\Doctrine\Orm\Filter\OrderFilter;
use ApiPlatform\Doctrine\Orm\Filter\SearchFilter;
@ -80,7 +81,7 @@ use Jbtronics\TFAWebauthn\Model\TwoFactorInterface as WebauthnTwoFactorInterface
#[ORM\Entity(repositoryClass: UserRepository::class)]
#[ORM\EntityListeners([TreeCacheInvalidationListener::class])]
#[ORM\Table('`users`')]
#[ORM\Index(name: 'user_idx_username', columns: ['name'])]
#[ORM\Index(columns: ['name'], name: 'user_idx_username')]
#[ORM\AttributeOverrides([
new ORM\AttributeOverride(name: 'name', column: new ORM\Column(type: Types::STRING, length: 180, unique: true))
])]
@ -100,9 +101,9 @@ use Jbtronics\TFAWebauthn\Model\TwoFactorInterface as WebauthnTwoFactorInterface
)]
#[ApiFilter(PropertyFilter::class)]
#[ApiFilter(LikeFilter::class, properties: ["name", "aboutMe"])]
#[ApiFilter(DateFilter::class, strategy: DateFilter::EXCLUDE_NULL)]
#[ApiFilter(DateFilter::class, strategy: DateFilterInterface::EXCLUDE_NULL)]
#[ApiFilter(OrderFilter::class, properties: ['name', 'id', 'addedDate', 'lastModified'])]
#[NoLockout()]
#[NoLockout]
class User extends AttachmentContainingDBElement implements UserInterface, HasPermissionsInterface, TwoFactorInterface,
BackupCodeInterface, TrustedDeviceInterface, WebauthnTwoFactorInterface, PreferredProviderInterface, PasswordAuthenticatedUserInterface, SamlUserInterface
{
@ -133,8 +134,8 @@ class User extends AttachmentContainingDBElement implements UserInterface, HasPe
* @var string|null The theme
*/
#[Groups(['full', 'import', 'user:read'])]
#[ORM\Column(type: Types::STRING, name: 'config_theme', nullable: true)]
#[ValidTheme()]
#[ORM\Column(name: 'config_theme', type: Types::STRING, nullable: true)]
#[ValidTheme]
protected ?string $theme = null;
/**
@ -143,10 +144,10 @@ class User extends AttachmentContainingDBElement implements UserInterface, HasPe
#[ORM\Column(type: Types::STRING, nullable: true)]
protected ?string $pw_reset_token = null;
#[ORM\Column(type: Types::TEXT, name: 'config_instock_comment_a')]
#[ORM\Column(name: 'config_instock_comment_a', type: Types::TEXT)]
protected string $instock_comment_a = '';
#[ORM\Column(type: Types::TEXT, name: 'config_instock_comment_w')]
#[ORM\Column(name: 'config_instock_comment_w', type: Types::TEXT)]
protected string $instock_comment_w = '';
/**
@ -189,7 +190,7 @@ class User extends AttachmentContainingDBElement implements UserInterface, HasPe
*/
#[Assert\Timezone]
#[Groups(['full', 'import', 'user:read'])]
#[ORM\Column(type: Types::STRING, name: 'config_timezone', nullable: true)]
#[ORM\Column(name: 'config_timezone', type: Types::STRING, nullable: true)]
protected ?string $timezone = '';
/**
@ -197,7 +198,7 @@ class User extends AttachmentContainingDBElement implements UserInterface, HasPe
*/
#[Assert\Language]
#[Groups(['full', 'import', 'user:read'])]
#[ORM\Column(type: Types::STRING, name: 'config_language', nullable: true)]
#[ORM\Column(name: 'config_language', type: Types::STRING, nullable: true)]
protected ?string $language = '';
/**
@ -310,7 +311,7 @@ class User extends AttachmentContainingDBElement implements UserInterface, HasPe
#[Groups(['simple', 'extended', 'full', 'import'])]
#[ORM\Embedded(class: 'PermissionData', columnPrefix: 'permissions_')]
#[ValidPermission()]
#[ValidPermission]
protected ?PermissionData $permissions = null;
/**