Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 67 additions & 0 deletions phpstan-baseline.neon
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
parameters:
ignoreErrors:
-
message: '#^Interface IteratorAggregate specifies template type TKey of interface Traversable as mixed but it''s already specified as \(int\|string\)\.$#'
identifier: generics.interfaceConflict
count: 1
path: src/FeedContext/ContextList.php

-
message: '#^Parameter \#1 \$context of method Setono\\SyliusFeedPlugin\\FeedContext\\ContextList\:\:add\(\) expects array\|object, mixed given\.$#'
identifier: argument.type
count: 1
path: src/FeedContext/ContextList.php

-
message: '#^PHPDoc tag @var with type Sylius\\Component\\Core\\Model\\ProductTranslationInterface\|null is not subtype of native type Sylius\\Component\\Resource\\Model\\TranslationInterface\|null\.$#'
identifier: varTag.nativeType
count: 1
path: src/FeedContext/Google/Shopping/ProductItemContext.php

-
message: '#^PHPDoc tag @var with type Sylius\\Component\\Taxonomy\\Model\\TaxonTranslationInterface\|null is not subtype of native type Sylius\\Component\\Resource\\Model\\TranslationInterface\|null\.$#'
identifier: varTag.nativeType
count: 1
path: src/FeedContext/Google/Shopping/ProductItemContext.php

-
message: '#^Parameter \#1 \$callback of function array_map expects \(callable\(Sylius\\Component\\Taxonomy\\Model\\TaxonInterface\)\: mixed\)\|null, Closure\(Sylius\\Component\\Core\\Model\\TaxonInterface\)\: string given\.$#'
identifier: argument.type
count: 1
path: src/FeedContext/Google/Shopping/ProductItemContext.php

-
message: '#^Parameter \#1 \$price of method Setono\\SyliusFeedPlugin\\Feed\\Model\\Google\\Shopping\\Product\:\:setPrice\(\) expects Setono\\SyliusFeedPlugin\\Feed\\Model\\Google\\Shopping\\Price\|null, mixed given\.$#'
identifier: argument.type
count: 1
path: src/FeedContext/Google/Shopping/ProductItemContext.php

-
message: '#^Parameter \#1 \$salePrice of method Setono\\SyliusFeedPlugin\\Feed\\Model\\Google\\Shopping\\Product\:\:setSalePrice\(\) expects Setono\\SyliusFeedPlugin\\Feed\\Model\\Google\\Shopping\\Price\|null, mixed given\.$#'
identifier: argument.type
count: 1
path: src/FeedContext/Google/Shopping/ProductItemContext.php

-
message: '#^Parameter \#1 \$translatable of method Setono\\SyliusFeedPlugin\\FeedContext\\Google\\Shopping\\ProductItemContext\:\:getTranslation\(\) expects Sylius\\Component\\Resource\\Model\\TranslatableInterface, Sylius\\Component\\Core\\Model\\ProductInterface given\.$#'
identifier: argument.type
count: 1
path: src/FeedContext/Google/Shopping/ProductItemContext.php

-
message: '#^Parameter \#1 \$translatable of method Setono\\SyliusFeedPlugin\\FeedContext\\Google\\Shopping\\ProductItemContext\:\:getTranslation\(\) expects Sylius\\Component\\Resource\\Model\\TranslatableInterface, Sylius\\Component\\Core\\Model\\TaxonInterface given\.$#'
identifier: argument.type
count: 1
path: src/FeedContext/Google/Shopping/ProductItemContext.php

-
message: '#^Parameter \#2 \$currency of class Setono\\SyliusFeedPlugin\\Feed\\Model\\Google\\Shopping\\Price constructor expects string\|Stringable, Sylius\\Component\\Currency\\Model\\CurrencyInterface given\.$#'
identifier: argument.type
count: 1
path: src/FeedContext/Google/Shopping/ProductItemContext.php

