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
checkFunctionNameCase: true
checkAlwaysTrueInstanceof: false
checkAlwaysTrueCheckTypeFunctionCall: false
checkAlwaysTrueStrictComparison: false
reportAlwaysTrueInLastCondition: false
reportMaybesInPropertyPhpDocTypes: false
reportMaybesInMethodSignatures: false
strictRules:
disallowedLooseComparison: false
booleansInConditions: false
uselessCast: false
requireParentConstructorCall: true
disallowedConstructs: false
overwriteVariablesWithLoop: true
overwriteVariablesWithLoop: false
closureUsesThis: false
matchingInheritedMethodNames: true
numericOperandsInArithmeticOperators: true

View file

@ -121,7 +121,7 @@ class CheckRequirementsCommand extends Command
}
$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.');
} else {
if (!$only_issues) {
@ -130,7 +130,7 @@ class CheckRequirementsCommand extends Command
$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');
} else {
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!');
}
if (!in_array('curl', $extensions)) {
if (!in_array('curl', $extensions, true)) {
$io->warning('curl extension is not installed. Install curl extension for better performance');
} elseif (!$only_issues) {
$io->success('PHP extension curl is installed.');
}
$gd_installed = in_array('gd', $extensions);
$gd_installed = in_array('gd', $extensions, true);
if (!$gd_installed) {
$io->error('GD is not installed. GD is required for image processing.');
} 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. '
. '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);
$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. '
. '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);
$this->entityManager->flush();

View file

@ -79,13 +79,13 @@ class UserListCommand extends Command
foreach ($users as $user) {
$table->addRow([
$user->getId(),
$user->getID(),
$user->getUsername(),
$user->getFullName(),
$user->getEmail(),
$user->getGroup() instanceof Group ? $user->getGroup()->getName() . ' (ID: ' . $user->getGroup()->getID() . ')' : 'No group',
$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;
}
$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);

View file

@ -402,7 +402,7 @@ abstract class BaseAdminController extends AbstractController
{
$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;

View file

@ -59,7 +59,7 @@ class GroupController extends BaseAdminController
//Handle permissions presets
if ($request->request->has('permission_preset')) {
$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');
$permissionPresetsHelper->applyPreset($entity, $preset);

View file

@ -113,7 +113,7 @@ class LogController extends AbstractController
{
$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
$entityManager->remove($logEntry);
//Flush changes

View file

@ -183,7 +183,7 @@ class PartController extends AbstractController
{
$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));

View file

@ -83,6 +83,6 @@ class RedirectController extends AbstractController
}
//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')) {
//Check if the admin has the needed permissions
$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
$entity->setGoogleAuthenticatorSecret(null);
$entity->setBackupCodes([]);
@ -96,7 +96,7 @@ class UserController extends BaseAdminController
foreach ($entity->getLegacyU2FKeys() as $key) {
$em->remove($key);
}
foreach ($entity->getWebAuthnKeys() as $key) {
foreach ($entity->getWebauthnKeys() as $key) {
$em->remove($key);
}
//Invalidate trusted devices
@ -115,7 +115,7 @@ class UserController extends BaseAdminController
//Handle permissions presets
if ($request->request->has('permission_preset')) {
$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');
$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!');
}
if ($this->isCsrfTokenValid('delete'.$user->getId(), $request->request->get('_token'))) {
if ($this->isCsrfTokenValid('delete'.$user->getID(), $request->request->get('_token'))) {
//Handle U2F key removal
if ($request->request->has('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!');
}
if ($this->isCsrfTokenValid('devices_reset'.$user->getId(), $request->request->get('_token'))) {
if ($this->isCsrfTokenValid('devices_reset'.$user->getID(), $request->request->get('_token'))) {
$user->invalidateTrustedDeviceTokens();
$entityManager->flush();
$this->addFlash('success', 'tfa_trustedDevice.invalidate.success');

View file

@ -39,7 +39,7 @@ use Omines\DataTablesBundle\Adapter\Doctrine\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;
@ -50,6 +50,6 @@ class CustomFetchJoinORMAdapter extends FetchJoinORMAdapter
$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
* @return mixed
*/
public function normalize($value)
public function normalize($value): mixed
{
/** @var AbstractNamedDBElement $value */
return $value;
}
public function configureOptions(OptionsResolver $resolver): self
/**
* @return $this
*/
public function configureOptions(OptionsResolver $resolver): static
{
parent::configureOptions($resolver);

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -29,6 +29,9 @@ use Symfony\Component\OptionsResolver\OptionsResolver;
class RowClassColumn extends AbstractColumn
{
/**
* @return $this
*/
public function configureOptions(OptionsResolver $resolver): self
{
parent::configureOptions($resolver);
@ -44,7 +47,7 @@ class RowClassColumn extends AbstractColumn
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
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
{
parent::configureOptions($resolver);

View file

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

View file

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

View file

@ -29,19 +29,13 @@ use Doctrine\ORM\QueryBuilder;
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;
/** @var ParameterValueConstraint */
protected ParameterValueConstraint $value;
/** @var string The alias to use for the subquery */

View file

@ -123,7 +123,7 @@ class LogDataTable implements DataTableTypeInterface
'label' => 'log.timestamp',
'timeFormat' => 'medium',
'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
)
]);

View file

@ -36,15 +36,14 @@ class BigDecimalType extends Type
return $platform->getDecimalTypeDeclarationSQL($fieldDeclaration);
}
/**
* @param string|null $value
*/
public function convertToPHPValue(mixed $value, AbstractPlatform $platform): ?BigNumber
{
if (null === $value) {
return null;
}
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).
*
* @return AttachmentContainingDBElement the associated Element
* @return AttachmentContainingDBElement|null the associated Element
* @phpstan-return T|null
*/
public function getElement(): ?AttachmentContainingDBElement
{
@ -360,7 +361,6 @@ abstract class Attachment extends AbstractNamedDBElement
/**
* Sets the element that is associated with this attachment.
*
* @return $this
*/
public function setElement(AttachmentContainingDBElement $element): self
@ -437,7 +437,7 @@ abstract class Attachment extends AbstractNamedDBElement
$tmp = explode('/', $path);
//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.
* @extends Attachment<Currency>
*/
#[UniqueEntity(['name', 'attachment_type', 'element'])]
#[ORM\Entity]
class CurrencyAttachment extends Attachment
{
final public const ALLOWED_ELEMENT_CLASS = Currency::class;
/**
* @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.
* @extends Attachment<Footprint>
*/
#[UniqueEntity(['name', 'attachment_type', 'element'])]
#[ORM\Entity]
class FootprintAttachment extends Attachment
{
final public const ALLOWED_ELEMENT_CLASS = Footprint::class;
/**
* @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.
* @extends Attachment<Group>
*/
#[UniqueEntity(['name', 'attachment_type', 'element'])]
#[ORM\Entity]

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -27,6 +27,7 @@ use App\Entity\Attachments\AttachmentContainingDBElement;
use App\Entity\Parameters\AbstractParameter;
use App\Entity\Parameters\ParametersTrait;
use App\Repository\AbstractPartsContainingRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Annotation\Groups;
@ -41,4 +42,10 @@ abstract class AbstractPartsContainingDBElement extends AbstractStructuralDBElem
{
#[Groups(['full'])]
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
{
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.
*
* @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
{

View file

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

View file

@ -107,12 +107,12 @@ class PartLot extends AbstractDBElement implements TimeStampableInterface, Named
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]
#[ORM\ManyToOne(targetEntity: Part::class, inversedBy: 'partLots')]
#[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
@ -226,7 +226,7 @@ class PartLot extends AbstractDBElement implements TimeStampableInterface, Named
/**
* Return the part that is stored in this part lot.
*/
public function getPart(): Part
public function getPart(): ?Part
{
return $this->part;
}

View file

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

View file

@ -47,12 +47,9 @@ class ProjectBOMEntry extends AbstractDBElement
{
use TimestampTrait;
/**
* @var float
*/
#[Assert\Positive]
#[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
@ -71,7 +68,7 @@ class ProjectBOMEntry extends AbstractDBElement
* @var string An optional comment for this BOM entry
*/
#[ORM\Column(type: Types::TEXT)]
protected string $comment;
protected string $comment = '';
/**
* @var Project|null

View file

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

View file

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

View file

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

View file

@ -174,10 +174,8 @@ final class ProjectBuildRequest
{
if ($lot instanceof PartLot) {
$lot_id = $lot->getID();
} elseif (is_int($lot)) {
} else { // Then it must be an int
$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)) {

View file

@ -27,6 +27,10 @@ use App\Entity\Base\PartsContainingRepositoryInterface;
use App\Entity\Parts\Part;
use InvalidArgumentException;
/**
* @template TEntityClass of AbstractPartsContainingDBElement
* @extends StructuralDBElementRepository<TEntityClass>
*/
abstract class AbstractPartsContainingRepository extends StructuralDBElementRepository implements PartsContainingRepositoryInterface
{
/** @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;
use App\Entity\Attachments\Attachment;
use Doctrine\ORM\NonUniqueResultException;
use Doctrine\ORM\NoResultException;
/**
* @template TEntityClass of Attachment
* @extends DBElementRepository<TEntityClass>
*/
class AttachmentRepository extends DBElementRepository
{
/**

View file

@ -45,6 +45,10 @@ use App\Entity\Base\AbstractDBElement;
use Doctrine\ORM\EntityRepository;
use ReflectionClass;
/**
* @template TEntityClass of AbstractDBElement
* @extends EntityRepository<TEntityClass>
*/
class DBElementRepository extends EntityRepository
{
/**
@ -53,7 +57,7 @@ class DBElementRepository extends EntityRepository
*
* @param AbstractDBElement $element The element whose ID should be changed
* @phpstan-param TEntityClass $element
* @param int $new_id The new ID
* @param int $new_id The new ID
*/
public function changeID(AbstractDBElement $element, int $new_id): void
{

View file

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

View file

@ -32,6 +32,10 @@ use App\Entity\UserSystem\User;
use DateTime;
use RuntimeException;
/**
* @template TEntityClass of AbstractLogEntry
* @extends DBElementRepository<TEntityClass>
*/
class LogEntryRepository extends DBElementRepository
{
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
{
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;
/**
* @see \App\Tests\Repository\NamedDBElementRepositoryTest
* @template TEntityClass of AbstractNamedDBElement
* @extends DBElementRepository<TEntityClass>
*/
class NamedDBElementRepository extends DBElementRepository
{
@ -66,6 +67,7 @@ class NamedDBElementRepository extends DBElementRepository
/**
* Returns the list of all nodes to use in a select box.
* @return AbstractNamedDBElement[]
* @phpstan-return array<int, AbstractNamedDBElement>
*/
public function toNodesList(): array
{

View file

@ -22,12 +22,19 @@ declare(strict_types=1);
*/
namespace App\Repository;
use App\Entity\Parameters\AbstractParameter;
/**
* @template TEntityClass of AbstractParameter
* @extends DBElementRepository<TEntityClass>
*/
class ParameterRepository extends DBElementRepository
{
/**
* Find parameters using a parameter name
* @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
* @phpstan-return array<array{name: string, symbol: string, unit: string}>
*/
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;
use App\Entity\Parts\Part;
use App\Entity\Parts\PartLot;
use Doctrine\ORM\NonUniqueResultException;
use Doctrine\ORM\NoResultException;
use Doctrine\ORM\QueryBuilder;
/**
* @extends NamedDBElementRepository<Part>
*/
class PartRepository extends NamedDBElementRepository
{
/**
@ -67,6 +71,9 @@ class PartRepository extends NamedDBElementRepository
return (int) ($query->getSingleScalarResult() ?? 0);
}
/**
* @return Part[]
*/
public function autocompleteSearch(string $query, int $max_limits = 50): array
{
$qb = $this->createQueryBuilder('part');

View file

@ -29,6 +29,8 @@ use RecursiveIteratorIterator;
/**
* @see \App\Tests\Repository\StructuralDBElementRepositoryTest
* @template TEntityClass of AbstractStructuralDBElement
* @extends NamedDBElementRepository<TEntityClass>
*/
class StructuralDBElementRepository extends NamedDBElementRepository
{
@ -52,7 +54,8 @@ class StructuralDBElementRepository extends NamedDBElementRepository
* Gets a tree of TreeViewNode elements. The root elements has $parent as parent.
* 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[]
*/
@ -78,8 +81,9 @@ class StructuralDBElementRepository extends NamedDBElementRepository
* 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
*
* @phpstan-param TEntityClass|null $parent
* @return AbstractStructuralDBElement[] a flattened list containing the tree elements
* @phpstan-return array<int, TEntityClass>
*/
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.
* An array of the created elements will be returned, with the last element being the deepest element.
* @return AbstractStructuralDBElement[]
* @phpstan-return array<int, TEntityClass>
*/
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.
* If no element was found, an empty array will be returned.
* @return AbstractStructuralDBElement[]
* @phpstan-return array<int, TEntityClass>
*/
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[] findAll()
* @method User[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
* @extends NamedDBElementRepository<User>
*/
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 ($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'));
}
} elseif ($user instanceof User && $user->isSamlUser()) {

View file

@ -110,7 +110,7 @@ class AttachmentVoter extends ExtendedVoter
$param = 'parts';
}
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;

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
$targetClass = $subject->getTargetClass();
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

View file

@ -63,7 +63,7 @@ class PartLotVoter extends ExtendedVoter
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;

View file

@ -44,7 +44,7 @@ class UserVoter extends ExtendedVoter
$this->resolver->listOperationsForPermission('self'),
['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
if(in_array($ext, self::BLACKLISTED_EXTENSIONS)) {
if(in_array($ext, self::BLACKLISTED_EXTENSIONS, true)) {
$new_path = $this->generateAttachmentPath($attachment, $attachment->isSecure())
.DIRECTORY_SEPARATOR.$this->generateAttachmentFilename($attachment, 'txt');

View file

@ -69,7 +69,7 @@ class FileTypeFilterTools
$element = trim($element);
if (!preg_match('#^\.\w+$#', $element) // .ext 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;
}
}
@ -173,6 +173,6 @@ class FileTypeFilterTools
{
$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
*/
public function getLocalizedTypeLabel($entity): string
public function getLocalizedTypeLabel(object|string $entity): string
{
$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)
foreach ($this->mapping as $class => $translation) {
if (is_a($entity, $class, true)) {
foreach ($this->mapping as $class_to_check => $translation) {
if (is_a($entity, $class_to_check, true)) {
return $translation;
}
}

View file

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

View file

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

View file

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

View file

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

View file

@ -64,7 +64,7 @@ class ProjectBuildHelper
public function getMaximumBuildableCount(Project $project): int
{
$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)
if (!$bom_entry->isPartBomEntry()) {
continue;

View file

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

View file

@ -65,8 +65,6 @@ class PermissionSchemaUpdater
$reflectionClass = new \ReflectionClass(self::class);
try {
$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);
} catch (\ReflectionException $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;
}
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
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 (!$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
$tmp = explode('/', $value);
//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;
}

View file

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