diff --git a/lib/Doctrine/Repository.php b/lib/Doctrine/Repository.php index ee7b5f4492..d76b6aedbe 100644 --- a/lib/Doctrine/Repository.php +++ b/lib/Doctrine/Repository.php @@ -13,10 +13,10 @@ abstract class Repository { /** @var EntityManager */ protected $entityManager; - /** @var ClassMetadata */ + /** @var ClassMetadata */ protected $classMetadata; - /** @var DoctrineEntityRepository */ + /** @var DoctrineEntityRepository */ protected $doctrineRepository; /** @var string[] */ diff --git a/lib/Doctrine/TablePrefixMetadataFactory.php b/lib/Doctrine/TablePrefixMetadataFactory.php index 15540ab123..2a2f0ffdec 100644 --- a/lib/Doctrine/TablePrefixMetadataFactory.php +++ b/lib/Doctrine/TablePrefixMetadataFactory.php @@ -25,6 +25,9 @@ class TablePrefixMetadataFactory extends ClassMetadataFactory { $this->setProxyClassNameResolver(new ProxyClassNameResolver()); } + /** + * @return ClassMetadata + */ public function getMetadataFor($className) { $classMetadata = parent::getMetadataFor($className); if (isset($this->prefixedMap[$classMetadata->getName()])) { @@ -42,6 +45,9 @@ class TablePrefixMetadataFactory extends ClassMetadataFactory { return $classMetadata; } + /** + * @param ClassMetadata $classMetadata + */ public function addPrefix(ClassMetadata $classMetadata) { if (!$classMetadata->isInheritanceTypeSingleTable() || $classMetadata->getName() === $classMetadata->rootEntityName) { $classMetadata->setPrimaryTable([ diff --git a/lib/Entities/NewsletterEntity.php b/lib/Entities/NewsletterEntity.php index 89ed8b3115..afe1973a1c 100644 --- a/lib/Entities/NewsletterEntity.php +++ b/lib/Entities/NewsletterEntity.php @@ -131,25 +131,25 @@ class NewsletterEntity { /** * @ORM\OneToMany(targetEntity="MailPoet\Entities\NewsletterEntity", mappedBy="parent") - * @var NewsletterEntity[]|ArrayCollection + * @var ArrayCollection */ private $children; /** * @ORM\OneToMany(targetEntity="MailPoet\Entities\NewsletterSegmentEntity", mappedBy="newsletter", orphanRemoval=true) - * @var NewsletterSegmentEntity[]|ArrayCollection + * @var ArrayCollection */ private $newsletterSegments; /** * @ORM\OneToMany(targetEntity="MailPoet\Entities\NewsletterOptionEntity", mappedBy="newsletter", orphanRemoval=true) - * @var NewsletterOptionEntity[]|ArrayCollection + * @var ArrayCollection */ private $options; /** * @ORM\OneToMany(targetEntity="MailPoet\Entities\SendingQueueEntity", mappedBy="newsletter") - * @var SendingQueueEntity[]|ArrayCollection + * @var ArrayCollection */ private $queues; @@ -404,21 +404,21 @@ class NewsletterEntity { } /** - * @return NewsletterEntity[]|ArrayCollection + * @return ArrayCollection */ public function getChildren() { return $this->children; } /** - * @return NewsletterSegmentEntity[]|ArrayCollection + * @return ArrayCollection */ public function getNewsletterSegments() { return $this->newsletterSegments; } /** - * @return NewsletterOptionEntity[]|ArrayCollection + * @return ArrayCollection */ public function getOptions() { return $this->options; @@ -437,7 +437,7 @@ class NewsletterEntity { } /** - * @return SendingQueueEntity[]|ArrayCollection + * @return ArrayCollection */ public function getQueues() { return $this->queues; @@ -453,6 +453,9 @@ class NewsletterEntity { return $this->queues->matching($criteria)->first() ?: null; } + /** + * @return Collection + */ private function getUnfinishedQueues(): Collection { $criteria = new Criteria(); $expr = Criteria::expr(); diff --git a/lib/Entities/NewsletterLinkEntity.php b/lib/Entities/NewsletterLinkEntity.php index 4762f38f20..dce387096c 100644 --- a/lib/Entities/NewsletterLinkEntity.php +++ b/lib/Entities/NewsletterLinkEntity.php @@ -50,7 +50,7 @@ class NewsletterLinkEntity { * If we didn't specify extra lazy the function would load all clicks and count them. This way it uses a single count query. * @ORM\OneToMany(targetEntity="MailPoet\Entities\StatisticsClickEntity", mappedBy="link", fetch="EXTRA_LAZY") * - * @var StatisticsClickEntity[]|ArrayCollection + * @var ArrayCollection */ private $clicks; diff --git a/lib/Entities/SegmentEntity.php b/lib/Entities/SegmentEntity.php index 05d5d74bdc..9bbeac011a 100644 --- a/lib/Entities/SegmentEntity.php +++ b/lib/Entities/SegmentEntity.php @@ -50,7 +50,7 @@ class SegmentEntity { /** * @ORM\OneToMany(targetEntity="MailPoet\Entities\DynamicSegmentFilterEntity", mappedBy="segment") - * @var DynamicSegmentFilterEntity[]|ArrayCollection + * @var ArrayCollection */ private $dynamicFilters; @@ -121,7 +121,7 @@ class SegmentEntity { } /** - * @return DynamicSegmentFilterEntity[]|ArrayCollection + * @return ArrayCollection */ public function getDynamicFilters() { return $this->dynamicFilters; diff --git a/lib/Entities/StatisticsClickEntity.php b/lib/Entities/StatisticsClickEntity.php index 055ee3bfb9..0328cc149b 100644 --- a/lib/Entities/StatisticsClickEntity.php +++ b/lib/Entities/StatisticsClickEntity.php @@ -48,7 +48,7 @@ class StatisticsClickEntity { /** * @ORM\OneToMany(targetEntity="MailPoet\Entities\StatisticsWooCommercePurchaseEntity", mappedBy="click", fetch="EXTRA_LAZY")* - * @var StatisticsWooCommercePurchaseEntity[]|ArrayCollection + * @var ArrayCollection */ private $wooCommercePurchases; @@ -140,7 +140,7 @@ class StatisticsClickEntity { } /** - * @return StatisticsWooCommercePurchaseEntity[]|ArrayCollection + * @return ArrayCollection */ public function getWooCommercePurchases() { return $this->wooCommercePurchases; diff --git a/lib/Entities/SubscriberEntity.php b/lib/Entities/SubscriberEntity.php index f228e29fa3..d794f089bc 100644 --- a/lib/Entities/SubscriberEntity.php +++ b/lib/Entities/SubscriberEntity.php @@ -139,7 +139,7 @@ class SubscriberEntity { /** * @ORM\OneToMany(targetEntity="MailPoet\Entities\SubscriberSegmentEntity", mappedBy="subscriber") - * @var iterable&Collection + * @var Collection */ private $subscriberSegments; @@ -395,7 +395,7 @@ class SubscriberEntity { } /** - * @return Collection + * @return Collection */ public function getSubscriberSegments() { return $this->subscriberSegments; diff --git a/lib/Newsletter/Renderer/Blocks/AbandonedCartContent.php b/lib/Newsletter/Renderer/Blocks/AbandonedCartContent.php index d54904b4cf..bb8333544d 100644 --- a/lib/Newsletter/Renderer/Blocks/AbandonedCartContent.php +++ b/lib/Newsletter/Renderer/Blocks/AbandonedCartContent.php @@ -36,8 +36,8 @@ class AbandonedCartContent { $optionField = $newsletterOption->getOptionField(); return $optionField && $optionField->getName() === 'event'; })->first(); - if ($groupOption->getValue() !== WooCommerceEmail::SLUG - || $eventOption->getValue() !== AbandonedCart::SLUG + if (($groupOption instanceof NewsletterOptionEntity && $groupOption->getValue() !== WooCommerceEmail::SLUG) + || ($eventOption instanceof NewsletterOptionEntity && $eventOption->getValue() !== AbandonedCart::SLUG) ) { // Do not display the block if not an AbandonedCart email return []; diff --git a/lib/Segments/SegmentsRepository.php b/lib/Segments/SegmentsRepository.php index 298fa093d3..8a3b9766c0 100644 --- a/lib/Segments/SegmentsRepository.php +++ b/lib/Segments/SegmentsRepository.php @@ -111,8 +111,10 @@ class SegmentsRepository extends Repository { // We want to remove redundant filters before update while ($segment->getDynamicFilters()->count() > count($filtersData)) { $filterEntity = $segment->getDynamicFilters()->last(); - $segment->getDynamicFilters()->removeElement($filterEntity); - $this->entityManager->remove($filterEntity); + if ($filterEntity) { + $segment->getDynamicFilters()->removeElement($filterEntity); + $this->entityManager->remove($filterEntity); + } } foreach ($filtersData as $key => $filterData) { if ($filterData instanceof DynamicSegmentFilterData) { diff --git a/lib/Subscribers/ImportExport/ImportExportRepository.php b/lib/Subscribers/ImportExport/ImportExportRepository.php index 3ad3068934..c190e0bbd6 100644 --- a/lib/Subscribers/ImportExport/ImportExportRepository.php +++ b/lib/Subscribers/ImportExport/ImportExportRepository.php @@ -54,6 +54,9 @@ class ImportExportRepository { $this->filterHandler = $filterHandler; } + /** + * @return ClassMetadata + */ protected function getClassMetadata(string $className): ClassMetadata { return $this->entityManager->getClassMetadata($className); } diff --git a/lib/Tasks/Subscribers/BatchIterator.php b/lib/Tasks/Subscribers/BatchIterator.php index 020580323d..7d0c9996d0 100644 --- a/lib/Tasks/Subscribers/BatchIterator.php +++ b/lib/Tasks/Subscribers/BatchIterator.php @@ -4,6 +4,9 @@ namespace MailPoet\Tasks\Subscribers; use MailPoet\Models\ScheduledTaskSubscriber; +/** + * @implements \Iterator + */ class BatchIterator implements \Iterator, \Countable { private $taskId; private $batchSize; diff --git a/lib/Tracy/ApiPanel/ApiPanel.php b/lib/Tracy/ApiPanel/ApiPanel.php index 5a95eda3c9..dd27a5a198 100644 --- a/lib/Tracy/ApiPanel/ApiPanel.php +++ b/lib/Tracy/ApiPanel/ApiPanel.php @@ -20,10 +20,10 @@ class ApiPanel implements IBarPanel { /** @var array */ protected $requestData; - /** @var ReflectionClass */ + /** @var ReflectionClass */ protected $endpointReflection; - public function __construct($endpoint, $requestMethod, $requestData) { + public function __construct(APIEndpoint $endpoint, $requestMethod, $requestData) { $this->endpoint = $endpoint; $this->requestMethod = $requestMethod; $this->requestData = $requestData; diff --git a/tasks/phpstan/phpstan-tests.neon b/tasks/phpstan/phpstan-tests.neon index b50fb34b18..800dd69d1e 100644 --- a/tasks/phpstan/phpstan-tests.neon +++ b/tasks/phpstan/phpstan-tests.neon @@ -32,7 +32,6 @@ parameters: maximumNumberOfProcesses: 4 # exclude level 6 errors - checkGenericClassInNonGenericObjectType: false checkMissingIterableValueType: false checkMissingTypehints: false diff --git a/tasks/phpstan/phpstan.neon b/tasks/phpstan/phpstan.neon index d60a033652..0aeb05e53d 100644 --- a/tasks/phpstan/phpstan.neon +++ b/tasks/phpstan/phpstan.neon @@ -28,7 +28,6 @@ parameters: objectManagerLoader: create-entity-manager.php # exclude level 6 errors - checkGenericClassInNonGenericObjectType: false checkMissingIterableValueType: false # analysis of templates is extremely slow, let's skip them for now diff --git a/tests/integration/Newsletter/NewsletterSaveControllerTest.php b/tests/integration/Newsletter/NewsletterSaveControllerTest.php index d23325c916..aa196421d8 100644 --- a/tests/integration/Newsletter/NewsletterSaveControllerTest.php +++ b/tests/integration/Newsletter/NewsletterSaveControllerTest.php @@ -112,6 +112,7 @@ class NewsletterSaveControllerTest extends \MailPoetTest { return $optionField && $optionField->getName() === 'schedule'; })->first(); + assert($scheduleOption instanceof NewsletterOptionEntity); // PHPStan expect($scheduleOption->getValue())->equals('0 14 * * 1'); // schedule should be recalculated when options change @@ -123,6 +124,7 @@ class NewsletterSaveControllerTest extends \MailPoetTest { return $optionField && $optionField->getName() === 'schedule'; })->first(); + assert($scheduleOption instanceof NewsletterOptionEntity); // PHPStan expect($scheduleOption->getValue())->equals('* * * * *'); } @@ -165,6 +167,7 @@ class NewsletterSaveControllerTest extends \MailPoetTest { return $optionField && $optionField->getName() === 'schedule'; })->first(); expect($task1->getScheduledAt())->notEquals($currentTime); + assert($scheduleOption instanceof NewsletterOptionEntity); // PHPStan expect($task1->getScheduledAt())->equals(Scheduler::getNextRunDate($scheduleOption->getValue())); expect($task2->getScheduledAt())->null(); } @@ -187,7 +190,11 @@ class NewsletterSaveControllerTest extends \MailPoetTest { $newsletter = $this->saveController->save($newsletterData); expect(count($newsletter->getNewsletterSegments()))->equals(1); - expect($newsletter->getNewsletterSegments()->first()->getSegment()->getName())->equals('Segment 1'); + $newsletterSegment = $newsletter->getNewsletterSegments()->first(); + assert($newsletterSegment instanceof NewsletterSegmentEntity); // PHPStan + $segment = $newsletterSegment->getSegment(); + assert($segment instanceof SegmentEntity); // PHPStan + expect($segment->getName())->equals('Segment 1'); } public function testItDeletesSendingQueueAndSetsNewsletterStatusToDraftWhenItIsUnscheduled() { diff --git a/tests/unit/Form/HtmlParser.php b/tests/unit/Form/HtmlParser.php index 8572c40db9..0c7d9c2b19 100644 --- a/tests/unit/Form/HtmlParser.php +++ b/tests/unit/Form/HtmlParser.php @@ -6,6 +6,9 @@ class HtmlParser { private $allowedHtml5Tags = [' + */ public function findByXpath(string $html, string $xpath): \DOMNodeList { $isHtml5 = str_replace($this->allowedHtml5Tags, '', $html) !== $html; $dom = new \DOMDocument();