diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6cbccd4e..dc16dd05 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -155,8 +155,12 @@ jobs: run: symfony security:check - - name: Run analysis - run: composer analyse + name: Validate composer.json + run: composer validate --ansi --strict + + - + name: Run PHPStan + run: vendor/bin/phpstan analyse -c phpstan.neon -l max src/ - name: Run PHPSpec diff --git a/composer.json b/composer.json index 5b070f4a..789b088d 100644 --- a/composer.json +++ b/composer.json @@ -43,8 +43,8 @@ "matthiasnoback/symfony-config-test": "^4.0", "matthiasnoback/symfony-dependency-injection-test": "^4.1", "phpspec/phpspec": "^7.0", - "phpstan/phpstan": "0.12.29", - "phpstan/phpstan-webmozart-assert": "0.12.6", + "phpstan/phpstan": "0.12.84", + "phpstan/phpstan-webmozart-assert": "0.12.12", "phpunit/phpunit": "^9.5", "sylius-labs/coding-standard": "^3.2", "symfony/browser-kit": "^4.4 || ^5.2", @@ -70,7 +70,7 @@ "scripts": { "analyse": [ "@composer validate --strict", - "vendor/bin/phpstan.phar analyse -c phpstan.neon -l max src/" + "vendor/bin/phpstan analyse -c phpstan.neon -l max src/" ], "fix": [ "vendor/bin/ecs check src/ spec/ --fix" diff --git a/phpstan.neon b/phpstan.neon index 4f8c4715..513a0624 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -14,4 +14,3 @@ parameters: - 'tests/Application/src/**.php' ignoreErrors: - - '/Parameter #1 $configuration of method Symfony\Component\DependencyInjection\Extension\Extension::processConfiguration() expects Symfony\Component\Config\Definition\ConfigurationInterface, Symfony\Component\Config\Definition\ConfigurationInterface|null given./' diff --git a/src/Action/Admin/OrderRefundsListAction.php b/src/Action/Admin/OrderRefundsListAction.php index cc59f9f1..2d67dce6 100644 --- a/src/Action/Admin/OrderRefundsListAction.php +++ b/src/Action/Admin/OrderRefundsListAction.php @@ -4,6 +4,7 @@ namespace Sylius\RefundPlugin\Action\Admin; +use Sylius\Component\Core\Model\ChannelInterface; use Sylius\Component\Core\Model\OrderInterface; use Sylius\Component\Core\Repository\OrderRepositoryInterface; use Sylius\RefundPlugin\Checker\OrderRefundingAvailabilityCheckerInterface; @@ -14,6 +15,7 @@ use Symfony\Component\HttpFoundation\Session\Session; use Symfony\Component\Routing\Generator\UrlGeneratorInterface; use Twig\Environment; +use Webmozart\Assert\Assert; final class OrderRefundsListAction { @@ -64,10 +66,14 @@ public function __invoke(Request $request): Response return $this->redirectToReferer($order, 'sylius_refund.order_should_be_paid'); } + /** @var ChannelInterface|null $channel */ + $channel = $order->getChannel(); + Assert::notNull($channel); + return new Response( $this->twig->render('@SyliusRefundPlugin/orderRefunds.html.twig', [ 'order' => $order, - 'payment_methods' => $this->refundPaymentMethodsProvider->findForChannel($order->getChannel()), + 'payment_methods' => $this->refundPaymentMethodsProvider->findForChannel($channel), ]) ); } diff --git a/src/Checker/OrderFullyRefundedTotalChecker.php b/src/Checker/OrderFullyRefundedTotalChecker.php index 0eee2319..a5c0ddb9 100644 --- a/src/Checker/OrderFullyRefundedTotalChecker.php +++ b/src/Checker/OrderFullyRefundedTotalChecker.php @@ -6,6 +6,7 @@ use Sylius\Component\Core\Model\OrderInterface; use Sylius\RefundPlugin\Provider\OrderRefundedTotalProviderInterface; +use Webmozart\Assert\Assert; final class OrderFullyRefundedTotalChecker implements OrderFullyRefundedTotalCheckerInterface { @@ -19,6 +20,10 @@ public function __construct(OrderRefundedTotalProviderInterface $orderRefundedTo public function isOrderFullyRefunded(OrderInterface $order): bool { - return $order->getTotal() === $this->orderRefundedTotalProvider->__invoke($order->getNumber()); + /** @var string|null $orderNumber */ + $orderNumber = $order->getNumber(); + Assert::notNull($orderNumber); + + return $order->getTotal() === $this->orderRefundedTotalProvider->__invoke($orderNumber); } } diff --git a/src/CommandHandler/RefundUnitsHandler.php b/src/CommandHandler/RefundUnitsHandler.php index bd7df7f1..4e6c1b16 100644 --- a/src/CommandHandler/RefundUnitsHandler.php +++ b/src/CommandHandler/RefundUnitsHandler.php @@ -11,6 +11,7 @@ use Sylius\RefundPlugin\Refunder\RefunderInterface; use Sylius\RefundPlugin\Validator\RefundUnitsCommandValidatorInterface; use Symfony\Component\Messenger\MessageBusInterface; +use Webmozart\Assert\Assert; final class RefundUnitsHandler { @@ -56,13 +57,17 @@ public function __invoke(RefundUnits $command): void $refundedTotal += $this->orderUnitsRefunder->refundFromOrder($command->units(), $orderNumber); $refundedTotal += $this->orderShipmentsRefunder->refundFromOrder($command->shipments(), $orderNumber); + /** @var string|null $currencyCode */ + $currencyCode = $order->getCurrencyCode(); + Assert::notNull($currencyCode); + $this->eventBus->dispatch(new UnitsRefunded( $orderNumber, $command->units(), $command->shipments(), $command->paymentMethodId(), $refundedTotal, - $order->getCurrencyCode(), + $currencyCode, $command->comment() )); } diff --git a/src/CommandHandler/SendCreditMemoHandler.php b/src/CommandHandler/SendCreditMemoHandler.php index b499d294..0d1988f9 100644 --- a/src/CommandHandler/SendCreditMemoHandler.php +++ b/src/CommandHandler/SendCreditMemoHandler.php @@ -4,6 +4,7 @@ namespace Sylius\RefundPlugin\CommandHandler; +use Sylius\Component\Core\Model\CustomerInterface; use Sylius\Component\Resource\Repository\RepositoryInterface; use Sylius\RefundPlugin\Command\SendCreditMemo; use Sylius\RefundPlugin\Entity\CreditMemoInterface; @@ -39,8 +40,14 @@ public function __invoke(SendCreditMemo $command): void $order = $creditMemo->getOrder(); - Assert::notNull($order->getCustomer(), 'Credit memo order has no customer'); + /** @var CustomerInterface|null $customer */ + $customer = $order->getCustomer(); + Assert::notNull($customer, 'Credit memo order has no customer'); - $this->creditMemoEmailSender->send($creditMemo, $order->getCustomer()->getEmail()); + /** @var string|null $recipient */ + $recipient = $customer->getEmail(); + Assert::notNull($recipient); + + $this->creditMemoEmailSender->send($creditMemo, $recipient); } } diff --git a/src/Converter/OrderItemUnitLineItemsConverter.php b/src/Converter/OrderItemUnitLineItemsConverter.php index b7b47014..2a209d88 100644 --- a/src/Converter/OrderItemUnitLineItemsConverter.php +++ b/src/Converter/OrderItemUnitLineItemsConverter.php @@ -55,8 +55,12 @@ private function convertUnitRefundToLineItem(OrderItemUnitRefund $unitRefund): L $taxAmount = (int) ($grossValue * $orderItemUnit->getTaxTotal() / $orderItemUnit->getTotal()); $netValue = $grossValue - $taxAmount; + /** @var string|null $productName */ + $productName = $orderItem->getProductName(); + Assert::notNull($productName); + return new LineItem( - $orderItem->getProductName(), + $productName, 1, $netValue, $grossValue, diff --git a/src/Converter/ShipmentLineItemsConverter.php b/src/Converter/ShipmentLineItemsConverter.php index cb0591d4..8ef72ff9 100644 --- a/src/Converter/ShipmentLineItemsConverter.php +++ b/src/Converter/ShipmentLineItemsConverter.php @@ -65,8 +65,12 @@ private function convertShipmentRefundToLineItem(ShipmentRefund $shipmentRefund) $taxAmount = (int) ($grossValue * $taxAdjustmentAmount / $shipment->getAdjustmentsTotal()); $netValue = $grossValue - $taxAmount; + /** @var string|null $label */ + $label = $shippingAdjustment->getLabel(); + Assert::notNull($label); + return new LineItem( - $shippingAdjustment->getLabel(), + $label, 1, $netValue, $grossValue, diff --git a/src/DependencyInjection/SyliusRefundExtension.php b/src/DependencyInjection/SyliusRefundExtension.php index 1e2d9222..aaaf75b6 100644 --- a/src/DependencyInjection/SyliusRefundExtension.php +++ b/src/DependencyInjection/SyliusRefundExtension.php @@ -5,6 +5,7 @@ namespace Sylius\RefundPlugin\DependencyInjection; use Sylius\Bundle\CoreBundle\DependencyInjection\PrependDoctrineMigrationsTrait; +use Symfony\Component\Config\Definition\ConfigurationInterface; use Symfony\Component\Config\FileLocator; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Extension\Extension; @@ -15,9 +16,12 @@ final class SyliusRefundExtension extends Extension implements PrependExtensionI { use PrependDoctrineMigrationsTrait; - public function load(array $config, ContainerBuilder $container): void + public function load(array $configs, ContainerBuilder $container): void { - $this->processConfiguration($this->getConfiguration([], $container), $config); + /** @var ConfigurationInterface $configuration */ + $configuration = $this->getConfiguration([], $container); + + $this->processConfiguration($configuration, $configs); $loader = new XmlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config')); $loader->load('services.xml'); @@ -43,6 +47,6 @@ protected function getNamespacesOfMigrationsExecutedBefore(): array return [ 'Sylius\Bundle\CoreBundle\Migrations', 'Sylius\Bundle\AdminApiBundle\Migrations', - ]; + ]; } } diff --git a/src/Generator/CreditMemoGenerator.php b/src/Generator/CreditMemoGenerator.php index f5ea17c1..a558b120 100644 --- a/src/Generator/CreditMemoGenerator.php +++ b/src/Generator/CreditMemoGenerator.php @@ -64,11 +64,22 @@ public function generate( Assert::allIsInstanceOf($units, OrderItemUnitRefund::class); Assert::allIsInstanceOf($shipments, ShipmentRefund::class); - /** @var ChannelInterface $channel */ + /** @var ChannelInterface|null $channel */ $channel = $order->getChannel(); - Assert::notNull($channel); + /** @var string|null $currencyCode */ + $currencyCode = $order->getCurrencyCode(); + Assert::notNull($currencyCode); + + /** @var string|null $localeCode */ + $localeCode = $order->getLocaleCode(); + Assert::notNull($localeCode); + + /** @var AddressInterface|null $billingAddress */ + $billingAddress = $order->getBillingAddress(); + Assert::notNull($billingAddress); + $lineItems = array_merge( $this->lineItemsConverter->convert($units), $this->shipmentLineItemsConverter->convert($shipments) @@ -79,20 +90,27 @@ public function generate( $this->creditMemoNumberGenerator->generate(), $order, $total, - $order->getCurrencyCode(), - $order->getLocaleCode(), + $currencyCode, + $localeCode, $channel, $lineItems, $this->taxItemsGenerator->generate($lineItems), $comment, $this->currentDateTimeImmutableProvider->now(), - $this->getFromAddress($order->getBillingAddress()), + $this->getFromAddress($billingAddress), $this->getToAddress($channel->getShopBillingData()) ); } private function getFromAddress(AddressInterface $address): CustomerBillingData { + Assert::notNull($address->getFirstName()); + Assert::notNull($address->getLastName()); + Assert::notNull($address->getStreet()); + Assert::notNull($address->getPostcode()); + Assert::notNull($address->getCountryCode()); + Assert::notNull($address->getCity()); + return new CustomerBillingData( $address->getFirstName(), $address->getLastName(), diff --git a/src/Menu/OrderShowMenuListener.php b/src/Menu/OrderShowMenuListener.php index 3b3aa7cc..cbea4100 100644 --- a/src/Menu/OrderShowMenuListener.php +++ b/src/Menu/OrderShowMenuListener.php @@ -6,6 +6,7 @@ use Sylius\Bundle\AdminBundle\Event\OrderShowMenuBuilderEvent; use Sylius\RefundPlugin\Checker\OrderRefundingAvailabilityCheckerInterface; +use Webmozart\Assert\Assert; final class OrderShowMenuListener { @@ -22,11 +23,15 @@ public function addRefundsButton(OrderShowMenuBuilderEvent $event): void $menu = $event->getMenu(); $order = $event->getOrder(); - if ($this->orderRefundsListAvailabilityChecker->__invoke($order->getNumber())) { + /** @var string|null $orderNumber */ + $orderNumber = $order->getNumber(); + Assert::notNull($orderNumber); + + if ($this->orderRefundsListAvailabilityChecker->__invoke($orderNumber)) { $menu ->addChild('refunds', [ 'route' => 'sylius_refund_order_refunds_list', - 'routeParameters' => ['orderNumber' => $order->getNumber()], + 'routeParameters' => ['orderNumber' => $orderNumber], ]) ->setLabel('sylius_refund.ui.refunds') ->setLabelAttribute('icon', 'reply all') diff --git a/src/TaxesApplicator/OrderItemUnitsTaxesApplicator.php b/src/TaxesApplicator/OrderItemUnitsTaxesApplicator.php index a5811f5c..dc05eb0b 100644 --- a/src/TaxesApplicator/OrderItemUnitsTaxesApplicator.php +++ b/src/TaxesApplicator/OrderItemUnitsTaxesApplicator.php @@ -16,12 +16,14 @@ use Sylius\Component\Addressing\Model\ZoneInterface; use Sylius\Component\Core\Model\OrderInterface; use Sylius\Component\Core\Model\OrderItemUnitInterface; +use Sylius\Component\Core\Model\ProductVariantInterface; use Sylius\Component\Core\Model\TaxRateInterface; use Sylius\Component\Core\Taxation\Applicator\OrderTaxesApplicatorInterface; use Sylius\Component\Order\Factory\AdjustmentFactoryInterface; use Sylius\Component\Taxation\Calculator\CalculatorInterface; use Sylius\Component\Taxation\Resolver\TaxRateResolverInterface; use Sylius\RefundPlugin\Entity\AdjustmentInterface; +use Webmozart\Assert\Assert; /** * @internal @@ -53,8 +55,12 @@ public function __construct( public function apply(OrderInterface $order, ZoneInterface $zone): void { foreach ($order->getItems() as $item) { + /** @var ProductVariantInterface|null $variant */ + $variant = $item->getVariant(); + Assert::notNull($variant); + /** @var TaxRateInterface|null $taxRate */ - $taxRate = $this->taxRateResolver->resolve($item->getVariant(), ['zone' => $zone]); + $taxRate = $this->taxRateResolver->resolve($variant, ['zone' => $zone]); if (null === $taxRate) { continue; } @@ -73,10 +79,14 @@ public function apply(OrderInterface $order, ZoneInterface $zone): void private function addAdjustment(OrderItemUnitInterface $unit, int $taxAmount, TaxRateInterface $taxRate): void { + /** @var string|null $label */ + $label = $taxRate->getLabel(); + Assert::notNull($label); + /** @var AdjustmentInterface $unitTaxAdjustment */ $unitTaxAdjustment = $this->adjustmentFactory->createWithData( AdjustmentInterface::TAX_ADJUSTMENT, - $taxRate->getLabel(), + $label, $taxAmount, $taxRate->isIncludedInPrice() ); diff --git a/src/TaxesApplicator/OrderItemsTaxesApplicator.php b/src/TaxesApplicator/OrderItemsTaxesApplicator.php index 9c07471c..11add5bb 100644 --- a/src/TaxesApplicator/OrderItemsTaxesApplicator.php +++ b/src/TaxesApplicator/OrderItemsTaxesApplicator.php @@ -17,6 +17,7 @@ use Sylius\Component\Core\Distributor\IntegerDistributorInterface; use Sylius\Component\Core\Model\OrderInterface; use Sylius\Component\Core\Model\OrderItemUnitInterface; +use Sylius\Component\Core\Model\ProductVariantInterface; use Sylius\Component\Core\Model\TaxRateInterface; use Sylius\Component\Core\Taxation\Applicator\OrderTaxesApplicatorInterface; use Sylius\Component\Order\Factory\AdjustmentFactoryInterface; @@ -66,8 +67,12 @@ public function apply(OrderInterface $order, ZoneInterface $zone): void $quantity = $item->getQuantity(); Assert::notSame($quantity, 0, 'Cannot apply tax to order item with 0 quantity.'); + /** @var ProductVariantInterface|null $variant */ + $variant = $item->getVariant(); + Assert::notNull($variant); + /** @var TaxRateInterface|null $taxRate */ - $taxRate = $this->taxRateResolver->resolve($item->getVariant(), ['zone' => $zone]); + $taxRate = $this->taxRateResolver->resolve($variant, ['zone' => $zone]); if (null === $taxRate) { continue; } @@ -90,10 +95,14 @@ public function apply(OrderInterface $order, ZoneInterface $zone): void private function addAdjustment(OrderItemUnitInterface $unit, int $taxAmount, TaxRateInterface $taxRate): void { + /** @var string|null $label */ + $label = $taxRate->getLabel(); + Assert::notNull($label); + /** @var AdjustmentInterface $unitTaxAdjustment */ $unitTaxAdjustment = $this->adjustmentFactory->createWithData( AdjustmentInterface::TAX_ADJUSTMENT, - $taxRate->getLabel(), + $label, $taxAmount, $taxRate->isIncludedInPrice() ); diff --git a/src/TaxesApplicator/OrderShipmentTaxesApplicator.php b/src/TaxesApplicator/OrderShipmentTaxesApplicator.php index 08aa5eb1..fa85ba15 100644 --- a/src/TaxesApplicator/OrderShipmentTaxesApplicator.php +++ b/src/TaxesApplicator/OrderShipmentTaxesApplicator.php @@ -87,10 +87,14 @@ private function addAdjustment( TaxRateInterface $taxRate, ShippingMethodInterface $shippingMethod ): void { + /** @var string|null $label */ + $label = $taxRate->getLabel(); + Assert::notNull($label); + /** @var AdjustmentInterface $adjustment */ $adjustment = $this->adjustmentFactory->createWithData( AdjustmentInterface::TAX_ADJUSTMENT, - $taxRate->getLabel(), + $label, $taxAmount, $taxRate->isIncludedInPrice() );