diff --git a/CHANGELOG-WIP.md b/CHANGELOG-WIP.md new file mode 100644 index 0000000000..eaba982a22 --- /dev/null +++ b/CHANGELOG-WIP.md @@ -0,0 +1,11 @@ +# WIP Release Notes for Craft Commerce + +### Store Management + +### Administration + +### Development + +### Extensibility + +### System \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index eb5c08f57f..0d00136ad2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## Unreleased - Fixed a bug where catalog pricing rules could generate promotional prices for non-promotable purchasables. ([#4118](https://github.com/craftcms/commerce/issues/4118)) +- Fixed a bug where variants weren’t duplicating correctly. ([#4125](https://github.com/craftcms/commerce/issues/4125)) - Fixed a SQL error that could occur when deleting a shipping method. ## 5.4.6 - 2025-09-04 diff --git a/src/base/Purchasable.php b/src/base/Purchasable.php index d1d8fa70b9..889ec54c6a 100644 --- a/src/base/Purchasable.php +++ b/src/base/Purchasable.php @@ -683,7 +683,7 @@ public function getSkuAsText(): string /** * @param string|null $sku */ - public function setSku(string $sku = null): void + public function setSku(?string $sku = null): void { $this->_sku = $sku; } diff --git a/src/base/Stat.php b/src/base/Stat.php index 6bc71ea77a..c3729bb3ed 100644 --- a/src/base/Stat.php +++ b/src/base/Stat.php @@ -41,7 +41,7 @@ abstract class Stat implements StatInterface, HasStoreInterface * @param DateTime|bool|null $endDate * @throws \Exception */ - public function __construct(string $dateRange = null, mixed $startDate = null, mixed $endDate = null, ?int $storeId = null) + public function __construct(?string $dateRange = null, mixed $startDate = null, mixed $endDate = null, ?int $storeId = null) { $user = Craft::$app->getUser()->getIdentity(); if ($user) { diff --git a/src/controllers/CatalogPricingRulesController.php b/src/controllers/CatalogPricingRulesController.php index 1d5fe92442..94adad958e 100755 --- a/src/controllers/CatalogPricingRulesController.php +++ b/src/controllers/CatalogPricingRulesController.php @@ -73,7 +73,7 @@ public function actionIndex(?string $storeHandle = null): Response * @throws HttpException * @throws InvalidConfigException */ - public function actionEdit(?string $storeHandle = null, int $id = null, CatalogPricingRule $catalogPricingRule = null): Response + public function actionEdit(?string $storeHandle = null, ?int $id = null, ?CatalogPricingRule $catalogPricingRule = null): Response { if ($id === null) { $this->requirePermission('commerce-createCatalogPricingRules'); diff --git a/src/controllers/DiscountsController.php b/src/controllers/DiscountsController.php index af15fcc82c..aa6963f910 100644 --- a/src/controllers/DiscountsController.php +++ b/src/controllers/DiscountsController.php @@ -65,7 +65,7 @@ public function init(): void /** * @throws HttpException */ - public function actionIndex(string $storeHandle = null): Response + public function actionIndex(?string $storeHandle = null): Response { if ($storeHandle) { $store = Plugin::getInstance()->getStores()->getStoreByHandle($storeHandle); @@ -178,7 +178,7 @@ public function actionTableData(): Response * @param Discount|null $discount * @throws HttpException */ - public function actionEdit(int $id = null, Discount $discount = null, string $storeHandle = null): Response + public function actionEdit(?int $id = null, ?Discount $discount = null, ?string $storeHandle = null): Response { if ($id === null) { $this->requirePermission('commerce-createDiscounts'); diff --git a/src/controllers/EmailsController.php b/src/controllers/EmailsController.php index 2632b4523d..6a2a2d27b3 100644 --- a/src/controllers/EmailsController.php +++ b/src/controllers/EmailsController.php @@ -59,7 +59,7 @@ public function actionIndex(): Response * @param Email|null $email * @throws HttpException */ - public function actionEdit(?string $storeHandle = null, int $id = null, Email $email = null): Response + public function actionEdit(?string $storeHandle = null, ?int $id = null, ?Email $email = null): Response { if ($storeHandle === null || !$store = Plugin::getInstance()->getStores()->getStoreByHandle($storeHandle)) { $store = Plugin::getInstance()->getStores()->getPrimaryStore(); diff --git a/src/controllers/GatewaysController.php b/src/controllers/GatewaysController.php index dfc34b1458..1e4f8e5a58 100644 --- a/src/controllers/GatewaysController.php +++ b/src/controllers/GatewaysController.php @@ -75,7 +75,7 @@ public function actionIndex(): Response * @throws DeprecationException * @throws InvalidConfigException */ - public function actionEdit(?string $storeHandle = null, int $id = null, ?GatewayInterface $gateway = null): Response + public function actionEdit(?string $storeHandle = null, ?int $id = null, ?GatewayInterface $gateway = null): Response { /** @var Gateway|null $gateway */ $variables = compact('id', 'gateway'); diff --git a/src/controllers/LineItemStatusesController.php b/src/controllers/LineItemStatusesController.php index 587ae407e9..86406a9459 100644 --- a/src/controllers/LineItemStatusesController.php +++ b/src/controllers/LineItemStatusesController.php @@ -55,7 +55,7 @@ public function actionIndex(): Response * @param LineItemStatus|null $lineItemStatus * @throws HttpException */ - public function actionEdit(?string $storeHandle = null, int $id = null, LineItemStatus $lineItemStatus = null): Response + public function actionEdit(?string $storeHandle = null, ?int $id = null, ?LineItemStatus $lineItemStatus = null): Response { if ($storeHandle === null || !$store = Plugin::getInstance()->getStores()->getStoreByHandle($storeHandle)) { $store = Plugin::getInstance()->getStores()->getPrimaryStore(); diff --git a/src/controllers/OrderStatusesController.php b/src/controllers/OrderStatusesController.php index 76b061f11c..ed425a73e8 100644 --- a/src/controllers/OrderStatusesController.php +++ b/src/controllers/OrderStatusesController.php @@ -55,7 +55,7 @@ public function actionIndex(): Response * @param OrderStatus|null $orderStatus * @throws HttpException */ - public function actionEdit(?string $storeHandle = null, int $id = null, OrderStatus $orderStatus = null): Response + public function actionEdit(?string $storeHandle = null, ?int $id = null, ?OrderStatus $orderStatus = null): Response { $variables = compact('id', 'orderStatus'); if ($storeHandle === null || !$store = Plugin::getInstance()->getStores()->getStoreByHandle($storeHandle)) { diff --git a/src/controllers/OrdersController.php b/src/controllers/OrdersController.php index 6ea8e66767..6a80c0aa3c 100644 --- a/src/controllers/OrdersController.php +++ b/src/controllers/OrdersController.php @@ -129,7 +129,7 @@ public function init(): void * * @throws Throwable */ - public function actionOrderIndex(string $orderStatusHandle = ''): Response + public function actionOrderIndex(?string $orderStatusHandle = ''): Response { Craft::$app->getView()->registerAssetBundle(CommerceCpAsset::class); @@ -213,7 +213,7 @@ public function actionCreate(string $storeHandle): Response * @throws RuntimeError * @throws SyntaxError */ - public function actionEditOrder(int $orderId, Order $order = null, $paymentForm = null): Response + public function actionEditOrder(int $orderId, ?Order $order = null, $paymentForm = null): Response { $plugin = Plugin::getInstance(); $variables = []; diff --git a/src/controllers/PaymentCurrenciesController.php b/src/controllers/PaymentCurrenciesController.php index a3a4e89a22..3f287f6ed4 100644 --- a/src/controllers/PaymentCurrenciesController.php +++ b/src/controllers/PaymentCurrenciesController.php @@ -47,7 +47,7 @@ public function actionIndex(?string $storeHandle = null): Response * @throws HttpException * @throws InvalidConfigException */ - public function actionEdit(int $id = null, PaymentCurrency $currency = null, string $storeHandle = null): Response + public function actionEdit(?int $id = null, ?PaymentCurrency $currency = null, ?string $storeHandle = null): Response { $variables = compact('id', 'currency'); diff --git a/src/controllers/PdfsController.php b/src/controllers/PdfsController.php index 5f8e6c772c..d05ac8216a 100644 --- a/src/controllers/PdfsController.php +++ b/src/controllers/PdfsController.php @@ -62,7 +62,7 @@ public function actionIndex(): Response * @throws InvalidConfigException * @since 3.2 */ - public function actionEdit(?string $storeHandle = null, int $id = null, Pdf $pdf = null): Response + public function actionEdit(?string $storeHandle = null, ?int $id = null, ?Pdf $pdf = null): Response { if ($storeHandle === null || !$store = Plugin::getInstance()->getStores()->getStoreByHandle($storeHandle)) { $store = Plugin::getInstance()->getStores()->getPrimaryStore(); diff --git a/src/controllers/PlansController.php b/src/controllers/PlansController.php index dbe65cb45b..6bbc723f12 100644 --- a/src/controllers/PlansController.php +++ b/src/controllers/PlansController.php @@ -66,7 +66,7 @@ public function actionPlanIndex(): Response * @throws DeprecationException * @throws ForbiddenHttpException */ - public function actionEditPlan(int $planId = null, Plan $plan = null): Response + public function actionEditPlan(?int $planId = null, ?Plan $plan = null): Response { $this->requirePermission('commerce-manageSubscriptions'); diff --git a/src/controllers/ProductTypesController.php b/src/controllers/ProductTypesController.php index 718f2b6266..3bd979f722 100644 --- a/src/controllers/ProductTypesController.php +++ b/src/controllers/ProductTypesController.php @@ -44,7 +44,7 @@ public function actionProductTypeIndex(): Response * @param ProductType|null $productType * @throws HttpException */ - public function actionEditProductType(int $productTypeId = null, ProductType $productType = null): Response + public function actionEditProductType(?int $productTypeId = null, ?ProductType $productType = null): Response { $variables = compact('productTypeId', 'productType'); diff --git a/src/controllers/SalesController.php b/src/controllers/SalesController.php index 49df5538f2..67c98746cd 100644 --- a/src/controllers/SalesController.php +++ b/src/controllers/SalesController.php @@ -74,7 +74,7 @@ public function actionIndex(?string $storeHandle = null): Response * @throws HttpException * @throws InvalidConfigException */ - public function actionEdit(int $id = null, Sale $sale = null, ?string $storeHandle = null): Response + public function actionEdit(?int $id = null, ?Sale $sale = null, ?string $storeHandle = null): Response { if ($id === null) { $this->requirePermission('commerce-createSales'); diff --git a/src/controllers/ShippingCategoriesController.php b/src/controllers/ShippingCategoriesController.php index 0d27d8d158..9eb0eba789 100644 --- a/src/controllers/ShippingCategoriesController.php +++ b/src/controllers/ShippingCategoriesController.php @@ -51,7 +51,7 @@ public function actionIndex(?string $storeHandle = null): Response * @param ShippingCategory|null $shippingCategory * @throws HttpException */ - public function actionEdit(?string $storeHandle = null, int $id = null, ShippingCategory $shippingCategory = null): Response + public function actionEdit(?string $storeHandle = null, ?int $id = null, ?ShippingCategory $shippingCategory = null): Response { $variables = [ 'id' => $id, diff --git a/src/controllers/ShippingMethodsController.php b/src/controllers/ShippingMethodsController.php index 9b2ada9723..0aea09801f 100644 --- a/src/controllers/ShippingMethodsController.php +++ b/src/controllers/ShippingMethodsController.php @@ -45,7 +45,7 @@ public function actionIndex(?string $storeHandle = null): Response * @throws HttpException * @throws InvalidConfigException */ - public function actionEdit(?string $storeHandle = null, int $id = null, ShippingMethod $shippingMethod = null): Response + public function actionEdit(?string $storeHandle = null, ?int $id = null, ?ShippingMethod $shippingMethod = null): Response { if ($storeHandle === null || !$store = Plugin::getInstance()->getStores()->getStoreByHandle($storeHandle)) { $store = Plugin::getInstance()->getStores()->getPrimaryStore(); diff --git a/src/controllers/ShippingRulesController.php b/src/controllers/ShippingRulesController.php index 5f3aadfc13..d694d413e1 100644 --- a/src/controllers/ShippingRulesController.php +++ b/src/controllers/ShippingRulesController.php @@ -48,7 +48,7 @@ class ShippingRulesController extends BaseShippingSettingsController * @throws SyntaxError * @throws Exception */ - public function actionEdit(?string $storeHandle = null, int $methodId = null, int $ruleId = null, ShippingRule $shippingRule = null): Response + public function actionEdit(?string $storeHandle = null, ?int $methodId = null, ?int $ruleId = null, ?ShippingRule $shippingRule = null): Response { if ($storeHandle === null || !$store = Plugin::getInstance()->getStores()->getStoreByHandle($storeHandle)) { $store = Plugin::getInstance()->getStores()->getPrimaryStore(); diff --git a/src/controllers/ShippingZonesController.php b/src/controllers/ShippingZonesController.php index 9d3a6627d4..36ccea56eb 100644 --- a/src/controllers/ShippingZonesController.php +++ b/src/controllers/ShippingZonesController.php @@ -42,7 +42,7 @@ public function actionIndex(?string $storeHandle = null): Response * @param ShippingAddressZone|null $shippingZone * @throws HttpException */ - public function actionEdit(?string $storeHandle = null, int $id = null, ShippingAddressZone $shippingZone = null): Response + public function actionEdit(?string $storeHandle = null, ?int $id = null, ?ShippingAddressZone $shippingZone = null): Response { if ($storeHandle === null || !$store = Plugin::getInstance()->getStores()->getStoreByHandle($storeHandle)) { $store = Plugin::getInstance()->getStores()->getPrimaryStore(); diff --git a/src/controllers/StoreManagementController.php b/src/controllers/StoreManagementController.php index 9e9d2ee56e..98bf0fbfb8 100644 --- a/src/controllers/StoreManagementController.php +++ b/src/controllers/StoreManagementController.php @@ -67,7 +67,7 @@ public function actionIndex(): Response * @throws TemplateLoaderException * @throws InvalidConfigException */ - public function actionEdit(StoreSettings $storeSettings = null, ?string $storeHandle = null): Response + public function actionEdit(?StoreSettings $storeSettings = null, ?string $storeHandle = null): Response { $this->requirePermission('commerce-manageGeneralStoreSettings'); diff --git a/src/controllers/StoresController.php b/src/controllers/StoresController.php index 6c48478a01..d0efbe235d 100644 --- a/src/controllers/StoresController.php +++ b/src/controllers/StoresController.php @@ -332,7 +332,7 @@ public function actionReorderStores(): Response * @return Response * @throws InvalidConfigException */ - public function actionEditSiteStores(Collection $sitesStores = null): Response + public function actionEditSiteStores(?Collection $sitesStores = null): Response { // Breadcrumbs $crumbs = [ diff --git a/src/controllers/SubscriptionsController.php b/src/controllers/SubscriptionsController.php index 3c54a21303..1f4174a623 100644 --- a/src/controllers/SubscriptionsController.php +++ b/src/controllers/SubscriptionsController.php @@ -53,7 +53,7 @@ public function actionIndex(): Response * @throws HttpException * @throws InvalidConfigException */ - public function actionEdit(int $subscriptionId = null, Subscription $subscription = null): Response + public function actionEdit(?int $subscriptionId = null, ?Subscription $subscription = null): Response { $variables = []; diff --git a/src/controllers/TaxCategoriesController.php b/src/controllers/TaxCategoriesController.php index 10297a53a1..61332709a5 100644 --- a/src/controllers/TaxCategoriesController.php +++ b/src/controllers/TaxCategoriesController.php @@ -48,7 +48,7 @@ public function actionIndex(?string $storeHandle = null): Response * @param TaxCategory|null $taxCategory * @throws HttpException */ - public function actionEdit(?string $storeHandle = null, int $id = null, TaxCategory $taxCategory = null): Response + public function actionEdit(?string $storeHandle = null, ?int $id = null, ?TaxCategory $taxCategory = null): Response { if ($storeHandle === null || !$store = Plugin::getInstance()->getStores()->getStoreByHandle($storeHandle)) { $store = Plugin::getInstance()->getStores()->getPrimaryStore(); diff --git a/src/controllers/TaxRatesController.php b/src/controllers/TaxRatesController.php index babaaf34db..cf811f2dc1 100644 --- a/src/controllers/TaxRatesController.php +++ b/src/controllers/TaxRatesController.php @@ -71,7 +71,7 @@ public function actionIndex(?string $storeHandle = null): Response * @throws SyntaxError * @throws Exception */ - public function actionEdit(?string $storeHandle = null, int $id = null, TaxRate $taxRate = null): Response + public function actionEdit(?string $storeHandle = null, ?int $id = null, ?TaxRate $taxRate = null): Response { if (!Plugin::getInstance()->getTaxes()->viewTaxRates()) { throw new ForbiddenHttpException('Tax engine does not permit you to perform this action'); diff --git a/src/controllers/TaxZonesController.php b/src/controllers/TaxZonesController.php index a3e890c745..1fa5978104 100644 --- a/src/controllers/TaxZonesController.php +++ b/src/controllers/TaxZonesController.php @@ -50,7 +50,7 @@ public function actionIndex(?string $storeHandle = null): Response * @param TaxAddressZone|null $taxZone * @throws HttpException */ - public function actionEdit(?string $storeHandle = null, int $id = null, TaxAddressZone $taxZone = null): Response + public function actionEdit(?string $storeHandle = null, ?int $id = null, ?TaxAddressZone $taxZone = null): Response { if ($storeHandle === null || !$store = Plugin::getInstance()->getStores()->getStoreByHandle($storeHandle)) { $store = Plugin::getInstance()->getStores()->getPrimaryStore(); diff --git a/src/elements/Order.php b/src/elements/Order.php index 2a01fcaf55..03c277d511 100644 --- a/src/elements/Order.php +++ b/src/elements/Order.php @@ -2422,7 +2422,7 @@ public function getCpEditUrl(): ?string * @param string|null $pdfHandle The handle of the PDF to use. If none is passed the default PDF is used. * @return string|null The URL to the order’s PDF invoice, or null if the PDF template doesn’t exist */ - public function getPdfUrl(string $option = null, string $pdfHandle = null): ?string + public function getPdfUrl(?string $option = null, ?string $pdfHandle = null): ?string { $path = "commerce/downloads/pdf"; $params = []; diff --git a/src/elements/Product.php b/src/elements/Product.php index 496c5b09d1..c8d2dc46f1 100644 --- a/src/elements/Product.php +++ b/src/elements/Product.php @@ -219,7 +219,7 @@ public static function createCondition(): ElementConditionInterface /** * @inheritdoc */ - protected static function defineSources(string $context = null): array + protected static function defineSources(?string $context = null): array { if ($context == 'index') { $productTypes = Plugin::getInstance()->getProductTypes()->getEditableProductTypes(); @@ -334,7 +334,7 @@ protected static function defineFieldLayouts(?string $source): array /** * @inheritdoc */ - protected static function defineActions(string $source = null): array + protected static function defineActions(?string $source = null): array { $elementsService = Craft::$app->getElements(); // Get the selected site @@ -1107,7 +1107,15 @@ public function getVariants(bool $includeDisabled = false): VariantCollection return VariantCollection::make(); } - $variants = self::createVariantQuery($this)->status(null)->collect(); + /** @var self|null $duplicatingProduct */ + $duplicatingProduct = $this->duplicateOf; + if ($duplicatingProduct) { + $query = self::createVariantQuery($duplicatingProduct)->status(null); + } else { + $query = self::createVariantQuery($this)->status(null); + } + + $variants = $query->collect(); // Don't memoize empty collections in favour of a new query next time if ($variants->isEmpty()) { @@ -1885,12 +1893,9 @@ protected static function defineSearchableAttributes(): array */ private static function createVariantQuery(Product $product): VariantQuery { - $productId = $product->duplicateOf?->id ?? $product->id; - $productSiteId = $product->duplicateOf?->siteId ?? $product->siteId; - $query = Variant::find() - ->productId($productId) - ->siteId($productSiteId) + ->productId($product->id) + ->siteId($product->siteId) ->orderBy(['sortOrder' => SORT_ASC]); if ($product->getIsRevision()) { diff --git a/src/elements/Subscription.php b/src/elements/Subscription.php index 71cb718aaa..9d09a49c4b 100644 --- a/src/elements/Subscription.php +++ b/src/elements/Subscription.php @@ -435,7 +435,7 @@ public function getStatus(): ?string /** * @inheritdoc */ - public static function defineSources(string $context = null): array + public static function defineSources(?string $context = null): array { $plans = Plugin::getInstance()->getPlans()->getAllPlans(); diff --git a/src/elements/Transfer.php b/src/elements/Transfer.php index a56ff033d8..ce7c830b21 100644 --- a/src/elements/Transfer.php +++ b/src/elements/Transfer.php @@ -443,7 +443,7 @@ public function getUriFormat(): ?string * @param string|null $context * @return array */ - protected static function defineSources(string $context = null): array + protected static function defineSources(?string $context = null): array { $transferStatuses = TransferStatusType::cases(); $transferStatusSources = []; diff --git a/src/elements/Variant.php b/src/elements/Variant.php index dd6d1b2e4b..9ff4ce5a64 100755 --- a/src/elements/Variant.php +++ b/src/elements/Variant.php @@ -881,30 +881,34 @@ public static function hasStatuses(): bool */ public static function eagerLoadingMap(array $sourceElements, string $handle): array|null|false { - if (in_array($handle, ['product', 'owner', 'primaryOwner'])) { - // Get the source element IDs - $sourceElementIds = []; + switch ($handle) { + case 'product': + // Get the source element IDs + $sourceElementIds = []; - foreach ($sourceElements as $sourceElement) { - $sourceElementIds[] = $sourceElement->id; - } + foreach ($sourceElements as $sourceElement) { + $sourceElementIds[] = $sourceElement->id; + } - $map = (new Query()) - ->select('id as source, primaryOwnerId as target') - ->from(Table::VARIANTS) - ->where(['in', 'id', $sourceElementIds]) - ->all(); - - return [ - 'elementType' => Product::class, - 'map' => $map, - 'criteria' => [ - 'status' => null, - ], - ]; + $map = (new Query()) + ->select('id as source, primaryOwnerId as target') + ->from(Table::VARIANTS) + ->where(['in', 'id', $sourceElementIds]) + ->all(); + + return [ + 'elementType' => Product::class, + 'map' => $map, + 'criteria' => [ + 'status' => null, + ], + ]; + default: + return array_merge( + self::traitEagerLoadingMap($sourceElements, $handle), + ['elementType' => Product::class], + ); } - - return self::traitEagerLoadingMap($sourceElements, $handle); } /** @@ -1041,18 +1045,24 @@ public function afterSave(bool $isNew): void ->max('[[eo.sortOrder]]'); $this->sortOrder = $max ? $max + 1 : 1; } - if ($isNew) { - Db::insert(CraftTable::ELEMENTS_OWNERS, [ + + $ownerIds = array_unique([ + $ownerId, + $this->getPrimaryOwnerId(), + ]); + + if (!$isNew) { + Db::delete(CraftTAble::ELEMENTS_OWNERS, [ 'elementId' => $this->id, - 'ownerId' => $ownerId, - 'sortOrder' => $this->sortOrder, + 'ownerId' => $ownerIds, ]); - } else { - Db::update(CraftTable::ELEMENTS_OWNERS, [ - 'sortOrder' => $this->sortOrder, - ], [ + } + + foreach ($ownerIds as $ownerId) { + Db::insert(CraftTAble::ELEMENTS_OWNERS, [ 'elementId' => $this->id, 'ownerId' => $ownerId, + 'sortOrder' => $this->sortOrder, ]); } } @@ -1292,7 +1302,7 @@ protected function availableTaxCategories(): array /** * @inheritdoc */ - protected static function defineSources(string $context = null): array + protected static function defineSources(?string $context = null): array { $sources = Product::defineSources($context); diff --git a/src/elements/traits/OrderElementTrait.php b/src/elements/traits/OrderElementTrait.php index 5a8e74a584..b380f4c8b4 100644 --- a/src/elements/traits/OrderElementTrait.php +++ b/src/elements/traits/OrderElementTrait.php @@ -294,7 +294,7 @@ public function getSearchKeywords(string $attribute): string * @inheritdoc * @throws Exception */ - protected static function defineSources(string $context = null): array + protected static function defineSources(?string $context = null): array { $siteHandle = Craft::$app->getRequest()->getParam('site'); $site = $siteHandle ? Craft::$app->getSites()->getSiteByHandle($siteHandle) : Craft::$app->getSites()->getCurrentSite(); @@ -505,7 +505,7 @@ protected static function defineTableAttributes(): array /** * @inheritdoc */ - protected static function defineDefaultTableAttributes(string $source = null): array + protected static function defineDefaultTableAttributes(?string $source = null): array { $attributes = []; $attributes[] = 'order'; diff --git a/src/fieldlayoutelements/ProductTitleField.php b/src/fieldlayoutelements/ProductTitleField.php index 372c182cea..5b3b8173cb 100644 --- a/src/fieldlayoutelements/ProductTitleField.php +++ b/src/fieldlayoutelements/ProductTitleField.php @@ -62,7 +62,7 @@ protected function translationDescription(?ElementInterface $element = null, boo /** * @inheritdoc */ - public function inputHtml(ElementInterface $element = null, bool $static = false): ?string + public function inputHtml(?ElementInterface $element = null, bool $static = false): ?string { if (!$element instanceof Product) { throw new InvalidArgumentException('ProductTitleField can only be used in product field layouts.'); diff --git a/src/fieldlayoutelements/PurchasableAllowedQtyField.php b/src/fieldlayoutelements/PurchasableAllowedQtyField.php index 302b2f29cb..af08dcbb4c 100644 --- a/src/fieldlayoutelements/PurchasableAllowedQtyField.php +++ b/src/fieldlayoutelements/PurchasableAllowedQtyField.php @@ -45,7 +45,7 @@ public function __construct(array $config = []) /** * @inheritdoc */ - public function inputHtml(ElementInterface $element = null, bool $static = false): ?string + public function inputHtml(?ElementInterface $element = null, bool $static = false): ?string { if (!$element instanceof Purchasable) { throw new InvalidArgumentException(static::class . ' can only be used in purchasable field layouts.'); diff --git a/src/fieldlayoutelements/PurchasableAvailableForPurchaseField.php b/src/fieldlayoutelements/PurchasableAvailableForPurchaseField.php index 455c920f7c..8969b73105 100644 --- a/src/fieldlayoutelements/PurchasableAvailableForPurchaseField.php +++ b/src/fieldlayoutelements/PurchasableAvailableForPurchaseField.php @@ -50,7 +50,7 @@ public function __construct(array $config = []) /** * @inheritdoc */ - public function inputHtml(ElementInterface $element = null, bool $static = false): ?string + public function inputHtml(?ElementInterface $element = null, bool $static = false): ?string { if (!$element instanceof Purchasable) { throw new InvalidArgumentException(static::class . ' can only be used in purchasable field layouts.'); diff --git a/src/fieldlayoutelements/PurchasableDimensionsField.php b/src/fieldlayoutelements/PurchasableDimensionsField.php index 89c693f4f2..4bb8caeba6 100644 --- a/src/fieldlayoutelements/PurchasableDimensionsField.php +++ b/src/fieldlayoutelements/PurchasableDimensionsField.php @@ -58,7 +58,7 @@ public function showInForm(?ElementInterface $element = null): bool /** * @inheritdoc */ - public function inputHtml(ElementInterface $element = null, bool $static = false): ?string + public function inputHtml(?ElementInterface $element = null, bool $static = false): ?string { if (!$element instanceof Purchasable) { throw new InvalidArgumentException(static::class . ' can only be used in purchasable field layouts.'); diff --git a/src/fieldlayoutelements/PurchasableFreeShippingField.php b/src/fieldlayoutelements/PurchasableFreeShippingField.php index 3158fcd551..2c44ae4037 100644 --- a/src/fieldlayoutelements/PurchasableFreeShippingField.php +++ b/src/fieldlayoutelements/PurchasableFreeShippingField.php @@ -44,7 +44,7 @@ public function __construct(array $config = []) /** * @inheritdoc */ - public function inputHtml(ElementInterface $element = null, bool $static = false): ?string + public function inputHtml(?ElementInterface $element = null, bool $static = false): ?string { if (!$element instanceof Purchasable) { throw new InvalidArgumentException(static::class . ' can only be used in purchasable field layouts.'); diff --git a/src/fieldlayoutelements/PurchasablePriceField.php b/src/fieldlayoutelements/PurchasablePriceField.php index fde9f48c78..a8042dc65f 100755 --- a/src/fieldlayoutelements/PurchasablePriceField.php +++ b/src/fieldlayoutelements/PurchasablePriceField.php @@ -63,7 +63,7 @@ protected function defaultLabel(?ElementInterface $element = null, bool $static /** * @inheritdoc */ - public function inputHtml(ElementInterface $element = null, bool $static = false): ?string + public function inputHtml(?ElementInterface $element = null, bool $static = false): ?string { $view = Craft::$app->getView(); $view->registerAssetBundle(HtmxAsset::class); diff --git a/src/fieldlayoutelements/PurchasablePromotableField.php b/src/fieldlayoutelements/PurchasablePromotableField.php index f3789bb2f8..793cebdb21 100644 --- a/src/fieldlayoutelements/PurchasablePromotableField.php +++ b/src/fieldlayoutelements/PurchasablePromotableField.php @@ -49,7 +49,7 @@ public function __construct(array $config = []) /** * @inheritdoc */ - public function inputHtml(ElementInterface $element = null, bool $static = false): ?string + public function inputHtml(?ElementInterface $element = null, bool $static = false): ?string { if (!$element instanceof Purchasable) { throw new InvalidArgumentException(static::class . ' can only be used in purchasable field layouts.'); diff --git a/src/fieldlayoutelements/PurchasableSkuField.php b/src/fieldlayoutelements/PurchasableSkuField.php index 3e44319074..12859561df 100644 --- a/src/fieldlayoutelements/PurchasableSkuField.php +++ b/src/fieldlayoutelements/PurchasableSkuField.php @@ -42,7 +42,7 @@ class PurchasableSkuField extends BaseNativeField /** * @inheritdoc */ - public function inputHtml(ElementInterface $element = null, bool $static = false): ?string + public function inputHtml(?ElementInterface $element = null, bool $static = false): ?string { if (!$element instanceof Purchasable) { throw new InvalidArgumentException(static::class . ' can only be used in purchasable field layouts.'); diff --git a/src/fieldlayoutelements/PurchasableStockField.php b/src/fieldlayoutelements/PurchasableStockField.php index 0fd969e8c7..3be80edf59 100644 --- a/src/fieldlayoutelements/PurchasableStockField.php +++ b/src/fieldlayoutelements/PurchasableStockField.php @@ -59,7 +59,7 @@ public function __construct(array $config = []) /** * @inheritdoc */ - public function inputHtml(ElementInterface $element = null, bool $static = false): ?string + public function inputHtml(?ElementInterface $element = null, bool $static = false): ?string { // If this is a revision get the canonical element to show the stock for. // @TODO re-evaluate this when we have a better way to handle revisions and inventory. diff --git a/src/fieldlayoutelements/PurchasableWeightField.php b/src/fieldlayoutelements/PurchasableWeightField.php index 92429e9698..28ab951929 100755 --- a/src/fieldlayoutelements/PurchasableWeightField.php +++ b/src/fieldlayoutelements/PurchasableWeightField.php @@ -57,7 +57,7 @@ public function showInForm(?ElementInterface $element = null): bool /** * @inheritdoc */ - public function inputHtml(ElementInterface $element = null, bool $static = false): ?string + public function inputHtml(?ElementInterface $element = null, bool $static = false): ?string { if (!$element instanceof Purchasable) { throw new InvalidArgumentException(static::class . ' can only be used in purchasable field layouts.'); diff --git a/src/fieldlayoutelements/TransferManagementField.php b/src/fieldlayoutelements/TransferManagementField.php index 37866dce1a..89abd927e4 100644 --- a/src/fieldlayoutelements/TransferManagementField.php +++ b/src/fieldlayoutelements/TransferManagementField.php @@ -50,7 +50,7 @@ class TransferManagementField extends BaseNativeField /** * @inheritdoc */ - public function inputHtml(ElementInterface $element = null, bool $static = false): ?string + public function inputHtml(?ElementInterface $element = null, bool $static = false): ?string { if (!$element instanceof Transfer) { throw new InvalidArgumentException('TransferLocationsField can only be used in transfer field layouts.'); diff --git a/src/fieldlayoutelements/UserAddressSettings.php b/src/fieldlayoutelements/UserAddressSettings.php index c234d43e59..885c48fd0a 100644 --- a/src/fieldlayoutelements/UserAddressSettings.php +++ b/src/fieldlayoutelements/UserAddressSettings.php @@ -56,7 +56,7 @@ protected function useFieldset(): bool /** * @inheritdoc */ - protected function defaultLabel(ElementInterface $element = null, bool $static = false): ?string + protected function defaultLabel(?ElementInterface $element = null, bool $static = false): ?string { return Craft::t('commerce', 'Commerce Settings'); } diff --git a/src/fieldlayoutelements/VariantTitleField.php b/src/fieldlayoutelements/VariantTitleField.php index 2ca44fa4ab..c5569fd522 100644 --- a/src/fieldlayoutelements/VariantTitleField.php +++ b/src/fieldlayoutelements/VariantTitleField.php @@ -62,7 +62,7 @@ protected function translationDescription(?ElementInterface $element = null, boo /** * @inheritdoc */ - public function inputHtml(ElementInterface $element = null, bool $static = false): ?string + public function inputHtml(?ElementInterface $element = null, bool $static = false): ?string { if (!$element instanceof Variant) { throw new InvalidArgumentException('VariantTitleField can only be used in variant field layouts.'); diff --git a/src/fieldlayoutelements/VariantsField.php b/src/fieldlayoutelements/VariantsField.php index ceef5f02d6..bba397b2f2 100644 --- a/src/fieldlayoutelements/VariantsField.php +++ b/src/fieldlayoutelements/VariantsField.php @@ -43,7 +43,7 @@ public function hasCustomWidth(): bool /** * @inheritdoc */ - protected function defaultLabel(ElementInterface $element = null, bool $static = false): ?string + protected function defaultLabel(?ElementInterface $element = null, bool $static = false): ?string { return Craft::t('commerce', 'Variants'); } @@ -51,7 +51,7 @@ protected function defaultLabel(ElementInterface $element = null, bool $static = /** * @inheritdoc */ - protected function inputHtml(ElementInterface $element = null, bool $static = false): ?string + protected function inputHtml(?ElementInterface $element = null, bool $static = false): ?string { if (!$element instanceof Product) { throw new InvalidArgumentException('ProductTitleField can only be used in product field layouts.'); diff --git a/src/models/Email.php b/src/models/Email.php index 7fa88f5fd4..8062f364fd 100644 --- a/src/models/Email.php +++ b/src/models/Email.php @@ -148,7 +148,7 @@ public function extraFields(): array * * @param Order|null $order */ - public function getRenderLanguage(Order $order = null): string + public function getRenderLanguage(?Order $order = null): string { $language = $this->language; diff --git a/src/models/LineItem.php b/src/models/LineItem.php index 548dd7cd0f..9b36a97138 100755 --- a/src/models/LineItem.php +++ b/src/models/LineItem.php @@ -317,7 +317,7 @@ public function getLineItemStatus(): ?LineItemStatus * @param LineItemStatus|null $status * @since 3.2.2 */ - public function setLineItemStatus(LineItemStatus $status = null): void + public function setLineItemStatus(?LineItemStatus $status = null): void { if ($status !== null) { $this->_lineItemStatus = $status; diff --git a/src/models/Pdf.php b/src/models/Pdf.php index 7e4d070188..deda0ef6ef 100644 --- a/src/models/Pdf.php +++ b/src/models/Pdf.php @@ -165,7 +165,7 @@ public function extraFields(): array * * @param Order|null $order */ - public function getRenderLanguage(Order $order = null): string + public function getRenderLanguage(?Order $order = null): string { $language = $this->language; diff --git a/src/models/Settings.php b/src/models/Settings.php index 5dde3db3a1..4042d14b19 100644 --- a/src/models/Settings.php +++ b/src/models/Settings.php @@ -297,7 +297,7 @@ public function getDimensionUnits(): array * @throws InvalidConfigException if the currency in the config file is not set up * @throws SiteNotFoundException */ - public function getPaymentCurrency(string $siteHandle = null): ?string + public function getPaymentCurrency(?string $siteHandle = null): ?string { /** @var Site|StoreBehavior|null $site */ $site = $siteHandle ? Craft::$app->getSites()->getSiteByHandle($siteHandle) : Craft::$app->getSites()->getPrimarySite(); diff --git a/src/services/CatalogPricing.php b/src/services/CatalogPricing.php index 1c66ebd974..8ea2370c40 100755 --- a/src/services/CatalogPricing.php +++ b/src/services/CatalogPricing.php @@ -67,7 +67,7 @@ private function setQueueProgress(Queue|QueueInterface|null $queue, float $progr * @throws Exception * @throws InvalidConfigException */ - public function generateCatalogPrices(?array $purchasableIds = null, ?array $catalogPricingRules = null, bool $showConsoleOutput = false, Queue|QueueInterface $queue = null): void + public function generateCatalogPrices(?array $purchasableIds = null, ?array $catalogPricingRules = null, bool $showConsoleOutput = false, Queue|QueueInterface|null $queue = null): void { $chunkSize = 1000; $this->setQueueProgress($queue, 10, 'Retrieving purchasables'); diff --git a/src/services/Discounts.php b/src/services/Discounts.php index bace3f3368..10de476888 100644 --- a/src/services/Discounts.php +++ b/src/services/Discounts.php @@ -448,7 +448,7 @@ public function getAllActiveDiscounts(?Order $order = null): array * @throws InvalidConfigException * @throws \Exception */ - public function orderCouponAvailable(Order $order, string &$explanation = null): bool + public function orderCouponAvailable(Order $order, ?string &$explanation = null): bool { $discount = $this->getDiscountByCode($order->couponCode, $order->storeId); diff --git a/src/services/LineItems.php b/src/services/LineItems.php index 52e945b769..ef92d7301c 100644 --- a/src/services/LineItems.php +++ b/src/services/LineItems.php @@ -391,7 +391,7 @@ public function getLineItemById(int $id): ?LineItem * @throws \Exception * @deprecated in 5.1.0. Use [[create()]] instead. */ - public function createLineItem(Order $order, int $purchasableId, array $options, int $qty = 1, string $note = '', string $uid = null): LineItem + public function createLineItem(Order $order, int $purchasableId, array $options, int $qty = 1, string $note = '', ?string $uid = null): LineItem { Craft::$app->getDeprecator()->log(__METHOD__, 'LineItems::createLineItem() has been deprecated. Use LineItems::create() instead.'); $lineItem = new LineItem(); diff --git a/src/services/PaymentSources.php b/src/services/PaymentSources.php index 8542df7adb..f61567526b 100644 --- a/src/services/PaymentSources.php +++ b/src/services/PaymentSources.php @@ -147,7 +147,7 @@ public function getAllPaymentSourcesByCustomerId(?int $customerId = null, ?int $ * @return Collection * @throws InvalidConfigException */ - public function getAllPaymentSourcesByGatewayId(int $gatewayId = null): Collection + public function getAllPaymentSourcesByGatewayId(?int $gatewayId = null): Collection { if ($gatewayId === null) { return collect(); @@ -177,7 +177,7 @@ public function getAllPaymentSourcesByGatewayId(int $gatewayId = null): Collecti * @return Collection * @throws InvalidConfigException */ - public function getAllGatewayPaymentSourcesByCustomerId(int $gatewayId = null, int $customerId = null): Collection + public function getAllGatewayPaymentSourcesByCustomerId(?int $gatewayId = null, ?int $customerId = null): Collection { if ($gatewayId === null || $customerId === null) { return collect(); @@ -263,7 +263,7 @@ public function getPaymentSourceByIdAndUserId(int $sourceId, int $userId): ?Paym * @throws InvalidConfigException * @throws PaymentSourceException If unable to create the payment source */ - public function createPaymentSource(int $customerId, GatewayInterface $gateway, BasePaymentForm $paymentForm, string $sourceDescription = null, bool $makePrimarySource = false): PaymentSource + public function createPaymentSource(int $customerId, GatewayInterface $gateway, BasePaymentForm $paymentForm, ?string $sourceDescription = null, bool $makePrimarySource = false): PaymentSource { $source = $gateway->createPaymentSource($paymentForm, $customerId); diff --git a/src/services/Payments.php b/src/services/Payments.php index ef88aee4b7..fd8c97041d 100644 --- a/src/services/Payments.php +++ b/src/services/Payments.php @@ -566,7 +566,7 @@ private function _capture(Transaction $parent): Transaction * @param string $note the administrators note on the refund * @throws RefundException if anything goes wrong during a refund */ - private function _refund(Transaction $parent, float $amount = null, string $note = ''): Transaction + private function _refund(Transaction $parent, ?float $amount = null, string $note = ''): Transaction { try { $gateway = $parent->getGateway(); diff --git a/src/services/Pdfs.php b/src/services/Pdfs.php index f2b371ecac..e1f7cb0eb1 100644 --- a/src/services/Pdfs.php +++ b/src/services/Pdfs.php @@ -466,7 +466,7 @@ public function reorderPdfs(array $ids): bool * @return string The PDF data. * @throws Exception */ - public function renderPdfForOrder(Order $order, string $option = '', string $templatePath = null, array $variables = [], Pdf $pdf = null): string + public function renderPdfForOrder(Order $order, string $option = '', ?string $templatePath = null, array $variables = [], ?Pdf $pdf = null): string { if ($pdf instanceof Pdf) { $templatePath = $pdf->templatePath; diff --git a/src/services/Products.php b/src/services/Products.php index 02d500161f..f89d468ee1 100644 --- a/src/services/Products.php +++ b/src/services/Products.php @@ -31,7 +31,7 @@ class Products extends Component * @param array|int|string|null $siteId * @return Product|null */ - public function getProductById(int $id, array|int|string $siteId = null, array $criteria = []): ?Product + public function getProductById(int $id, array|int|string|null $siteId = null, array $criteria = []): ?Product { if (!$id) { return null; diff --git a/src/services/Purchasables.php b/src/services/Purchasables.php index e7b9629700..62fb8c1e32 100644 --- a/src/services/Purchasables.php +++ b/src/services/Purchasables.php @@ -144,7 +144,7 @@ class Purchasables extends Component * @throws Throwable * @since 5.3.0 */ - public function isPurchasableOutOfStockPurchasingAllowed(Purchasable $purchasable, Order $order = null, User $currentUser = null): bool + public function isPurchasableOutOfStockPurchasingAllowed(Purchasable $purchasable, ?Order $order = null, ?User $currentUser = null): bool { if ($currentUser === null) { $currentUser = Craft::$app->getUser()->getIdentity(); @@ -166,7 +166,7 @@ public function isPurchasableOutOfStockPurchasingAllowed(Purchasable $purchasabl * @param User|null $currentUser * @since 3.3.1 */ - public function isPurchasableAvailable(PurchasableInterface $purchasable, Order $order = null, User $currentUser = null): bool + public function isPurchasableAvailable(PurchasableInterface $purchasable, ?Order $order = null, ?User $currentUser = null): bool { if ($currentUser === null) { $currentUser = Craft::$app->getUser()->getIdentity(); @@ -187,7 +187,7 @@ public function isPurchasableAvailable(PurchasableInterface $purchasable, Order * @param User|null $currentUser * @since 3.3.2 */ - public function isPurchasableShippable(PurchasableInterface $purchasable, Order $order = null, User $currentUser = null): bool + public function isPurchasableShippable(PurchasableInterface $purchasable, ?Order $order = null, ?User $currentUser = null): bool { if ($currentUser === null) { $currentUser = Craft::$app->getUser()->getIdentity(); diff --git a/src/services/Sales.php b/src/services/Sales.php index 1d16a0da2e..116a691b40 100644 --- a/src/services/Sales.php +++ b/src/services/Sales.php @@ -273,7 +273,7 @@ public function getAllSales(): array * @return Sale[] * @throws InvalidConfigException */ - public function getSalesForPurchasable(PurchasableInterface $purchasable, Order $order = null): array + public function getSalesForPurchasable(PurchasableInterface $purchasable, ?Order $order = null): array { $matchedSales = []; @@ -335,7 +335,7 @@ public function getSalesRelatedToPurchasable(PurchasableInterface $purchasable): * * @param Order|null $order */ - public function getSalePriceForPurchasable(PurchasableInterface $purchasable, Order $order = null): float + public function getSalePriceForPurchasable(PurchasableInterface $purchasable, ?Order $order = null): float { $sales = $this->getSalesForPurchasable($purchasable, $order); $originalPrice = $purchasable->getPrice(); @@ -398,7 +398,7 @@ public function getSalePriceForPurchasable(PurchasableInterface $purchasable, Or * @param Order|null $order * @throws InvalidConfigException */ - public function matchPurchasableAndSale(PurchasableInterface $purchasable, Sale $sale, Order $order = null): bool + public function matchPurchasableAndSale(PurchasableInterface $purchasable, Sale $sale, ?Order $order = null): bool { /** @var Purchasable $purchasable */ $purchasableId = $purchasable->id; diff --git a/src/services/Subscriptions.php b/src/services/Subscriptions.php index 1953b9bde9..24d7cd200b 100644 --- a/src/services/Subscriptions.php +++ b/src/services/Subscriptions.php @@ -422,7 +422,7 @@ public function beforeDeleteUserHandler(ModelEvent $event): void * @throws Exception * @throws Throwable if cannot expire subscription */ - public function expireSubscription(Subscription $subscription, DateTime $dateTime = null): bool + public function expireSubscription(Subscription $subscription, ?DateTime $dateTime = null): bool { $subscription->isExpired = true; $subscription->dateExpired = $dateTime; diff --git a/src/services/Transactions.php b/src/services/Transactions.php index 55d5ba4b51..4d336c6b3e 100644 --- a/src/services/Transactions.php +++ b/src/services/Transactions.php @@ -183,7 +183,7 @@ public function refundableAmountForTransaction(Transaction $transaction): float * @throws CurrencyException * @throws InvalidConfigException */ - public function createTransaction(Order $order = null, Transaction $parentTransaction = null, ?string $typeOverride = null): Transaction + public function createTransaction(?Order $order = null, ?Transaction $parentTransaction = null, ?string $typeOverride = null): Transaction { if (!$order && !$parentTransaction) { throw new TransactionException('Tried to create a transaction without order or parent transaction'); diff --git a/src/services/Variants.php b/src/services/Variants.php index 3136478288..69fd5eb70a 100644 --- a/src/services/Variants.php +++ b/src/services/Variants.php @@ -38,7 +38,7 @@ class Variants extends Component * @param int|null $siteId Site ID for which to return the variants. Defaults to `null` which is current site. * @return Variant[] */ - public function getAllVariantsByProductId(int $productId, int $siteId = null, bool $includeDisabled = true): array + public function getAllVariantsByProductId(int $productId, ?int $siteId = null, bool $includeDisabled = true): array { $variantQuery = Variant::find() ->productId($productId) @@ -58,7 +58,7 @@ public function getAllVariantsByProductId(int $productId, int $siteId = null, bo * @param int $variantId The variant’s ID. * @param int|null $siteId The site ID for which to fetch the variant. Defaults to `null` which is current site. */ - public function getVariantById(int $variantId, int $siteId = null): ?Variant + public function getVariantById(int $variantId, ?int $siteId = null): ?Variant { return Craft::$app->getElements()->getElementById($variantId, Variant::class, $siteId); } diff --git a/src/stats/TopCustomers.php b/src/stats/TopCustomers.php index a2c472e7c7..c7f8d74be6 100644 --- a/src/stats/TopCustomers.php +++ b/src/stats/TopCustomers.php @@ -38,7 +38,7 @@ class TopCustomers extends Stat /** * @inheritDoc */ - public function __construct(string $dateRange = null, string $type = null, $startDate = null, $endDate = null, ?int $storeId = null) + public function __construct(?string $dateRange = null, ?string $type = null, $startDate = null, $endDate = null, ?int $storeId = null) { if ($type) { $this->type = $type; diff --git a/src/stats/TopProductTypes.php b/src/stats/TopProductTypes.php index a5048c26f0..ae51d04723 100644 --- a/src/stats/TopProductTypes.php +++ b/src/stats/TopProductTypes.php @@ -40,7 +40,7 @@ class TopProductTypes extends Stat /** * @inheritDoc */ - public function __construct(string $dateRange = null, string $type = null, $startDate = null, $endDate = null, ?int $storeId = null) + public function __construct(?string $dateRange = null, ?string $type = null, $startDate = null, $endDate = null, ?int $storeId = null) { $this->type = $type ?? $this->type; diff --git a/src/stats/TopProducts.php b/src/stats/TopProducts.php index 08975ba76b..861e621689 100644 --- a/src/stats/TopProducts.php +++ b/src/stats/TopProducts.php @@ -103,7 +103,7 @@ class TopProducts extends Stat /** * @inheritDoc */ - public function __construct(string $dateRange = null, string $type = null, $startDate = null, $endDate = null, array $revenueOptions = null, ?int $storeId = null) + public function __construct(?string $dateRange = null, ?string $type = null, $startDate = null, $endDate = null, ?array $revenueOptions = null, ?int $storeId = null) { $this->_ifNullDbFunc = Craft::$app->getDb()->getIsPgsql() ? 'COALESCE' : 'IFNULL'; diff --git a/src/stats/TopPurchasables.php b/src/stats/TopPurchasables.php index ceb6f402ad..6c8a18a1a9 100644 --- a/src/stats/TopPurchasables.php +++ b/src/stats/TopPurchasables.php @@ -38,7 +38,7 @@ class TopPurchasables extends Stat /** * @inheritDoc */ - public function __construct(string $dateRange = null, string $type = null, $startDate = null, $endDate = null, ?int $storeId = null) + public function __construct(?string $dateRange = null, ?string $type = null, $startDate = null, $endDate = null, ?int $storeId = null) { $this->type = $type ?? $this->type; diff --git a/src/stats/TotalOrdersByCountry.php b/src/stats/TotalOrdersByCountry.php index 4b193a895c..493ca09a3e 100644 --- a/src/stats/TotalOrdersByCountry.php +++ b/src/stats/TotalOrdersByCountry.php @@ -36,7 +36,7 @@ class TotalOrdersByCountry extends Stat /** * @inheritDoc */ - public function __construct(string $dateRange = null, string $type = null, $startDate = null, $endDate = null, ?int $storeId = null) + public function __construct(?string $dateRange = null, ?string $type = null, $startDate = null, $endDate = null, ?int $storeId = null) { $this->type = $type ?? $this->type; diff --git a/tests/unit/elements/product/ProductGetVariantsTest.php b/tests/unit/elements/product/ProductGetVariantsTest.php index 7fefab35a5..2be28e7ccf 100644 --- a/tests/unit/elements/product/ProductGetVariantsTest.php +++ b/tests/unit/elements/product/ProductGetVariantsTest.php @@ -27,7 +27,7 @@ class ProductGetVariantsTest extends Unit * @var \UnitTester */ protected $tester; - + /** * @return array */ @@ -47,7 +47,7 @@ public function testGetVariantsReturnsEmptyCollectionForNewProduct(): void { $product = new Product(); $variants = $product->getVariants(); - + self::assertInstanceOf(VariantCollection::class, $variants); self::assertTrue($variants->isEmpty()); } @@ -60,23 +60,23 @@ public function testGetVariantsDoesNotMemoizeEmptyCollections(): void $product = new Product(); $product->id = 999999; // Non-existent ID $product->typeId = 2000; - + // First call should return empty collection $variants1 = $product->getVariants(); self::assertTrue($variants1->isEmpty()); - + // Access private _variants property to check if it was memoized $reflection = new ReflectionClass($product); $variantsProperty = $reflection->getProperty('_variants'); $variantsProperty->setAccessible(true); - + // Should be null, not an empty collection self::assertNull($variantsProperty->getValue($product)); - + // Second call should also return empty collection (new query) $variants2 = $product->getVariants(); self::assertTrue($variants2->isEmpty()); - + // Still should not be memoized self::assertNull($variantsProperty->getValue($product)); } @@ -91,21 +91,21 @@ public function testGetVariantsMemoizesNonEmptyCollections(): void $productFixture = $this->tester->grabFixture('products'); $product = $productFixture->getElement('rad-hoodie'); self::assertNotNull($product); - + // First call $variants1 = $product->getVariants(); self::assertFalse($variants1->isEmpty()); - + // Access private _variants property $reflection = new ReflectionClass($product); $variantsProperty = $reflection->getProperty('_variants'); $variantsProperty->setAccessible(true); - + // Should be memoized $memoizedVariants = $variantsProperty->getValue($product); self::assertInstanceOf(VariantCollection::class, $memoizedVariants); self::assertNotNull($memoizedVariants); - + // Second call should return the memoized collection $variants2 = $product->getVariants(); self::assertCount($variants1->count(), $variants2); @@ -113,40 +113,40 @@ public function testGetVariantsMemoizesNonEmptyCollections(): void } /** - * Test that createVariantQuery uses duplicateOf product ID when available + * Test that createVariantQuery does not use duplicateOf product ID when available */ - public function testCreateVariantQueryUsesDuplicateOfId(): void + public function testCreateVariantQueryDoesNotUseDuplicateOfId(): void { /** @var ProductFixture $productFixture */ $productFixture = $this->tester->grabFixture('products'); $originalProduct = $productFixture->getElement('rad-hoodie'); self::assertNotNull($originalProduct); - + // Create a duplicate product $duplicateProduct = new Product(); $duplicateProduct->id = 999998; $duplicateProduct->typeId = $originalProduct->typeId; $duplicateProduct->siteId = 1002; // Different site $duplicateProduct->duplicateOf = $originalProduct; - + // Use reflection to access private createVariantQuery method $reflection = new ReflectionClass(Product::class); $method = $reflection->getMethod('createVariantQuery'); $method->setAccessible(true); - + /** @var VariantQuery $query */ $query = $method->invoke(null, $duplicateProduct); - + // Use reflection to check the query's ownerId and siteId $queryReflection = new ReflectionClass($query); $ownerIdProperty = $queryReflection->getProperty('ownerId'); $ownerIdProperty->setAccessible(true); $siteIdProperty = $queryReflection->getProperty('siteId'); $siteIdProperty->setAccessible(true); - + // Should use the original product's ID and siteId - self::assertEquals($originalProduct->id, $ownerIdProperty->getValue($query)); - self::assertEquals($originalProduct->siteId, $siteIdProperty->getValue($query)); + self::assertNotEquals($originalProduct->id, $ownerIdProperty->getValue($query)); + self::assertNotEquals($originalProduct->siteId, $siteIdProperty->getValue($query)); } /** @@ -158,25 +158,25 @@ public function testGetVariantsIncludeDisabledParameter(): void $productFixture = $this->tester->grabFixture('products'); $product = $productFixture->getElement('hypercolor-tshirt'); self::assertNotNull($product); - + // Create a disabled variant $disabledVariant = new Variant(); $disabledVariant->title = 'Disabled Variant'; $disabledVariant->sku = 'disabled-variant-sku'; $disabledVariant->enabled = false; $disabledVariant->setOwner($product); - + // Add to product's variants $variants = $product->getVariants()->all(); $variants[] = $disabledVariant; $product->setVariants($variants); - + // Test without includeDisabled (default) $enabledVariants = $product->getVariants(false); foreach ($enabledVariants as $variant) { self::assertTrue($variant->enabled); } - + // Test with includeDisabled $allVariants = $product->getVariants(true); $hasDisabledVariant = false;