Applied rector with PHP8.1 migration rules

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

View file

@ -35,11 +35,8 @@ use function strlen;
*/
class AttachmentManager
{
protected AttachmentPathResolver $pathResolver;
public function __construct(AttachmentPathResolver $pathResolver)
public function __construct(protected AttachmentPathResolver $pathResolver)
{
$this->pathResolver = $pathResolver;
}
/**

View file

@ -32,14 +32,12 @@ use Symfony\Component\Filesystem\Filesystem;
*/
class AttachmentPathResolver
{
protected string $project_dir;
protected ?string $media_path;
protected ?string $footprints_path;
protected ?string $models_path;
protected ?string $secure_path;
protected array $placeholders;
protected array $placeholders = ['%MEDIA%', '%BASE%/data/media', '%FOOTPRINTS%', '%FOOTPRINTS_3D%', '%SECURE%'];
protected array $pathes;
protected array $placeholders_regex;
protected array $pathes_regex;
@ -53,18 +51,13 @@ class AttachmentPathResolver
* Set to null if this ressource should be disabled.
* @param string|null $models_path set to null if this ressource should be disabled
*/
public function __construct(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)
{
$this->project_dir = $project_dir;
//Determine the path for our ressources
$this->media_path = $this->parameterToAbsolutePath($media_path);
$this->footprints_path = $this->parameterToAbsolutePath($footprints_path);
$this->models_path = $this->parameterToAbsolutePath($models_path);
$this->secure_path = $this->parameterToAbsolutePath($secure_path);
//Here we define the valid placeholders and their replacement values
$this->placeholders = ['%MEDIA%', '%BASE%/data/media', '%FOOTPRINTS%', '%FOOTPRINTS_3D%', '%SECURE%'];
$this->pathes = [$this->media_path, $this->media_path, $this->footprints_path, $this->models_path, $this->secure_path];
//Remove all disabled placeholders
@ -248,7 +241,7 @@ class AttachmentPathResolver
$ret = [];
foreach ($array as $item) {
$item = str_replace(['\\'], ['/'], $item);
$item = str_replace(['\\'], ['/'], (string) $item);
$ret[] = '/'.preg_quote($item, '/').'/';
}

View file

@ -34,18 +34,8 @@ use Symfony\Component\Filesystem\Filesystem;
*/
class AttachmentReverseSearch
{
protected EntityManagerInterface $em;
protected AttachmentPathResolver $pathResolver;
protected CacheManager $cacheManager;
protected AttachmentURLGenerator $attachmentURLGenerator;
public function __construct(EntityManagerInterface $em, AttachmentPathResolver $pathResolver,
CacheManager $cacheManager, AttachmentURLGenerator $attachmentURLGenerator)
public function __construct(protected EntityManagerInterface $em, protected AttachmentPathResolver $pathResolver, protected CacheManager $cacheManager, protected AttachmentURLGenerator $attachmentURLGenerator)
{
$this->em = $em;
$this->pathResolver = $pathResolver;
$this->cacheManager = $cacheManager;
$this->attachmentURLGenerator = $attachmentURLGenerator;
}
/**

View file

@ -55,16 +55,7 @@ use Symfony\Contracts\HttpClient\HttpClientInterface;
*/
class AttachmentSubmitHandler
{
protected AttachmentPathResolver $pathResolver;
protected array $folder_mapping;
protected bool $allow_attachments_downloads;
protected HttpClientInterface $httpClient;
protected MimeTypesInterface $mimeTypes;
protected FileTypeFilterTools $filterTools;
/**
* @var string The user configured maximum upload size. This is a string like "10M" or "1G" and will be converted to
*/
protected string $max_upload_size;
private ?int $max_upload_size_bytes = null;
@ -72,18 +63,13 @@ class AttachmentSubmitHandler
'asp', 'cgi', 'py', 'pl', 'exe', 'aspx', 'js', 'mjs', 'jsp', 'css', 'jar', 'html', 'htm', 'shtm', 'shtml', 'htaccess',
'htpasswd', ''];
public function __construct(AttachmentPathResolver $pathResolver, bool $allow_attachments_downloads,
HttpClientInterface $httpClient, MimeTypesInterface $mimeTypes,
FileTypeFilterTools $filterTools, string $max_upload_size)
public function __construct(protected AttachmentPathResolver $pathResolver, protected bool $allow_attachments_downloads,
protected HttpClientInterface $httpClient, protected MimeTypesInterface $mimeTypes,
protected FileTypeFilterTools $filterTools, /**
* @var string The user configured maximum upload size. This is a string like "10M" or "1G" and will be converted to
*/
protected string $max_upload_size)
{
$this->pathResolver = $pathResolver;
$this->allow_attachments_downloads = $allow_attachments_downloads;
$this->httpClient = $httpClient;
$this->mimeTypes = $mimeTypes;
$this->max_upload_size = $max_upload_size;
$this->filterTools = $filterTools;
//The mapping used to determine which folder will be used for an attachment type
$this->folder_mapping = [
PartAttachment::class => 'part',
@ -155,25 +141,21 @@ class AttachmentSubmitHandler
*/
public function generateAttachmentPath(Attachment $attachment, bool $secure_upload = false): string
{
if ($secure_upload) {
$base_path = $this->pathResolver->getSecurePath();
} else {
$base_path = $this->pathResolver->getMediaPath();
}
$base_path = $secure_upload ? $this->pathResolver->getSecurePath() : $this->pathResolver->getMediaPath();
//Ensure the given attachment class is known to mapping
if (!isset($this->folder_mapping[get_class($attachment)])) {
throw new InvalidArgumentException('The given attachment class is not known! The passed class was: '.get_class($attachment));
if (!isset($this->folder_mapping[$attachment::class])) {
throw new InvalidArgumentException('The given attachment class is not known! The passed class was: '.$attachment::class);
}
//Ensure the attachment has an assigned element
if (null === $attachment->getElement()) {
if (!$attachment->getElement() instanceof \App\Entity\Attachments\AttachmentContainingDBElement) {
throw new InvalidArgumentException('The given attachment is not assigned to an element! An element is needed to generate a path!');
}
//Build path
return
$base_path.DIRECTORY_SEPARATOR //Base path
.$this->folder_mapping[get_class($attachment)].DIRECTORY_SEPARATOR.$attachment->getElement()->getID();
.$this->folder_mapping[$attachment::class].DIRECTORY_SEPARATOR.$attachment->getElement()->getID();
}
/**
@ -194,7 +176,7 @@ class AttachmentSubmitHandler
$options = $resolver->resolve($options);
//When a file is given then upload it, otherwise check if we need to download the URL
if ($file) {
if ($file instanceof \Symfony\Component\HttpFoundation\File\UploadedFile) {
$this->upload($attachment, $file, $options);
} elseif ($options['download_url'] && $attachment->isExternal()) {
$this->downloadURL($attachment, $options);
@ -210,7 +192,7 @@ class AttachmentSubmitHandler
//this is only possible if the attachment is new (not yet persisted to DB)
if ($options['become_preview_if_empty'] && null === $attachment->getID() && $attachment->isPicture()) {
$element = $attachment->getElement();
if ($element instanceof AttachmentContainingDBElement && null === $element->getMasterPictureAttachment()) {
if ($element instanceof AttachmentContainingDBElement && !$element->getMasterPictureAttachment() instanceof \App\Entity\Attachments\Attachment) {
$element->setMasterPictureAttachment($attachment);
}
}
@ -220,8 +202,6 @@ class AttachmentSubmitHandler
/**
* Rename attachments with an unsafe extension (meaning files which would be run by a to a safe one).
* @param Attachment $attachment
* @return Attachment
*/
protected function renameBlacklistedExtensions(Attachment $attachment): Attachment
{
@ -391,7 +371,7 @@ class AttachmentSubmitHandler
$new_path = $this->pathResolver->realPathToPlaceholder($new_path);
//Save the path to the attachment
$attachment->setPath($new_path);
} catch (TransportExceptionInterface $transportExceptionInterface) {
} catch (TransportExceptionInterface) {
throw new AttachmentDownloadException('Transport error!');
}
@ -428,8 +408,6 @@ class AttachmentSubmitHandler
/**
* Parses the given file size string and returns the size in bytes.
* Taken from https://github.com/symfony/symfony/blob/6.2/src/Symfony/Component/Validator/Constraints/File.php
* @param string $maxSize
* @return int
*/
private function parseFileSizeString(string $maxSize): int
{

View file

@ -32,26 +32,12 @@ use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
class AttachmentURLGenerator
{
protected Packages $assets;
protected string $public_path;
protected AttachmentPathResolver $pathResolver;
protected UrlGeneratorInterface $urlGenerator;
protected AttachmentManager $attachmentHelper;
protected CacheManager $thumbnailManager;
protected LoggerInterface $logger;
public function __construct(Packages $assets, AttachmentPathResolver $pathResolver,
UrlGeneratorInterface $urlGenerator, AttachmentManager $attachmentHelper,
CacheManager $thumbnailManager, LoggerInterface $logger)
public function __construct(protected Packages $assets, protected AttachmentPathResolver $pathResolver,
protected UrlGeneratorInterface $urlGenerator, protected AttachmentManager $attachmentHelper,
protected CacheManager $thumbnailManager, protected LoggerInterface $logger)
{
$this->assets = $assets;
$this->pathResolver = $pathResolver;
$this->urlGenerator = $urlGenerator;
$this->attachmentHelper = $attachmentHelper;
$this->thumbnailManager = $thumbnailManager;
$this->logger = $logger;
//Determine a normalized path to the public folder (assets are relative to this folder)
$this->public_path = $this->pathResolver->parameterToAbsolutePath('public');
}

View file

@ -33,13 +33,8 @@ use Symfony\Contracts\Cache\CacheInterface;
*/
class BuiltinAttachmentsFinder
{
protected AttachmentPathResolver $pathResolver;
protected CacheInterface $cache;
public function __construct(CacheInterface $cache, AttachmentPathResolver $pathResolver)
public function __construct(protected CacheInterface $cache, protected AttachmentPathResolver $pathResolver)
{
$this->pathResolver = $pathResolver;
$this->cache = $cache;
}
/**
@ -49,7 +44,6 @@ class BuiltinAttachmentsFinder
* '%FOOTPRINTS%/path/to/folder/file1.png',
* '%FOOTPRINTS%/path/to/folder/file2.png',
* ]
* @return array
*/
public function getListOfFootprintsGroupedByFolder(): array
{
@ -109,7 +103,7 @@ class BuiltinAttachmentsFinder
return $results;
});
} catch (InvalidArgumentException $invalidArgumentException) {
} catch (InvalidArgumentException) {
return [];
}
}

View file

@ -43,13 +43,8 @@ class FileTypeFilterTools
protected const AUDIO_EXTS = ['mp3', 'flac', 'ogg', 'oga', 'wav', 'm4a', 'opus'];
protected const ALLOWED_MIME_PLACEHOLDERS = ['image/*', 'audio/*', 'video/*'];
protected MimeTypesInterface $mimeTypes;
protected CacheInterface $cache;
public function __construct(MimeTypesInterface $mimeTypes, CacheInterface $cache)
public function __construct(protected MimeTypesInterface $mimeTypes, protected CacheInterface $cache)
{
$this->mimeTypes = $mimeTypes;
$this->cache = $cache;
}
/**

View file

@ -27,11 +27,8 @@ use App\Entity\Parts\Part;
class PartPreviewGenerator
{
protected AttachmentManager $attachmentHelper;
public function __construct(AttachmentManager $attachmentHelper)
public function __construct(protected AttachmentManager $attachmentHelper)
{
$this->attachmentHelper = $attachmentHelper;
}
/**
@ -55,21 +52,21 @@ class PartPreviewGenerator
$list[] = $attachment;
}
if (null !== $part->getFootprint()) {
if ($part->getFootprint() instanceof \App\Entity\Parts\Footprint) {
$attachment = $part->getFootprint()->getMasterPictureAttachment();
if ($this->isAttachmentValidPicture($attachment)) {
$list[] = $attachment;
}
}
if (null !== $part->getBuiltProject()) {
if ($part->getBuiltProject() instanceof \App\Entity\ProjectSystem\Project) {
$attachment = $part->getBuiltProject()->getMasterPictureAttachment();
if ($this->isAttachmentValidPicture($attachment)) {
$list[] = $attachment;
}
}
if (null !== $part->getCategory()) {
if ($part->getCategory() instanceof \App\Entity\Parts\Category) {
$attachment = $part->getCategory()->getMasterPictureAttachment();
if ($this->isAttachmentValidPicture($attachment)) {
$list[] = $attachment;
@ -77,7 +74,7 @@ class PartPreviewGenerator
}
foreach ($part->getPartLots() as $lot) {
if (null !== $lot->getStorageLocation()) {
if ($lot->getStorageLocation() instanceof \App\Entity\Parts\Storelocation) {
$attachment = $lot->getStorageLocation()->getMasterPictureAttachment();
if ($this->isAttachmentValidPicture($attachment)) {
$list[] = $attachment;
@ -85,14 +82,14 @@ class PartPreviewGenerator
}
}
if (null !== $part->getPartUnit()) {
if ($part->getPartUnit() instanceof \App\Entity\Parts\MeasurementUnit) {
$attachment = $part->getPartUnit()->getMasterPictureAttachment();
if ($this->isAttachmentValidPicture($attachment)) {
$list[] = $attachment;
}
}
if (null !== $part->getManufacturer()) {
if ($part->getManufacturer() instanceof \App\Entity\Parts\Manufacturer) {
$attachment = $part->getManufacturer()->getMasterPictureAttachment();
if ($this->isAttachmentValidPicture($attachment)) {
$list[] = $attachment;
@ -117,7 +114,7 @@ class PartPreviewGenerator
}
//Otherwise check if the part has a footprint with a valid master attachment
if (null !== $part->getFootprint()) {
if ($part->getFootprint() instanceof \App\Entity\Parts\Footprint) {
$attachment = $part->getFootprint()->getMasterPictureAttachment();
if ($this->isAttachmentValidPicture($attachment)) {
return $attachment;
@ -125,7 +122,7 @@ class PartPreviewGenerator
}
//With lowest priority use the master attachment of the project this part represents (when existing)
if (null !== $part->getBuiltProject()) {
if ($part->getBuiltProject() instanceof \App\Entity\ProjectSystem\Project) {
$attachment = $part->getBuiltProject()->getMasterPictureAttachment();
if ($this->isAttachmentValidPicture($attachment)) {
return $attachment;
@ -145,7 +142,7 @@ class PartPreviewGenerator
*/
protected function isAttachmentValidPicture(?Attachment $attachment): bool
{
return null !== $attachment
return $attachment instanceof \App\Entity\Attachments\Attachment
&& $attachment->isPicture()
&& $this->attachmentHelper->isFileExisting($attachment);
}

View file

@ -35,7 +35,7 @@ final class CustomEnvVarProcessor implements EnvVarProcessorInterface
$env = $getEnv($name);
return !empty($env) && 'null://null' !== $env;
} catch (EnvNotFoundException $envNotFoundException) {
} catch (EnvNotFoundException) {
return false;
}
}

View file

@ -50,15 +50,10 @@ use Symfony\Contracts\Translation\TranslatorInterface;
class ElementTypeNameGenerator
{
protected TranslatorInterface $translator;
private EntityURLGenerator $entityURLGenerator;
protected array $mapping;
public function __construct(TranslatorInterface $translator, EntityURLGenerator $entityURLGenerator)
public function __construct(protected TranslatorInterface $translator, private readonly EntityURLGenerator $entityURLGenerator)
{
$this->translator = $translator;
$this->entityURLGenerator = $entityURLGenerator;
//Child classes has to become before parent classes
$this->mapping = [
Attachment::class => $this->translator->trans('attachment.label'),
@ -97,7 +92,7 @@ class ElementTypeNameGenerator
*/
public function getLocalizedTypeLabel($entity): string
{
$class = is_string($entity) ? $entity : get_class($entity);
$class = is_string($entity) ? $entity : $entity::class;
//Check if we have a direct array entry for our entity class, then we can use it
if (isset($this->mapping[$class])) {
@ -112,7 +107,7 @@ class ElementTypeNameGenerator
}
//When nothing was found throw an exception
throw new EntityNotSupportedException(sprintf('No localized label for the element with type %s was found!', is_object($entity) ? get_class($entity) : (string) $entity));
throw new EntityNotSupportedException(sprintf('No localized label for the element with type %s was found!', is_object($entity) ? $entity::class : (string) $entity));
}
/**
@ -143,7 +138,6 @@ class ElementTypeNameGenerator
* "Type: ID" (on elements without a name). If possible the value is given as a link to the element.
* @param AbstractDBElement $entity The entity for which the label should be generated
* @param bool $include_associated If set to true, the associated entity (like the part belonging to a part lot) is included in the label to give further information
* @return string
*/
public function formatLabelHTMLForEntity(AbstractDBElement $entity, bool $include_associated = false): string
{
@ -155,7 +149,7 @@ class ElementTypeNameGenerator
$this->entityURLGenerator->infoURL($entity),
$this->getTypeNameCombination($entity, true)
);
} catch (EntityNotSupportedException $exception) {
} catch (EntityNotSupportedException) {
$tmp = $this->getTypeNameCombination($entity, true);
}
} else { //Target does not have a name
@ -168,17 +162,17 @@ class ElementTypeNameGenerator
//Add a hint to the associated element if possible
if ($include_associated) {
if ($entity instanceof Attachment && null !== $entity->getElement()) {
if ($entity instanceof Attachment && $entity->getElement() instanceof \App\Entity\Attachments\AttachmentContainingDBElement) {
$on = $entity->getElement();
} elseif ($entity instanceof AbstractParameter && null !== $entity->getElement()) {
} elseif ($entity instanceof AbstractParameter && $entity->getElement() instanceof \App\Entity\Base\AbstractDBElement) {
$on = $entity->getElement();
} elseif ($entity instanceof PartLot && null !== $entity->getPart()) {
} elseif ($entity instanceof PartLot && $entity->getPart() instanceof \App\Entity\Parts\Part) {
$on = $entity->getPart();
} elseif ($entity instanceof Orderdetail && null !== $entity->getPart()) {
} elseif ($entity instanceof Orderdetail && $entity->getPart() instanceof \App\Entity\Parts\Part) {
$on = $entity->getPart();
} elseif ($entity instanceof Pricedetail && null !== $entity->getOrderdetail() && null !== $entity->getOrderdetail()->getPart()) {
} elseif ($entity instanceof Pricedetail && $entity->getOrderdetail() instanceof \App\Entity\PriceInformations\Orderdetail && $entity->getOrderdetail()->getPart() instanceof \App\Entity\Parts\Part) {
$on = $entity->getOrderdetail()->getPart();
} elseif ($entity instanceof ProjectBOMEntry && null !== $entity->getProject()) {
} elseif ($entity instanceof ProjectBOMEntry && $entity->getProject() instanceof \App\Entity\ProjectSystem\Project) {
$on = $entity->getProject();
}
@ -189,7 +183,7 @@ class ElementTypeNameGenerator
$this->entityURLGenerator->infoURL($on),
$this->getTypeNameCombination($on, true)
);
} catch (EntityNotSupportedException $exception) {
} catch (EntityNotSupportedException) {
}
}
}
@ -200,9 +194,6 @@ class ElementTypeNameGenerator
/**
* Create a HTML formatted label for a deleted element of which we only know the class and the ID.
* Please note that it is not checked if the element really not exists anymore, so you have to do this yourself.
* @param string $class
* @param int $id
* @return string
*/
public function formatElementDeletedHTML(string $class, int $id): string
{

View file

@ -57,13 +57,8 @@ use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
*/
class EntityURLGenerator
{
protected UrlGeneratorInterface $urlGenerator;
protected AttachmentURLGenerator $attachmentURLGenerator;
public function __construct(UrlGeneratorInterface $urlGenerator, AttachmentURLGenerator $attachmentURLGenerator)
public function __construct(protected UrlGeneratorInterface $urlGenerator, protected AttachmentURLGenerator $attachmentURLGenerator)
{
$this->urlGenerator = $urlGenerator;
$this->attachmentURLGenerator = $attachmentURLGenerator;
}
/**
@ -79,29 +74,19 @@ class EntityURLGenerator
* @throws EntityNotSupportedException thrown if the entity is not supported for the given type
* @throws InvalidArgumentException thrown if the givent type is not existing
*/
public function getURL($entity, string $type): string
public function getURL(mixed $entity, string $type): string
{
switch ($type) {
case 'info':
return $this->infoURL($entity);
case 'edit':
return $this->editURL($entity);
case 'create':
return $this->createURL($entity);
case 'clone':
return $this->cloneURL($entity);
case 'list':
case 'list_parts':
return $this->listPartsURL($entity);
case 'delete':
return $this->deleteURL($entity);
case 'file_download':
return $this->downloadURL($entity);
case 'file_view':
return $this->viewURL($entity);
}
throw new InvalidArgumentException('Method is not supported!');
return match ($type) {
'info' => $this->infoURL($entity),
'edit' => $this->editURL($entity),
'create' => $this->createURL($entity),
'clone' => $this->cloneURL($entity),
'list', 'list_parts' => $this->listPartsURL($entity),
'delete' => $this->deleteURL($entity),
'file_download' => $this->downloadURL($entity),
'file_view' => $this->viewURL($entity),
default => throw new InvalidArgumentException('Method is not supported!'),
};
}
/**
@ -134,7 +119,7 @@ class EntityURLGenerator
'timestamp' => $dateTime->getTimestamp(),
]
);
} catch (EntityNotSupportedException $exception) {
} catch (EntityNotSupportedException) {
if ($entity instanceof PartLot) {
return $this->urlGenerator->generate('part_info', [
'id' => $entity->getPart()->getID(),
@ -168,7 +153,7 @@ class EntityURLGenerator
}
//Otherwise throw an error
throw new EntityNotSupportedException('The given entity is not supported yet! Passed class type: '.get_class($entity));
throw new EntityNotSupportedException('The given entity is not supported yet! Passed class type: '.$entity::class);
}
public function viewURL(Attachment $entity): string
@ -191,7 +176,7 @@ class EntityURLGenerator
}
//Otherwise throw an error
throw new EntityNotSupportedException(sprintf('The given entity is not supported yet! Passed class type: %s', get_class($entity)));
throw new EntityNotSupportedException(sprintf('The given entity is not supported yet! Passed class type: %s', $entity::class));
}
/**
@ -235,7 +220,7 @@ class EntityURLGenerator
*
* @throws EntityNotSupportedException If the method is not supported for the given Entity
*/
public function editURL($entity): string
public function editURL(mixed $entity): string
{
$map = [
Part::class => 'part_edit',
@ -265,7 +250,7 @@ class EntityURLGenerator
*
* @throws EntityNotSupportedException If the method is not supported for the given Entity
*/
public function createURL($entity): string
public function createURL(mixed $entity): string
{
$map = [
Part::class => 'part_new',
@ -373,9 +358,9 @@ class EntityURLGenerator
*
* @throws EntityNotSupportedException
*/
protected function mapToController(array $map, $entity): string
protected function mapToController(array $map, mixed $entity): string
{
$class = get_class($entity);
$class = $entity::class;
//Check if we have an direct mapping for the given class
if (!array_key_exists($class, $map)) {
@ -386,7 +371,7 @@ class EntityURLGenerator
}
}
throw new EntityNotSupportedException(sprintf('The given entity is not supported yet! Passed class type: %s', get_class($entity)));
throw new EntityNotSupportedException(sprintf('The given entity is not supported yet! Passed class type: %s', $entity::class));
}
return $map[$class];

View file

@ -32,25 +32,20 @@ use Symfony\Component\OptionsResolver\OptionsResolver;
*/
class AmountFormatter
{
protected SIFormatter $siFormatter;
public function __construct(SIFormatter $siFormatter)
public function __construct(protected SIFormatter $siFormatter)
{
$this->siFormatter = $siFormatter;
}
/**
* Formats the given value using the measurement unit and options.
*
* @param float|string|int $value
* @param MeasurementUnit|null $unit The measurement unit, whose unit symbol should be used for formatting.
* If set to null, it is assumed that the part amount is measured in pieces.
*
* @return string The formatted string
*
* @throws InvalidArgumentException thrown if $value is not numeric
*/
public function format($value, ?MeasurementUnit $unit = null, array $options = []): string
public function format(float|string|int $value, ?MeasurementUnit $unit = null, array $options = []): string
{
if (!is_numeric($value)) {
throw new InvalidArgumentException('$value must be an numeric value!');

View file

@ -29,11 +29,8 @@ use Symfony\Contracts\Translation\TranslatorInterface;
*/
class MarkdownParser
{
protected TranslatorInterface $translator;
public function __construct(TranslatorInterface $translator)
public function __construct(protected TranslatorInterface $translator)
{
$this->translator = $translator;
}
/**

View file

@ -28,12 +28,10 @@ use NumberFormatter;
class MoneyFormatter
{
protected string $base_currency;
protected string $locale;
public function __construct(string $base_currency)
public function __construct(protected string $base_currency)
{
$this->base_currency = $base_currency;
$this->locale = Locale::getDefault();
}
@ -45,10 +43,10 @@ class MoneyFormatter
* @param int $decimals the number of decimals that should be shown
* @param bool $show_all_digits if set to true, all digits are shown, even if they are null
*/
public function format($value, ?Currency $currency = null, int $decimals = 5, bool $show_all_digits = false): string
public function format(string|float $value, ?Currency $currency = null, int $decimals = 5, bool $show_all_digits = false): string
{
$iso_code = $this->base_currency;
if (null !== $currency && !empty($currency->getIsoCode())) {
if ($currency instanceof \App\Entity\PriceInformations\Currency && !empty($currency->getIsoCode())) {
$iso_code = $currency->getIsoCode();
}

View file

@ -93,11 +93,7 @@ class SIFormatter
[$divisor, $symbol] = $this->getPrefixByMagnitude($this->getMagnitude($value));
$value /= $divisor;
//Build the format string, e.g.: %.2d km
if ('' !== $unit || '' !== $symbol) {
$format_string = '%.'.$decimals.'f '.$symbol.$unit;
} else {
$format_string = '%.'.$decimals.'f';
}
$format_string = '' !== $unit || '' !== $symbol ? '%.'.$decimals.'f '.$symbol.$unit : '%.'.$decimals.'f';
return sprintf($format_string, $value);
}

View file

@ -54,9 +54,6 @@ class BOMImporter
/**
* Converts the given file into an array of BOM entries using the given options and save them into the given project.
* The changes are not saved into the database yet.
* @param File $file
* @param array $options
* @param Project $project
* @return ProjectBOMEntry[]
*/
public function importFileIntoProject(File $file, Project $project, array $options): array
@ -73,8 +70,6 @@ class BOMImporter
/**
* Converts the given file into an array of BOM entries using the given options.
* @param File $file
* @param array $options
* @return ProjectBOMEntry[]
*/
public function fileToBOMEntries(File $file, array $options): array
@ -94,12 +89,10 @@ class BOMImporter
$resolver = $this->configureOptions($resolver);
$options = $resolver->resolve($options);
switch ($options['type']) {
case 'kicad_pcbnew':
return $this->parseKiCADPCB($data, $options);
default:
throw new InvalidArgumentException('Invalid import type!');
}
return match ($options['type']) {
'kicad_pcbnew' => $this->parseKiCADPCB($data, $options),
default => throw new InvalidArgumentException('Invalid import type!'),
};
}
private function parseKiCADPCB(string $data, array $options = []): array
@ -112,9 +105,7 @@ class BOMImporter
foreach ($csv->getRecords() as $offset => $entry) {
//Translate the german field names to english
$entry = array_combine(array_map(static function ($key) {
return self::MAP_KICAD_PCB_FIELDS[$key] ?? $key;
}, array_keys($entry)), $entry);
$entry = array_combine(array_map(static fn($key) => self::MAP_KICAD_PCB_FIELDS[$key] ?? $key, array_keys($entry)), $entry);
//Ensure that the entry has all required fields
if (!isset ($entry['Designator'])) {

View file

@ -39,11 +39,8 @@ use function Symfony\Component\String\u;
*/
class EntityExporter
{
protected SerializerInterface $serializer;
public function __construct(SerializerInterface $serializer)
public function __construct(protected SerializerInterface $serializer)
{
$this->serializer = $serializer;
}
protected function configureOptions(OptionsResolver $resolver): void
@ -67,7 +64,7 @@ class EntityExporter
* @param array $options The options to use for exporting
* @return string The serialized data
*/
public function exportEntities($entities, array $options): string
public function exportEntities(\App\Entity\Base\AbstractNamedDBElement|array $entities, array $options): string
{
if (!is_array($entities)) {
$entities = [$entities];
@ -111,7 +108,7 @@ class EntityExporter
*
* @throws ReflectionException
*/
public function exportEntityFromRequest($entities, Request $request): Response
public function exportEntityFromRequest(\App\Entity\Base\AbstractNamedDBElement|array $entities, Request $request): Response
{
$options = [
'format' => $request->get('format') ?? 'json',

View file

@ -38,15 +38,8 @@ use Symfony\Component\Validator\Validator\ValidatorInterface;
class EntityImporter
{
protected SerializerInterface $serializer;
protected EntityManagerInterface $em;
protected ValidatorInterface $validator;
public function __construct(SerializerInterface $serializer, EntityManagerInterface $em, ValidatorInterface $validator)
public function __construct(protected SerializerInterface $serializer, protected EntityManagerInterface $em, protected ValidatorInterface $validator)
{
$this->serializer = $serializer;
$this->em = $em;
$this->validator = $validator;
}
/**
@ -68,7 +61,7 @@ class EntityImporter
if (!is_a($class_name, AbstractNamedDBElement::class, true)) {
throw new InvalidArgumentException('$class_name must be a StructuralDBElement type!');
}
if (null !== $parent && !is_a($parent, $class_name)) {
if ($parent instanceof \App\Entity\Base\AbstractStructuralDBElement && !$parent instanceof $class_name) {
throw new InvalidArgumentException('$parent must have the same type as specified in $class_name!');
}
@ -297,20 +290,13 @@ class EntityImporter
//Convert the extension to lower case
$extension = strtolower($extension);
switch ($extension) {
case 'json':
return 'json';
case 'xml':
return 'xml';
case 'csv':
case 'tsv':
return 'csv';
case 'yaml':
case 'yml':
return 'yaml';
default:
return null;
}
return match ($extension) {
'json' => 'json',
'xml' => 'xml',
'csv', 'tsv' => 'csv',
'yaml', 'yml' => 'yaml',
default => null,
};
}
/**

View file

@ -87,7 +87,7 @@ class PKDatastructureImporter
$this->em->flush();
return count($distributor_data);
return is_countable($distributor_data) ? count($distributor_data) : 0;
}
public function importManufacturers(array $data): int
@ -130,7 +130,7 @@ class PKDatastructureImporter
$this->importAttachments($data, 'manufacturericlogo', Manufacturer::class, 'manufacturer_id', ManufacturerAttachment::class);
return count($manufacturer_data);
return is_countable($manufacturer_data) ? count($manufacturer_data) : 0;
}
public function importPartUnits(array $data): int
@ -151,7 +151,7 @@ class PKDatastructureImporter
$this->em->flush();
return count($partunit_data);
return is_countable($partunit_data) ? count($partunit_data) : 0;
}
public function importCategories(array $data): int
@ -180,15 +180,11 @@ class PKDatastructureImporter
}
$this->em->flush();
return count($partcategory_data);
return is_countable($partcategory_data) ? count($partcategory_data) : 0;
}
/**
* The common import functions for footprints and storeloactions
* @param array $data
* @param string $target_class
* @param string $data_prefix
* @return int
*/
private function importElementsWithCategory(array $data, string $target_class, string $data_prefix): int
{
@ -249,7 +245,7 @@ class PKDatastructureImporter
$this->em->flush();
return count($footprint_data) + count($footprintcategory_data);
return (is_countable($footprint_data) ? count($footprint_data) : 0) + (is_countable($footprintcategory_data) ? count($footprintcategory_data) : 0);
}
public function importFootprints(array $data): int

View file

@ -28,18 +28,14 @@ use Doctrine\ORM\EntityManagerInterface;
*/
class PKImportHelper
{
protected EntityManagerInterface $em;
public function __construct(EntityManagerInterface $em)
public function __construct(protected EntityManagerInterface $em)
{
$this->em = $em;
}
/**
* Purges the database tables for the import, so that all data can be created from scratch.
* Existing users and groups are not purged.
* This is needed to avoid ID collisions.
* @return void
*/
public function purgeDatabaseForImport(): void
{
@ -50,8 +46,6 @@ class PKImportHelper
/**
* Extracts the current database schema version from the PartKeepr XML dump.
* @param array $data
* @return string
*/
public function getDatabaseSchemaVersion(array $data): string
{
@ -64,7 +58,6 @@ class PKImportHelper
/**
* Checks that the database schema of the PartKeepr XML dump is compatible with the importer
* @param array $data
* @return bool True if the schema is compatible, false otherwise
*/
public function checkVersion(array $data): bool

View file

@ -45,7 +45,6 @@ trait PKImportHelperTrait
* @param array $attachment_row The attachment row from the PartKeepr database
* @param string $target_class The target class for the attachment
* @param string $type The type of the attachment (attachment or image)
* @return Attachment
* @throws \Exception
*/
protected function convertAttachmentDataToEntity(array $attachment_row, string $target_class, string $type): Attachment
@ -87,10 +86,10 @@ trait PKImportHelperTrait
//Use mime type to determine the extension like PartKeepr does in legacy implementation (just use the second part of the mime type)
//See UploadedFile.php:291 in PartKeepr (https://github.com/partkeepr/PartKeepr/blob/f6176c3354b24fa39ac8bc4328ee0df91de3d5b6/src/PartKeepr/UploadedFileBundle/Entity/UploadedFile.php#L291)
if (!empty ($attachment_row['mimetype'])) {
$attachment_row['extension'] = explode('/', $attachment_row['mimetype'])[1];
$attachment_row['extension'] = explode('/', (string) $attachment_row['mimetype'])[1];
} else {
//If the mime type is empty, we use the original extension
$attachment_row['extension'] = pathinfo($attachment_row['originalname'], PATHINFO_EXTENSION);
$attachment_row['extension'] = pathinfo((string) $attachment_row['originalname'], PATHINFO_EXTENSION);
}
}
@ -115,7 +114,6 @@ trait PKImportHelperTrait
* @param string $target_class The target class (e.g. Part)
* @param string $target_id_field The field name where the target ID is stored
* @param string $attachment_class The attachment class (e.g. PartAttachment)
* @return void
*/
protected function importAttachments(array $data, string $table_name, string $target_class, string $target_id_field, string $attachment_class): void
{
@ -156,12 +154,9 @@ trait PKImportHelperTrait
/**
* Assigns the parent to the given entity, using the numerical IDs from the imported data.
* @param string $class
* @param int|string $element_id
* @param int|string $parent_id
* @return AbstractStructuralDBElement The structural element that was modified (with $element_id)
*/
protected function setParent(string $class, $element_id, $parent_id): AbstractStructuralDBElement
protected function setParent(string $class, int|string $element_id, int|string $parent_id): AbstractStructuralDBElement
{
$element = $this->em->find($class, (int) $element_id);
if (!$element) {
@ -184,7 +179,6 @@ trait PKImportHelperTrait
/**
* Sets the given field of the given entity to the entity with the given ID.
* @return AbstractDBElement
*/
protected function setAssociationField(AbstractDBElement $element, string $field, string $other_class, $other_id): AbstractDBElement
{
@ -205,11 +199,8 @@ trait PKImportHelperTrait
/**
* Set the ID of an entity to a specific value. Must be called before persisting the entity, but before flushing.
* @param AbstractDBElement $element
* @param int|string $id
* @return void
*/
protected function setIDOfEntity(AbstractDBElement $element, $id): void
protected function setIDOfEntity(AbstractDBElement $element, int|string $id): void
{
if (!is_int($id) && !is_string($id)) {
throw new \InvalidArgumentException('ID must be an integer or string');
@ -217,7 +208,7 @@ trait PKImportHelperTrait
$id = (int) $id;
$metadata = $this->em->getClassMetadata(get_class($element));
$metadata = $this->em->getClassMetadata($element::class);
$metadata->setIdGeneratorType(ClassMetadataInfo::GENERATOR_TYPE_NONE);
$metadata->setIdGenerator(new \Doctrine\ORM\Id\AssignedGenerator());
$metadata->setIdentifierValues($element, ['id' => $id]);

View file

@ -45,7 +45,6 @@ class PKOptionalImporter
/**
* Import the projects from the given data.
* @param array $data
* @return int The number of imported projects
*/
public function importProjects(array $data): int
@ -99,12 +98,11 @@ class PKOptionalImporter
$this->importAttachments($data, 'projectattachment', Project::class, 'project_id', ProjectAttachment::class);
return count($projects_data);
return is_countable($projects_data) ? count($projects_data) : 0;
}
/**
* Import the users from the given data.
* @param array $data
* @return int The number of imported users
*/
public function importUsers(array $data): int
@ -144,6 +142,6 @@ class PKOptionalImporter
$this->em->flush();
return count($users_data);
return is_countable($users_data) ? count($users_data) : 0;
}
}

View file

@ -45,13 +45,10 @@ class PKPartImporter
{
use PKImportHelperTrait;
private string $base_currency;
public function __construct(EntityManagerInterface $em, PropertyAccessorInterface $propertyAccessor, string $default_currency)
public function __construct(EntityManagerInterface $em, PropertyAccessorInterface $propertyAccessor, private readonly string $base_currency)
{
$this->em = $em;
$this->propertyAccessor = $propertyAccessor;
$this->base_currency = $default_currency;
}
public function importParts(array $data): int
@ -128,7 +125,7 @@ class PKPartImporter
//Import attachments
$this->importAttachments($data, 'partattachment', Part::class, 'part_id', PartAttachment::class);
return count($part_data);
return is_countable($part_data) ? count($part_data) : 0;
}
protected function importPartManufacturers(array $data): void
@ -146,7 +143,7 @@ class PKPartImporter
throw new \RuntimeException(sprintf('Could not find part with ID %s', $partmanufacturer['part_id']));
}
$manufacturer = $this->em->find(Manufacturer::class, (int) $partmanufacturer['manufacturer_id']);
if (!$manufacturer) {
if (!$manufacturer instanceof \App\Entity\Parts\Manufacturer) {
throw new \RuntimeException(sprintf('Could not find manufacturer with ID %s', $partmanufacturer['manufacturer_id']));
}
$part->setManufacturer($manufacturer);
@ -190,7 +187,7 @@ class PKPartImporter
}
$part = $this->em->find(Part::class, (int) $partparameter['part_id']);
if (!$part) {
if (!$part instanceof \App\Entity\Parts\Part) {
throw new \RuntimeException(sprintf('Could not find part with ID %s', $partparameter['part_id']));
}
@ -203,8 +200,6 @@ class PKPartImporter
/**
* Returns the currency for the given ISO code. If the currency does not exist, it is created.
* This function returns null if the ISO code is the base currency.
* @param string $currency_iso_code
* @return Currency|null
*/
protected function getOrCreateCurrency(string $currency_iso_code): ?Currency
{
@ -240,12 +235,12 @@ class PKPartImporter
foreach ($data['partdistributor'] as $partdistributor) {
//Retrieve the part
$part = $this->em->find(Part::class, (int) $partdistributor['part_id']);
if (!$part) {
if (!$part instanceof \App\Entity\Parts\Part) {
throw new \RuntimeException(sprintf('Could not find part with ID %s', $partdistributor['part_id']));
}
//Retrieve the distributor
$supplier = $this->em->find(Supplier::class, (int) $partdistributor['distributor_id']);
if (!$supplier) {
if (!$supplier instanceof \App\Entity\Parts\Supplier) {
throw new \RuntimeException(sprintf('Could not find supplier with ID %s', $partdistributor['distributor_id']));
}
@ -305,9 +300,6 @@ class PKPartImporter
/**
* Returns the (parameter) unit symbol for the given ID.
* @param array $data
* @param int $id
* @return string
*/
protected function getUnitSymbol(array $data, int $id): string
{

View file

@ -50,12 +50,8 @@ use InvalidArgumentException;
final class BarcodeGenerator
{
private BarcodeContentGenerator $barcodeContentGenerator;
public function __construct(BarcodeContentGenerator $barcodeContentGenerator)
public function __construct(private readonly BarcodeContentGenerator $barcodeContentGenerator)
{
$this->barcodeContentGenerator = $barcodeContentGenerator;
}
public function generateHTMLBarcode(LabelOptions $options, object $target): ?string
@ -126,18 +122,11 @@ final class BarcodeGenerator
public function getContent(LabelOptions $options, AbstractDBElement $target): ?string
{
switch ($options->getBarcodeType()) {
case 'qr':
case 'datamatrix':
return $this->barcodeContentGenerator->getURLContent($target);
case 'code39':
case 'code93':
case 'code128':
return $this->barcodeContentGenerator->get1DBarcodeContent($target);
case 'none':
return null;
default:
throw new InvalidArgumentException('Unknown label type!');
}
return match ($options->getBarcodeType()) {
'qr', 'datamatrix' => $this->barcodeContentGenerator->getURLContent($target),
'code39', 'code93', 'code128' => $this->barcodeContentGenerator->get1DBarcodeContent($target),
'none' => null,
default => throw new InvalidArgumentException('Unknown label type!'),
};
}
}

View file

@ -62,11 +62,8 @@ final class BarcodeContentGenerator
Storelocation::class => 'location',
];
private UrlGeneratorInterface $urlGenerator;
public function __construct(UrlGeneratorInterface $urlGenerator)
public function __construct(private readonly UrlGeneratorInterface $urlGenerator)
{
$this->urlGenerator = $urlGenerator;
}
/**
@ -97,17 +94,17 @@ final class BarcodeContentGenerator
private function classToString(array $map, object $target): string
{
$class = get_class($target);
$class = $target::class;
if (isset($map[$class])) {
return $map[$class];
}
foreach ($map as $class => $string) {
if (is_a($target, $class)) {
if ($target instanceof $class) {
return $string;
}
}
throw new InvalidArgumentException('Unknown object class '.get_class($target));
throw new InvalidArgumentException('Unknown object class '.$target::class);
}
}

View file

@ -49,13 +49,8 @@ use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
final class BarcodeRedirector
{
private UrlGeneratorInterface $urlGenerator;
private EntityManagerInterface $em;
public function __construct(UrlGeneratorInterface $urlGenerator, EntityManagerInterface $entityManager)
public function __construct(private readonly UrlGeneratorInterface $urlGenerator, private readonly EntityManagerInterface $em)
{
$this->urlGenerator = $urlGenerator;
$this->em = $entityManager;
}
/**
@ -76,7 +71,7 @@ final class BarcodeRedirector
case 'lot':
//Try to determine the part to the given lot
$lot = $this->em->find(PartLot::class, $id);
if (null === $lot) {
if (!$lot instanceof \App\Entity\Parts\PartLot) {
throw new EntityNotFoundException();
}

View file

@ -57,16 +57,12 @@ final class LabelExampleElementsGenerator
{
public function getElement(string $type): object
{
switch ($type) {
case 'part':
return $this->getExamplePart();
case 'part_lot':
return $this->getExamplePartLot();
case 'storelocation':
return $this->getStorelocation();
default:
throw new InvalidArgumentException('Unknown $type.');
}
return match ($type) {
'part' => $this->getExamplePart(),
'part_lot' => $this->getExamplePartLot(),
'storelocation' => $this->getStorelocation(),
default => throw new InvalidArgumentException('Unknown $type.'),
};
}
public function getExamplePart(): Part

View file

@ -58,11 +58,8 @@ final class LabelGenerator
public const MM_TO_POINTS_FACTOR = 2.83465;
private LabelHTMLGenerator $labelHTMLGenerator;
public function __construct(LabelHTMLGenerator $labelHTMLGenerator)
public function __construct(private readonly LabelHTMLGenerator $labelHTMLGenerator)
{
$this->labelHTMLGenerator = $labelHTMLGenerator;
}
/**

View file

@ -52,29 +52,13 @@ use Twig\Error\Error;
final class LabelHTMLGenerator
{
private Environment $twig;
private ElementTypeNameGenerator $elementTypeNameGenerator;
private LabelTextReplacer $replacer;
private BarcodeGenerator $barcodeGenerator;
private SandboxedTwigProvider $sandboxedTwigProvider;
private string $partdb_title;
private \Symfony\Bundle\SecurityBundle\Security $security;
public function __construct(ElementTypeNameGenerator $elementTypeNameGenerator, LabelTextReplacer $replacer, Environment $twig,
BarcodeGenerator $barcodeGenerator, SandboxedTwigProvider $sandboxedTwigProvider, \Symfony\Bundle\SecurityBundle\Security $security, string $partdb_title)
public function __construct(private readonly ElementTypeNameGenerator $elementTypeNameGenerator, private readonly LabelTextReplacer $replacer, private readonly Environment $twig, private readonly BarcodeGenerator $barcodeGenerator, private readonly SandboxedTwigProvider $sandboxedTwigProvider, private readonly \Symfony\Bundle\SecurityBundle\Security $security, private readonly string $partdb_title)
{
$this->twig = $twig;
$this->elementTypeNameGenerator = $elementTypeNameGenerator;
$this->replacer = $replacer;
$this->barcodeGenerator = $barcodeGenerator;
$this->sandboxedTwigProvider = $sandboxedTwigProvider;
$this->security = $security;
$this->partdb_title = $partdb_title;
}
public function getLabelHTML(LabelOptions $options, array $elements): string
{
if (empty($elements)) {
if ($elements === []) {
throw new InvalidArgumentException('$elements must not be empty');
}

View file

@ -50,15 +50,8 @@ use Symfony\Contracts\Cache\TagAwareCacheInterface;
final class LabelProfileDropdownHelper
{
private TagAwareCacheInterface $cache;
private EntityManagerInterface $entityManager;
private UserCacheKeyGenerator $keyGenerator;
public function __construct(TagAwareCacheInterface $treeCache, EntityManagerInterface $entityManager, UserCacheKeyGenerator $keyGenerator)
public function __construct(private readonly TagAwareCacheInterface $cache, private readonly EntityManagerInterface $entityManager, private readonly UserCacheKeyGenerator $keyGenerator)
{
$this->cache = $treeCache;
$this->entityManager = $entityManager;
$this->keyGenerator = $keyGenerator;
}
public function getDropdownProfiles(string $type): array

View file

@ -49,11 +49,8 @@ use App\Services\LabelSystem\PlaceholderProviders\PlaceholderProviderInterface;
*/
final class LabelTextReplacer
{
private iterable $providers;
public function __construct(iterable $providers)
public function __construct(private readonly iterable $providers)
{
$this->providers = $providers;
}
/**
@ -89,9 +86,7 @@ final class LabelTextReplacer
public function replace(string $lines, object $target): string
{
$patterns = [
'/(\[\[[A-Z_0-9]+\]\])/' => function ($match) use ($target) {
return $this->handlePlaceholder($match[0], $target);
},
'/(\[\[[A-Z_0-9]+\]\])/' => fn($match) => $this->handlePlaceholder($match[0], $target),
];
return preg_replace_callback_array($patterns, $lines);

View file

@ -46,11 +46,8 @@ use App\Services\ElementTypeNameGenerator;
final class AbstractDBElementProvider implements PlaceholderProviderInterface
{
private ElementTypeNameGenerator $elementTypeNameGenerator;
public function __construct(ElementTypeNameGenerator $elementTypeNameGenerator)
public function __construct(private readonly ElementTypeNameGenerator $elementTypeNameGenerator)
{
$this->elementTypeNameGenerator = $elementTypeNameGenerator;
}
public function replace(string $placeholder, object $label_target, array $options = []): ?string

View file

@ -26,13 +26,8 @@ use App\Services\LabelSystem\Barcodes\BarcodeContentGenerator;
final class BarcodeProvider implements PlaceholderProviderInterface
{
private BarcodeGenerator $barcodeGenerator;
private BarcodeContentGenerator $barcodeContentGenerator;
public function __construct(BarcodeGenerator $barcodeGenerator, BarcodeContentGenerator $barcodeContentGenerator)
public function __construct(private readonly BarcodeGenerator $barcodeGenerator, private readonly BarcodeContentGenerator $barcodeContentGenerator)
{
$this->barcodeGenerator = $barcodeGenerator;
$this->barcodeContentGenerator = $barcodeContentGenerator;
}
public function replace(string $placeholder, object $label_target, array $options = []): ?string
@ -40,7 +35,7 @@ final class BarcodeProvider implements PlaceholderProviderInterface
if ('[[1D_CONTENT]]' === $placeholder) {
try {
return $this->barcodeContentGenerator->get1DBarcodeContent($label_target);
} catch (\InvalidArgumentException $e) {
} catch (\InvalidArgumentException) {
return 'ERROR!';
}
}
@ -48,7 +43,7 @@ final class BarcodeProvider implements PlaceholderProviderInterface
if ('[[2D_CONTENT]]' === $placeholder) {
try {
return $this->barcodeContentGenerator->getURLContent($label_target);
} catch (\InvalidArgumentException $e) {
} catch (\InvalidArgumentException) {
return 'ERROR!';
}
}

View file

@ -53,15 +53,8 @@ use Symfony\Component\Security\Core\Security;
*/
final class GlobalProviders implements PlaceholderProviderInterface
{
private string $partdb_title;
private \Symfony\Bundle\SecurityBundle\Security $security;
private UrlGeneratorInterface $url_generator;
public function __construct(string $partdb_title, \Symfony\Bundle\SecurityBundle\Security $security, UrlGeneratorInterface $url_generator)
public function __construct(private readonly string $partdb_title, private readonly \Symfony\Bundle\SecurityBundle\Security $security, private readonly UrlGeneratorInterface $url_generator)
{
$this->partdb_title = $partdb_title;
$this->security = $security;
$this->url_generator = $url_generator;
}
public function replace(string $placeholder, object $label_target, array $options = []): ?string

View file

@ -49,13 +49,8 @@ use Locale;
final class PartLotProvider implements PlaceholderProviderInterface
{
private LabelTextReplacer $labelTextReplacer;
private AmountFormatter $amountFormatter;
public function __construct(LabelTextReplacer $labelTextReplacer, AmountFormatter $amountFormatter)
public function __construct(private readonly LabelTextReplacer $labelTextReplacer, private readonly AmountFormatter $amountFormatter)
{
$this->labelTextReplacer = $labelTextReplacer;
$this->amountFormatter = $amountFormatter;
}
public function replace(string $placeholder, object $label_target, array $options = []): ?string
@ -74,7 +69,7 @@ final class PartLotProvider implements PlaceholderProviderInterface
}
if ('[[EXPIRATION_DATE]]' === $placeholder) {
if (null === $label_target->getExpirationDate()) {
if (!$label_target->getExpirationDate() instanceof \DateTimeInterface) {
return '';
}
$formatter = IntlDateFormatter::create(
@ -95,19 +90,19 @@ final class PartLotProvider implements PlaceholderProviderInterface
}
if ('[[LOCATION]]' === $placeholder) {
return $label_target->getStorageLocation() ? $label_target->getStorageLocation()->getName() : '';
return $label_target->getStorageLocation() instanceof \App\Entity\Parts\Storelocation ? $label_target->getStorageLocation()->getName() : '';
}
if ('[[LOCATION_FULL]]' === $placeholder) {
return $label_target->getStorageLocation() ? $label_target->getStorageLocation()->getFullPath() : '';
return $label_target->getStorageLocation() instanceof \App\Entity\Parts\Storelocation ? $label_target->getStorageLocation()->getFullPath() : '';
}
if ('[[OWNER]]' === $placeholder) {
return $label_target->getOwner() ? $label_target->getOwner()->getFullName() : '';
return $label_target->getOwner() instanceof \App\Entity\UserSystem\User ? $label_target->getOwner()->getFullName() : '';
}
if ('[[OWNER_USERNAME]]' === $placeholder) {
return $label_target->getOwner() ? $label_target->getOwner()->getUsername() : '';
return $label_target->getOwner() instanceof \App\Entity\UserSystem\User ? $label_target->getOwner()->getUsername() : '';
}
return $this->labelTextReplacer->handlePlaceholder($placeholder, $label_target->getPart());

View file

@ -48,13 +48,8 @@ use Symfony\Contracts\Translation\TranslatorInterface;
final class PartProvider implements PlaceholderProviderInterface
{
private SIFormatter $siFormatter;
private TranslatorInterface $translator;
public function __construct(SIFormatter $SIFormatter, TranslatorInterface $translator)
public function __construct(private readonly SIFormatter $siFormatter, private readonly TranslatorInterface $translator)
{
$this->siFormatter = $SIFormatter;
$this->translator = $translator;
}
public function replace(string $placeholder, object $part, array $options = []): ?string
@ -64,27 +59,27 @@ final class PartProvider implements PlaceholderProviderInterface
}
if ('[[CATEGORY]]' === $placeholder) {
return $part->getCategory() ? $part->getCategory()->getName() : '';
return $part->getCategory() instanceof \App\Entity\Parts\Category ? $part->getCategory()->getName() : '';
}
if ('[[CATEGORY_FULL]]' === $placeholder) {
return $part->getCategory() ? $part->getCategory()->getFullPath() : '';
return $part->getCategory() instanceof \App\Entity\Parts\Category ? $part->getCategory()->getFullPath() : '';
}
if ('[[MANUFACTURER]]' === $placeholder) {
return $part->getManufacturer() ? $part->getManufacturer()->getName() : '';
return $part->getManufacturer() instanceof \App\Entity\Parts\Manufacturer ? $part->getManufacturer()->getName() : '';
}
if ('[[MANUFACTURER_FULL]]' === $placeholder) {
return $part->getManufacturer() ? $part->getManufacturer()->getFullPath() : '';
return $part->getManufacturer() instanceof \App\Entity\Parts\Manufacturer ? $part->getManufacturer()->getFullPath() : '';
}
if ('[[FOOTPRINT]]' === $placeholder) {
return $part->getFootprint() ? $part->getFootprint()->getName() : '';
return $part->getFootprint() instanceof \App\Entity\Parts\Footprint ? $part->getFootprint()->getName() : '';
}
if ('[[FOOTPRINT_FULL]]' === $placeholder) {
return $part->getFootprint() ? $part->getFootprint()->getFullPath() : '';
return $part->getFootprint() instanceof \App\Entity\Parts\Footprint ? $part->getFootprint()->getFullPath() : '';
}
if ('[[MASS]]' === $placeholder) {
@ -114,7 +109,7 @@ final class PartProvider implements PlaceholderProviderInterface
}
if ('[[DESCRIPTION_T]]' === $placeholder) {
return strip_tags($parsedown->line($part->getDescription()));
return strip_tags((string) $parsedown->line($part->getDescription()));
}
if ('[[COMMENT]]' === $placeholder) {
@ -122,7 +117,7 @@ final class PartProvider implements PlaceholderProviderInterface
}
if ('[[COMMENT_T]]' === $placeholder) {
return strip_tags($parsedown->line($part->getComment()));
return strip_tags((string) $parsedown->line($part->getComment()));
}
return null;

View file

@ -28,11 +28,11 @@ class StorelocationProvider implements PlaceholderProviderInterface
{
if ($label_target instanceof Storelocation) {
if ('[[OWNER]]' === $placeholder) {
return $label_target->getOwner() ? $label_target->getOwner()->getFullName() : '';
return $label_target->getOwner() instanceof \App\Entity\UserSystem\User ? $label_target->getOwner()->getFullName() : '';
}
if ('[[OWNER_USERNAME]]' === $placeholder) {
return $label_target->getOwner() ? $label_target->getOwner()->getUsername() : '';
return $label_target->getOwner() instanceof \App\Entity\UserSystem\User ? $label_target->getOwner()->getUsername() : '';
}
}

View file

@ -58,10 +58,10 @@ final class StructuralDBElementProvider implements PlaceholderProviderInterface
return $label_target->getFullPath();
}
if ('[[PARENT]]' === $placeholder) {
return $label_target->getParent() ? $label_target->getParent()->getName() : '';
return $label_target->getParent() instanceof \App\Entity\Base\AbstractStructuralDBElement ? $label_target->getParent()->getName() : '';
}
if ('[[PARENT_FULL_PATH]]' === $placeholder) {
return $label_target->getParent() ? $label_target->getParent()->getFullPath() : '';
return $label_target->getParent() instanceof \App\Entity\Base\AbstractStructuralDBElement ? $label_target->getParent()->getFullPath() : '';
}
}

View file

@ -114,11 +114,8 @@ final class SandboxedTwigProvider
];
private const ALLOWED_PROPERTIES = [];
private FormatExtension $appExtension;
public function __construct(FormatExtension $appExtension)
public function __construct(private readonly FormatExtension $appExtension)
{
$this->appExtension = $appExtension;
}
public function getTwig(LabelOptions $options): Environment

View file

@ -45,11 +45,10 @@ class EventCommentHelper
{
protected const MAX_MESSAGE_LENGTH = 255;
protected ?string $message;
protected ?string $message = null;
public function __construct()
{
$this->message = null;
}
/**
@ -60,11 +59,7 @@ class EventCommentHelper
public function setMessage(?string $message): void
{
//Restrict the length of the string
if ($message) {
$this->message = mb_strimwidth($message, 0, self::MAX_MESSAGE_LENGTH, '...');
} else {
$this->message = null;
}
$this->message = $message ? mb_strimwidth($message, 0, self::MAX_MESSAGE_LENGTH, '...') : null;
}
/**

View file

@ -26,9 +26,7 @@ namespace App\Services\LogSystem;
*/
class EventCommentNeededHelper
{
protected array $enforce_change_comments_for;
public const VALID_OPERATION_TYPES = [
final public const VALID_OPERATION_TYPES = [
'part_edit',
'part_create',
'part_delete',
@ -38,15 +36,12 @@ class EventCommentNeededHelper
'datastructure_delete',
];
public function __construct(array $enforce_change_comments_for)
public function __construct(protected array $enforce_change_comments_for)
{
$this->enforce_change_comments_for = $enforce_change_comments_for;
}
/**
* Checks if a log change comment is needed for the given operation type
* @param string $comment_type
* @return bool
*/
public function isCommentNeeded(string $comment_type): bool
{

View file

@ -30,22 +30,8 @@ use Symfony\Component\Security\Core\Security;
class EventLogger
{
protected int $minimum_log_level;
protected array $blacklist;
protected array $whitelist;
protected EntityManagerInterface $em;
protected \Symfony\Bundle\SecurityBundle\Security $security;
protected ConsoleInfoHelper $console_info_helper;
public function __construct(int $minimum_log_level, array $blacklist, array $whitelist, EntityManagerInterface $em,
\Symfony\Bundle\SecurityBundle\Security $security, ConsoleInfoHelper $console_info_helper)
public function __construct(protected int $minimum_log_level, protected array $blacklist, protected array $whitelist, protected EntityManagerInterface $em, protected \Symfony\Bundle\SecurityBundle\Security $security, protected ConsoleInfoHelper $console_info_helper)
{
$this->minimum_log_level = $minimum_log_level;
$this->blacklist = $blacklist;
$this->whitelist = $whitelist;
$this->em = $em;
$this->security = $security;
$this->console_info_helper = $console_info_helper;
}
/**
@ -58,14 +44,14 @@ class EventLogger
{
$user = $this->security->getUser();
//If the user is not specified explicitly, set it to the current user
if ((null === $user || $user instanceof User) && null === $logEntry->getUser()) {
if (null === $user) {
if ((!$user instanceof \Symfony\Component\Security\Core\User\UserInterface || $user instanceof User) && !$logEntry->getUser() instanceof \App\Entity\UserSystem\User) {
if (!$user instanceof \App\Entity\UserSystem\User) {
$repo = $this->em->getRepository(User::class);
$user = $repo->getAnonymousUser();
}
//If no anonymous user is available skip the log (needed for data fixtures)
if (null === $user) {
if (!$user instanceof \App\Entity\UserSystem\User) {
return false;
}
$logEntry->setUser($user);
@ -88,15 +74,13 @@ class EventLogger
/**
* Same as log(), but this function can be safely called from within the onFlush() doctrine event, as it
* updated the changesets of the unit of work.
* @param AbstractLogEntry $logEntry
* @return bool
*/
public function logFromOnFlush(AbstractLogEntry $logEntry): bool
{
if ($this->log($logEntry)) {
$uow = $this->em->getUnitOfWork();
//As we call it from onFlush, we have to recompute the changeset here, according to https://www.doctrine-project.org/projects/doctrine-orm/en/2.14/reference/events.html#reference-events-on-flush
$uow->computeChangeSet($this->em->getClassMetadata(get_class($logEntry)), $logEntry);
$uow->computeChangeSet($this->em->getClassMetadata($logEntry::class), $logEntry);
return true;
}
@ -125,9 +109,9 @@ class EventLogger
?array $whitelist = null
): bool {
//Apply the global settings, if nothing was specified
$minimum_log_level = $minimum_log_level ?? $this->minimum_log_level;
$blacklist = $blacklist ?? $this->blacklist;
$whitelist = $whitelist ?? $this->whitelist;
$minimum_log_level ??= $this->minimum_log_level;
$blacklist ??= $this->blacklist;
$whitelist ??= $this->whitelist;
//Don't add the entry if it does not reach the minimum level
if ($logEntry->getLevel() > $minimum_log_level) {
@ -135,17 +119,12 @@ class EventLogger
}
//Check if the event type is blacklisted
if (!empty($blacklist) && $this->isObjectClassInArray($logEntry, $blacklist)) {
if ($blacklist !== [] && $this->isObjectClassInArray($logEntry, $blacklist)) {
return false;
}
//Check for whitelisting
if (!empty($whitelist) && !$this->isObjectClassInArray($logEntry, $whitelist)) {
return false;
}
// By default, all things should be added
return true;
return !($whitelist !== [] && !$this->isObjectClassInArray($logEntry, $whitelist));
}
/**
@ -157,13 +136,13 @@ class EventLogger
protected function isObjectClassInArray(object $object, array $classes): bool
{
//Check if the class is directly in the classes array
if (in_array(get_class($object), $classes, true)) {
if (in_array($object::class, $classes, true)) {
return true;
}
//Iterate over all classes and check for inheritance
foreach ($classes as $class) {
if (is_a($object, $class)) {
if ($object instanceof $class) {
return true;
}
}

View file

@ -46,18 +46,16 @@ use InvalidArgumentException;
class EventUndoHelper
{
public const MODE_UNDO = 'undo';
public const MODE_REVERT = 'revert';
final public const MODE_UNDO = 'undo';
final public const MODE_REVERT = 'revert';
protected const ALLOWED_MODES = [self::MODE_REVERT, self::MODE_UNDO];
protected ?AbstractLogEntry $undone_event;
protected string $mode;
protected ?AbstractLogEntry $undone_event = null;
protected string $mode = self::MODE_UNDO;
public function __construct()
{
$this->undone_event = null;
$this->mode = self::MODE_UNDO;
}
public function setMode(string $mode): void

View file

@ -29,25 +29,14 @@ class LogDataFormatter
{
private const STRING_MAX_LENGTH = 1024;
private TranslatorInterface $translator;
private EntityManagerInterface $entityManager;
private ElementTypeNameGenerator $elementTypeNameGenerator;
public function __construct(TranslatorInterface $translator, EntityManagerInterface $entityManager, ElementTypeNameGenerator $elementTypeNameGenerator)
public function __construct(private readonly TranslatorInterface $translator, private readonly EntityManagerInterface $entityManager, private readonly ElementTypeNameGenerator $elementTypeNameGenerator)
{
$this->translator = $translator;
$this->entityManager = $entityManager;
$this->elementTypeNameGenerator = $elementTypeNameGenerator;
}
/**
* Formats the given data of a log entry as HTML
* @param mixed $data
* @param AbstractLogEntry $logEntry
* @param string $fieldName
* @return string
*/
public function formatData($data, AbstractLogEntry $logEntry, string $fieldName): string
public function formatData(mixed $data, AbstractLogEntry $logEntry, string $fieldName): string
{
if (is_string($data)) {
$tmp = '<span class="text-muted user-select-none">"</span>' . mb_strimwidth(htmlspecialchars($data), 0, self::STRING_MAX_LENGTH, ) . '<span class="text-muted user-select-none">"</span>';
@ -55,9 +44,8 @@ class LogDataFormatter
//Show special characters and line breaks
$tmp = preg_replace('/\n/', '<span class="text-muted user-select-none">\\n</span><br>', $tmp);
$tmp = preg_replace('/\r/', '<span class="text-muted user-select-none">\\r</span>', $tmp);
$tmp = preg_replace('/\t/', '<span class="text-muted user-select-none">\\t</span>', $tmp);
return $tmp;
return preg_replace('/\t/', '<span class="text-muted user-select-none">\\t</span>', $tmp);
}
if (is_bool($data)) {
@ -126,7 +114,7 @@ class LogDataFormatter
}
} catch (\InvalidArgumentException|\ReflectionException $exception) {
} catch (\InvalidArgumentException|\ReflectionException) {
return '<i>unknown target class</i>: ' . $id;
}
}
@ -147,7 +135,7 @@ class LogDataFormatter
try {
$dateTime = new \DateTime($date, new \DateTimeZone($timezone));
} catch (\Exception $exception) {
} catch (\Exception) {
return '<i>unknown DateTime format</i>';
}

View file

@ -29,7 +29,6 @@ class LogDiffFormatter
* If the diff is not possible, an empty string is returned.
* @param $old_data
* @param $new_data
* @return string
*/
public function formatDiff($old_data, $new_data): string
{
@ -67,7 +66,7 @@ class LogDiffFormatter
//Positive difference
if ($difference > 0) {
return sprintf('<span class="text-success">+%s</span>', $difference);
} else if ($difference < 0) {
} elseif ($difference < 0) {
return sprintf('<span class="text-danger">%s</span>', $difference);
} else {
return sprintf('<span class="text-muted">%s</span>', $difference);

View file

@ -48,13 +48,9 @@ class LogEntryExtraFormatter
{
protected const CONSOLE_SEARCH = ['<i class="fas fa-long-arrow-alt-right"></i>', '<i>', '</i>', '<b>', '</b>'];
protected const CONSOLE_REPLACE = ['→', '<info>', '</info>', '<error>', '</error>'];
protected TranslatorInterface $translator;
protected ElementTypeNameGenerator $elementTypeNameGenerator;
public function __construct(TranslatorInterface $translator, ElementTypeNameGenerator $elementTypeNameGenerator)
public function __construct(protected TranslatorInterface $translator, protected ElementTypeNameGenerator $elementTypeNameGenerator)
{
$this->translator = $translator;
$this->elementTypeNameGenerator = $elementTypeNameGenerator;
}
/**
@ -163,7 +159,7 @@ class LogEntryExtraFormatter
'%s <i class="fas fa-long-arrow-alt-right"></i> %s (%s)',
$context->getOldInstock(),
$context->getNewInstock(),
(!$context->isWithdrawal() ? '+' : '-').$context->getDifference(true)
($context->isWithdrawal() ? '-' : '+').$context->getDifference(true)
);
$array['log.instock_changed.comment'] = htmlspecialchars($context->getComment());
}

View file

@ -29,30 +29,20 @@ class LogLevelHelper
* Returns the FontAwesome icon class for the given log level.
* This returns just the specific icon class (so 'fa-info' for example).
* @param string $logLevel The string representation of the log level (one of the LogLevel::* constants)
* @return string
*/
public function logLevelToIconClass(string $logLevel): string
{
switch ($logLevel) {
case LogLevel::DEBUG:
return 'fa-bug';
case LogLevel::INFO:
return 'fa-info';
case LogLevel::NOTICE:
return 'fa-flag';
case LogLevel::WARNING:
return 'fa-exclamation-circle';
case LogLevel::ERROR:
return 'fa-exclamation-triangle';
case LogLevel::CRITICAL:
return 'fa-bolt';
case LogLevel::ALERT:
return 'fa-radiation';
case LogLevel::EMERGENCY:
return 'fa-skull-crossbones';
default:
return 'fa-question-circle';
}
return match ($logLevel) {
LogLevel::DEBUG => 'fa-bug',
LogLevel::INFO => 'fa-info',
LogLevel::NOTICE => 'fa-flag',
LogLevel::WARNING => 'fa-exclamation-circle',
LogLevel::ERROR => 'fa-exclamation-triangle',
LogLevel::CRITICAL => 'fa-bolt',
LogLevel::ALERT => 'fa-radiation',
LogLevel::EMERGENCY => 'fa-skull-crossbones',
default => 'fa-question-circle',
};
}
/**
@ -63,18 +53,11 @@ class LogLevelHelper
public function logLevelToTableColorClass(string $logLevel): string
{
switch ($logLevel) {
case LogLevel::EMERGENCY:
case LogLevel::ALERT:
case LogLevel::CRITICAL:
case LogLevel::ERROR:
return 'table-danger';
case LogLevel::WARNING:
return 'table-warning';
case LogLevel::NOTICE:
return 'table-info';
default:
return '';
}
return match ($logLevel) {
LogLevel::EMERGENCY, LogLevel::ALERT, LogLevel::CRITICAL, LogLevel::ERROR => 'table-danger',
LogLevel::WARNING => 'table-warning',
LogLevel::NOTICE => 'table-info',
default => '',
};
}
}

View file

@ -40,21 +40,12 @@ use Symfony\Contracts\Translation\TranslatorInterface;
class LogTargetHelper
{
protected EntityManagerInterface $em;
protected LogEntryRepository $entryRepository;
protected EntityURLGenerator $entityURLGenerator;
protected ElementTypeNameGenerator $elementTypeNameGenerator;
protected TranslatorInterface $translator;
public function __construct(EntityManagerInterface $entityManager, EntityURLGenerator $entityURLGenerator,
ElementTypeNameGenerator $elementTypeNameGenerator, TranslatorInterface $translator)
public function __construct(protected EntityManagerInterface $em, protected EntityURLGenerator $entityURLGenerator,
protected ElementTypeNameGenerator $elementTypeNameGenerator, protected TranslatorInterface $translator)
{
$this->em = $entityManager;
$this->entryRepository = $entityManager->getRepository(AbstractLogEntry::class);
$this->entityURLGenerator = $entityURLGenerator;
$this->elementTypeNameGenerator = $elementTypeNameGenerator;
$this->translator = $translator;
$this->entryRepository = $em->getRepository(AbstractLogEntry::class);
}
private function configureOptions(OptionsResolver $resolver): self
@ -79,7 +70,7 @@ class LogTargetHelper
$target = $this->entryRepository->getTargetElement($context);
//If the target is null and the context has a target, that means that the target was deleted. Show it that way.
if ($target === null) {
if (!$target instanceof \App\Entity\Base\AbstractDBElement) {
if ($context->hasTarget()) {
return $this->elementTypeNameGenerator->formatElementDeletedHTML($context->getTargetClass(),
$context->getTargetId());

View file

@ -43,12 +43,10 @@ use ReflectionClass;
class TimeTravel
{
protected EntityManagerInterface $em;
protected LogEntryRepository $repo;
public function __construct(EntityManagerInterface $em)
public function __construct(protected EntityManagerInterface $em)
{
$this->em = $em;
$this->repo = $em->getRepository(AbstractLogEntry::class);
}
@ -126,7 +124,7 @@ class TimeTravel
}
// Revert any of the associated elements
$metadata = $this->em->getClassMetadata(get_class($element));
$metadata = $this->em->getClassMetadata($element::class);
$associations = $metadata->getAssociationMappings();
foreach ($associations as $field => $mapping) {
if (
@ -148,10 +146,10 @@ class TimeTravel
} elseif ( //Revert *_TO_MANY associations (collection properties)
(ClassMetadataInfo::MANY_TO_MANY === $mapping['type']
|| ClassMetadataInfo::ONE_TO_MANY === $mapping['type'])
&& false === $mapping['isOwningSide']
&& !$mapping['isOwningSide']
) {
$target_elements = $this->getField($element, $field);
if (null === $target_elements || count($target_elements) > 10) {
if (null === $target_elements || (is_countable($target_elements) ? count($target_elements) : 0) > 10) {
continue;
}
foreach ($target_elements as $target_element) {
@ -200,7 +198,7 @@ class TimeTravel
if (!$element instanceof TimeStampableInterface) {
return;
}
$metadata = $this->em->getClassMetadata(get_class($element));
$metadata = $this->em->getClassMetadata($element::class);
$old_data = $logEntry->getOldData();
foreach ($old_data as $field => $data) {
@ -232,19 +230,16 @@ class TimeTravel
protected function getField(AbstractDBElement $element, string $field)
{
$reflection = new ReflectionClass(get_class($element));
$reflection = new ReflectionClass($element::class);
$property = $reflection->getProperty($field);
$property->setAccessible(true);
return $property->getValue($element);
}
/**
* @param DateTime|int|null $new_value
*/
protected function setField(AbstractDBElement $element, string $field, $new_value): void
protected function setField(AbstractDBElement $element, string $field, \DateTime|int|null $new_value): void
{
$reflection = new ReflectionClass(get_class($element));
$reflection = new ReflectionClass($element::class);
$property = $reflection->getProperty($field);
$property->setAccessible(true);

View file

@ -31,11 +31,9 @@ use Doctrine\ORM\EntityManagerInterface;
class DBInfoHelper
{
protected Connection $connection;
protected EntityManagerInterface $entityManager;
public function __construct(EntityManagerInterface $entityManager)
public function __construct(protected EntityManagerInterface $entityManager)
{
$this->entityManager = $entityManager;
$this->connection = $entityManager->getConnection();
}
@ -58,7 +56,6 @@ class DBInfoHelper
/**
* Returns the database version of the used database.
* @return string|null
* @throws \Doctrine\DBAL\Exception
*/
public function getDatabaseVersion(): ?string
@ -84,7 +81,7 @@ class DBInfoHelper
if ($this->connection->getDatabasePlatform() instanceof AbstractMySQLPlatform) {
try {
return $this->connection->fetchOne('SELECT SUM(data_length + index_length) FROM information_schema.TABLES WHERE table_schema = DATABASE()');
} catch (\Doctrine\DBAL\Exception $e) {
} catch (\Doctrine\DBAL\Exception) {
return null;
}
}
@ -92,7 +89,7 @@ class DBInfoHelper
if ($this->connection->getDatabasePlatform() instanceof SqlitePlatform) {
try {
return $this->connection->fetchOne('SELECT page_count * page_size as size FROM pragma_page_count(), pragma_page_size();');
} catch (\Doctrine\DBAL\Exception $e) {
} catch (\Doctrine\DBAL\Exception) {
return null;
}
}
@ -102,7 +99,6 @@ class DBInfoHelper
/**
* Returns the name of the database.
* @return string|null
*/
public function getDatabaseName(): ?string
{
@ -111,14 +107,13 @@ class DBInfoHelper
/**
* Returns the name of the database user.
* @return string|null
*/
public function getDatabaseUsername(): ?string
{
if ($this->connection->getDatabasePlatform() instanceof AbstractMySQLPlatform) {
try {
return $this->connection->fetchOne('SELECT USER()');
} catch (\Doctrine\DBAL\Exception $e) {
} catch (\Doctrine\DBAL\Exception) {
return null;
}
}

View file

@ -94,7 +94,7 @@ class RangeParser
$this->parse($range_str);
return true;
} catch (InvalidArgumentException $exception) {
} catch (InvalidArgumentException) {
return false;
}
}

View file

@ -74,7 +74,7 @@ class ParameterExtractor
$split = $this->splitString($input);
foreach ($split as $param_string) {
$tmp = $this->stringToParam($param_string, $class);
if (null !== $tmp) {
if ($tmp instanceof \App\Entity\Parameters\AbstractParameter) {
$parameters[] = $tmp;
}
}
@ -89,7 +89,7 @@ class ParameterExtractor
$matches = [];
preg_match($regex, $input, $matches);
if (!empty($matches)) {
if ($matches !== []) {
[, $name, $value] = $matches;
$value = trim($value);

View file

@ -9,20 +9,12 @@ use App\Services\LogSystem\EventLogger;
final class PartLotWithdrawAddHelper
{
private EventLogger $eventLogger;
private EventCommentHelper $eventCommentHelper;
public function __construct(EventLogger $eventLogger, EventCommentHelper $eventCommentHelper)
public function __construct(private readonly EventLogger $eventLogger, private readonly EventCommentHelper $eventCommentHelper)
{
$this->eventLogger = $eventLogger;
$this->eventCommentHelper = $eventCommentHelper;
}
/**
* Checks whether the given part can
* @param PartLot $partLot
* @return bool
*/
public function canAdd(PartLot $partLot): bool
{
@ -32,16 +24,11 @@ final class PartLotWithdrawAddHelper
}
//So far all other restrictions are defined at the storelocation level
if($partLot->getStorageLocation() === null) {
if(!$partLot->getStorageLocation() instanceof \App\Entity\Parts\Storelocation) {
return true;
}
//We can not add parts if the storage location of the lot is marked as full
if($partLot->getStorageLocation()->isFull()) {
return false;
}
return true;
return !$partLot->getStorageLocation()->isFull();
}
public function canWithdraw(PartLot $partLot): bool
@ -50,13 +37,8 @@ final class PartLotWithdrawAddHelper
if ($partLot->isInstockUnknown()) {
return false;
}
//Part must contain more than 0 parts
if ($partLot->getAmount() <= 0) {
return false;
}
return true;
return $partLot->getAmount() > 0;
}
/**
@ -153,7 +135,6 @@ final class PartLotWithdrawAddHelper
* @param PartLot $target The part lot to which the parts should be added
* @param float $amount The amount of parts that should be moved
* @param string|null $comment A comment describing the reason for the move
* @return void
*/
public function move(PartLot $origin, PartLot $target, float $amount, ?string $comment = null): void
{

View file

@ -37,15 +37,8 @@ use Symfony\Component\Security\Core\Security;
final class PartsTableActionHandler
{
private EntityManagerInterface $entityManager;
private \Symfony\Bundle\SecurityBundle\Security $security;
private UrlGeneratorInterface $urlGenerator;
public function __construct(EntityManagerInterface $entityManager, \Symfony\Bundle\SecurityBundle\Security $security, UrlGeneratorInterface $urlGenerator)
public function __construct(private readonly EntityManagerInterface $entityManager, private readonly \Symfony\Bundle\SecurityBundle\Security $security, private readonly UrlGeneratorInterface $urlGenerator)
{
$this->entityManager = $entityManager;
$this->security = $security;
$this->urlGenerator = $urlGenerator;
}
/**
@ -86,10 +79,8 @@ final class PartsTableActionHandler
if ($action === 'generate_label') {
$targets = implode(',', array_map(static fn (Part $part) => $part->getID(), $selected_parts));
} else { //For lots we have to extract the part lots
$targets = implode(',', array_map(static function (Part $part) {
//We concat the lot IDs of every part with a comma (which are later concated with a comma too per part)
return implode(',', array_map(static fn (PartLot $lot) => $lot->getID(), $part->getPartLots()->toArray()));
}, $selected_parts));
$targets = implode(',', array_map(static fn(Part $part): string => //We concat the lot IDs of every part with a comma (which are later concated with a comma too per part)
implode(',', array_map(static fn (PartLot $lot) => $lot->getID(), $part->getPartLots()->toArray())), $selected_parts));
}
return new RedirectResponse(
@ -106,18 +97,11 @@ final class PartsTableActionHandler
$matches = [];
if (preg_match('/^export_(json|yaml|xml|csv)$/', $action, $matches)) {
$ids = implode(',', array_map(static fn (Part $part) => $part->getID(), $selected_parts));
switch ($target_id) {
case 1:
default:
$level = 'simple';
break;
case 2:
$level = 'extended';
break;
case 3:
$level = 'full';
break;
}
$level = match ($target_id) {
2 => 'extended',
3 => 'full',
default => 'simple',
};
return new RedirectResponse(

View file

@ -34,12 +34,10 @@ use function count;
class PricedetailHelper
{
protected string $base_currency;
protected string $locale;
public function __construct(string $base_currency)
public function __construct(protected string $base_currency)
{
$this->base_currency = $base_currency;
$this->locale = Locale::getDefault();
}
@ -67,9 +65,7 @@ class PricedetailHelper
} else {
// We have to sort the pricedetails manually
$array = $pricedetails->map(
static function (Pricedetail $pricedetail) {
return $pricedetail->getMinDiscountQuantity();
}
static fn(Pricedetail $pricedetail) => $pricedetail->getMinDiscountQuantity()
)->toArray();
sort($array);
$max_amount = end($array);
@ -154,13 +150,13 @@ class PricedetailHelper
$pricedetail = $orderdetail->findPriceForQty($amount);
//When we don't have information about this amount, ignore it
if (null === $pricedetail) {
if (!$pricedetail instanceof \App\Entity\PriceInformations\Pricedetail) {
continue;
}
$converted = $this->convertMoneyToCurrency($pricedetail->getPricePerUnit(), $pricedetail->getCurrency(), $currency);
//Ignore price information that can not be converted to base currency.
if (null !== $converted) {
if ($converted instanceof \Brick\Math\BigDecimal) {
$avg = $avg->plus($converted);
++$count;
}
@ -193,9 +189,9 @@ class PricedetailHelper
$val_base = $value;
//Convert value to base currency
if (null !== $originCurrency) {
if ($originCurrency instanceof \App\Entity\PriceInformations\Currency) {
//Without an exchange rate we can not calculate the exchange rate
if (null === $originCurrency->getExchangeRate() || $originCurrency->getExchangeRate()->isZero()) {
if (!$originCurrency->getExchangeRate() instanceof \Brick\Math\BigDecimal || $originCurrency->getExchangeRate()->isZero()) {
return null;
}
@ -204,9 +200,9 @@ class PricedetailHelper
$val_target = $val_base;
//Convert value in base currency to target currency
if (null !== $targetCurrency) {
if ($targetCurrency instanceof \App\Entity\PriceInformations\Currency) {
//Without an exchange rate we can not calculate the exchange rate
if (null === $targetCurrency->getExchangeRate()) {
if (!$targetCurrency->getExchangeRate() instanceof \Brick\Math\BigDecimal) {
return null;
}

View file

@ -27,24 +27,19 @@ use App\Services\Parts\PartLotWithdrawAddHelper;
class ProjectBuildHelper
{
private PartLotWithdrawAddHelper $withdraw_add_helper;
public function __construct(PartLotWithdrawAddHelper $withdraw_add_helper)
public function __construct(private readonly PartLotWithdrawAddHelper $withdraw_add_helper)
{
$this->withdraw_add_helper = $withdraw_add_helper;
}
/**
* Returns the maximum buildable amount of the given BOM entry based on the stock of the used parts.
* This function only works for BOM entries that are associated with a part.
* @param ProjectBOMEntry $projectBOMEntry
* @return int
*/
public function getMaximumBuildableCountForBOMEntry(ProjectBOMEntry $projectBOMEntry): int
{
$part = $projectBOMEntry->getPart();
if ($part === null) {
if (!$part instanceof \App\Entity\Parts\Part) {
throw new \InvalidArgumentException('This function cannot determine the maximum buildable count for a BOM entry without a part!');
}
@ -59,8 +54,6 @@ class ProjectBuildHelper
/**
* Returns the maximum buildable amount of the given project, based on the stock of the used parts in the BOM.
* @param Project $project
* @return int
*/
public function getMaximumBuildableCount(Project $project): int
{
@ -81,9 +74,7 @@ class ProjectBuildHelper
/**
* Checks if the given project can be built with the current stock.
* This means that the maximum buildable count is greater or equal than the requested $number_of_projects
* @param Project $project
* @parm int $number_of_builds
* @return bool
*/
public function isProjectBuildable(Project $project, int $number_of_builds = 1): bool
{
@ -93,9 +84,6 @@ class ProjectBuildHelper
/**
* Check if the given BOM entry can be built with the current stock.
* This means that the maximum buildable count is greater or equal than the requested $number_of_projects
* @param ProjectBOMEntry $bom_entry
* @param int $number_of_builds
* @return bool
*/
public function isBOMEntryBuildable(ProjectBOMEntry $bom_entry, int $number_of_builds = 1): bool
{
@ -120,7 +108,7 @@ class ProjectBuildHelper
$part = $bomEntry->getPart();
//Skip BOM entries without a part (as we can not determine that)
if ($part === null) {
if (!$part instanceof \App\Entity\Parts\Part) {
continue;
}
@ -138,8 +126,6 @@ class ProjectBuildHelper
* Withdraw the parts from the stock using the given ProjectBuildRequest and create the build parts entries, if needed.
* The ProjectBuildRequest has to be validated before!!
* You have to flush changes to DB afterward
* @param ProjectBuildRequest $buildRequest
* @return void
*/
public function doBuild(ProjectBuildRequest $buildRequest): void
{

View file

@ -10,8 +10,6 @@ class ProjectBuildPartHelper
/**
* Returns a part that represents the builds of a project. This part is not saved to the database, and can be used
* as initial data for the new part form.
* @param Project $project
* @return Part
*/
public function getPartInitialization(Project $project): Part
{

View file

@ -27,13 +27,8 @@ use Swap\Swap;
class ExchangeRateUpdater
{
private string $base_currency;
private Swap $swap;
public function __construct(string $base_currency, Swap $swap)
public function __construct(private readonly string $base_currency, private readonly Swap $swap)
{
$this->base_currency = $base_currency;
$this->swap = $swap;
}
/**

View file

@ -62,13 +62,11 @@ use InvalidArgumentException;
class StatisticsHelper
{
protected EntityManagerInterface $em;
protected PartRepository $part_repo;
protected AttachmentRepository $attachment_repo;
public function __construct(EntityManagerInterface $em)
public function __construct(protected EntityManagerInterface $em)
{
$this->em = $em;
$this->part_repo = $this->em->getRepository(Part::class);
$this->attachment_repo = $this->em->getRepository(Attachment::class);
}

View file

@ -34,11 +34,8 @@ use function array_slice;
*/
class TagFinder
{
protected EntityManagerInterface $em;
public function __construct(EntityManagerInterface $entityManager)
public function __construct(protected EntityManagerInterface $em)
{
$this->em = $entityManager;
}
/**
@ -78,7 +75,7 @@ class TagFinder
//Iterate over each possible tags (which are comma separated) and extract tags which match our keyword
foreach ($possible_tags as $tags) {
$tags = explode(',', $tags['tags']);
$tags = explode(',', (string) $tags['tags']);
$results = array_merge($results, preg_grep($keyword_regex, $tags));
}

View file

@ -32,7 +32,7 @@ use Symfony\Component\Translation\MessageCatalogue;
*/
final class PermissionExtractor implements ExtractorInterface
{
private array $permission_structure;
private readonly array $permission_structure;
private bool $finished = false;
public function __construct(PermissionManager $resolver)

View file

@ -34,15 +34,8 @@ use Symfony\Contracts\Cache\TagAwareCacheInterface;
*/
class NodesListBuilder
{
protected EntityManagerInterface $em;
protected TagAwareCacheInterface $cache;
protected UserCacheKeyGenerator $keyGenerator;
public function __construct(EntityManagerInterface $em, TagAwareCacheInterface $treeCache, UserCacheKeyGenerator $keyGenerator)
public function __construct(protected EntityManagerInterface $em, protected TagAwareCacheInterface $cache, protected UserCacheKeyGenerator $keyGenerator)
{
$this->em = $em;
$this->keyGenerator = $keyGenerator;
$this->cache = $treeCache;
}
/**
@ -56,7 +49,7 @@ class NodesListBuilder
*/
public function typeToNodesList(string $class_name, ?AbstractStructuralDBElement $parent = null): array
{
$parent_id = null !== $parent ? $parent->getID() : '0';
$parent_id = $parent instanceof \App\Entity\Base\AbstractStructuralDBElement ? $parent->getID() : '0';
// Backslashes are not allowed in cache keys
$secure_class_name = str_replace('\\', '_', $class_name);
$key = 'list_'.$this->keyGenerator->generateKey().'_'.$secure_class_name.$parent_id;
@ -81,6 +74,6 @@ class NodesListBuilder
*/
public function getChildrenFlatList(AbstractStructuralDBElement $element): array
{
return $this->typeToNodesList(get_class($element), $element);
return $this->typeToNodesList($element::class, $element);
}
}

View file

@ -27,19 +27,18 @@ use Symfony\Contracts\Cache\TagAwareCacheInterface;
final class SidebarTreeUpdater
{
private const CACHE_KEY = 'sidebar_tree_updated';
private const TTL = 60 * 60 * 24; // 24 hours
private const TTL = 60 * 60 * 24;
private CacheInterface $cache;
public function __construct(TagAwareCacheInterface $treeCache)
public function __construct(
// 24 hours
private readonly TagAwareCacheInterface $cache
)
{
$this->cache = $treeCache;
}
/**
* Returns the time when the sidebar tree was updated the last time.
* The frontend uses this information to reload the sidebar tree.
* @return \DateTimeInterface
*/
public function getLastTreeUpdate(): \DateTimeInterface
{

View file

@ -27,11 +27,8 @@ use Doctrine\ORM\EntityManagerInterface;
class StructuralElementRecursionHelper
{
protected EntityManagerInterface $em;
public function __construct(EntityManagerInterface $em)
public function __construct(protected EntityManagerInterface $em)
{
$this->em = $em;
}
/**

View file

@ -49,24 +49,8 @@ use Symfony\Contracts\Translation\TranslatorInterface;
*/
class ToolsTreeBuilder
{
protected TranslatorInterface $translator;
protected UrlGeneratorInterface $urlGenerator;
protected UserCacheKeyGenerator $keyGenerator;
protected TagAwareCacheInterface $cache;
protected \Symfony\Bundle\SecurityBundle\Security $security;
public function __construct(TranslatorInterface $translator, UrlGeneratorInterface $urlGenerator,
TagAwareCacheInterface $treeCache, UserCacheKeyGenerator $keyGenerator,
\Symfony\Bundle\SecurityBundle\Security $security)
public function __construct(protected TranslatorInterface $translator, protected UrlGeneratorInterface $urlGenerator, protected TagAwareCacheInterface $cache, protected UserCacheKeyGenerator $keyGenerator, protected \Symfony\Bundle\SecurityBundle\Security $security)
{
$this->translator = $translator;
$this->urlGenerator = $urlGenerator;
$this->cache = $treeCache;
$this->keyGenerator = $keyGenerator;
$this->security = $security;
}
/**

View file

@ -47,26 +47,8 @@ use function count;
class TreeViewGenerator
{
protected EntityURLGenerator $urlGenerator;
protected EntityManagerInterface $em;
protected TagAwareCacheInterface $cache;
protected UserCacheKeyGenerator $keyGenerator;
protected TranslatorInterface $translator;
protected bool $rootNodeExpandedByDefault;
protected bool $rootNodeEnabled;
public function __construct(EntityURLGenerator $URLGenerator, EntityManagerInterface $em,
TagAwareCacheInterface $treeCache, UserCacheKeyGenerator $keyGenerator, TranslatorInterface $translator, bool $rootNodeExpandedByDefault, bool $rootNodeEnabled)
public function __construct(protected EntityURLGenerator $urlGenerator, protected EntityManagerInterface $em, protected TagAwareCacheInterface $cache, protected UserCacheKeyGenerator $keyGenerator, protected TranslatorInterface $translator, protected bool $rootNodeExpandedByDefault, protected bool $rootNodeEnabled)
{
$this->urlGenerator = $URLGenerator;
$this->em = $em;
$this->cache = $treeCache;
$this->keyGenerator = $keyGenerator;
$this->translator = $translator;
$this->rootNodeExpandedByDefault = $rootNodeExpandedByDefault;
$this->rootNodeEnabled = $rootNodeEnabled;
}
/**
@ -92,7 +74,7 @@ class TreeViewGenerator
$href = $this->urlGenerator->createURL(new $class());
$new_node = new TreeViewNode($this->translator->trans('entity.tree.new'), $href);
//When the id of the selected element is null, then we have a new element, and we need to select "new" node
if (null === $selectedElement || null === $selectedElement->getID()) {
if (!$selectedElement instanceof \App\Entity\Base\AbstractDBElement || null === $selectedElement->getID()) {
$new_node->setSelected(true);
}
$head[] = $new_node;
@ -116,7 +98,7 @@ class TreeViewGenerator
$recursiveIterator = new RecursiveIteratorIterator($treeIterator, RecursiveIteratorIterator::SELF_FIRST);
foreach ($recursiveIterator as $item) {
/** @var TreeViewNode $item */
if (null !== $selectedElement && $item->getId() === $selectedElement->getID()) {
if ($selectedElement instanceof \App\Entity\Base\AbstractDBElement && $item->getId() === $selectedElement->getID()) {
$item->setSelected(true);
}
@ -202,7 +184,7 @@ class TreeViewGenerator
if (!is_a($class, AbstractNamedDBElement::class, true)) {
throw new InvalidArgumentException('$class must be a class string that implements StructuralDBElement or NamedDBElement!');
}
if (null !== $parent && !is_a($parent, $class)) {
if ($parent instanceof \App\Entity\Base\AbstractStructuralDBElement && !$parent instanceof $class) {
throw new InvalidArgumentException('$parent must be of the type $class!');
}
@ -210,7 +192,7 @@ class TreeViewGenerator
$repo = $this->em->getRepository($class);
//If we just want a part of a tree, don't cache it
if (null !== $parent) {
if ($parent instanceof \App\Entity\Base\AbstractStructuralDBElement) {
return $repo->getGenericNodeTree($parent);
}

View file

@ -35,21 +35,13 @@ use Symfony\Contracts\Translation\TranslatorInterface;
class PasswordResetManager
{
protected MailerInterface $mailer;
protected EntityManagerInterface $em;
protected PasswordHasherInterface $passwordEncoder;
protected TranslatorInterface $translator;
protected UserPasswordHasherInterface $userPasswordEncoder;
public function __construct(MailerInterface $mailer, EntityManagerInterface $em,
TranslatorInterface $translator, UserPasswordHasherInterface $userPasswordEncoder,
public function __construct(protected MailerInterface $mailer, protected EntityManagerInterface $em,
protected TranslatorInterface $translator, protected UserPasswordHasherInterface $userPasswordEncoder,
PasswordHasherFactoryInterface $encoderFactory)
{
$this->em = $em;
$this->mailer = $mailer;
$this->passwordEncoder = $encoderFactory->getPasswordHasher(User::class);
$this->translator = $translator;
$this->userPasswordEncoder = $userPasswordEncoder;
}
public function request(string $name_or_email): void
@ -59,7 +51,7 @@ class PasswordResetManager
//Try to find a user by the given string
$user = $repo->findByEmailOrName($name_or_email);
//Do nothing if no user was found
if (null === $user) {
if (!$user instanceof \App\Entity\UserSystem\User) {
return;
}
@ -109,7 +101,7 @@ class PasswordResetManager
$user = $repo->findOneBy(['name' => $username]);
//If no user matching the name, show an error message
if (null === $user) {
if (!$user instanceof \App\Entity\UserSystem\User) {
return false;
}

View file

@ -40,19 +40,16 @@ use Symfony\Component\Yaml\Yaml;
class PermissionManager
{
protected $permission_structure;
protected bool $is_debug;
protected string $cache_file;
/**
* PermissionResolver constructor.
*/
public function __construct(bool $kernel_debug, string $kernel_cache_dir)
public function __construct(protected bool $is_debug, string $kernel_cache_dir)
{
$cache_dir = $kernel_cache_dir;
//Here the cached structure will be saved.
$this->cache_file = $cache_dir.'/permissions.php.cache';
$this->is_debug = $kernel_debug;
$this->permission_structure = $this->generatePermissionStructure();
}
@ -113,7 +110,7 @@ class PermissionManager
/** @var Group $parent */
$parent = $user->getGroup();
while (null !== $parent) { //The top group, has parent == null
while ($parent instanceof \App\Entity\Base\AbstractStructuralDBElement) { //The top group, has parent == null
//Check if our current element gives an info about disallow/allow
$allowed = $this->dontInherit($parent, $permission, $operation);
if (null !== $allowed) {
@ -196,8 +193,6 @@ class PermissionManager
/**
* This functions sets all operations mentioned in the alsoSet value of a permission, so that the structure is always valid.
* @param HasPermissionsInterface $user
* @return void
*/
public function ensureCorrectSetOperations(HasPermissionsInterface $user): void
{
@ -215,12 +210,7 @@ class PermissionManager
//Set every op listed in also Set
foreach ($op['alsoSet'] as $set_also) {
//If the alsoSet value contains a dot then we set the operation of another permission
if (str_contains($set_also, '.')) {
[$set_perm, $set_op] = explode('.', $set_also);
} else {
//Else we set the operation of the same permission
[$set_perm, $set_op] = [$perm_key, $set_also];
}
[$set_perm, $set_op] = str_contains((string) $set_also, '.') ? explode('.', (string) $set_also) : [$perm_key, $set_also];
//Check if we change the value of the permission
if ($this->dontInherit($user, $set_perm, $set_op) !== true) {
@ -237,9 +227,6 @@ class PermissionManager
/**
* Sets all possible operations of all possible permissions of the given entity to the given value.
* @param HasPermissionsInterface $perm_holder
* @param bool|null $new_value
* @return void
*/
public function setAllPermissions(HasPermissionsInterface $perm_holder, ?bool $new_value): void
{
@ -253,11 +240,6 @@ class PermissionManager
/**
* Sets all operations of the given permissions to the given value.
* Please note that you have to call ensureCorrectSetOperations() after this function, to ensure that all alsoSet values are set.
*
* @param HasPermissionsInterface $perm_holder
* @param string $permission
* @param bool|null $new_value
* @return void
*/
public function setAllOperationsOfPermission(HasPermissionsInterface $perm_holder, string $permission, ?bool $new_value): void
{
@ -272,11 +254,6 @@ class PermissionManager
/**
* This function sets all operations of the given permission to the given value, except the ones listed in the except array.
* @param HasPermissionsInterface $perm_holder
* @param string $permission
* @param bool|null $new_value
* @param array $except
* @return void
*/
public function setAllOperationsOfPermissionExcept(HasPermissionsInterface $perm_holder, string $permission, ?bool $new_value, array $except): void
{

View file

@ -25,18 +25,15 @@ use App\Security\Interfaces\HasPermissionsInterface;
class PermissionPresetsHelper
{
public const PRESET_ALL_INHERIT = 'all_inherit';
public const PRESET_ALL_FORBID = 'all_forbid';
public const PRESET_ALL_ALLOW = 'all_allow';
public const PRESET_READ_ONLY = 'read_only';
public const PRESET_EDITOR = 'editor';
public const PRESET_ADMIN = 'admin';
final public const PRESET_ALL_INHERIT = 'all_inherit';
final public const PRESET_ALL_FORBID = 'all_forbid';
final public const PRESET_ALL_ALLOW = 'all_allow';
final public const PRESET_READ_ONLY = 'read_only';
final public const PRESET_EDITOR = 'editor';
final public const PRESET_ADMIN = 'admin';
private PermissionManager $permissionResolver;
public function __construct(PermissionManager $permissionResolver)
public function __construct(private readonly PermissionManager $permissionResolver)
{
$this->permissionResolver = $permissionResolver;
}
/**
@ -44,7 +41,6 @@ class PermissionPresetsHelper
* The permission data will be reset during the process and then the preset will be applied.
*
* @param string $preset_name The name of the preset to use
* @return HasPermissionsInterface
*/
public function applyPreset(HasPermissionsInterface $perm_holder, string $preset_name): HasPermissionsInterface
{

View file

@ -29,7 +29,6 @@ class PermissionSchemaUpdater
{
/**
* Check if the given user/group needs an update of its permission schema.
* @param HasPermissionsInterface $holder
* @return bool True if the permission schema needs an update, false otherwise.
*/
public function isSchemaUpdateNeeded(HasPermissionsInterface $holder): bool
@ -42,12 +41,11 @@ class PermissionSchemaUpdater
/**
* Upgrades the permission schema of the given user/group to the chosen version.
* Please note that this function does not flush the changes to DB!
* @param HasPermissionsInterface $holder
* @param int $target_version
* @return bool True, if an upgrade was done, false if it was not needed.
*/
public function upgradeSchema(HasPermissionsInterface $holder, int $target_version = PermissionData::CURRENT_SCHEMA_VERSION): bool
{
$e = null;
if ($target_version > PermissionData::CURRENT_SCHEMA_VERSION) {
throw new \InvalidArgumentException('The target version is higher than the maximum possible schema version!');
}
@ -66,7 +64,7 @@ class PermissionSchemaUpdater
$method->setAccessible(true);
$method->invoke($this, $holder);
} catch (\ReflectionException $e) {
throw new \RuntimeException('Could not find update method for schema version '.($n + 1));
throw new \RuntimeException('Could not find update method for schema version '.($n + 1), $e->getCode(), $e);
}
//Bump the schema version
@ -80,8 +78,6 @@ class PermissionSchemaUpdater
/**
* Upgrades the permission schema of the given group and all of its parent groups to the chosen version.
* Please note that this function does not flush the changes to DB!
* @param Group $group
* @param int $target_version
* @return bool True if an upgrade was done, false if it was not needed.
*/
public function groupUpgradeSchemaRecursively(Group $group, int $target_version = PermissionData::CURRENT_SCHEMA_VERSION): bool
@ -101,14 +97,12 @@ class PermissionSchemaUpdater
/**
* Upgrades the permissions schema of the given users and its parent (including parent groups) to the chosen version.
* Please note that this function does not flush the changes to DB!
* @param User $user
* @param int $target_version
* @return bool True if an upgrade was done, false if it was not needed.
*/
public function userUpgradeSchemaRecursively(User $user, int $target_version = PermissionData::CURRENT_SCHEMA_VERSION): bool
{
$updated = $this->upgradeSchema($user, $target_version);
if ($user->getGroup()) {
if ($user->getGroup() instanceof \App\Entity\UserSystem\Group) {
$updated = $this->groupUpgradeSchemaRecursively($user->getGroup(), $target_version) || $updated;
}

View file

@ -31,7 +31,6 @@ use RuntimeException;
class BackupCodeGenerator
{
protected int $code_length;
protected int $code_count;
/**
* BackupCodeGenerator constructor.
@ -39,7 +38,7 @@ class BackupCodeGenerator
* @param int $code_length how many characters a single code should have
* @param int $code_count how many codes are generated for a whole backup set
*/
public function __construct(int $code_length, int $code_count)
public function __construct(int $code_length, protected int $code_count)
{
if ($code_length > 32) {
throw new RuntimeException('Backup code can have maximum 32 digits!');
@ -47,8 +46,6 @@ class BackupCodeGenerator
if ($code_length < 6) {
throw new RuntimeException('Code must have at least 6 digits to ensure security!');
}
$this->code_count = $code_count;
$this->code_length = $code_length;
}

View file

@ -29,11 +29,8 @@ use App\Entity\UserSystem\User;
*/
class BackupCodeManager
{
protected BackupCodeGenerator $backupCodeGenerator;
public function __construct(BackupCodeGenerator $backupCodeGenerator)
public function __construct(protected BackupCodeGenerator $backupCodeGenerator)
{
$this->backupCodeGenerator = $backupCodeGenerator;
}
/**

View file

@ -33,34 +33,18 @@ use Symfony\Component\HttpFoundation\File\UploadedFile;
class UserAvatarHelper
{
private bool $use_gravatar;
private Packages $packages;
private AttachmentURLGenerator $attachmentURLGenerator;
private FilterService $filterService;
private EntityManagerInterface $entityManager;
private AttachmentSubmitHandler $submitHandler;
public function __construct(bool $use_gravatar, Packages $packages, AttachmentURLGenerator $attachmentURLGenerator,
FilterService $filterService, EntityManagerInterface $entityManager, AttachmentSubmitHandler $attachmentSubmitHandler)
public function __construct(private readonly bool $use_gravatar, private readonly Packages $packages, private readonly AttachmentURLGenerator $attachmentURLGenerator, private readonly FilterService $filterService, private readonly EntityManagerInterface $entityManager, private readonly AttachmentSubmitHandler $submitHandler)
{
$this->use_gravatar = $use_gravatar;
$this->packages = $packages;
$this->attachmentURLGenerator = $attachmentURLGenerator;
$this->filterService = $filterService;
$this->entityManager = $entityManager;
$this->submitHandler = $attachmentSubmitHandler;
}
/**
* Returns the URL to the profile picture of the given user (in big size)
* @param User $user
* @return string
*/
public function getAvatarURL(User $user): string
{
//Check if the user has a master attachment defined (meaning he has explicitly defined a profile picture)
if ($user->getMasterPictureAttachment() !== null) {
if ($user->getMasterPictureAttachment() instanceof \App\Entity\Attachments\Attachment) {
return $this->attachmentURLGenerator->getThumbnailURL($user->getMasterPictureAttachment(), 'thumbnail_md');
}
@ -76,7 +60,7 @@ class UserAvatarHelper
public function getAvatarSmURL(User $user): string
{
//Check if the user has a master attachment defined (meaning he has explicitly defined a profile picture)
if ($user->getMasterPictureAttachment() !== null) {
if ($user->getMasterPictureAttachment() instanceof \App\Entity\Attachments\Attachment) {
return $this->attachmentURLGenerator->getThumbnailURL($user->getMasterPictureAttachment(), 'thumbnail_xs');
}
@ -88,7 +72,7 @@ class UserAvatarHelper
try {
//Otherwise we can serve the relative path via Asset component
return $this->filterService->getUrlOfFilteredImage('/img/default_avatar.png', 'thumbnail_xs');
} catch (\Imagine\Exception\RuntimeException $e) {
} catch (\Imagine\Exception\RuntimeException) {
//If the filter fails, we can not serve the thumbnail and fall back to the original image and log an warning
return $this->packages->getUrl('/img/default_avatar.png');
}
@ -97,7 +81,7 @@ class UserAvatarHelper
public function getAvatarMdURL(User $user): string
{
//Check if the user has a master attachment defined (meaning he has explicitly defined a profile picture)
if ($user->getMasterPictureAttachment() !== null) {
if ($user->getMasterPictureAttachment() instanceof \App\Entity\Attachments\Attachment) {
return $this->attachmentURLGenerator->getThumbnailURL($user->getMasterPictureAttachment(), 'thumbnail_sm');
}
@ -109,7 +93,7 @@ class UserAvatarHelper
try {
//Otherwise we can serve the relative path via Asset component
return $this->filterService->getUrlOfFilteredImage('/img/default_avatar.png', 'thumbnail_xs');
} catch (\Imagine\Exception\RuntimeException $e) {
} catch (\Imagine\Exception\RuntimeException) {
//If the filter fails, we can not serve the thumbnail and fall back to the original image and log an warning
return $this->packages->getUrl('/img/default_avatar.png');
}
@ -136,22 +120,18 @@ class UserAvatarHelper
$url = 'https://www.gravatar.com/avatar/';
$url .= md5(strtolower(trim($email)));
$url .= "?s=${s}&d=${d}&r=${r}";
return $url;
return $url . "?s=${s}&d=${d}&r=${r}";
}
/**
* Handles the upload of the user avatar.
* @param User $user
* @param UploadedFile $file
* @return Attachment
*/
public function handleAvatarUpload(User $user, UploadedFile $file): Attachment
{
//Determine which attachment to user
//If the user already has a master attachment, we use this one
if ($user->getMasterPictureAttachment()) {
if ($user->getMasterPictureAttachment() instanceof \App\Entity\Attachments\Attachment) {
$attachment = $user->getMasterPictureAttachment();
} else { //Otherwise we have to create one
$attachment = new UserAttachment();

View file

@ -32,13 +32,8 @@ use Symfony\Component\Security\Core\Security;
*/
class UserCacheKeyGenerator
{
protected \Symfony\Bundle\SecurityBundle\Security $security;
protected RequestStack $requestStack;
public function __construct(\Symfony\Bundle\SecurityBundle\Security $security, RequestStack $requestStack)
public function __construct(protected \Symfony\Bundle\SecurityBundle\Security $security, protected RequestStack $requestStack)
{
$this->security = $security;
$this->requestStack = $requestStack;
}
/**
@ -51,10 +46,10 @@ class UserCacheKeyGenerator
{
$request = $this->requestStack->getCurrentRequest();
//Retrieve the locale from the request, if possible, otherwise use the default locale
$locale = $request ? $request->getLocale() : Locale::getDefault();
$locale = $request instanceof \Symfony\Component\HttpFoundation\Request ? $request->getLocale() : Locale::getDefault();
//If no user was specified, use the currently used one.
if (null === $user) {
if (!$user instanceof \App\Entity\UserSystem\User) {
$user = $this->security->getUser();
}