-
message: '#^PHPDoc tag @var with type array\<array\{basename\: string, path\: string\}\>\|League\\Flysystem\\DirectoryListing\<League\\Flysystem\\StorageAttributes\> is not subtype of type League\\Flysystem\\DirectoryListing\<League\\Flysystem\\StorageAttributes\>\.$#'
identifier: varTag.type
count: 1
path: src/Message/Handler/FinishGenerationHandler.php
6 changes: 5 additions & 1 deletion phpstan.neon
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
includes:
- phpstan-baseline.neon

parameters:
level: max

Expand All @@ -22,7 +25,7 @@ parameters:
objectManagerLoader: tests/PHPStan/object_manager.php

reportUnmatchedIgnoredErrors: false
treatPhpDocTypesAsCertain: false
treatPhpDocTypesAsCertain: true

ignoreErrors:
-
Expand All @@ -31,6 +34,7 @@ parameters:
- doctrine.associationType
- doctrine.columnType
- missingType.generics
- missingType.parameter
-
identifier: class.notFound
message: '#League\\Flysystem\\#'
3 changes: 1 addition & 2 deletions src/Controller/Action/Shop/ShowFeedAction.php
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,8 @@ public function __invoke(string $code): StreamedResponse
}
}

/** @var resource|false $stream */
$stream = $filesystem->readStream((string) $feedPath);
if (false === $stream) {
if (!\is_resource($stream)) {
throw new RuntimeException(sprintf('An error occurred trying to read the feed file %s', $feedPath));
}

Expand Down
4 changes: 4 additions & 0 deletions src/DataProvider/DataProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ class DataProvider implements DataProviderInterface
/** @var CollectionBatcherInterface[] */
private array $batchers = [];

/**
* @param class-string $class
*/
public function __construct(
private readonly BatcherFactoryInterface $batcherFactory,
private readonly QueryRebuilderInterface $queryRebuilder,
Expand Down Expand Up @@ -53,6 +56,7 @@ public function getBatchCount(ChannelInterface $channel, LocaleInterface $locale

public function getItems(BatchInterface $batch): iterable
{
/** @phpstan-ignore return.type */
return $this->queryRebuilder->rebuild($batch)->getResult();
}

Expand Down
2 changes: 2 additions & 0 deletions src/DataProvider/DataProviderInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ interface DataProviderInterface
{
/**
* This will be the root class of the data provided by this data provider
*
* @return class-string
*/
public function getClass(): string;

Expand Down
2 changes: 2 additions & 0 deletions src/DependencyInjection/Compiler/RegisterFilesystemPass.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ public function process(ContainerBuilder $container): void

foreach (self::PARAMETERS as $parameter) {
$parameterValue = $container->getParameter($parameter);
Assert::string($parameterValue);

if (!$container->hasDefinition($parameterValue)) {
throw new InvalidArgumentException(sprintf('No service definition exists with id "%s"', $parameterValue));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ public function process(ContainerBuilder $container): void
throw new InvalidArgumentException(sprintf('The service %s needs the code attribute. Something like this: <tag name="setono_sylius_feed.data_provider" code="insert code here"/>', $id));
}

/** @var array{code?: string} $attributes */
foreach ($tagged as $attributes) {
if (!isset($attributes['code'])) {
throw new InvalidArgumentException(sprintf('The service %s needs the code attribute. Something like this: <tag name="setono_sylius_feed.data_provider" code="insert code here"/>', $id));
Expand Down
7 changes: 7 additions & 0 deletions src/DependencyInjection/SetonoSyliusFeedExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,13 @@ final class SetonoSyliusFeedExtension extends AbstractResourceExtension implemen
{
public function load(array $configs, ContainerBuilder $container): void
{
/**
* @var array{
* driver: string,
* storage: array{feed: string, feed_tmp: string},
* resources: array
* } $config
*/
$config = $this->processConfiguration($this->getConfiguration([], $container), $configs);
$loader = new XmlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config'));

Expand Down
7 changes: 6 additions & 1 deletion src/Doctrine/ORM/FeedRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,16 @@ class FeedRepository extends EntityRepository implements FeedRepositoryInterface
{
public function findOneByCode(string $code): ?FeedInterface
{
return $this->createQueryBuilder('o')
$result = $this->createQueryBuilder('o')
->where('o.code = :code')
->setParameter('code', $code)
->getQuery()
->getOneOrNullResult()
;

Assert::nullOrIsInstanceOf($result, FeedInterface::class);

return $result;
}

public function findEnabled(): array
Expand All @@ -29,6 +33,7 @@ public function findEnabled(): array
->getResult()
;

Assert::isArray($res);
Assert::allIsInstanceOf($res, FeedInterface::class);

return $res;
Expand Down
3 changes: 1 addition & 2 deletions src/Doctrine/ORM/ViolationRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@ public function findCountsGroupedBySeverity($feed = null): array
$feed = (int) $feed->getId();
}

Assert::nullOrInteger($feed);

$qb = $this->createQueryBuilder('o')
->select('NEW Setono\SyliusFeedPlugin\DTO\SeverityCount(o.severity, count(o))')
->groupBy('o.severity')
Expand All @@ -32,6 +30,7 @@ public function findCountsGroupedBySeverity($feed = null): array
}

$res = $qb->getQuery()->getResult();
Assert::isArray($res);
Assert::allIsInstanceOf($res, SeverityCount::class);

return $res;
Expand Down
5 changes: 4 additions & 1 deletion src/EventListener/Filter/AbstractFilterListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ public function __construct(private readonly string $class)
{
}

/**
* @param list<class-string> $additionalInstanceChecks
*/
protected function isEligible(QueryBuilderEvent $event, array $additionalInstanceChecks = []): bool
{
$class = $event->getDataProvider()->getClass();
Expand All @@ -39,7 +42,7 @@ protected function getAlias(QueryBuilder $queryBuilder): string
throw new InvalidArgumentException('This filter only works with one root alias');
}

return reset($aliases);
return $aliases[0];
}

protected function getClassMetadata(QueryBuilderEvent $event): ClassMetadata
Expand Down
3 changes: 1 addition & 2 deletions src/EventListener/MoveGeneratedFeedSubscriber.php
Original file line number Diff line number Diff line change
Expand Up @@ -87,9 +87,8 @@ public function move(TransitionEvent $event): void
);
$temporaryFilesystem = $this->temporaryFilesystem;
$temporaryPath = TemporaryFeedPathGenerator::getBaseFile($temporaryDir);
/** @var resource|false $tempFile */
$tempFile = $temporaryFilesystem->readStream((string) $temporaryPath);
if (false === $tempFile) {
if (!\is_resource($tempFile)) {
throw new \RuntimeException(sprintf(
'The file with path "%s" could not be found',
$temporaryPath,
Expand Down
14 changes: 4 additions & 10 deletions src/Exception/GenerateBatchException.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ final class GenerateBatchException extends RuntimeException implements Exception

private ?int $feedId = null;

/** @var mixed */
private $resourceId;
/** @var scalar|null */
private mixed $resourceId = null;

private ?string $channelCode = null;

Expand All @@ -40,18 +40,12 @@ public function setFeedId(int $feedId): void
$this->updateMessage();
}

/**
* @return mixed
*/
public function getResourceId()
public function getResourceId(): mixed
{
return $this->resourceId;
}

/**
* @param mixed $resourceId
*/
public function setResourceId($resourceId): void
public function setResourceId(mixed $resourceId): void
{
Assert::scalar($resourceId);

Expand Down
5 changes: 3 additions & 2 deletions src/Factory/ViolationFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,14 @@ public function createFromConstraintViolation(
$violation->setChannel($channel);
$violation->setLocale($locale);
$violation->setMessage(
$constraintViolation->getPropertyPath() . ': ' . sprintf((string) $constraintViolation->getMessage(), $constraintViolation->getInvalidValue()),
/** @phpstan-ignore cast.string */
$constraintViolation->getPropertyPath() . ': ' . sprintf((string) $constraintViolation->getMessage(), (string) $constraintViolation->getInvalidValue()),
);
$violation->setData($data);

if ($constraintViolation instanceof ConstraintViolation) {
$constraint = $constraintViolation->getConstraint();
if (null !== $constraint && isset($constraint->payload['severity'])) {
if (null !== $constraint && is_array($constraint->payload) && isset($constraint->payload['severity']) && is_string($constraint->payload['severity'])) {
$violation->setSeverity($constraint->payload['severity']);
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/Feed/Model/Google/Shopping/Price.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ final class Price implements JsonSerializable, \Stringable
private readonly string $currency;

/**
* @param object|string $currency
* @param \Stringable|string $currency
*/
public function __construct(int $amount, $currency)
{
Expand Down
2 changes: 1 addition & 1 deletion src/FeedContext/ContextListInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
use Traversable;

/**
* @extends Traversable<array-key, array>
* @extends Traversable<array-key, array|object>
*/
interface ContextListInterface extends Traversable, Countable
{
Expand Down
4 changes: 4 additions & 0 deletions src/FeedType/FeedType.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,12 @@

final class FeedType implements FeedTypeInterface
{
/** @var list<string> */
private readonly array $validationGroups;

/**
* @param list<string> $validationGroups
*/
public function __construct(
private readonly string $code,
private readonly string $template,
Expand Down
2 changes: 2 additions & 0 deletions src/FeedType/FeedTypeInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ public function getItemContext(): ItemContextInterface;

/**
* The validation groups used when validating each item
*
* @return list<string>
*/
public function getValidationGroups(): array;
}
20 changes: 14 additions & 6 deletions src/Message/Handler/FinishGenerationHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ public function __invoke(FinishGeneration $message): void

[$feedStart, $feedEnd] = $this->getFeedParts($feed, $feedType, $channel, $locale);

fwrite($batchStream, (string) $feedStart);
fwrite($batchStream, $feedStart);

$filesystem = $this->filesystem;

Expand All @@ -105,25 +105,24 @@ public function __invoke(FinishGeneration $message): void
}
/** @var string $path */
$path = $file['path'];
/** @var resource|false $fp */
$fp = $filesystem->readStream($path);
if (false === $fp) {
if (!is_resource($fp)) {
throw new \RuntimeException(sprintf(
'The file "%s" could not be opened as a resource',
$path,
));
}

while (!feof($fp)) {
fwrite($batchStream, fread($fp, 8192));
fwrite($batchStream, (string) fread($fp, 8192));
}

fclose($fp);

$filesystem->delete($path);
}

fwrite($batchStream, (string) $feedEnd);
fwrite($batchStream, $feedEnd);

if (interface_exists(FilesystemInterface::class) && $filesystem instanceof FilesystemInterface) {
/** @var resource|false $res */
Expand Down Expand Up @@ -170,9 +169,18 @@ public function __invoke(FinishGeneration $message): void
private function getBatchStream()
{
// needs to be w+ since we use the same stream later to read from
return fopen('php://temp', 'w+b');
$resource = fopen('php://temp', 'w+b');

if (!is_resource($resource)) {
throw new RuntimeException('Could not open the stream');
}

return $resource;
}

/**
* @return non-empty-list<string>
*/
private function getFeedParts(
FeedInterface $feed,
FeedTypeInterface $feedType,
Expand Down
8 changes: 7 additions & 1 deletion src/Message/Handler/GenerateBatchHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,13 @@ private function getWorkflow(FeedInterface $feed): WorkflowInterface
private function openStream()
{
// needs to be w+ since we use the same stream later to read from
return fopen('php://temp', 'w+b');
$resource = fopen('php://temp', 'w+b');

if (!is_resource($resource)) {
throw new \RuntimeException('Could not open the stream');
}

return $resource;
}

private function applyErrorTransition(WorkflowInterface $workflow, FeedInterface $feed): void
Expand Down
Loading
Loading