Improved typing and phpdoc type annotations

This commit is contained in:
Jan Böhmer 2023-06-18 15:37:42 +02:00
parent 3817ba774d
commit b7c8ca2a48
39 changed files with 189 additions and 129 deletions

View file

@ -63,7 +63,7 @@ class CheckRequirementsCommand extends Command
} }
protected function checkPHP(SymfonyStyle $io, $only_issues = false): void protected function checkPHP(SymfonyStyle $io, bool $only_issues = false): void
{ {
//Check PHP versions //Check PHP versions
if ($io->isVerbose()) { if ($io->isVerbose()) {
@ -98,7 +98,7 @@ class CheckRequirementsCommand extends Command
} }
} }
protected function checkPartDBConfig(SymfonyStyle $io, $only_issues = false): void protected function checkPartDBConfig(SymfonyStyle $io, bool $only_issues = false): void
{ {
//Check if APP_ENV is set to prod //Check if APP_ENV is set to prod
if ($io->isVerbose()) { if ($io->isVerbose()) {
@ -112,7 +112,7 @@ class CheckRequirementsCommand extends Command
} }
protected function checkPHPExtensions(SymfonyStyle $io, $only_issues = false): void protected function checkPHPExtensions(SymfonyStyle $io, bool $only_issues = false): void
{ {
//Get all installed PHP extensions //Get all installed PHP extensions
$extensions = get_loaded_extensions(); $extensions = get_loaded_extensions();

View file

@ -244,7 +244,7 @@ abstract class BaseAdminController extends AbstractController
return true; return true;
} }
protected function _new(Request $request, EntityManagerInterface $em, EntityImporter $importer, ?AbstractNamedDBElement $entity = null) protected function _new(Request $request, EntityManagerInterface $em, EntityImporter $importer, ?AbstractNamedDBElement $entity = null): Response
{ {
$new_entity = $entity instanceof AbstractNamedDBElement ? clone $entity : new $this->entity_class(); $new_entity = $entity instanceof AbstractNamedDBElement ? clone $entity : new $this->entity_class();

View file

@ -44,11 +44,18 @@ class HomepageController extends AbstractController
public function getBanner(): string public function getBanner(): string
{ {
$banner = $this->getParameter('partdb.banner'); $banner = $this->getParameter('partdb.banner');
if (!is_string($banner)) {
throw new \RuntimeException('The parameter "partdb.banner" must be a string.');
}
if (empty($banner)) { if (empty($banner)) {
$banner_path = $this->kernel->getProjectDir() $banner_path = $this->kernel->getProjectDir()
.DIRECTORY_SEPARATOR.'config'.DIRECTORY_SEPARATOR.'banner.md'; .DIRECTORY_SEPARATOR.'config'.DIRECTORY_SEPARATOR.'banner.md';
return file_get_contents($banner_path); $tmp = file_get_contents($banner_path);
if (false === $tmp) {
throw new \RuntimeException('The banner file could not be read.');
}
$banner = $tmp;
} }
return $banner; return $banner;

View file

@ -66,7 +66,7 @@ class UserSettingsController extends AbstractController
} }
#[Route(path: '/2fa_backup_codes', name: 'show_backup_codes')] #[Route(path: '/2fa_backup_codes', name: 'show_backup_codes')]
public function showBackupCodes() public function showBackupCodes(): Response
{ {
$user = $this->getUser(); $user = $this->getUser();
@ -74,7 +74,7 @@ class UserSettingsController extends AbstractController
$this->denyAccessUnlessGranted('IS_AUTHENTICATED_FULLY'); $this->denyAccessUnlessGranted('IS_AUTHENTICATED_FULLY');
if (!$user instanceof User) { if (!$user instanceof User) {
return new RuntimeException('This controller only works only for Part-DB User objects!'); throw new RuntimeException('This controller only works only for Part-DB User objects!');
} }
if ($user->isSamlUser()) { if ($user->isSamlUser()) {

View file

@ -29,6 +29,7 @@ use Jbtronics\TFAWebauthn\Services\TFAWebauthnRegistrationHelper;
use RuntimeException; use RuntimeException;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route; use Symfony\Component\Routing\Annotation\Route;
use function Symfony\Component\Translation\t; use function Symfony\Component\Translation\t;
@ -40,7 +41,7 @@ class WebauthnKeyRegistrationController extends AbstractController
} }
#[Route(path: '/webauthn/register', name: 'webauthn_register')] #[Route(path: '/webauthn/register', name: 'webauthn_register')]
public function register(Request $request, TFAWebauthnRegistrationHelper $registrationHelper, EntityManagerInterface $em) public function register(Request $request, TFAWebauthnRegistrationHelper $registrationHelper, EntityManagerInterface $em): Response
{ {
//When user change its settings, he should be logged in fully. //When user change its settings, he should be logged in fully.
$this->denyAccessUnlessGranted('IS_AUTHENTICATED_FULLY'); $this->denyAccessUnlessGranted('IS_AUTHENTICATED_FULLY');

View file

@ -48,7 +48,7 @@ class ErrorDataTable implements DataTableTypeInterface
}); });
} }
public function configure(DataTable $dataTable, array $options) public function configure(DataTable $dataTable, array $options): void
{ {
$optionsResolver = new OptionsResolver(); $optionsResolver = new OptionsResolver();
$this->configureOptions($optionsResolver); $this->configureOptions($optionsResolver);
@ -74,7 +74,10 @@ class ErrorDataTable implements DataTableTypeInterface
$dataTable->createAdapter(ArrayAdapter::class, $data); $dataTable->createAdapter(ArrayAdapter::class, $data);
} }
public static function errorTable(DataTableFactory $dataTableFactory, Request $request, $errors): Response /**
* @param string[]|string $errors
*/
public static function errorTable(DataTableFactory $dataTableFactory, Request $request, array|string $errors): Response
{ {
$error_table = $dataTableFactory->createFromType(self::class, ['errors' => $errors]); $error_table = $dataTableFactory->createFromType(self::class, ['errors' => $errors]);
$error_table->handleRequest($request); $error_table->handleRequest($request);

View file

@ -49,7 +49,7 @@ class NumberConstraint extends AbstractConstraint
$this->value2 = $value2; $this->value2 = $value2;
} }
public function getOperator(): string public function getOperator(): string|null
{ {
return $this->operator; return $this->operator;
} }

View file

@ -47,7 +47,7 @@ class ProjectBomEntriesDataTable implements DataTableTypeInterface
} }
public function configure(DataTable $dataTable, array $options) public function configure(DataTable $dataTable, array $options): void
{ {
$dataTable $dataTable
//->add('select', SelectColumn::class) //->add('select', SelectColumn::class)

View file

@ -23,6 +23,7 @@ declare(strict_types=1);
namespace App\Doctrine\Types; namespace App\Doctrine\Types;
use DateTime; use DateTime;
use DateTimeInterface;
use DateTimeZone; use DateTimeZone;
use Doctrine\DBAL\Platforms\AbstractPlatform; use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Types\ConversionException; use Doctrine\DBAL\Types\ConversionException;
@ -58,7 +59,16 @@ class UTCDateTimeType extends DateTimeType
return parent::convertToDatabaseValue($value, $platform); return parent::convertToDatabaseValue($value, $platform);
} }
public function convertToPHPValue($value, AbstractPlatform $platform): ?DateTime /**
* {@inheritDoc}
*
* @param T $value
*
* @return (T is null ? null : DateTimeInterface)
*
* @template T
*/
public function convertToPHPValue($value, AbstractPlatform $platform): ?\DateTimeInterface
{ {
if (!self::$utc_timezone instanceof \DateTimeZone) { if (!self::$utc_timezone instanceof \DateTimeZone) {
self::$utc_timezone = new DateTimeZone('UTC'); self::$utc_timezone = new DateTimeZone('UTC');

View file

@ -80,7 +80,7 @@ abstract class AttachmentContainingDBElement extends AbstractNamedDBElement impl
/** /**
* Gets all attachments associated with this element. * Gets all attachments associated with this element.
* *
* @return Collection<Attachment> * @phpstan-return Collection<int, AT>
*/ */
public function getAttachments(): Collection public function getAttachments(): Collection
{ {

View file

@ -91,8 +91,9 @@ class AttachmentType extends AbstractStructuralDBElement
/** /**
* Get all attachments ("Attachment" objects) with this type. * Get all attachments ("Attachment" objects) with this type.
* *
* @return Collection|Attachment[] all attachments with this type, as a one-dimensional array of Attachments * @return Collection all attachments with this type, as a one-dimensional array of Attachments
* (sorted by their names) * (sorted by their names)
* @phpstan-return Collection<int, Attachment>
*/ */
public function getAttachmentsForType(): Collection public function getAttachmentsForType(): Collection
{ {

View file

@ -249,7 +249,7 @@ abstract class AbstractLogEntry extends AbstractDBElement
/** /**
* Returns the timestamp when the event that caused this log entry happened. * Returns the timestamp when the event that caused this log entry happened.
*/ */
public function getTimestamp(): \DateTimeInterface public function getTimestamp(): \DateTimeInterface|null
{ {
return $this->timestamp; return $this->timestamp;
} }

View file

@ -144,7 +144,7 @@ class Part extends AttachmentContainingDBElement
} }
#[Assert\Callback] #[Assert\Callback]
public function validate(ExecutionContextInterface $context, $payload) public function validate(ExecutionContextInterface $context, $payload): void
{ {
//Ensure that the part name fullfills the regex of the category //Ensure that the part name fullfills the regex of the category
if ($this->category instanceof Category) { if ($this->category instanceof Category) {

View file

@ -322,7 +322,7 @@ class PartLot extends AbstractDBElement implements TimeStampableInterface, Named
} }
#[Assert\Callback] #[Assert\Callback]
public function validate(ExecutionContextInterface $context, $payload) public function validate(ExecutionContextInterface $context, $payload): void
{ {
//Ensure that the owner is not the anonymous user //Ensure that the owner is not the anonymous user
if ($this->getOwner() && $this->getOwner()->isAnonymousUser()) { if ($this->getOwner() && $this->getOwner()->isAnonymousUser()) {

View file

@ -63,8 +63,7 @@ trait InstockTrait
/** /**
* Get all part lots where this part is stored. * Get all part lots where this part is stored.
* * @phpstan-return Collection<int, PartLot>
* @return PartLot[]|Collection
*/ */
public function getPartLots(): Collection public function getPartLots(): Collection
{ {

View file

@ -36,7 +36,7 @@ use Doctrine\ORM\Mapping as ORM;
trait OrderTrait trait OrderTrait
{ {
/** /**
* @var Orderdetail[]|Collection the details about how and where you can order this part * @var Collection<int, Orderdetail> the details about how and where you can order this part
*/ */
#[Assert\Valid] #[Assert\Valid]
#[Groups(['extended', 'full', 'import'])] #[Groups(['extended', 'full', 'import'])]
@ -66,7 +66,7 @@ trait OrderTrait
/** /**
* Get the selected order orderdetails of this part. * Get the selected order orderdetails of this part.
* *
* @return Orderdetail the selected order orderdetails * @return Orderdetail|null the selected order orderdetails
*/ */
public function getOrderOrderdetails(): ?Orderdetail public function getOrderOrderdetails(): ?Orderdetail
{ {

View file

@ -30,7 +30,8 @@ trait ProjectTrait
/** /**
* Returns all ProjectBOMEntries that use this part. * Returns all ProjectBOMEntries that use this part.
* @return Collection<int, ProjectBOMEntry>|ProjectBOMEntry[] *
* @phpstan-return Collection<int, ProjectBOMEntry>
*/ */
public function getProjectBomEntries(): Collection public function getProjectBomEntries(): Collection
{ {

View file

@ -205,8 +205,7 @@ class Orderdetail extends AbstractDBElement implements TimeStampableInterface, N
/** /**
* Get all pricedetails. * Get all pricedetails.
* *
* @return Pricedetail[]|Collection all pricedetails as a one-dimensional array of Pricedetails objects, * @return Collection<int, Pricedetail>
* sorted by minimum discount quantity
*/ */
public function getPricedetails(): Collection public function getPricedetails(): Collection
{ {

View file

@ -183,9 +183,6 @@ class Project extends AbstractStructuralDBElement
return $this; return $this;
} }
/**
* @return Collection<int, ProjectBOMEntry>|ProjectBOMEntry[]
*/
public function getBomEntries(): Collection public function getBomEntries(): Collection
{ {
return $this->bom_entries; return $this->bom_entries;
@ -265,7 +262,7 @@ class Project extends AbstractStructuralDBElement
} }
#[Assert\Callback] #[Assert\Callback]
public function validate(ExecutionContextInterface $context, $payload) public function validate(ExecutionContextInterface $context, $payload): void
{ {
//If this project has subprojects, and these have builds part, they must be included in the BOM //If this project has subprojects, and these have builds part, they must be included in the BOM
foreach ($this->getChildren() as $child) { foreach ($this->getChildren() as $child) {

View file

@ -141,7 +141,7 @@ class U2FKey implements LegacyU2FKeyInterface
/** /**
* Gets the user, this U2F key belongs to. * Gets the user, this U2F key belongs to.
*/ */
public function getUser(): User public function getUser(): User|null
{ {
return $this->user; return $this->user;
} }

View file

@ -470,7 +470,7 @@ class User extends AttachmentContainingDBElement implements UserInterface, HasPe
/** /**
* Gets the datetime when the password reset token expires. * Gets the datetime when the password reset token expires.
*/ */
public function getPwResetExpires(): \DateTimeInterface public function getPwResetExpires(): \DateTimeInterface|null
{ {
return $this->pw_reset_expires; return $this->pw_reset_expires;
} }

View file

@ -162,9 +162,11 @@ class CollectionTypeExtension extends AbstractTypeExtension
/** /**
* Set the option of the form. * Set the option of the form.
* This a bit hacky because we access private properties.... * This a bit hacky because we access private properties....
* * @param FormConfigInterface $builder The form on which the option should be set
* @param string $option The option which should be changed
* @param mixed $value The new value
*/ */
public function setOption(FormConfigInterface $builder, string $option, $value): void public function setOption(FormConfigInterface $builder, string $option, mixed $value): void
{ {
if (!$builder instanceof FormConfigBuilder) { if (!$builder instanceof FormConfigBuilder) {
throw new \RuntimeException('This method only works with FormConfigBuilder instances.'); throw new \RuntimeException('This method only works with FormConfigBuilder instances.');
@ -173,10 +175,8 @@ class CollectionTypeExtension extends AbstractTypeExtension
//We have to use FormConfigBuilder::class here, because options is private and not available in subclasses //We have to use FormConfigBuilder::class here, because options is private and not available in subclasses
$reflection = new ReflectionClass(FormConfigBuilder::class); $reflection = new ReflectionClass(FormConfigBuilder::class);
$property = $reflection->getProperty('options'); $property = $reflection->getProperty('options');
$property->setAccessible(true);
$tmp = $property->getValue($builder); $tmp = $property->getValue($builder);
$tmp[$option] = $value; $tmp[$option] = $value;
$property->setValue($builder, $tmp); $property->setValue($builder, $tmp);
$property->setAccessible(false);
} }
} }

View file

@ -45,7 +45,7 @@ final class PermissionsMapper implements DataMapperInterface
* on the children of compound forms, defining their underlying model data. * on the children of compound forms, defining their underlying model data.
* *
* @param mixed $viewData View data of the compound form being initialized * @param mixed $viewData View data of the compound form being initialized
* @param FormInterface[]|Traversable $forms A list of {@link FormInterface} instances * @param Traversable $forms A list of {@link FormInterface} instances
*/ */
public function mapDataToForms($viewData, \Traversable $forms): void public function mapDataToForms($viewData, \Traversable $forms): void
{ {
@ -90,7 +90,7 @@ final class PermissionsMapper implements DataMapperInterface
* The model data can be an array or an object, so this second argument is always passed * The model data can be an array or an object, so this second argument is always passed
* by reference. * by reference.
* *
* @param FormInterface[]|Traversable $forms A list of {@link FormInterface} instances * @param Traversable $forms A list of {@link FormInterface} instances
* @param mixed $viewData The compound form's view data that get mapped * @param mixed $viewData The compound form's view data that get mapped
* its children model data * its children model data
*/ */

View file

@ -149,7 +149,7 @@ final class SIUnitType extends AbstractType implements DataMapperInterface
* on the children of compound forms, defining their underlying model data. * on the children of compound forms, defining their underlying model data.
* *
* @param mixed $viewData View data of the compound form being initialized * @param mixed $viewData View data of the compound form being initialized
* @param FormInterface[]|Traversable $forms A list of {@link FormInterface} instances * @param Traversable $forms A list of {@link FormInterface} instances
* *
* @throws Exception\UnexpectedTypeException if the type of the data parameter is not supported * @throws Exception\UnexpectedTypeException if the type of the data parameter is not supported
*/ */
@ -198,7 +198,7 @@ final class SIUnitType extends AbstractType implements DataMapperInterface
* The model data can be an array or an object, so this second argument is always passed * The model data can be an array or an object, so this second argument is always passed
* by reference. * by reference.
* *
* @param FormInterface[]|Traversable $forms A list of {@link FormInterface} instances * @param Traversable $forms A list of {@link FormInterface} instances
* @param mixed $viewData The compound form's view data that get mapped * @param mixed $viewData The compound form's view data that get mapped
* its children model data * its children model data
* *

View file

@ -45,7 +45,10 @@ class BigNumberNormalizer implements NormalizerInterface
return (string) $object; return (string) $object;
} }
public function getSupportedTypes(?string $format) /**
* @return bool[]
*/
public function getSupportedTypes(?string $format): array
{ {
return [ return [
BigNumber::class => true, BigNumber::class => true,

View file

@ -68,7 +68,12 @@ class PartNormalizer implements NormalizerInterface, DenormalizerInterface
return $data instanceof Part; return $data instanceof Part;
} }
public function normalize($object, string $format = null, array $context = []): array /**
* @return (float|mixed)[]|\ArrayObject|null|scalar
*
* @psalm-return \ArrayObject|array{total_instock: float|mixed,...}|null|scalar
*/
public function normalize($object, string $format = null, array $context = [])
{ {
if (!$object instanceof Part) { if (!$object instanceof Part) {
throw new \InvalidArgumentException('This normalizer only supports Part objects!'); throw new \InvalidArgumentException('This normalizer only supports Part objects!');
@ -178,7 +183,10 @@ class PartNormalizer implements NormalizerInterface, DenormalizerInterface
return $object; return $object;
} }
public function getSupportedTypes(?string $format) /**
* @return bool[]
*/
public function getSupportedTypes(?string $format): array
{ {
//Must be false, because we rely on is_array($data) in supportsDenormalization() //Must be false, because we rely on is_array($data) in supportsDenormalization()
return [ return [

View file

@ -42,7 +42,12 @@ class StructuralElementFromNameDenormalizer implements DenormalizerInterface
return is_string($data) && is_subclass_of($type, AbstractStructuralDBElement::class); return is_string($data) && is_subclass_of($type, AbstractStructuralDBElement::class);
} }
public function denormalize($data, string $type, string $format = null, array $context = []): ?AbstractStructuralDBElement /**
* @template T
* @phpstan-param class-string<T> $type
* @phpstan-return T|null
*/
public function denormalize($data, string $type, string $format = null, array $context = []): AbstractStructuralDBElement|null
{ {
//Retrieve the repository for the given type //Retrieve the repository for the given type
/** @var StructuralDBElementRepository $repo */ /** @var StructuralDBElementRepository $repo */
@ -69,7 +74,10 @@ class StructuralElementFromNameDenormalizer implements DenormalizerInterface
return end($elements); return end($elements);
} }
public function getSupportedTypes(?string $format) /**
* @return bool[]
*/
public function getSupportedTypes(?string $format): array
{ {
//Cachable value Must be false, because we do an is_string check on data in supportsDenormalization //Cachable value Must be false, because we do an is_string check on data in supportsDenormalization
return [ return [

View file

@ -46,7 +46,10 @@ class StructuralElementNormalizer implements NormalizerInterface
return $data instanceof AbstractStructuralDBElement; return $data instanceof AbstractStructuralDBElement;
} }
public function normalize($object, string $format = null, array $context = []): array /**
* @return array<string, mixed>
*/
public function normalize($object, string $format = null, array $context = [])
{ {
if (!$object instanceof AbstractStructuralDBElement) { if (!$object instanceof AbstractStructuralDBElement) {
throw new \InvalidArgumentException('This normalizer only supports AbstractStructural objects!'); throw new \InvalidArgumentException('This normalizer only supports AbstractStructural objects!');
@ -64,7 +67,10 @@ class StructuralElementNormalizer implements NormalizerInterface
return $data; return $data;
} }
public function getSupportedTypes(?string $format) /**
* @return bool[]
*/
public function getSupportedTypes(?string $format): array
{ {
return [ return [
AbstractStructuralDBElement::class => true, AbstractStructuralDBElement::class => true,

View file

@ -33,8 +33,8 @@ use Symfony\Component\Filesystem\Filesystem;
*/ */
class AttachmentPathResolver class AttachmentPathResolver
{ {
protected ?string $media_path; protected string $media_path;
protected ?string $footprints_path; protected string $footprints_path;
protected ?string $models_path; protected ?string $models_path;
protected ?string $secure_path; protected ?string $secure_path;
@ -54,11 +54,11 @@ class AttachmentPathResolver
*/ */
public function __construct(protected string $project_dir, string $media_path, string $secure_path, ?string $footprints_path, ?string $models_path) public function __construct(protected string $project_dir, string $media_path, string $secure_path, ?string $footprints_path, ?string $models_path)
{ {
//Determine the path for our ressources //Determine the path for our resources
$this->media_path = $this->parameterToAbsolutePath($media_path); $this->media_path = $this->parameterToAbsolutePath($media_path) ?? throw new \InvalidArgumentException('The media path must be set and valid!');
$this->secure_path = $this->parameterToAbsolutePath($secure_path) ?? throw new \InvalidArgumentException('The secure path must be set and valid!');
$this->footprints_path = $this->parameterToAbsolutePath($footprints_path) ; $this->footprints_path = $this->parameterToAbsolutePath($footprints_path) ;
$this->models_path = $this->parameterToAbsolutePath($models_path); $this->models_path = $this->parameterToAbsolutePath($models_path);
$this->secure_path = $this->parameterToAbsolutePath($secure_path);
$this->pathes = [$this->media_path, $this->media_path, $this->footprints_path, $this->models_path, $this->secure_path]; $this->pathes = [$this->media_path, $this->media_path, $this->footprints_path, $this->models_path, $this->secure_path];
//Remove all disabled placeholders //Remove all disabled placeholders
@ -215,7 +215,7 @@ class AttachmentPathResolver
/** /**
* The string where the builtin footprints are stored. * The string where the builtin footprints are stored.
* *
* @return string|null The absolute path to the footprints folder. Null if built footprints were disabled. * @return string|null The absolute path to the footprints' folder. Null if built footprints were disabled.
*/ */
public function getFootprintsPath(): ?string public function getFootprintsPath(): ?string
{ {
@ -225,7 +225,7 @@ class AttachmentPathResolver
/** /**
* The string where the builtin 3D models are stored. * The string where the builtin 3D models are stored.
* *
* @return string|null The absolute path to the models folder. Null if builtin models were disabled. * @return string|null The absolute path to the models' folder. Null if builtin models were disabled.
*/ */
public function getModelsPath(): ?string public function getModelsPath(): ?string
{ {

View file

@ -159,7 +159,7 @@ class EntityURLGenerator
public function viewURL(Attachment $entity): string public function viewURL(Attachment $entity): string
{ {
if ($entity->isExternal()) { //For external attachments, return the link to external path if ($entity->isExternal()) { //For external attachments, return the link to external path
return $entity->getURL(); return $entity->getURL() ?? throw new \RuntimeException('External attachment has no URL!');
} }
//return $this->urlGenerator->generate('attachment_view', ['id' => $entity->getID()]); //return $this->urlGenerator->generate('attachment_view', ['id' => $entity->getID()]);
return $this->attachmentURLGenerator->getViewURL($entity) ?? ''; return $this->attachmentURLGenerator->getViewURL($entity) ?? '';
@ -169,7 +169,7 @@ class EntityURLGenerator
{ {
if ($entity instanceof Attachment) { if ($entity instanceof Attachment) {
if ($entity->isExternal()) { //For external attachments, return the link to external path if ($entity->isExternal()) { //For external attachments, return the link to external path
return $entity->getURL(); return $entity->getURL() ?? throw new \RuntimeException('External attachment has no URL!');
} }
return $this->attachmentURLGenerator->getDownloadURL($entity); return $this->attachmentURLGenerator->getDownloadURL($entity);

View file

@ -61,6 +61,8 @@ final class LabelGenerator
/** /**
* @param object|object[] $elements An element or an array of elements for which labels should be generated * @param object|object[] $elements An element or an array of elements for which labels should be generated
*
* @return null|string
*/ */
public function generateLabel(LabelOptions $options, object|array $elements): string public function generateLabel(LabelOptions $options, object|array $elements): string
{ {
@ -83,7 +85,7 @@ final class LabelGenerator
$dompdf->loadHtml($this->labelHTMLGenerator->getLabelHTML($options, $elements)); $dompdf->loadHtml($this->labelHTMLGenerator->getLabelHTML($options, $elements));
$dompdf->render(); $dompdf->render();
return $dompdf->output(); return $dompdf->output() ?? throw new \RuntimeException('Could not generate label!');
} }
/** /**

View file

@ -80,16 +80,17 @@ final class LabelTextReplacer
* Replaces all placeholders in the input lines. * Replaces all placeholders in the input lines.
* *
* @param string $lines The input lines that should be replaced * @param string $lines The input lines that should be replaced
* @param object $target the object that should be used as source for the informations * @param object $target the object that should be used as source for the information
* *
* @return string the Lines with replaced informations * @return string the Lines with replaced information
*/ */
public function replace(string $lines, object $target): string public function replace(string $lines, object $target): string
{ {
$patterns = [ $patterns = [
'/(\[\[[A-Z_0-9]+\]\])/' => fn($match) => $this->handlePlaceholder($match[0], $target), '/(\[\[[A-Z_0-9]+\]\])/' => fn($match): string => $this->handlePlaceholder($match[0], $target),
]; ];
return preg_replace_callback_array($patterns, $lines); return preg_replace_callback_array($patterns, $lines) ?? throw new \RuntimeException('Could not replace placeholders!');
} }
} }

View file

@ -58,7 +58,7 @@ class HistoryHelper
* Returns an array containing all elements that are associated with the argument. * Returns an array containing all elements that are associated with the argument.
* The returned array contains the given element. * The returned array contains the given element.
* *
* @psalm-return array<AbstractParameter|array-key, mixed> * @return AbstractDBElement[]
*/ */
public function getAssociatedElements(AbstractDBElement $element): array public function getAssociatedElements(AbstractDBElement $element): array
{ {

View file

@ -57,7 +57,11 @@ class LogDiffFormatter
]); ]);
} }
private function diffNumeric($old_data, $new_data): string /**
* @param numeric $old_data
* @param numeric $new_data
*/
private function diffNumeric(int|float|string $old_data, int|float|string $new_data): string
{ {
if ((!is_numeric($old_data)) || (!is_numeric($new_data))) { if ((!is_numeric($old_data)) || (!is_numeric($new_data))) {
throw new \InvalidArgumentException('The given data is not numeric.'); throw new \InvalidArgumentException('The given data is not numeric.');

View file

@ -232,16 +232,17 @@ class TimeTravel
{ {
$reflection = new ReflectionClass($element::class); $reflection = new ReflectionClass($element::class);
$property = $reflection->getProperty($field); $property = $reflection->getProperty($field);
$property->setAccessible(true);
return $property->getValue($element); return $property->getValue($element);
} }
/**
* @param int|null|object $new_value
*/
protected function setField(AbstractDBElement $element, string $field, mixed $new_value): void protected function setField(AbstractDBElement $element, string $field, mixed $new_value): void
{ {
$reflection = new ReflectionClass($element::class); $reflection = new ReflectionClass($element::class);
$property = $reflection->getProperty($field); $property = $reflection->getProperty($field);
$property->setAccessible(true);
$property->setValue($element, $new_value); $property->setValue($element, $new_value);
} }

View file

@ -178,7 +178,7 @@ implode(',', array_map(static fn (PartLot $lot) => $lot->getID(), $part->getPart
* *
* @throws AccessDeniedException * @throws AccessDeniedException
*/ */
private function denyAccessUnlessGranted($attributes, $subject = null, string $message = 'Access Denied.'): void private function denyAccessUnlessGranted(mixed $attributes, mixed $subject = null, string $message = 'Access Denied.'): void
{ {
if (!$this->security->isGranted($attributes, $subject)) { if (!$this->security->isGranted($attributes, $subject)) {
$exception = new AccessDeniedException($message); $exception = new AccessDeniedException($message);

View file

@ -70,8 +70,12 @@ class NodesListBuilder
* The value is cached for performance reasons. * The value is cached for performance reasons.
* *
* @template T of AbstractStructuralDBElement * @template T of AbstractStructuralDBElement
*
* @param T $element * @param T $element
* @return T[] *
* @return AbstractStructuralDBElement[]
*
* @phpstan-return list<T>
*/ */
public function getChildrenFlatList(AbstractStructuralDBElement $element): array public function getChildrenFlatList(AbstractStructuralDBElement $element): array
{ {

View file

@ -43,12 +43,15 @@ class UserAvatarHelper
/** /**
* Returns the URL to the profile picture of the given user (in big size) * Returns the URL to the profile picture of the given user (in big size)
*
* @return string
*/ */
public function getAvatarURL(User $user): string public function getAvatarURL(User $user): string
{ {
//Check if the user has a master attachment defined (meaning he has explicitly defined a profile picture) //Check if the user has a master attachment defined (meaning he has explicitly defined a profile picture)
if ($user->getMasterPictureAttachment() instanceof Attachment) { if ($user->getMasterPictureAttachment() instanceof Attachment) {
return $this->attachmentURLGenerator->getThumbnailURL($user->getMasterPictureAttachment(), 'thumbnail_md'); return $this->attachmentURLGenerator->getThumbnailURL($user->getMasterPictureAttachment(), 'thumbnail_md')
?? throw new RuntimeException('Could not generate thumbnail URL');
} }
//If not check if gravatar is enabled (then use gravatar URL) //If not check if gravatar is enabled (then use gravatar URL)
@ -64,7 +67,8 @@ class UserAvatarHelper
{ {
//Check if the user has a master attachment defined (meaning he has explicitly defined a profile picture) //Check if the user has a master attachment defined (meaning he has explicitly defined a profile picture)
if ($user->getMasterPictureAttachment() instanceof Attachment) { if ($user->getMasterPictureAttachment() instanceof Attachment) {
return $this->attachmentURLGenerator->getThumbnailURL($user->getMasterPictureAttachment(), 'thumbnail_xs'); return $this->attachmentURLGenerator->getThumbnailURL($user->getMasterPictureAttachment(), 'thumbnail_xs')
?? throw new RuntimeException('Could not generate thumbnail URL');;
} }
//If not check if gravatar is enabled (then use gravatar URL) //If not check if gravatar is enabled (then use gravatar URL)
@ -85,7 +89,8 @@ class UserAvatarHelper
{ {
//Check if the user has a master attachment defined (meaning he has explicitly defined a profile picture) //Check if the user has a master attachment defined (meaning he has explicitly defined a profile picture)
if ($user->getMasterPictureAttachment() instanceof Attachment) { if ($user->getMasterPictureAttachment() instanceof Attachment) {
return $this->attachmentURLGenerator->getThumbnailURL($user->getMasterPictureAttachment(), 'thumbnail_sm'); return $this->attachmentURLGenerator->getThumbnailURL($user->getMasterPictureAttachment(), 'thumbnail_sm')
?? throw new RuntimeException('Could not generate thumbnail URL');
} }
//If not check if gravatar is enabled (then use gravatar URL) //If not check if gravatar is enabled (then use gravatar URL)

View file

@ -58,6 +58,10 @@ final class TwigCoreExtension extends AbstractExtension
]; ];
} }
/**
* @param string $enum_class
* @phpstan-param class-string $enum_class
*/
public function getEnumCases(string $enum_class): array public function getEnumCases(string $enum_class): array
{ {
if (!enum_exists($enum_class)) { if (!enum_exists($enum_class)) {
@ -75,12 +79,8 @@ final class TwigCoreExtension extends AbstractExtension
]; ];
} }
public function toArray($object) public function toArray(object|array $object): array
{ {
if(! is_object($object) && ! is_array($object)) {
throw new \InvalidArgumentException('The given variable is not an object or array!');
}
//If it is already an array, we can just return it //If it is already an array, we can just return it
if(is_array($object)) { if(is_array($object)) {
return $object; return $object;