Fixed phpstan analysis issues and bad code that showed up with phpstan 2.0

This commit is contained in:
Jan Böhmer 2024-12-28 22:31:04 +01:00
parent a273acbecd
commit 946032a101
42 changed files with 98 additions and 85 deletions

View file

@ -58,3 +58,6 @@ parameters:
# Ignore doctrine type mapping mismatch
- '#Property .* type mapping mismatch: property can contain .* but database expects .*#'
# Ignore error of unused WithPermPresetsTrait, as it is used in the migrations which are not analyzed by Phpstan
- '#Trait App\\Migration\\WithPermPresetsTrait is used zero times and is not analysed#'

View file

@ -79,7 +79,7 @@ class CheckRequirementsCommand extends Command
//Checking 32-bit system
if (PHP_INT_SIZE === 4) {
$io->warning('You are using a 32-bit system. You will have problems with working with dates after the year 2038, therefore a 64-bit system is recommended.');
} elseif (PHP_INT_SIZE === 8) {
} elseif (PHP_INT_SIZE === 8) { //@phpstan-ignore-line //PHP_INT_SIZE is always 4 or 8
if (!$only_issues) {
$io->success('You are using a 64-bit system.');
}

View file

@ -79,6 +79,7 @@ class ConvertBBCodeCommand extends Command
/**
* Returns a list which entities and which properties need to be checked.
* @return array<class-string<AbstractNamedDBElement>, string[]>
*/
protected function getTargetsLists(): array
{
@ -109,7 +110,6 @@ class ConvertBBCodeCommand extends Command
$class
));
//Determine which entities of this type we need to modify
/** @var EntityRepository $repo */
$repo = $this->em->getRepository($class);
$qb = $repo->createQueryBuilder('e')
->select('e');

View file

@ -206,12 +206,15 @@ class UsersPermissionsCommand extends Command
return '<fg=green>Allow</>';
} elseif ($permission_value === false) {
return '<fg=red>Disallow</>';
} elseif ($permission_value === null && !$inherit) {
}
// Permission value is null by this point
elseif (!$inherit) {
return '<fg=blue>Inherit</>';
} elseif ($permission_value === null && $inherit) {
} elseif ($inherit) {
return '<fg=red>Disallow (Inherited)</>';
}
//@phpstan-ignore-next-line This line is never reached, but PHPstorm complains otherwise
return '???';
}
}

View file

