Fixed some more phpstan issues

This commit is contained in:
Jan Böhmer 2023-06-18 00:00:58 +02:00
parent 2f46fbfc7a
commit e8771ea118
77 changed files with 192 additions and 109 deletions

View file

@ -21,13 +21,23 @@ parameters:
checkUninitializedProperties: true checkUninitializedProperties: true
checkFunctionNameCase: true
checkAlwaysTrueInstanceof: false
checkAlwaysTrueCheckTypeFunctionCall: false
checkAlwaysTrueStrictComparison: false
reportAlwaysTrueInLastCondition: false
reportMaybesInPropertyPhpDocTypes: false
reportMaybesInMethodSignatures: false
strictRules: strictRules:
disallowedLooseComparison: false disallowedLooseComparison: false
booleansInConditions: false booleansInConditions: false
uselessCast: false uselessCast: false
requireParentConstructorCall: true requireParentConstructorCall: true
disallowedConstructs: false disallowedConstructs: false
overwriteVariablesWithLoop: true overwriteVariablesWithLoop: false
closureUsesThis: false closureUsesThis: false
matchingInheritedMethodNames: true matchingInheritedMethodNames: true
numericOperandsInArithmeticOperators: true numericOperandsInArithmeticOperators: true

View file

@ -121,7 +121,7 @@ class CheckRequirementsCommand extends Command
} }
$db_drivers_count = 0; $db_drivers_count = 0;
if(!in_array('pdo_mysql', $extensions)) { if(!in_array('pdo_mysql', $extensions, true)) {
$io->error('pdo_mysql is not installed. You will not be able to use MySQL databases.'); $io->error('pdo_mysql is not installed. You will not be able to use MySQL databases.');
} else { } else {
if (!$only_issues) { if (!$only_issues) {
@ -130,7 +130,7 @@ class CheckRequirementsCommand extends Command
$db_drivers_count++; $db_drivers_count++;
} }
if(!in_array('pdo_sqlite', $extensions)) { if(!in_array('pdo_sqlite', $extensions, true)) {
$io->error('pdo_sqlite is not installed. You will not be able to use SQLite. databases'); $io->error('pdo_sqlite is not installed. You will not be able to use SQLite. databases');
} else { } else {
if (!$only_issues) { if (!$only_issues) {
@ -146,13 +146,13 @@ class CheckRequirementsCommand extends Command
$io->error('You have no database drivers installed. You have to install at least one database driver!'); $io->error('You have no database drivers installed. You have to install at least one database driver!');
} }
if (!in_array('curl', $extensions)) { if (!in_array('curl', $extensions, true)) {
$io->warning('curl extension is not installed. Install curl extension for better performance'); $io->warning('curl extension is not installed. Install curl extension for better performance');
} elseif (!$only_issues) { } elseif (!$only_issues) {
$io->success('PHP extension curl is installed.'); $io->success('PHP extension curl is installed.');
} }
$gd_installed = in_array('gd', $extensions); $gd_installed = in_array('gd', $extensions, true);
if (!$gd_installed) { if (!$gd_installed) {
$io->error('GD is not installed. GD is required for image processing.'); $io->error('GD is not installed. GD is required for image processing.');
} elseif (!$only_issues) { } elseif (!$only_issues) {

View file

@ -82,7 +82,7 @@ class ConvertToSAMLUserCommand extends Command
$io->confirm('You are going to convert a SAML user to a local user. This means, that the user can only login via the login form. ' $io->confirm('You are going to convert a SAML user to a local user. This means, that the user can only login via the login form. '
. 'The permissions and groups settings of the user will remain unchanged. Do you really want to continue?'); . 'The permissions and groups settings of the user will remain unchanged. Do you really want to continue?');
$user->setSAMLUser(false); $user->setSamlUser(false);
$user->setPassword(SamlUserFactory::SAML_PASSWORD_PLACEHOLDER); $user->setPassword(SamlUserFactory::SAML_PASSWORD_PLACEHOLDER);
$this->entityManager->flush(); $this->entityManager->flush();
@ -97,7 +97,7 @@ class ConvertToSAMLUserCommand extends Command
$io->confirm('You are going to convert a local user to a SAML user. This means, that the user can only login via SAML afterwards. The password in the DB will be removed. ' $io->confirm('You are going to convert a local user to a SAML user. This means, that the user can only login via SAML afterwards. The password in the DB will be removed. '
. 'The permissions and groups settings of the user will remain unchanged. Do you really want to continue?'); . 'The permissions and groups settings of the user will remain unchanged. Do you really want to continue?');
$user->setSAMLUser(true); $user->setSamlUser(true);
$user->setPassword(SamlUserFactory::SAML_PASSWORD_PLACEHOLDER); $user->setPassword(SamlUserFactory::SAML_PASSWORD_PLACEHOLDER);
$this->entityManager->flush(); $this->entityManager->flush();

View file

@ -79,13 +79,13 @@ class UserListCommand extends Command
foreach ($users as $user) { foreach ($users as $user) {
$table->addRow([ $table->addRow([
$user->getId(), $user->getID(),
$user->getUsername(), $user->getUsername(),
$user->getFullName(), $user->getFullName(),
$user->getEmail(), $user->getEmail(),
$user->getGroup() instanceof Group ? $user->getGroup()->getName() . ' (ID: ' . $user->getGroup()->getID() . ')' : 'No group', $user->getGroup() instanceof Group ? $user->getGroup()->getName() . ' (ID: ' . $user->getGroup()->getID() . ')' : 'No group',
$user->isDisabled() ? 'Yes' : 'No', $user->isDisabled() ? 'Yes' : 'No',
$user->isSAMLUser() ? 'SAML' : 'Local', $user->isSamlUser() ? 'SAML' : 'Local',
]); ]);
} }

View file

@ -73,7 +73,7 @@ class UsersPermissionsCommand extends Command
return Command::FAILURE; return Command::FAILURE;
} }
$io->note(sprintf('Found user %s with ID %d', $user->getFullName(true), $user->getId())); $io->note(sprintf('Found user %s with ID %d', $user->getFullName(true), $user->getID()));
$edit_mapping = $this->renderPermissionTable($output, $user, $inherit); $edit_mapping = $this->renderPermissionTable($output, $user, $inherit);

View file

@ -402,7 +402,7 @@ abstract class BaseAdminController extends AbstractController
{ {
$this->denyAccessUnlessGranted('delete', $entity); $this->denyAccessUnlessGranted('delete', $entity);
if ($this->isCsrfTokenValid('delete'.$entity->getId(), $request->request->get('_token'))) { if ($this->isCsrfTokenValid('delete'.$entity->getID(), $request->request->get('_token'))) {
$entityManager = $this->entityManager; $entityManager = $this->entityManager;

View file

@ -59,7 +59,7 @@ class GroupController extends BaseAdminController
//Handle permissions presets //Handle permissions presets
if ($request->request->has('permission_preset')) { if ($request->request->has('permission_preset')) {
$this->denyAccessUnlessGranted('edit_permissions', $entity); $this->denyAccessUnlessGranted('edit_permissions', $entity);
if ($this->isCsrfTokenValid('group'.$entity->getId(), $request->request->get('_token'))) { if ($this->isCsrfTokenValid('group'.$entity->getID(), $request->request->get('_token'))) {
$preset = $request->request->get('permission_preset'); $preset = $request->request->get('permission_preset');
$permissionPresetsHelper->applyPreset($entity, $preset); $permissionPresetsHelper->applyPreset($entity, $preset);

View file

@ -113,7 +113,7 @@ class LogController extends AbstractController
{ {
$this->denyAccessUnlessGranted('delete', $logEntry); $this->denyAccessUnlessGranted('delete', $logEntry);
if ($this->isCsrfTokenValid('delete'.$logEntry->getId(), $request->request->get('_token'))) { if ($this->isCsrfTokenValid('delete'.$logEntry->getID(), $request->request->get('_token'))) {
//Remove part //Remove part
$entityManager->remove($logEntry); $entityManager->remove($logEntry);
//Flush changes //Flush changes

View file

@ -183,7 +183,7 @@ class PartController extends AbstractController
{ {
$this->denyAccessUnlessGranted('delete', $part); $this->denyAccessUnlessGranted('delete', $part);
if ($this->isCsrfTokenValid('delete'.$part->getId(), $request->request->get('_token'))) { if ($this->isCsrfTokenValid('delete'.$part->getID(), $request->request->get('_token'))) {
$this->commentHelper->setMessage($request->request->get('log_comment', null)); $this->commentHelper->setMessage($request->request->get('log_comment', null));

View file

@ -83,6 +83,6 @@ class RedirectController extends AbstractController
} }
//Check if the mod_rewrite module is loaded //Check if the mod_rewrite module is loaded
return in_array('mod_rewrite', apache_get_modules(), false); return in_array('mod_rewrite', apache_get_modules(), true);
} }
} }

View file

@ -88,7 +88,7 @@ class UserController extends BaseAdminController
if ($request->request->has('reset_2fa')) { if ($request->request->has('reset_2fa')) {
//Check if the admin has the needed permissions //Check if the admin has the needed permissions
$this->denyAccessUnlessGranted('set_password', $entity); $this->denyAccessUnlessGranted('set_password', $entity);
if ($this->isCsrfTokenValid('reset_2fa'.$entity->getId(), $request->request->get('_token'))) { if ($this->isCsrfTokenValid('reset_2fa'.$entity->getID(), $request->request->get('_token'))) {
//Disable Google authenticator //Disable Google authenticator
$entity->setGoogleAuthenticatorSecret(null); $entity->setGoogleAuthenticatorSecret(null);
$entity->setBackupCodes([]); $entity->setBackupCodes([]);
@ -96,7 +96,7 @@ class UserController extends BaseAdminController
foreach ($entity->getLegacyU2FKeys() as $key) { foreach ($entity->getLegacyU2FKeys() as $key) {
$em->remove($key); $em->remove($key);
} }
foreach ($entity->getWebAuthnKeys() as $key) { foreach ($entity->getWebauthnKeys() as $key) {
$em->remove($key); $em->remove($key);
} }
//Invalidate trusted devices //Invalidate trusted devices
@ -115,7 +115,7 @@ class UserController extends BaseAdminController
//Handle permissions presets //Handle permissions presets
if ($request->request->has('permission_preset')) { if ($request->request->has('permission_preset')) {
$this->denyAccessUnlessGranted('edit_permissions', $entity); $this->denyAccessUnlessGranted('edit_permissions', $entity);
if ($this->isCsrfTokenValid('reset_2fa'.$entity->getId(), $request->request->get('_token'))) { if ($this->isCsrfTokenValid('reset_2fa'.$entity->getID(), $request->request->get('_token'))) {
$preset = $request->request->get('permission_preset'); $preset = $request->request->get('permission_preset');
$permissionPresetsHelper->applyPreset($entity, $preset); $permissionPresetsHelper->applyPreset($entity, $preset);

View file

@ -112,7 +112,7 @@ class UserSettingsController extends AbstractController
throw new RuntimeException('You can not remove U2F keys from SAML users!'); throw new RuntimeException('You can not remove U2F keys from SAML users!');
} }
if ($this->isCsrfTokenValid('delete'.$user->getId(), $request->request->get('_token'))) { if ($this->isCsrfTokenValid('delete'.$user->getID(), $request->request->get('_token'))) {
//Handle U2F key removal //Handle U2F key removal
if ($request->request->has('key_id')) { if ($request->request->has('key_id')) {
$key_id = $request->request->get('key_id'); $key_id = $request->request->get('key_id');
@ -186,7 +186,7 @@ class UserSettingsController extends AbstractController
throw new RuntimeException('You can not remove U2F keys from SAML users!'); throw new RuntimeException('You can not remove U2F keys from SAML users!');
} }
if ($this->isCsrfTokenValid('devices_reset'.$user->getId(), $request->request->get('_token'))) { if ($this->isCsrfTokenValid('devices_reset'.$user->getID(), $request->request->get('_token'))) {
$user->invalidateTrustedDeviceTokens(); $user->invalidateTrustedDeviceTokens();
$entityManager->flush(); $entityManager->flush();
$this->addFlash('success', 'tfa_trustedDevice.invalidate.success'); $this->addFlash('success', 'tfa_trustedDevice.invalidate.success');

View file

@ -39,7 +39,7 @@ use Omines\DataTablesBundle\Adapter\Doctrine\FetchJoinORMAdapter;
*/ */
class CustomFetchJoinORMAdapter extends FetchJoinORMAdapter class CustomFetchJoinORMAdapter extends FetchJoinORMAdapter
{ {
public function getCount(QueryBuilder $queryBuilder, $identifier): ?int public function getCount(QueryBuilder $queryBuilder, $identifier): int
{ {
$qb_without_group_by = clone $queryBuilder; $qb_without_group_by = clone $queryBuilder;
@ -50,6 +50,6 @@ class CustomFetchJoinORMAdapter extends FetchJoinORMAdapter
$paginator = new Paginator($qb_without_group_by); $paginator = new Paginator($qb_without_group_by);
return $paginator->count(); return $paginator->count() ?? 0;
} }
} }

View file

@ -41,13 +41,16 @@ class EntityColumn extends AbstractColumn
* @param mixed $value The single value of the column * @param mixed $value The single value of the column
* @return mixed * @return mixed
*/ */
public function normalize($value) public function normalize($value): mixed
{ {
/** @var AbstractNamedDBElement $value */ /** @var AbstractNamedDBElement $value */
return $value; return $value;
} }
public function configureOptions(OptionsResolver $resolver): self /**
* @return $this
*/
public function configureOptions(OptionsResolver $resolver): static
{ {
parent::configureOptions($resolver); parent::configureOptions($resolver);

View file

@ -50,12 +50,15 @@ class IconLinkColumn extends AbstractColumn
* @param $value * @param $value
* @return mixed * @return mixed
*/ */
public function normalize($value) public function normalize($value): mixed
{ {
return $value; return $value;
} }
public function configureOptions(OptionsResolver $resolver): self /**
* @return $this
*/
public function configureOptions(OptionsResolver $resolver): static
{ {
parent::configureOptions($resolver); parent::configureOptions($resolver);
$resolver->setDefaults([ $resolver->setDefaults([

View file

@ -79,6 +79,9 @@ class LocaleDateTimeColumn extends AbstractColumn
); );
} }
/**
* @return $this
*/
protected function configureOptions(OptionsResolver $resolver): self protected function configureOptions(OptionsResolver $resolver): self
{ {
parent::configureOptions($resolver); parent::configureOptions($resolver);

View file

@ -36,7 +36,7 @@ class LogEntryExtraColumn extends AbstractColumn
* @param $value * @param $value
* @return mixed * @return mixed
*/ */
public function normalize($value) public function normalize($value): mixed
{ {
return $value; return $value;
} }

View file

@ -52,11 +52,14 @@ class LogEntryTargetColumn extends AbstractColumn
* @param $value * @param $value
* @return mixed * @return mixed
*/ */
public function normalize($value) public function normalize($value): mixed
{ {
return $value; return $value;
} }
/**
* @return $this
*/
public function configureOptions(OptionsResolver $resolver): self public function configureOptions(OptionsResolver $resolver): self
{ {
parent::configureOptions($resolver); parent::configureOptions($resolver);

View file

@ -37,7 +37,7 @@ class MarkdownColumn extends AbstractColumn
* @param mixed $value The single value of the column * @param mixed $value The single value of the column
* @return mixed * @return mixed
*/ */
public function normalize($value) public function normalize($value): mixed
{ {
return $this->markdown->markForRendering($value, true); return $this->markdown->markForRendering($value, true);
} }

View file

@ -43,7 +43,7 @@ class PartAttachmentsColumn extends AbstractColumn
* @param mixed $value The single value of the column * @param mixed $value The single value of the column
* @return mixed * @return mixed
*/ */
public function normalize($value) public function normalize($value): mixed
{ {
return $value; return $value;
} }
@ -79,6 +79,9 @@ class PartAttachmentsColumn extends AbstractColumn
return $tmp; return $tmp;
} }
/**
* @return $this
*/
public function configureOptions(OptionsResolver $resolver): self public function configureOptions(OptionsResolver $resolver): self
{ {
parent::configureOptions($resolver); parent::configureOptions($resolver);

View file

@ -59,7 +59,7 @@ class RevertLogColumn extends AbstractColumn
* @param $value * @param $value
* @return mixed * @return mixed
*/ */
public function normalize($value) public function normalize($value): mixed
{ {
return $value; return $value;
} }

View file

@ -29,6 +29,9 @@ use Symfony\Component\OptionsResolver\OptionsResolver;
class RowClassColumn extends AbstractColumn class RowClassColumn extends AbstractColumn
{ {
/**
* @return $this
*/
public function configureOptions(OptionsResolver $resolver): self public function configureOptions(OptionsResolver $resolver): self
{ {
parent::configureOptions($resolver); parent::configureOptions($resolver);
@ -44,7 +47,7 @@ class RowClassColumn extends AbstractColumn
return $this; return $this;
} }
public function initialize(string $name, int $index, array $options, DataTable $dataTable) public function initialize(string $name, int $index, array $options, DataTable $dataTable): void
{ {
//The field name is always "$$rowClass" as this is the name the frontend controller expects //The field name is always "$$rowClass" as this is the name the frontend controller expects
parent::initialize('$$rowClass', $index, $options, $dataTable); // TODO: Change the autogenerated stub parent::initialize('$$rowClass', $index, $options, $dataTable); // TODO: Change the autogenerated stub

View file

@ -32,6 +32,9 @@ class SIUnitNumberColumn extends AbstractColumn
{ {
} }
/**
* @return $this
*/
public function configureOptions(OptionsResolver $resolver): self public function configureOptions(OptionsResolver $resolver): self
{ {
parent::configureOptions($resolver); parent::configureOptions($resolver);

View file

@ -30,6 +30,9 @@ use Symfony\Component\OptionsResolver\OptionsResolver;
*/ */
class SelectColumn extends AbstractColumn class SelectColumn extends AbstractColumn
{ {
/**
* @return $this
*/
public function configureOptions(OptionsResolver $resolver): self public function configureOptions(OptionsResolver $resolver): self
{ {
parent::configureOptions($resolver); parent::configureOptions($resolver);
@ -48,7 +51,7 @@ class SelectColumn extends AbstractColumn
/** /**
* @return mixed * @return mixed
*/ */
public function normalize($value) public function normalize($value): mixed
{ {
return $value; return $value;
} }

View file

@ -37,7 +37,7 @@ class TagsColumn extends AbstractColumn
* @param mixed $value The single value of the column * @param mixed $value The single value of the column
* @return mixed * @return mixed
*/ */
public function normalize($value) public function normalize($value): mixed
{ {
if (empty($value)) { if (empty($value)) {
return []; return [];
@ -48,6 +48,10 @@ class TagsColumn extends AbstractColumn
public function render($tags, $context): string public function render($tags, $context): string
{ {
if (!is_iterable($tags)) {
throw new \LogicException('TagsColumn::render() expects an iterable');
}
$html = ''; $html = '';
$count = 10; $count = 10;
foreach ($tags as $tag) { foreach ($tags as $tag) {

View file

@ -29,19 +29,13 @@ use Doctrine\ORM\QueryBuilder;
class ParameterConstraint extends AbstractConstraint class ParameterConstraint extends AbstractConstraint
{ {
/** @var string */ protected string $name = '';
protected string $name;
/** @var string */ protected string $symbol = '';
protected string $symbol;
/** @var string */ protected string $unit = '';
protected string $unit;
/** @var TextConstraint */
protected TextConstraint $value_text; protected TextConstraint $value_text;
/** @var ParameterValueConstraint */
protected ParameterValueConstraint $value; protected ParameterValueConstraint $value;
/** @var string The alias to use for the subquery */ /** @var string The alias to use for the subquery */

View file

@ -123,7 +123,7 @@ class LogDataTable implements DataTableTypeInterface
'label' => 'log.timestamp', 'label' => 'log.timestamp',
'timeFormat' => 'medium', 'timeFormat' => 'medium',
'render' => fn(string $value, AbstractLogEntry $context): string => sprintf('<a href="%s">%s</a>', 'render' => fn(string $value, AbstractLogEntry $context): string => sprintf('<a href="%s">%s</a>',
$this->urlGenerator->generate('log_details', ['id' => $context->getId()]), $this->urlGenerator->generate('log_details', ['id' => $context->getID()]),
$value $value
) )
]); ]);

View file

@ -36,15 +36,14 @@ class BigDecimalType extends Type
return $platform->getDecimalTypeDeclarationSQL($fieldDeclaration); return $platform->getDecimalTypeDeclarationSQL($fieldDeclaration);
} }
/**
* @param string|null $value
*/
public function convertToPHPValue(mixed $value, AbstractPlatform $platform): ?BigNumber public function convertToPHPValue(mixed $value, AbstractPlatform $platform): ?BigNumber
{ {
if (null === $value) { if (null === $value) {
return null; return null;
} }
return BigDecimal::of($value); return BigDecimal::of($value);
} }

View file

@ -242,7 +242,8 @@ abstract class Attachment extends AbstractNamedDBElement
/** /**
* Get the element, associated with this Attachment (for example a "Part" object). * Get the element, associated with this Attachment (for example a "Part" object).
* *
* @return AttachmentContainingDBElement the associated Element * @return AttachmentContainingDBElement|null the associated Element
* @phpstan-return T|null
*/ */
public function getElement(): ?AttachmentContainingDBElement public function getElement(): ?AttachmentContainingDBElement
{ {
@ -360,7 +361,6 @@ abstract class Attachment extends AbstractNamedDBElement
/** /**
* Sets the element that is associated with this attachment. * Sets the element that is associated with this attachment.
*
* @return $this * @return $this
*/ */
public function setElement(AttachmentContainingDBElement $element): self public function setElement(AttachmentContainingDBElement $element): self
@ -437,7 +437,7 @@ abstract class Attachment extends AbstractNamedDBElement
$tmp = explode('/', $path); $tmp = explode('/', $path);
//Builtins must have a %PLACEHOLDER% construction //Builtins must have a %PLACEHOLDER% construction
return in_array($tmp[0], static::BUILTIN_PLACEHOLDER, false); return in_array($tmp[0], static::BUILTIN_PLACEHOLDER, true);
} }
/** /**

View file

@ -28,12 +28,14 @@ use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
/** /**
* An attachment attached to a currency element. * An attachment attached to a currency element.
* @extends Attachment<Currency>
*/ */
#[UniqueEntity(['name', 'attachment_type', 'element'])] #[UniqueEntity(['name', 'attachment_type', 'element'])]
#[ORM\Entity] #[ORM\Entity]
class CurrencyAttachment extends Attachment class CurrencyAttachment extends Attachment
{ {
final public const ALLOWED_ELEMENT_CLASS = Currency::class; final public const ALLOWED_ELEMENT_CLASS = Currency::class;
/** /**
* @var Currency|null the element this attachment is associated with * @var Currency|null the element this attachment is associated with
*/ */

View file

@ -28,12 +28,14 @@ use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
/** /**
* An attachment attached to a footprint element. * An attachment attached to a footprint element.
* @extends Attachment<Footprint>
*/ */
#[UniqueEntity(['name', 'attachment_type', 'element'])] #[UniqueEntity(['name', 'attachment_type', 'element'])]
#[ORM\Entity] #[ORM\Entity]
class FootprintAttachment extends Attachment class FootprintAttachment extends Attachment
{ {
final public const ALLOWED_ELEMENT_CLASS = Footprint::class; final public const ALLOWED_ELEMENT_CLASS = Footprint::class;
/** /**
* @var Footprint|null the element this attachment is associated with * @var Footprint|null the element this attachment is associated with
*/ */

View file

@ -28,6 +28,7 @@ use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
/** /**
* An attachment attached to a Group element. * An attachment attached to a Group element.
* @extends Attachment<Group>
*/ */
#[UniqueEntity(['name', 'attachment_type', 'element'])] #[UniqueEntity(['name', 'attachment_type', 'element'])]
#[ORM\Entity] #[ORM\Entity]

View file

@ -47,6 +47,7 @@ use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
/** /**
* A attachment attached to a user element. * A attachment attached to a user element.
* @extends Attachment<LabelProfile>
*/ */
#[UniqueEntity(['name', 'attachment_type', 'element'])] #[UniqueEntity(['name', 'attachment_type', 'element'])]
#[ORM\Entity] #[ORM\Entity]

View file

@ -28,6 +28,7 @@ use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
/** /**
* An attachment attached to a manufacturer element. * An attachment attached to a manufacturer element.
* @extends Attachment<Manufacturer>
*/ */
#[UniqueEntity(['name', 'attachment_type', 'element'])] #[UniqueEntity(['name', 'attachment_type', 'element'])]
#[ORM\Entity] #[ORM\Entity]

View file

@ -29,6 +29,7 @@ use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
/** /**
* An attachment attached to a measurement unit element. * An attachment attached to a measurement unit element.
* @extends Attachment<MeasurementUnit>
*/ */
#[UniqueEntity(['name', 'attachment_type', 'element'])] #[UniqueEntity(['name', 'attachment_type', 'element'])]
#[ORM\Entity] #[ORM\Entity]

View file

@ -28,6 +28,7 @@ use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
/** /**
* A attachment attached to a part element. * A attachment attached to a part element.
* @extends Attachment<Part>
*/ */
#[UniqueEntity(['name', 'attachment_type', 'element'])] #[UniqueEntity(['name', 'attachment_type', 'element'])]
#[ORM\Entity] #[ORM\Entity]

View file

@ -28,6 +28,7 @@ use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
/** /**
* A attachment attached to a device element. * A attachment attached to a device element.
* @extends Attachment<Project>
*/ */
#[UniqueEntity(['name', 'attachment_type', 'element'])] #[UniqueEntity(['name', 'attachment_type', 'element'])]
#[ORM\Entity] #[ORM\Entity]

View file

@ -28,6 +28,7 @@ use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
/** /**
* An attachment attached to a measurement unit element. * An attachment attached to a measurement unit element.
* @extends Attachment<Storelocation>
*/ */
#[UniqueEntity(['name', 'attachment_type', 'element'])] #[UniqueEntity(['name', 'attachment_type', 'element'])]
#[ORM\Entity] #[ORM\Entity]

View file

@ -28,6 +28,7 @@ use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
/** /**
* A attachment attached to a supplier element. * A attachment attached to a supplier element.
* @extends Attachment<Supplier>
*/ */
#[UniqueEntity(['name', 'attachment_type', 'element'])] #[UniqueEntity(['name', 'attachment_type', 'element'])]
#[ORM\Entity] #[ORM\Entity]

View file

@ -28,6 +28,7 @@ use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
/** /**
* An attachment attached to a user element. * An attachment attached to a user element.
* @extends Attachment<User>
*/ */
#[UniqueEntity(['name', 'attachment_type', 'element'])] #[UniqueEntity(['name', 'attachment_type', 'element'])]
#[ORM\Entity] #[ORM\Entity]

View file

@ -27,6 +27,7 @@ use App\Entity\Attachments\AttachmentContainingDBElement;
use App\Entity\Parameters\AbstractParameter; use App\Entity\Parameters\AbstractParameter;
use App\Entity\Parameters\ParametersTrait; use App\Entity\Parameters\ParametersTrait;
use App\Repository\AbstractPartsContainingRepository; use App\Repository\AbstractPartsContainingRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection; use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM; use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Annotation\Groups; use Symfony\Component\Serializer\Annotation\Groups;
@ -41,4 +42,10 @@ abstract class AbstractPartsContainingDBElement extends AbstractStructuralDBElem
{ {
#[Groups(['full'])] #[Groups(['full'])]
protected Collection $parameters; protected Collection $parameters;
public function __construct()
{
parent::__construct();
$this->parameters = new ArrayCollection();
}
} }

View file

@ -195,7 +195,7 @@ abstract class AbstractStructuralDBElement extends AttachmentContainingDBElement
*/ */
public function isRoot(): bool public function isRoot(): bool
{ {
return !$this->parent instanceof \App\Entity\Base\AbstractStructuralDBElement; return $this->parent === null;
} }
/****************************************************************************** /******************************************************************************
@ -207,7 +207,7 @@ abstract class AbstractStructuralDBElement extends AttachmentContainingDBElement
/** /**
* Get the parent of this element. * Get the parent of this element.
* *
* @return AbstractStructuralDBElement|null The parent element. Null if this element, does not have a parent. * @return static|null The parent element. Null if this element, does not have a parent.
*/ */
public function getParent(): ?self public function getParent(): ?self
{ {

View file

@ -50,6 +50,8 @@ use Symfony\Component\Validator\Context\ExecutionContextInterface;
* The class properties are split over various traits in directory PartTraits. * The class properties are split over various traits in directory PartTraits.
* Otherwise, this class would be too big, to be maintained. * Otherwise, this class would be too big, to be maintained.
* @see \App\Tests\Entity\Parts\PartTest * @see \App\Tests\Entity\Parts\PartTest
* @extends AttachmentContainingDBElement<PartAttachment>
* @template-use ParametersTrait<PartParameter>
*/ */
#[UniqueEntity(fields: ['ipn'], message: 'part.ipn.must_be_unique')] #[UniqueEntity(fields: ['ipn'], message: 'part.ipn.must_be_unique')]
#[ORM\Entity(repositoryClass: PartRepository::class)] #[ORM\Entity(repositoryClass: PartRepository::class)]

View file

@ -107,12 +107,12 @@ class PartLot extends AbstractDBElement implements TimeStampableInterface, Named
protected bool $needs_refill = false; protected bool $needs_refill = false;
/** /**
* @var Part The part that is stored in this lot * @var Part|null The part that is stored in this lot
*/ */
#[Assert\NotNull] #[Assert\NotNull]
#[ORM\ManyToOne(targetEntity: Part::class, inversedBy: 'partLots')] #[ORM\ManyToOne(targetEntity: Part::class, inversedBy: 'partLots')]
#[ORM\JoinColumn(name: 'id_part', nullable: false, onDelete: 'CASCADE')] #[ORM\JoinColumn(name: 'id_part', nullable: false, onDelete: 'CASCADE')]
protected Part $part; protected ?Part $part = null;
/** /**
* @var User|null The owner of this part lot * @var User|null The owner of this part lot
@ -226,7 +226,7 @@ class PartLot extends AbstractDBElement implements TimeStampableInterface, Named
/** /**
* Return the part that is stored in this part lot. * Return the part that is stored in this part lot.
*/ */
public function getPart(): Part public function getPart(): ?Part
{ {
return $this->part; return $this->part;
} }

View file

@ -188,7 +188,7 @@ trait InstockTrait
$sum = 0; $sum = 0;
foreach ($this->getPartLots() as $lot) { foreach ($this->getPartLots() as $lot) {
//Don't use the in stock value, if it is unknown //Don't use the in stock value, if it is unknown
if ($lot->isInstockUnknown() || $lot->isExpired() ?? false) { if ($lot->isInstockUnknown() || ($lot->isExpired() ?? false)) {
continue; continue;
} }

View file

@ -47,12 +47,9 @@ class ProjectBOMEntry extends AbstractDBElement
{ {
use TimestampTrait; use TimestampTrait;
/**
* @var float
*/
#[Assert\Positive] #[Assert\Positive]
#[ORM\Column(type: Types::FLOAT, name: 'quantity')] #[ORM\Column(type: Types::FLOAT, name: 'quantity')]
protected float $quantity; protected float $quantity = 1.0;
/** /**
* @var string A comma separated list of the names, where this parts should be placed * @var string A comma separated list of the names, where this parts should be placed
@ -71,7 +68,7 @@ class ProjectBOMEntry extends AbstractDBElement
* @var string An optional comment for this BOM entry * @var string An optional comment for this BOM entry
*/ */
#[ORM\Column(type: Types::TEXT)] #[ORM\Column(type: Types::TEXT)]
protected string $comment; protected string $comment = '';
/** /**
* @var Project|null * @var Project|null

View file

@ -43,25 +43,25 @@ class U2FKey implements LegacyU2FKeyInterface
* @var string * @var string
**/ **/
#[ORM\Column(type: Types::STRING, length: 128)] #[ORM\Column(type: Types::STRING, length: 128)]
public string $keyHandle; public string $keyHandle = '';
/** /**
* @var string * @var string
**/ **/
#[ORM\Column(type: Types::STRING)] #[ORM\Column(type: Types::STRING)]
public string $publicKey; public string $publicKey = '';
/** /**
* @var string * @var string
**/ **/
#[ORM\Column(type: Types::TEXT)] #[ORM\Column(type: Types::TEXT)]
public string $certificate; public string $certificate = '';
/** /**
* @var int * @var string
**/ **/
#[ORM\Column(type: Types::STRING)] #[ORM\Column(type: Types::STRING)]
public int $counter; public string $counter = '0';
#[ORM\Id] #[ORM\Id]
#[ORM\Column(type: Types::INTEGER)] #[ORM\Column(type: Types::INTEGER)]
@ -72,7 +72,7 @@ class U2FKey implements LegacyU2FKeyInterface
* @var string * @var string
**/ **/
#[ORM\Column(type: Types::STRING)] #[ORM\Column(type: Types::STRING)]
protected string $name; protected string $name = '';
#[ORM\ManyToOne(targetEntity: User::class, inversedBy: 'u2fKeys')] #[ORM\ManyToOne(targetEntity: User::class, inversedBy: 'u2fKeys')]
protected ?User $user = null; protected ?User $user = null;
@ -114,7 +114,7 @@ class U2FKey implements LegacyU2FKeyInterface
return $this; return $this;
} }
public function getCounter(): int public function getCounter(): string
{ {
return $this->counter; return $this->counter;
} }

View file

@ -900,7 +900,7 @@ class User extends AttachmentContainingDBElement implements UserInterface, HasPe
{ {
return new PublicKeyCredentialUserEntity( return new PublicKeyCredentialUserEntity(
$this->getUsername(), $this->getUsername(),
(string) $this->getId(), (string) $this->getID(),
$this->getFullName(), $this->getFullName(),
); );
} }

View file

@ -25,6 +25,7 @@ namespace App\Entity\UserSystem;
use Doctrine\DBAL\Types\Types; use Doctrine\DBAL\Types\Types;
use App\Entity\Base\TimestampTrait; use App\Entity\Base\TimestampTrait;
use Doctrine\ORM\Mapping as ORM; use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints\NotBlank;
use Webauthn\PublicKeyCredentialSource as BasePublicKeyCredentialSource; use Webauthn\PublicKeyCredentialSource as BasePublicKeyCredentialSource;
#[ORM\Entity] #[ORM\Entity]
@ -40,7 +41,8 @@ class WebauthnKey extends BasePublicKeyCredentialSource
protected int $id; protected int $id;
#[ORM\Column(type: Types::STRING)] #[ORM\Column(type: Types::STRING)]
protected string $name; #[NotBlank]
protected string $name = '';
#[ORM\ManyToOne(targetEntity: User::class, inversedBy: 'webauthn_keys')] #[ORM\ManyToOne(targetEntity: User::class, inversedBy: 'webauthn_keys')]
protected ?User $user = null; protected ?User $user = null;

View file

@ -174,10 +174,8 @@ final class ProjectBuildRequest
{ {
if ($lot instanceof PartLot) { if ($lot instanceof PartLot) {
$lot_id = $lot->getID(); $lot_id = $lot->getID();
} elseif (is_int($lot)) { } else { // Then it must be an int
$lot_id = $lot; $lot_id = $lot;
} else {
throw new \InvalidArgumentException('The given lot must be an instance of PartLot or an ID of a PartLot!');
} }
if (! array_key_exists($lot_id, $this->withdraw_amounts)) { if (! array_key_exists($lot_id, $this->withdraw_amounts)) {

View file

@ -27,6 +27,10 @@ use App\Entity\Base\PartsContainingRepositoryInterface;
use App\Entity\Parts\Part; use App\Entity\Parts\Part;
use InvalidArgumentException; use InvalidArgumentException;
/**
* @template TEntityClass of AbstractPartsContainingDBElement
* @extends StructuralDBElementRepository<TEntityClass>
*/
abstract class AbstractPartsContainingRepository extends StructuralDBElementRepository implements PartsContainingRepositoryInterface abstract class AbstractPartsContainingRepository extends StructuralDBElementRepository implements PartsContainingRepositoryInterface
{ {
/** @var int The maximum number of levels for which we can recurse before throwing an error */ /** @var int The maximum number of levels for which we can recurse before throwing an error */

View file

@ -41,9 +41,14 @@ declare(strict_types=1);
namespace App\Repository; namespace App\Repository;
use App\Entity\Attachments\Attachment;
use Doctrine\ORM\NonUniqueResultException; use Doctrine\ORM\NonUniqueResultException;
use Doctrine\ORM\NoResultException; use Doctrine\ORM\NoResultException;
/**
* @template TEntityClass of Attachment
* @extends DBElementRepository<TEntityClass>
*/
class AttachmentRepository extends DBElementRepository class AttachmentRepository extends DBElementRepository
{ {
/** /**

View file

@ -45,6 +45,10 @@ use App\Entity\Base\AbstractDBElement;
use Doctrine\ORM\EntityRepository; use Doctrine\ORM\EntityRepository;
use ReflectionClass; use ReflectionClass;
/**
* @template TEntityClass of AbstractDBElement
* @extends EntityRepository<TEntityClass>
*/
class DBElementRepository extends EntityRepository class DBElementRepository extends EntityRepository
{ {
/** /**

View file

@ -47,6 +47,10 @@ use App\Entity\LabelSystem\LabelSupportedElement;
use App\Helpers\Trees\TreeViewNode; use App\Helpers\Trees\TreeViewNode;
use InvalidArgumentException; use InvalidArgumentException;
/**
* @template TEntityClass of LabelProfile
* @extends NamedDBElementRepository<TEntityClass>
*/
class LabelProfileRepository extends NamedDBElementRepository class LabelProfileRepository extends NamedDBElementRepository
{ {
/** /**

View file

@ -32,6 +32,10 @@ use App\Entity\UserSystem\User;
use DateTime; use DateTime;
use RuntimeException; use RuntimeException;
/**
* @template TEntityClass of AbstractLogEntry
* @extends DBElementRepository<TEntityClass>
*/
class LogEntryRepository extends DBElementRepository class LogEntryRepository extends DBElementRepository
{ {
public function findBy(array $criteria, ?array $orderBy = null, $limit = null, $offset = null): array public function findBy(array $criteria, ?array $orderBy = null, $limit = null, $offset = null): array
@ -60,7 +64,8 @@ class LogEntryRepository extends DBElementRepository
*/ */
public function getElementHistory(AbstractDBElement $element, string $order = 'DESC', ?int $limit = null, ?int $offset = null): array public function getElementHistory(AbstractDBElement $element, string $order = 'DESC', ?int $limit = null, ?int $offset = null): array
{ {
return $this->findBy(['element' => $element], ['timestamp' => $order], $limit, $offset); //@phpstan-ignore-next-line Target is parsed dynamically in findBy
return $this->findBy(['target' => $element], ['timestamp' => $order], $limit, $offset);
} }
/** /**

View file

@ -27,7 +27,8 @@ use App\Entity\UserSystem\User;
use App\Helpers\Trees\TreeViewNode; use App\Helpers\Trees\TreeViewNode;
/** /**
* @see \App\Tests\Repository\NamedDBElementRepositoryTest * @template TEntityClass of AbstractNamedDBElement
* @extends DBElementRepository<TEntityClass>
*/ */
class NamedDBElementRepository extends DBElementRepository class NamedDBElementRepository extends DBElementRepository
{ {
@ -66,6 +67,7 @@ class NamedDBElementRepository extends DBElementRepository
/** /**
* Returns the list of all nodes to use in a select box. * Returns the list of all nodes to use in a select box.
* @return AbstractNamedDBElement[] * @return AbstractNamedDBElement[]
* @phpstan-return array<int, AbstractNamedDBElement>
*/ */
public function toNodesList(): array public function toNodesList(): array
{ {

View file

@ -22,12 +22,19 @@ declare(strict_types=1);
*/ */
namespace App\Repository; namespace App\Repository;
use App\Entity\Parameters\AbstractParameter;
/**
* @template TEntityClass of AbstractParameter
* @extends DBElementRepository<TEntityClass>
*/
class ParameterRepository extends DBElementRepository class ParameterRepository extends DBElementRepository
{ {
/** /**
* Find parameters using a parameter name * Find parameters using a parameter name
* @param string $name The name to search for * @param string $name The name to search for
* @param bool $exact True, if only exact names should match. False, if the name just needs to be contained in the parameter name * @param bool $exact True, if only exact names should match. False, if the name just needs to be contained in the parameter name
* @phpstan-return array<array{name: string, symbol: string, unit: string}>
*/ */
public function autocompleteParamName(string $name, bool $exact = false, int $max_results = 50): array public function autocompleteParamName(string $name, bool $exact = false, int $max_results = 50): array
{ {

View file

@ -22,11 +22,15 @@ declare(strict_types=1);
namespace App\Repository; namespace App\Repository;
use App\Entity\Parts\Part;
use App\Entity\Parts\PartLot; use App\Entity\Parts\PartLot;
use Doctrine\ORM\NonUniqueResultException; use Doctrine\ORM\NonUniqueResultException;
use Doctrine\ORM\NoResultException; use Doctrine\ORM\NoResultException;
use Doctrine\ORM\QueryBuilder; use Doctrine\ORM\QueryBuilder;
/**
* @extends NamedDBElementRepository<Part>
*/
class PartRepository extends NamedDBElementRepository class PartRepository extends NamedDBElementRepository
{ {
/** /**
@ -67,6 +71,9 @@ class PartRepository extends NamedDBElementRepository
return (int) ($query->getSingleScalarResult() ?? 0); return (int) ($query->getSingleScalarResult() ?? 0);
} }
/**
* @return Part[]
*/
public function autocompleteSearch(string $query, int $max_limits = 50): array public function autocompleteSearch(string $query, int $max_limits = 50): array
{ {
$qb = $this->createQueryBuilder('part'); $qb = $this->createQueryBuilder('part');

View file

@ -29,6 +29,8 @@ use RecursiveIteratorIterator;
/** /**
* @see \App\Tests\Repository\StructuralDBElementRepositoryTest * @see \App\Tests\Repository\StructuralDBElementRepositoryTest
* @template TEntityClass of AbstractStructuralDBElement
* @extends NamedDBElementRepository<TEntityClass>
*/ */
class StructuralDBElementRepository extends NamedDBElementRepository class StructuralDBElementRepository extends NamedDBElementRepository
{ {
@ -53,6 +55,7 @@ class StructuralDBElementRepository extends NamedDBElementRepository
* The treeview is generic, that means the href are null and ID values are set. * The treeview is generic, that means the href are null and ID values are set.
* *
* @param AbstractStructuralDBElement|null $parent the parent the root elements should have * @param AbstractStructuralDBElement|null $parent the parent the root elements should have
* @phpstan-param TEntityClass|null $parent
* *
* @return TreeViewNode[] * @return TreeViewNode[]
*/ */
@ -78,8 +81,9 @@ class StructuralDBElementRepository extends NamedDBElementRepository
* Gets a flattened hierarchical tree. Useful for generating option lists. * Gets a flattened hierarchical tree. Useful for generating option lists.
* *
* @param AbstractStructuralDBElement|null $parent This entity will be used as root element. Set to null, to use global root * @param AbstractStructuralDBElement|null $parent This entity will be used as root element. Set to null, to use global root
* * @phpstan-param TEntityClass|null $parent
* @return AbstractStructuralDBElement[] a flattened list containing the tree elements * @return AbstractStructuralDBElement[] a flattened list containing the tree elements
* @phpstan-return array<int, TEntityClass>
*/ */
public function toNodesList(?AbstractStructuralDBElement $parent = null): array public function toNodesList(?AbstractStructuralDBElement $parent = null): array
{ {
@ -104,6 +108,7 @@ class StructuralDBElementRepository extends NamedDBElementRepository
* This function will try to use existing elements, if they are already in the database. If not, they will be created. * This function will try to use existing elements, if they are already in the database. If not, they will be created.
* An array of the created elements will be returned, with the last element being the deepest element. * An array of the created elements will be returned, with the last element being the deepest element.
* @return AbstractStructuralDBElement[] * @return AbstractStructuralDBElement[]
* @phpstan-return array<int, TEntityClass>
*/ */
public function getNewEntityFromPath(string $path, string $separator = '->'): array public function getNewEntityFromPath(string $path, string $separator = '->'): array
{ {
@ -156,6 +161,7 @@ class StructuralDBElementRepository extends NamedDBElementRepository
* An array of the created elements will be returned, with the last element being the deepest element. * An array of the created elements will be returned, with the last element being the deepest element.
* If no element was found, an empty array will be returned. * If no element was found, an empty array will be returned.
* @return AbstractStructuralDBElement[] * @return AbstractStructuralDBElement[]
* @phpstan-return array<int, TEntityClass>
*/ */
public function getEntityByPath(string $path, string $separator = '->'): array public function getEntityByPath(string $path, string $separator = '->'): array
{ {

View file

@ -33,6 +33,7 @@ use Symfony\Component\Security\Core\User\UserInterface;
* @method User|null findOneBy(array $criteria, array $orderBy = null) * @method User|null findOneBy(array $criteria, array $orderBy = null)
* @method User[] findAll() * @method User[] findAll()
* @method User[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null) * @method User[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
* @extends NamedDBElementRepository<User>
*/ */
final class UserRepository extends NamedDBElementRepository implements PasswordUpgraderInterface final class UserRepository extends NamedDBElementRepository implements PasswordUpgraderInterface
{ {

View file

@ -52,7 +52,7 @@ class EnsureSAMLUserForSAMLLoginChecker implements EventSubscriberInterface
//If we are using SAML, we need to check that the user is a SAML user. //If we are using SAML, we need to check that the user is a SAML user.
if ($token instanceof SamlToken) { if ($token instanceof SamlToken) {
if ($user instanceof User && !$user->isSAMLUser()) { if ($user instanceof User && !$user->isSamlUser()) {
throw new CustomUserMessageAccountStatusException($this->translator->trans('saml.error.cannot_login_local_user_per_saml', [], 'security')); throw new CustomUserMessageAccountStatusException($this->translator->trans('saml.error.cannot_login_local_user_per_saml', [], 'security'));
} }
} elseif ($user instanceof User && $user->isSamlUser()) { } elseif ($user instanceof User && $user->isSamlUser()) {

View file

@ -110,7 +110,7 @@ class AttachmentVoter extends ExtendedVoter
$param = 'parts'; $param = 'parts';
} }
else { else {
throw new RuntimeException('Encountered unknown Parameter type: ' . (is_object($subject) ? $subject::class : $subject)); throw new RuntimeException('Encountered unknown Parameter type: ' . $subject);
} }
return $this->resolver->inherit($user, $param, $this->mapOperation($attribute)) ?? false; return $this->resolver->inherit($user, $param, $this->mapOperation($attribute)) ?? false;

View file

@ -63,7 +63,7 @@ class LogEntryVoter extends ExtendedVoter
//To view details of a element related log entry, the user needs to be able to view the history of this entity type //To view details of a element related log entry, the user needs to be able to view the history of this entity type
$targetClass = $subject->getTargetClass(); $targetClass = $subject->getTargetClass();
if (null !== $targetClass) { if (null !== $targetClass) {
return $this->security->isGranted('show_history', $targetClass) ?? false; return $this->security->isGranted('show_history', $targetClass);
} }
//In other cases, this behaves like the read permission //In other cases, this behaves like the read permission

View file

@ -63,7 +63,7 @@ class PartLotVoter extends ExtendedVoter
throw new \RuntimeException('This voter can only handle PartLot objects!'); throw new \RuntimeException('This voter can only handle PartLot objects!');
} }
if (in_array($attribute, ['withdraw', 'add', 'move'])) if (in_array($attribute, ['withdraw', 'add', 'move'], true))
{ {
$base_permission = $this->resolver->inherit($user, 'parts_stock', $attribute) ?? false; $base_permission = $this->resolver->inherit($user, 'parts_stock', $attribute) ?? false;

View file

@ -44,7 +44,7 @@ class UserVoter extends ExtendedVoter
$this->resolver->listOperationsForPermission('self'), $this->resolver->listOperationsForPermission('self'),
['info'] ['info']
), ),
false true
); );
} }

View file

@ -220,7 +220,7 @@ class AttachmentSubmitHandler
//Check if the extension is blacklisted and replace the file extension with txt if needed //Check if the extension is blacklisted and replace the file extension with txt if needed
if(in_array($ext, self::BLACKLISTED_EXTENSIONS)) { if(in_array($ext, self::BLACKLISTED_EXTENSIONS, true)) {
$new_path = $this->generateAttachmentPath($attachment, $attachment->isSecure()) $new_path = $this->generateAttachmentPath($attachment, $attachment->isSecure())
.DIRECTORY_SEPARATOR.$this->generateAttachmentFilename($attachment, 'txt'); .DIRECTORY_SEPARATOR.$this->generateAttachmentFilename($attachment, 'txt');

View file

@ -69,7 +69,7 @@ class FileTypeFilterTools
$element = trim($element); $element = trim($element);
if (!preg_match('#^\.\w+$#', $element) // .ext is allowed if (!preg_match('#^\.\w+$#', $element) // .ext is allowed
&& !preg_match('#^[-\w.]+/[-\w.]+#', $element) //Explicit MIME type is allowed && !preg_match('#^[-\w.]+/[-\w.]+#', $element) //Explicit MIME type is allowed
&& !in_array($element, static::ALLOWED_MIME_PLACEHOLDERS, false)) { //image/* is allowed && !in_array($element, static::ALLOWED_MIME_PLACEHOLDERS, true)) { //image/* is allowed
return false; return false;
} }
} }
@ -173,6 +173,6 @@ class FileTypeFilterTools
{ {
$extension = strtolower($extension); $extension = strtolower($extension);
return $filter === '' || in_array($extension, $this->resolveFileExtensions($filter), false); return $filter === '' || in_array($extension, $this->resolveFileExtensions($filter), true);
} }
} }

View file

@ -95,7 +95,7 @@ class ElementTypeNameGenerator
* *
* @throws EntityNotSupportedException when the passed entity is not supported * @throws EntityNotSupportedException when the passed entity is not supported
*/ */
public function getLocalizedTypeLabel($entity): string public function getLocalizedTypeLabel(object|string $entity): string
{ {
$class = is_string($entity) ? $entity : $entity::class; $class = is_string($entity) ? $entity : $entity::class;
@ -105,8 +105,8 @@ class ElementTypeNameGenerator
} }
//Otherwise iterate over array and check for inheritance (needed when the proxy element from doctrine are passed) //Otherwise iterate over array and check for inheritance (needed when the proxy element from doctrine are passed)
foreach ($this->mapping as $class => $translation) { foreach ($this->mapping as $class_to_check => $translation) {
if (is_a($entity, $class, true)) { if (is_a($entity, $class_to_check, true)) {
return $translation; return $translation;
} }
} }

View file

@ -172,7 +172,7 @@ class EntityURLGenerator
return $entity->getURL(); return $entity->getURL();
} }
return $this->attachmentURLGenerator->getDownloadURL($entity) ?? ''; return $this->attachmentURLGenerator->getDownloadURL($entity);
} }
//Otherwise throw an error //Otherwise throw an error

View file

@ -99,7 +99,6 @@ final class BarcodeGenerator
BarcodeType::CODE39 => 'C39', BarcodeType::CODE39 => 'C39',
BarcodeType::CODE93 => 'C93', BarcodeType::CODE93 => 'C93',
BarcodeType::CODE128 => 'C128A', BarcodeType::CODE128 => 'C128A',
default => throw new InvalidArgumentException('Unknown label type!'),
}; };
if ($type === null) { if ($type === null) {

View file

@ -62,7 +62,6 @@ final class LabelExampleElementsGenerator
LabelSupportedElement::PART => $this->getExamplePart(), LabelSupportedElement::PART => $this->getExamplePart(),
LabelSupportedElement::PART_LOT => $this->getExamplePartLot(), LabelSupportedElement::PART_LOT => $this->getExamplePartLot(),
LabelSupportedElement::STORELOCATION => $this->getStorelocation(), LabelSupportedElement::STORELOCATION => $this->getStorelocation(),
default => throw new InvalidArgumentException('Unknown $type.'),
}; };
} }

View file

@ -75,7 +75,7 @@ class LogTargetHelper
if (!$target instanceof AbstractDBElement) { if (!$target instanceof AbstractDBElement) {
if ($context->hasTarget()) { if ($context->hasTarget()) {
return $this->elementTypeNameGenerator->formatElementDeletedHTML($context->getTargetClass(), return $this->elementTypeNameGenerator->formatElementDeletedHTML($context->getTargetClass(),
$context->getTargetId()); $context->getTargetID());
} }
//If no target is set, we can't do anything //If no target is set, we can't do anything
return ''; return '';

View file

@ -64,7 +64,7 @@ class ProjectBuildHelper
public function getMaximumBuildableCount(Project $project): int public function getMaximumBuildableCount(Project $project): int
{ {
$maximum_buildable_count = PHP_INT_MAX; $maximum_buildable_count = PHP_INT_MAX;
foreach ($project->getBOMEntries() as $bom_entry) { foreach ($project->getBomEntries() as $bom_entry) {
//Skip BOM entries without a part (as we can not determine that) //Skip BOM entries without a part (as we can not determine that)
if (!$bom_entry->isPartBomEntry()) { if (!$bom_entry->isPartBomEntry()) {
continue; continue;

View file

@ -172,19 +172,13 @@ class PermissionPresetsHelper
return $perm_holder; return $perm_holder;
} }
/** private function allForbid(HasPermissionsInterface $perm_holder): HasPermissionsInterface
* @phpstan-api
*/
private function AllForbid(HasPermissionsInterface $perm_holder): HasPermissionsInterface
{ {
$this->permissionResolver->setAllPermissions($perm_holder, PermissionData::DISALLOW); $this->permissionResolver->setAllPermissions($perm_holder, PermissionData::DISALLOW);
return $perm_holder; return $perm_holder;
} }
/** private function allAllow(HasPermissionsInterface $perm_holder): HasPermissionsInterface
* @phpstan-api
*/
private function AllAllow(HasPermissionsInterface $perm_holder): HasPermissionsInterface
{ {
$this->permissionResolver->setAllPermissions($perm_holder, PermissionData::ALLOW); $this->permissionResolver->setAllPermissions($perm_holder, PermissionData::ALLOW);
return $perm_holder; return $perm_holder;

View file

@ -65,8 +65,6 @@ class PermissionSchemaUpdater
$reflectionClass = new \ReflectionClass(self::class); $reflectionClass = new \ReflectionClass(self::class);
try { try {
$method = $reflectionClass->getMethod('upgradeSchemaToVersion'.($n + 1)); $method = $reflectionClass->getMethod('upgradeSchemaToVersion'.($n + 1));
//Set the method accessible, so we can call it (needed for PHP < 8.1)
$method->setAccessible(true);
$method->invoke($this, $holder); $method->invoke($this, $holder);
} catch (\ReflectionException $e) { } catch (\ReflectionException $e) {
throw new \RuntimeException('Could not find update method for schema version '.($n + 1), $e->getCode(), $e); throw new \RuntimeException('Could not find update method for schema version '.($n + 1), $e->getCode(), $e);
@ -114,7 +112,7 @@ class PermissionSchemaUpdater
return $updated; return $updated;
} }
private function upgradeSchemaToVersion1(HasPermissionsInterface $holder): void private function upgradeSchemaToVersion1(HasPermissionsInterface $holder): void //@phpstan-ignore-line This is called via reflection
{ {
//Use the part edit permission to set the preset value for the new part stock permission //Use the part edit permission to set the preset value for the new part stock permission
if ( if (
@ -131,7 +129,7 @@ class PermissionSchemaUpdater
} }
} }
private function upgradeSchemaToVersion2(HasPermissionsInterface $holder): void private function upgradeSchemaToVersion2(HasPermissionsInterface $holder): void //@phpstan-ignore-line This is called via reflection
{ {
//If the projects permissions are not defined yet, rename devices permission to projects (just copy its data over) //If the projects permissions are not defined yet, rename devices permission to projects (just copy its data over)
if (!$holder->getPermissions()->isAnyOperationOfPermissionSet('projects')) { if (!$holder->getPermissions()->isAnyOperationOfPermissionSet('projects')) {

View file

@ -57,7 +57,7 @@ class UrlOrBuiltinValidator extends UrlValidator
//After the %PLACEHOLDER% comes a slash, so we can check if we have a placholder via explode //After the %PLACEHOLDER% comes a slash, so we can check if we have a placholder via explode
$tmp = explode('/', $value); $tmp = explode('/', $value);
//Builtins must have a %PLACEHOLDER% construction //Builtins must have a %PLACEHOLDER% construction
if (in_array($tmp[0], $constraint->allowed_placeholders, false)) { if (in_array($tmp[0], $constraint->allowed_placeholders, true)) {
return; return;
} }

View file

@ -30,8 +30,6 @@ use Symfony\Component\Validator\ConstraintValidator;
class ValidPermissionValidator extends ConstraintValidator class ValidPermissionValidator extends ConstraintValidator
{ {
protected array $perm_structure;
public function __construct(protected PermissionManager $resolver) public function __construct(protected PermissionManager $resolver)
{ {
} }