@ -221,7 +221,6 @@ abstract class BaseAdminController extends AbstractController
}
}
/** @var AbstractPartsContainingRepository $repo */
$repo = $this->entityManager->getRepository($this->entity_class);
return $this->render($this->twig_template, [
@ -397,7 +396,7 @@ abstract class BaseAdminController extends AbstractController
{
if ($entity instanceof AbstractPartsContainingDBElement) {
/** @var AbstractPartsContainingRepository $repo */
$repo = $this->entityManager->getRepository($this->entity_class);
$repo = $this->entityManager->getRepository($this->entity_class); //@phpstan-ignore-line
if ($repo->getPartsCount($entity) > 0) {
$this->addFlash('error', t('entity.delete.must_not_contain_parts', ['%PATH%' => $entity->getFullPath()]));

View file

@ -152,7 +152,7 @@ class LabelController extends AbstractController
{
$id_array = $this->rangeParser->parse($ids);
/** @var DBElementRepository $repo */
/** @var DBElementRepository<AbstractDBElement> $repo */
$repo = $this->em->getRepository($type->getEntityClass());
return $repo->getElementsFromIDArray($id_array);

View file

@ -60,6 +60,7 @@ class PartListsController extends AbstractController
$ids = $request->request->get('ids');
$action = $request->request->get('action');
$target = $request->request->get('target');
$redirectResponse = null;
if (!$this->isCsrfTokenValid('table_action', $request->request->get('_token'))) {
$this->addFlash('error', 'csfr_invalid');
@ -80,7 +81,7 @@ class PartListsController extends AbstractController
}
//If the action handler returned a response, we use it, otherwise we redirect back to the previous page.
if (isset($redirectResponse) && $redirectResponse instanceof Response) {
if ($redirectResponse !== null) {
return $redirectResponse;
}

View file

@ -22,6 +22,7 @@ declare(strict_types=1);
namespace App\Controller;
use App\Entity\Parameters\AbstractParameter;
use Symfony\Component\HttpFoundation\Response;
use App\Entity\Attachments\Attachment;
use App\Entity\Parts\Category;
@ -92,7 +93,7 @@ class TypeaheadController extends AbstractController
/**
* This function map the parameter type to the class, so we can access its repository
* @return class-string
* @return class-string<AbstractParameter>
*/
private function typeToParameterClass(string $type): string
{
@ -155,7 +156,7 @@ class TypeaheadController extends AbstractController
//Ensure user has the correct permissions
$this->denyAccessUnlessGranted('read', $test_obj);
/** @var ParameterRepository $repository */
/** @var ParameterRepository<AbstractParameter> $repository */
$repository = $entityManager->getRepository($class);
$data = $repository->autocompleteParamName($query);

View file

@ -240,7 +240,10 @@ class UserSettingsController extends AbstractController
$page_need_reload = true;
}
/** @var Form $form We need a form implementation for the next calls */
if (!$form instanceof Form) {
throw new RuntimeException('Form is not an instance of Form, so we cannot retrieve the clicked button!');
}
//Remove the avatar attachment from the user if requested
if ($form->getClickedButton() && 'remove_avatar' === $form->getClickedButton()->getName() && $user->getMasterPictureAttachment() instanceof Attachment) {
$em->remove($user->getMasterPictureAttachment());

View file

@ -133,6 +133,7 @@ class TagsConstraint extends AbstractConstraint
return;
}
//@phpstan-ignore-next-line Keep this check to ensure that everything has the same structure even if we add a new operator
if ($this->operator === 'NONE') {
$queryBuilder->andWhere($queryBuilder->expr()->not($queryBuilder->expr()->orX(...$tagsExpressions)));
return;

View file

@ -87,16 +87,14 @@ class ProjectBomEntriesDataTable implements DataTableTypeInterface
if(!$context->getPart() instanceof Part) {
return htmlspecialchars((string) $context->getName());
}
if($context->getPart() instanceof Part) {
$tmp = $this->partDataTableHelper->renderName($context->getPart());
if($context->getName() !== null && $context->getName() !== '') {
$tmp .= '<br><b>'.htmlspecialchars($context->getName()).'</b>';
}
return $tmp;
}
//@phpstan-ignore-next-line
throw new \RuntimeException('This should never happen!');
//Part exists if we reach this point
$tmp = $this->partDataTableHelper->renderName($context->getPart());
if($context->getName() !== null && $context->getName() !== '') {
$tmp .= '<br><b>'.htmlspecialchars($context->getName()).'</b>';
}
return $tmp;
},
])
->add('ipn', TextColumn::class, [

View file

@ -44,15 +44,13 @@ class SQLiteRegexExtensionMiddlewareDriver extends AbstractDriverMiddleware
$native_connection = $connection->getNativeConnection();
//Ensure that the function really exists on the connection, as it is marked as experimental according to PHP documentation
if($native_connection instanceof \PDO && method_exists($native_connection, 'sqliteCreateFunction' )) {
if($native_connection instanceof \PDO) {
$native_connection->sqliteCreateFunction('REGEXP', self::regexp(...), 2, \PDO::SQLITE_DETERMINISTIC);
$native_connection->sqliteCreateFunction('FIELD', self::field(...), -1, \PDO::SQLITE_DETERMINISTIC);
$native_connection->sqliteCreateFunction('FIELD2', self::field2(...), 2, \PDO::SQLITE_DETERMINISTIC);
//Create a new collation for natural sorting
if (method_exists($native_connection, 'sqliteCreateCollation')) {
$native_connection->sqliteCreateCollation('NATURAL_CMP', strnatcmp(...));
}
$native_connection->sqliteCreateCollation('NATURAL_CMP', strnatcmp(...));
}
}

View file

@ -531,7 +531,7 @@ abstract class Attachment extends AbstractNamedDBElement
$url = str_replace(' ', '%20', $url);
//Only set if the URL is not empty
if ($url !== null && $url !== '') {
if ($url !== '') {
if (str_contains($url, '%BASE%') || str_contains($url, '%MEDIA%')) {
throw new InvalidArgumentException('You can not reference internal files via the url field! But nice try!');
}

View file

@ -33,7 +33,7 @@ use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Annotation\Groups;
/**
* @template-covariant AT of Attachment
* @template AT of Attachment
*/
#[ORM\MappedSuperclass(repositoryClass: AttachmentContainingDBElementRepository::class)]
abstract class AttachmentContainingDBElement extends AbstractNamedDBElement implements HasMasterAttachmentInterface, HasAttachmentsInterface

View file

@ -33,8 +33,8 @@ use Symfony\Component\Validator\Constraints as Assert;
/**
* This abstract class is used for companies like suppliers or manufacturers.
*
* @template-covariant AT of Attachment
* @template-covariant PT of AbstractParameter
* @template AT of Attachment
* @template PT of AbstractParameter
* @extends AbstractPartsContainingDBElement<AT, PT>
*/
#[ORM\MappedSuperclass]

View file

@ -31,8 +31,8 @@ use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Annotation\Groups;
/**
* @template-covariant AT of Attachment
* @template-covariant PT of AbstractParameter
* @template AT of Attachment
* @template PT of AbstractParameter
* @extends AbstractStructuralDBElement<AT, PT>
*/
#[ORM\MappedSuperclass(repositoryClass: AbstractPartsContainingRepository::class)]

View file

@ -53,8 +53,8 @@ use Symfony\Component\Serializer\Annotation\Groups;
*
* @see \App\Tests\Entity\Base\AbstractStructuralDBElementTest
*
* @template-covariant AT of Attachment
* @template-covariant PT of AbstractParameter
* @template AT of Attachment
* @template PT of AbstractParameter
* @template-use ParametersTrait<PT>
* @extends AttachmentContainingDBElement<AT>
* @uses ParametersTrait<PT>

View file

@ -22,6 +22,8 @@ declare(strict_types=1);
*/
namespace App\Entity\LabelSystem;
use App\Entity\Base\AbstractDBElement;
use App\Entity\Base\AbstractNamedDBElement;
use App\Entity\Parts\Part;
use App\Entity\Parts\PartLot;
use App\Entity\Parts\StorageLocation;
@ -34,7 +36,7 @@ enum LabelSupportedElement: string
/**
* Returns the entity class for the given element type
* @return string
* @return class-string<AbstractDBElement>
*/
public function getEntityClass(): string
{

View file

@ -185,7 +185,6 @@ class PartLot extends AbstractDBElement implements TimeStampableInterface, Named
*
* @return bool|null True, if the part lot is expired. Returns null, if no expiration date was set.
*
* @throws Exception If an error with the DateTime occurs
*/
public function isExpired(): ?bool
{

View file

@ -103,7 +103,7 @@ class Supplier extends AbstractCompany
protected ?AbstractStructuralDBElement $parent = null;
/**
* @var Collection<int, Orderdetail>|Orderdetail[]
* @var Collection<int, Orderdetail>
*/
#[ORM\OneToMany(mappedBy: 'supplier', targetEntity: Orderdetail::class)]
protected Collection $orderdetails;

View file

@ -333,7 +333,6 @@ class Project extends AbstractStructuralDBElement
{
//If this project has subprojects, and these have builds part, they must be included in the BOM
foreach ($this->getChildren() as $child) {
/** @var $child Project */
if (!$child->getBuildPart() instanceof Part) {
continue;
}

View file

@ -893,8 +893,6 @@ class User extends AttachmentContainingDBElement implements UserInterface, HasPe
* @param string[] $codes An array containing the backup codes
*
* @return $this
*
* @throws Exception If an error with the datetime occurs
*/
public function setBackupCodes(array $codes): self
{

View file

@ -43,7 +43,7 @@ class StructuralEntityChoiceHelper
/**
* Generates the choice attributes for the given AbstractStructuralDBElement.
* @return array|string[]
* @return array<string, mixed>
*/
public function generateChoiceAttr(AbstractNamedDBElement $choice, Options|array $options): array
{

View file

@ -24,6 +24,7 @@ declare(strict_types=1);
namespace App\Form\Type\Helper;
use App\Entity\Base\AbstractNamedDBElement;
use App\Entity\Base\AbstractStructuralDBElement;
use App\Repository\StructuralDBElementRepository;
use App\Services\Trees\NodesListBuilder;
use Doctrine\ORM\EntityManagerInterface;
@ -33,6 +34,9 @@ use Symfony\Component\Form\FormInterface;
use Symfony\Component\OptionsResolver\Options;
use Symfony\Contracts\Translation\TranslatorInterface;
/**
* @template T of AbstractStructuralDBElement
*/
class StructuralEntityChoiceLoader extends AbstractChoiceLoader
{
private ?string $additional_element = null;
@ -90,10 +94,14 @@ class StructuralEntityChoiceLoader extends AbstractChoiceLoader
}
}
/** @var class-string<T> $class */
$class = $this->options['class'];
/** @var StructuralDBElementRepository $repo */
/** @var StructuralDBElementRepository<T> $repo */
$repo = $this->entityManager->getRepository($class);
$entities = $repo->getNewEntityFromPath($value, '->');
$results = [];

View file

@ -99,7 +99,6 @@ final class TriStateCheckboxType extends AbstractType implements DataTransformer
*
* @return mixed The value in the transformed representation
*
* @throws TransformationFailedException when the transformation fails
*/
public function transform(mixed $value)
{
@ -142,8 +141,6 @@ final class TriStateCheckboxType extends AbstractType implements DataTransformer
* @param mixed $value The value in the transformed representation
*
* @return mixed The value in the original representation
*
* @throws TransformationFailedException when the transformation fails
*/
public function reverseTransform(mixed $value)
{

View file

@ -151,7 +151,7 @@ class StructuralDBElementRepository extends AttachmentContainingDBElementReposit
}
if (null === $entity) {
$class = $this->getClassName();
/** @var AbstractStructuralDBElement $entity */
/** @var TEntityClass $entity */
$entity = new $class;
$entity->setName($name);
$entity->setParent($parent);
@ -265,7 +265,7 @@ class StructuralDBElementRepository extends AttachmentContainingDBElementReposit
}
$class = $this->getClassName();
/** @var AbstractStructuralDBElement $entity */
/** @var TEntityClass $entity */
$entity = new $class;
$entity->setName($name);

View file

@ -40,12 +40,10 @@ final class UserChecker implements UserCheckerInterface
/**
* Checks the user account before authentication.
*
* @throws AccountStatusException
*/
public function checkPreAuth(UserInterface $user): void
{
// TODO: Implement checkPreAuth() method.
//We don't need to check the user before authentication, just implemented to fulfill the interface
}
/**

View file

@ -69,6 +69,15 @@ class StructuralElementDenormalizer implements DenormalizerInterface, Denormaliz
&& in_array('import', $context['groups'] ?? [], true);
}
/**
* @template T of AbstractStructuralDBElement
* @param $data
* @phpstan-param class-string<T> $type
* @param string|null $format
* @param array $context
* @return AbstractStructuralDBElement|null
* @phpstan-return T|null
*/
public function denormalize($data, string $type, string $format = null, array $context = []): ?AbstractStructuralDBElement
{
//Do not use API Platform's denormalizer
@ -85,7 +94,7 @@ class StructuralElementDenormalizer implements DenormalizerInterface, Denormaliz
$deserialized_entity = $this->denormalizer->denormalize($data, $type, $format, $context);
//Check if we already have the entity in the database (via path)
/** @var StructuralDBElementRepository $repo */
/** @var StructuralDBElementRepository<T> $repo */
$repo = $this->entityManager->getRepository($type);
$path = $deserialized_entity->getFullPath(AbstractStructuralDBElement::PATH_DELIMITER_ARROW);

View file

@ -54,7 +54,7 @@ class StructuralElementFromNameDenormalizer implements DenormalizerInterface
public function denormalize($data, string $type, string $format = null, array $context = []): AbstractStructuralDBElement|null
{
//Retrieve the repository for the given type
/** @var StructuralDBElementRepository $repo */
/** @var StructuralDBElementRepository<T> $repo */
$repo = $this->em->getRepository($type);
$path_delimiter = $context['path_delimiter'] ?? '->';

View file

@ -46,7 +46,7 @@ class MoneyFormatter
public function format(string|float $value, ?Currency $currency = null, int $decimals = 5, bool $show_all_digits = false): string
{
$iso_code = $this->base_currency;
if ($currency instanceof Currency && ($currency->getIsoCode() !== null && $currency->getIsoCode() !== '')) {
if ($currency instanceof Currency && ($currency->getIsoCode() !== '')) {
$iso_code = $currency->getIsoCode();
}

View file

@ -153,6 +153,7 @@ class BOMImporter
break;
}
//@phpstan-ignore-next-line We want to keep this check just to be safe when something changes
$new_index = self::MAP_KICAD_PCB_FIELDS[$index] ?? throw new \UnexpectedValueException('Invalid field index!');
$out[$new_index] = $field;
}

View file

@ -64,7 +64,7 @@ class EntityImporter
* @phpstan-param class-string<T> $class_name
* @param AbstractStructuralDBElement|null $parent the element which will be used as parent element for new elements
* @param array $errors an associative array containing all validation errors
* @param-out array<string, array{'entity': object, 'violations': ConstraintViolationListInterface}> $errors
* @param-out list<array{'entity': object, 'violations': ConstraintViolationListInterface}> $errors
*
* @return AbstractNamedDBElement[] An array containing all valid imported entities (with the type $class_name)
* @return T[]
@ -133,13 +133,15 @@ class EntityImporter
if ($repo instanceof StructuralDBElementRepository) {
$entities = $repo->getNewEntityFromPath($new_path);
$entity = end($entities);
if ($entity === false) {
throw new InvalidArgumentException('getNewEntityFromPath returned an empty array!');
}
} else { //Otherwise just create a new entity
$entity = new $class_name;
$entity->setName($name);
}
//Validate entity
$tmp = $this->validator->validate($entity);
//If no error occured, write entry to DB:
@ -227,6 +229,11 @@ class EntityImporter
//Iterate over each $entity write it to DB.
foreach ($entities as $key => $entity) {
//Ensure that entity is a NamedDBElement
if (!$entity instanceof AbstractNamedDBElement) {
throw new \RuntimeException("Encountered an entity that is not a NamedDBElement!");
}
//Validate entity
$tmp = $this->validator->validate($entity);
@ -281,7 +288,7 @@ class EntityImporter
*
* @param File $file the file that should be used for importing
* @param array $options options for the import process
* @param AbstractNamedDBElement[] $entities The imported entities are returned in this array
* @param-out AbstractNamedDBElement[] $entities The imported entities are returned in this array
*
* @return array<string, array{'entity': object, 'violations': ConstraintViolationListInterface}> An associative array containing an ConstraintViolationList and the entity name as key are returned,
* if an error happened during validation. When everything was successfully, the array should be empty.
@ -317,7 +324,7 @@ class EntityImporter
* @param array $options options for the import process
* @param-out array<string, array{'entity': object, 'violations': ConstraintViolationListInterface}> $errors
*
* @return array an array containing the deserialized elements
* @return AbstractNamedDBElement[] an array containing the deserialized elements
*/
public function importFile(File $file, array $options = [], array &$errors = []): array
{

View file

@ -205,10 +205,6 @@ trait PKImportHelperTrait
*/
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');
}
$id = (int) $id;
$metadata = $this->em->getClassMetadata($element::class);

View file

@ -771,11 +771,6 @@ class OEMSecretsProvider implements InfoProviderInterface
// Logic to extract parameters from the description
$extractedParameters = $this->parseDescriptionToParameters($description) ?? [];
// Ensure that $extractedParameters is an array
if (!is_array($extractedParameters)) {
$extractedParameters = [];
}
foreach ($extractedParameters as $newParam) {
$isDuplicate = false;
foreach ($parameters as $existingParam) {

View file

@ -146,11 +146,11 @@ final class LabelExampleElementsGenerator
throw new InvalidArgumentException('$class must be an child of AbstractStructuralDBElement');
}
/** @var AbstractStructuralDBElement $parent */
/** @var T $parent */
$parent = new $class();
$parent->setName('Example');
/** @var AbstractStructuralDBElement $child */
/** @var T $child */
$child = new $class();
$child->setName((new ReflectionClass($class))->getShortName());
$child->setParent($parent);

View file

@ -62,10 +62,6 @@ final class LabelGenerator
*/
public function generateLabel(LabelOptions $options, object|array $elements): string
{
if (!is_array($elements) && !is_object($elements)) {
throw new InvalidArgumentException('$element must be an object or an array of objects!');
}
if (!is_array($elements)) {
$elements = [$elements];
}

View file

@ -75,7 +75,6 @@ final class LabelProfileDropdownHelper
$secure_class_name = $this->tagGenerator->getElementTypeCacheTag(LabelProfile::class);
$key = 'profile_dropdown_'.$this->keyGenerator->generateKey().'_'.$secure_class_name.'_'.$type->value;
/** @var LabelProfileRepository $repo */
$repo = $this->entityManager->getRepository(LabelProfile::class);
return $this->cache->get($key, function (ItemInterface $item) use ($repo, $type, $secure_class_name) {

View file

@ -53,7 +53,6 @@ final class PartsTableActionHandler
{
$id_array = explode(',', $ids);
/** @var PartRepository $repo */
$repo = $this->entityManager->getRepository(Part::class);
return $repo->getElementsFromIDArray($id_array);

View file

@ -40,9 +40,6 @@ class BannerHelper
public function getBanner(): string
{
$banner = $this->partdb_banner;
if (!is_string($banner)) {
throw new \RuntimeException('The parameter "partdb.banner" must be a string.');
}
if ($banner === '') {
$banner_path = $this->project_dir
.DIRECTORY_SEPARATOR.'config'.DIRECTORY_SEPARATOR.'banner.md';

View file

@ -122,7 +122,6 @@ class StatisticsHelper
throw new InvalidArgumentException('No count for the given type available!');
}
/** @var EntityRepository $repo */
$repo = $this->em->getRepository($arr[$type]);
return $repo->count([]);

View file

@ -23,9 +23,11 @@ declare(strict_types=1);
namespace App\Services\Trees;
use App\Entity\Base\AbstractDBElement;
use App\Entity\Base\AbstractNamedDBElement;
use App\Entity\Base\AbstractStructuralDBElement;
use App\Repository\AttachmentContainingDBElementRepository;
use App\Repository\DBElementRepository;
use App\Repository\NamedDBElementRepository;
use App\Repository\StructuralDBElementRepository;
use App\Services\Cache\ElementCacheTagGenerator;
use App\Services\Cache\UserCacheKeyGenerator;
@ -51,7 +53,7 @@ class NodesListBuilder
* Gets a flattened hierarchical tree. Useful for generating option lists.
* In difference to the Repository Function, the results here are cached.
*
* @template T of AbstractDBElement
* @template T of AbstractNamedDBElement
*
* @param string $class_name the class name of the entity you want to retrieve
* @phpstan-param class-string<T> $class_name
@ -69,7 +71,7 @@ class NodesListBuilder
$ids = $this->getFlattenedIDs($class_name, $parent);
//Retrieve the elements from the IDs, the order is the same as in the $ids array
/** @var DBElementRepository $repo */
/** @var NamedDBElementRepository<T> $repo */
$repo = $this->em->getRepository($class_name);
if ($repo instanceof AttachmentContainingDBElementRepository) {
@ -81,7 +83,9 @@ class NodesListBuilder
/**
* This functions returns the (cached) list of the IDs of the elements for the flattened tree.
* @template T of AbstractNamedDBElement
* @param string $class_name
* @phpstan-param class-string<T> $class_name
* @param AbstractStructuralDBElement|null $parent
* @return int[]
*/
@ -96,10 +100,11 @@ class NodesListBuilder
// Invalidate when groups, an element with the class or the user changes
$item->tag(['groups', 'tree_list', $this->keyGenerator->generateKey(), $secure_class_name]);
/** @var StructuralDBElementRepository $repo */
/** @var NamedDBElementRepository<T> $repo */
$repo = $this->em->getRepository($class_name);
return array_map(static fn(AbstractDBElement $element) => $element->getID(), $repo->getFlatList($parent));
return array_map(static fn(AbstractDBElement $element) => $element->getID(),
$repo instanceof AbstractStructuralDBElement ? $repo->getFlatList($parent) : $repo->getFlatList());
});
}

View file

@ -33,6 +33,7 @@ use App\Entity\Parts\Supplier;
use App\Entity\ProjectSystem\Project;
use App\Helpers\Trees\TreeViewNode;
use App\Helpers\Trees\TreeViewNodeIterator;
use App\Repository\NamedDBElementRepository;
use App\Repository\StructuralDBElementRepository;
use App\Services\Cache\ElementCacheTagGenerator;
use App\Services\Cache\UserCacheKeyGenerator;
@ -219,6 +220,7 @@ class TreeViewGenerator
* The treeview is generic, that means the href are null and ID values are set.
*
* @param string $class The class for which the tree should be generated
* @phpstan-param class-string<AbstractNamedDBElement> $class
* @param AbstractStructuralDBElement|null $parent the parent the root elements should have
*
* @return TreeViewNode[]
@ -232,12 +234,12 @@ class TreeViewGenerator
throw new InvalidArgumentException('$parent must be of the type $class!');
}
/** @var StructuralDBElementRepository $repo */
/** @var NamedDBElementRepository<AbstractNamedDBElement> $repo */
$repo = $this->em->getRepository($class);
//If we just want a part of a tree, don't cache it
if ($parent instanceof AbstractStructuralDBElement) {
return $repo->getGenericNodeTree($parent);
return $repo->getGenericNodeTree($parent); //@phpstan-ignore-line PHPstan does not seem to recognize, that we have a StructuralDBElementRepository here, which have 1 argument
}
$secure_class_name = $this->tagGenerator->getElementTypeCacheTag($class);
@ -246,7 +248,7 @@ class TreeViewGenerator
return $this->cache->get($key, function (ItemInterface $item) use ($repo, $parent, $secure_class_name) {
// Invalidate when groups, an element with the class or the user changes
$item->tag(['groups', 'tree_treeview', $this->keyGenerator->generateKey(), $secure_class_name]);
return $repo->getGenericNodeTree($parent);
return $repo->getGenericNodeTree($parent); //@phpstan-ignore-line
});
}
}