diff --git a/.github/CODE_OF_CONDUCT.md b/.github/CODE_OF_CONDUCT.md
index 4e82725a7fb08..c2e9fa9cef242 100644
--- a/.github/CODE_OF_CONDUCT.md
+++ b/.github/CODE_OF_CONDUCT.md
@@ -1,46 +1,80 @@
-# Contributor Covenant Code of Conduct
+# Magento Code of Conduct
## Our Pledge
-In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
+We as members, contributors, and leaders pledge to make participation in our project and community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, caste, color, religion, or sexual identity and orientation.
+
+We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community.
+
## Our Standards
-Examples of behavior that contributes to creating a positive environment include:
+Examples of behavior that contribute to a positive environment for our project and community include:
+
+
+* Demonstrating empathy and kindness toward other people
+* Being respectful of differing opinions, viewpoints, and experiences
+* Giving and gracefully accepting constructive feedback
+* Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience
+* Focusing on what is best, not just for us as individuals but for the overall community
-* Using welcoming and inclusive language
-* Being respectful of differing viewpoints and experiences
-* Gracefully accepting constructive criticism
-* Focusing on what is best for the community
-* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
-* The use of sexualized language or imagery and unwelcome sexual attention or advances
-* Trolling, insulting/derogatory comments, and personal or political attacks
+* The use of sexualized language or imagery and sexual attention or advances of any kind
+* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
-* Publishing others' private information, such as a physical or electronic address, without explicit permission
+* Publishing others’ private information, such as a physical or email address, without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a professional setting
+
## Our Responsibilities
-Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
+Project maintainers are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any instances of unacceptable behavior.
-Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
+Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for behaviors that they deem inappropriate, threatening, offensive, or harmful.
## Scope
-This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
+This Code of Conduct applies when an individual is representing the project or its community both within project spaces and in public spaces. Examples of representing a project or community include using an official e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
## Enforcement
-Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at engcom@magento.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
+Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by first contacting the project team at engcom@adobe.com. Oversight of Adobe projects is handled by the Adobe Open Source Office, which has final say in any violations and enforcement of this Code of Conduct and can be reached at Grp-opensourceoffice@adobe.com. All complaints will be reviewed and investigated promptly and fairly.
-Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
+The project team must respect the privacy and security of the reporter of any incident.
-## Attribution
+Project maintainers who do not follow or enforce the Code of Conduct may face temporary or permanent repercussions as determined by other members of the project's leadership or the Adobe Open Source Office.
+
+
+## Enforcement Guidelines
+
+Project maintainers will follow these Community Impact Guidelines in determining the consequences for any action they deem to be in violation of this Code of Conduct:
+
+### 1. Correction
+
+Community Impact: Use of inappropriate language or other behavior deemed unprofessional or unwelcome in the community.
+Consequence: A private, written warning from project maintainers describing the violation and why the behavior was unacceptable. A public apology may be requested from the violator before any further involvement in the project by violator.
-This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
+### 2. Warning
+
+Community Impact: A relatively minor violation through a single incident or series of actions.
+
+Consequence: A written warning from project maintainers that includes stated consequences for continued unacceptable behavior. Violator must refrain from interacting with the people involved for a specified period of time as determined by the project maintainers, including, but not limited to, unsolicited interaction with those enforcing the Code of Conduct through channels such as community spaces and social media. Continued violations may lead to a temporary or permanent ban.
+
+### 3. Temporary Ban
+
+Community Impact: A more serious violation of community standards, including sustained unacceptable behavior.
+
+Consequence: A temporary ban from any interaction or public communication with the community for a specified period of time. No public or private interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, is allowed during this period. Failure to comply with the temporary ban may lead to a permanent ban.
+
+### 4. Permanent Ban
+
+Community Impact: Demonstrating a consistent pattern of violation of community standards or an egregious violation of community standards, including, but not limited to, sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals.
+
+Consequence: A permanent ban from any interaction with the community.
+
+
+## Attribution
-[homepage]: http://contributor-covenant.org
-[version]: http://contributor-covenant.org/version/1/4/
+This Code of Conduct is adapted from the Contributor Covenant, version 2.1, available at https://www.contributor-covenant.org/version/2/1/code_of_conduct.html.
diff --git a/app/bootstrap.php b/app/bootstrap.php
index 46d9e52b40019..8fbe2f770f53b 100644
--- a/app/bootstrap.php
+++ b/app/bootstrap.php
@@ -14,14 +14,14 @@
#ini_set('display_errors', 1);
/* PHP version validation */
-if (!defined('PHP_VERSION_ID') || PHP_VERSION_ID < 70400) {
+if (!defined('PHP_VERSION_ID') || PHP_VERSION_ID < 80100) {
if (PHP_SAPI == 'cli') {
- echo 'Magento supports PHP 7.4.0 or later. ' .
+ echo 'Magento supports PHP 8.1.0 or later. ' .
'Please read https://devdocs.magento.com/guides/v2.4/install-gde/system-requirements-tech.html';
} else {
echo <<
-
Magento supports PHP 7.4.0 or later. Please read
+
Magento supports PHP 8.1.0 or later. Please read
Magento System Requirements .
diff --git a/app/code/Magento/AdminAdobeIms/composer.json b/app/code/Magento/AdminAdobeIms/composer.json
index 0e556a483a51d..623d2ceb77a09 100644
--- a/app/code/Magento/AdminAdobeIms/composer.json
+++ b/app/code/Magento/AdminAdobeIms/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-adobe-ims": "*",
"magento/module-adobe-ims-api": "*",
diff --git a/app/code/Magento/AdminAnalytics/composer.json b/app/code/Magento/AdminAnalytics/composer.json
index ef3829fd149c6..e2f2bb182422d 100644
--- a/app/code/Magento/AdminAnalytics/composer.json
+++ b/app/code/Magento/AdminAnalytics/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-backend": "*",
"magento/module-config": "*",
diff --git a/app/code/Magento/AdminNotification/composer.json b/app/code/Magento/AdminNotification/composer.json
index 28ca1f626a2cd..1354cc202d7d2 100644
--- a/app/code/Magento/AdminNotification/composer.json
+++ b/app/code/Magento/AdminNotification/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"lib-libxml": "*",
"magento/framework": "*",
"magento/module-backend": "*",
diff --git a/app/code/Magento/AdobeIms/composer.json b/app/code/Magento/AdobeIms/composer.json
index b8542bc129294..9a3d8f27a87d2 100644
--- a/app/code/Magento/AdobeIms/composer.json
+++ b/app/code/Magento/AdobeIms/composer.json
@@ -2,7 +2,7 @@
"name": "magento/module-adobe-ims",
"description": "Magento module responsible for authentication to Adobe services",
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-adobe-ims-api": "*",
"magento/module-authorization": "*",
diff --git a/app/code/Magento/AdobeImsApi/composer.json b/app/code/Magento/AdobeImsApi/composer.json
index 231f1ddfa1513..13a02442e5c9b 100644
--- a/app/code/Magento/AdobeImsApi/composer.json
+++ b/app/code/Magento/AdobeImsApi/composer.json
@@ -2,7 +2,7 @@
"name": "magento/module-adobe-ims-api",
"description": "Implementation of Magento module responsible for authentication to Adobe services",
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*"
},
"type": "magento2-module",
diff --git a/app/code/Magento/AdvancedPricingImportExport/composer.json b/app/code/Magento/AdvancedPricingImportExport/composer.json
index 59ea74cf4ddcb..9ba5c58657f4f 100644
--- a/app/code/Magento/AdvancedPricingImportExport/composer.json
+++ b/app/code/Magento/AdvancedPricingImportExport/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-catalog": "*",
"magento/module-catalog-import-export": "*",
diff --git a/app/code/Magento/AdvancedSearch/Helper/Data.php b/app/code/Magento/AdvancedSearch/Helper/Data.php
new file mode 100644
index 0000000000000..9516472773461
--- /dev/null
+++ b/app/code/Magento/AdvancedSearch/Helper/Data.php
@@ -0,0 +1,53 @@
+engineResolver = $engineResolver;
+ }
+
+ /**
+ * Check if opensearch v2.x
+ *
+ * @return bool
+ */
+ public function isClientOpenSearchV2(): bool
+ {
+ $searchEngine = $this->engineResolver->getCurrentSearchEngine();
+ if (stripos($searchEngine, self::OPENSEARCH) !== false) {
+ if (substr(Client::VERSION, 0, 1) == self::MAJOR_VERSION) {
+ return true;
+ }
+ }
+ return false;
+ }
+}
diff --git a/app/code/Magento/AdvancedSearch/Model/Client/ClientFactory.php b/app/code/Magento/AdvancedSearch/Model/Client/ClientFactory.php
index 05eb513d68399..70ff445fb2b6c 100644
--- a/app/code/Magento/AdvancedSearch/Model/Client/ClientFactory.php
+++ b/app/code/Magento/AdvancedSearch/Model/Client/ClientFactory.php
@@ -6,11 +6,12 @@
namespace Magento\AdvancedSearch\Model\Client;
use Magento\Framework\ObjectManagerInterface;
+use Magento\AdvancedSearch\Helper\Data;
class ClientFactory implements ClientFactoryInterface
{
/**
- * Object manager
+ * Object var
*
* @var ObjectManagerInterface
*/
@@ -21,14 +22,32 @@ class ClientFactory implements ClientFactoryInterface
*/
private $clientClass;
+ /**
+ * @var string
+ */
+ private $openSearch;
+
+ /**
+ * @var Data
+ */
+ protected $helper;
+
/**
* @param ObjectManagerInterface $objectManager
* @param string $clientClass
+ * @param Data $helper
+ * @param string|null $openSearch
*/
- public function __construct(ObjectManagerInterface $objectManager, $clientClass)
- {
+ public function __construct(
+ ObjectManagerInterface $objectManager,
+ $clientClass,
+ Data $helper,
+ $openSearch = null
+ ) {
$this->objectManager = $objectManager;
$this->clientClass = $clientClass;
+ $this->openSearch = $openSearch;
+ $this->helper = $helper;
}
/**
@@ -39,8 +58,13 @@ public function __construct(ObjectManagerInterface $objectManager, $clientClass)
*/
public function create(array $options = [])
{
+ $class = $this->clientClass;
+ if ($this->helper->isClientOpenSearchV2()) {
+ $class = $this->openSearch;
+ }
+
return $this->objectManager->create(
- $this->clientClass,
+ $class,
['options' => $options]
);
}
diff --git a/app/code/Magento/AdvancedSearch/Test/Unit/Helper/DataTest.php b/app/code/Magento/AdvancedSearch/Test/Unit/Helper/DataTest.php
new file mode 100644
index 0000000000000..936d7c0928f08
--- /dev/null
+++ b/app/code/Magento/AdvancedSearch/Test/Unit/Helper/DataTest.php
@@ -0,0 +1,72 @@
+contextMock = $this->getMockBuilder(Context::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $this->engineResolverMock = $this->getMockForAbstractClass(EngineResolverInterface::class);
+
+ $this->engineResolverMock->expects($this->any())
+ ->method('getCurrentSearchEngine')
+ ->willReturn('');
+
+ $this->objectManager = new ObjectManagerHelper($this);
+ $this->helper = $this->objectManager->getObject(
+ Data::class,
+ [
+ 'context' => $this->contextMock,
+ 'engineResolver' => $this->engineResolverMock
+ ]
+ );
+ }
+
+ public function testIsClientOpenSearchV2()
+ {
+ $this->assertIsBool($this->helper->isClientOpenSearchV2());
+ }
+}
diff --git a/app/code/Magento/AdvancedSearch/composer.json b/app/code/Magento/AdvancedSearch/composer.json
index 30205c5255cdd..289207e2fa1c4 100644
--- a/app/code/Magento/AdvancedSearch/composer.json
+++ b/app/code/Magento/AdvancedSearch/composer.json
@@ -13,7 +13,7 @@
"magento/module-customer": "*",
"magento/module-search": "*",
"magento/module-store": "*",
- "php": "~7.4.0||~8.1.0"
+ "php": "~8.1.0||~8.2.0"
},
"type": "magento2-module",
"license": [
diff --git a/app/code/Magento/Amqp/composer.json b/app/code/Magento/Amqp/composer.json
index c7d8d49fb0003..2382864a4c4f5 100644
--- a/app/code/Magento/Amqp/composer.json
+++ b/app/code/Magento/Amqp/composer.json
@@ -8,7 +8,7 @@
"magento/framework": "*",
"magento/framework-amqp": "*",
"magento/framework-message-queue": "*",
- "php": "~7.4.0||~8.1.0"
+ "php": "~8.1.0||~8.2.0"
},
"type": "magento2-module",
"license": [
diff --git a/app/code/Magento/Analytics/composer.json b/app/code/Magento/Analytics/composer.json
index 9bf08b4b068ca..d52a4dc2a98a4 100644
--- a/app/code/Magento/Analytics/composer.json
+++ b/app/code/Magento/Analytics/composer.json
@@ -2,7 +2,7 @@
"name": "magento/module-analytics",
"description": "N/A",
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/module-backend": "*",
"magento/module-config": "*",
"magento/module-integration": "*",
diff --git a/app/code/Magento/AsynchronousOperations/Controller/Adminhtml/Notification/Dismiss.php b/app/code/Magento/AsynchronousOperations/Controller/Adminhtml/Notification/Dismiss.php
index 0a71c130fb20a..d6feed3915a92 100644
--- a/app/code/Magento/AsynchronousOperations/Controller/Adminhtml/Notification/Dismiss.php
+++ b/app/code/Magento/AsynchronousOperations/Controller/Adminhtml/Notification/Dismiss.php
@@ -8,12 +8,13 @@
use Magento\AsynchronousOperations\Model\BulkNotificationManagement;
use Magento\Backend\App\Action\Context;
use Magento\Backend\App\Action;
+use Magento\Framework\App\Action\HttpGetActionInterface;
use Magento\Framework\Controller\ResultFactory;
/**
* Class Bulk Notification Dismiss Controller
*/
-class Dismiss extends Action
+class Dismiss extends Action implements HttpGetActionInterface
{
/**
* @var BulkNotificationManagement
@@ -43,7 +44,7 @@ protected function _isAllowed()
}
/**
- * {@inheritdoc}
+ * @inheritdoc
*/
public function execute()
{
@@ -55,7 +56,7 @@ public function execute()
$isAcknowledged = $this->notificationManagement->acknowledgeBulks($bulkUuids);
/** @var \Magento\Framework\Controller\Result\Json $result */
- $result = $this->resultFactory->create(ResultFactory::TYPE_JSON);
+ $result = $this->resultFactory->create(ResultFactory::TYPE_RAW);
if (!$isAcknowledged) {
$result->setHttpResponseCode(400);
}
diff --git a/app/code/Magento/AsynchronousOperations/Test/Unit/Controller/Adminhtml/Notification/DismissTest.php b/app/code/Magento/AsynchronousOperations/Test/Unit/Controller/Adminhtml/Notification/DismissTest.php
index 463989efdfa4c..b4fc8ff4f76cb 100644
--- a/app/code/Magento/AsynchronousOperations/Test/Unit/Controller/Adminhtml/Notification/DismissTest.php
+++ b/app/code/Magento/AsynchronousOperations/Test/Unit/Controller/Adminhtml/Notification/DismissTest.php
@@ -11,6 +11,7 @@
use Magento\AsynchronousOperations\Model\BulkNotificationManagement;
use Magento\Framework\App\RequestInterface;
use Magento\Framework\Controller\Result\Json;
+use Magento\Framework\Controller\Result\Raw;
use Magento\Framework\Controller\ResultFactory;
use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
use PHPUnit\Framework\MockObject\MockObject;
@@ -43,6 +44,11 @@ class DismissTest extends TestCase
*/
private $jsonResultMock;
+ /**
+ * @var MockObject
+ */
+ private $rawResultMock;
+
protected function setUp(): void
{
$objectManager = new ObjectManager($this);
@@ -78,10 +84,10 @@ public function testExecute()
$this->resultFactoryMock->expects($this->once())
->method('create')
- ->with(ResultFactory::TYPE_JSON, [])
- ->willReturn($this->jsonResultMock);
+ ->with(ResultFactory::TYPE_RAW, [])
+ ->willReturn($this->rawResultMock);
- $this->assertEquals($this->jsonResultMock, $this->model->execute());
+ $this->assertEquals($this->rawResultMock, $this->model->execute());
}
public function testExecuteSetsBadRequestResponseStatusIfBulkWasNotAcknowledgedCorrectly()
@@ -95,7 +101,7 @@ public function testExecuteSetsBadRequestResponseStatusIfBulkWasNotAcknowledgedC
$this->resultFactoryMock->expects($this->once())
->method('create')
- ->with(ResultFactory::TYPE_JSON, [])
+ ->with(ResultFactory::TYPE_RAW, [])
->willReturn($this->jsonResultMock);
$this->notificationManagementMock->expects($this->once())
diff --git a/app/code/Magento/AsynchronousOperations/composer.json b/app/code/Magento/AsynchronousOperations/composer.json
index b09ca94052e87..7efcf27821405 100644
--- a/app/code/Magento/AsynchronousOperations/composer.json
+++ b/app/code/Magento/AsynchronousOperations/composer.json
@@ -11,7 +11,7 @@
"magento/module-authorization": "*",
"magento/module-backend": "*",
"magento/module-ui": "*",
- "php": "~7.4.0||~8.1.0"
+ "php": "~8.1.0||~8.2.0"
},
"suggest": {
"magento/module-admin-notification": "*",
diff --git a/app/code/Magento/Authorization/composer.json b/app/code/Magento/Authorization/composer.json
index d122e8b29b46e..268db947994fe 100644
--- a/app/code/Magento/Authorization/composer.json
+++ b/app/code/Magento/Authorization/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-backend": "*"
},
diff --git a/app/code/Magento/AwsS3/composer.json b/app/code/Magento/AwsS3/composer.json
index 19078b9ee7b77..9b9d55c18140a 100644
--- a/app/code/Magento/AwsS3/composer.json
+++ b/app/code/Magento/AwsS3/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-remote-storage": "*"
},
diff --git a/app/code/Magento/Backend/Test/Mftf/Test/AdminLoginSuccessfulTest.xml b/app/code/Magento/Backend/Test/Mftf/Test/AdminLoginSuccessfulTest.xml
index 7bb249e974c31..73b14bdc14151 100644
--- a/app/code/Magento/Backend/Test/Mftf/Test/AdminLoginSuccessfulTest.xml
+++ b/app/code/Magento/Backend/Test/Mftf/Test/AdminLoginSuccessfulTest.xml
@@ -19,8 +19,6 @@
-
-
diff --git a/app/code/Magento/Backend/composer.json b/app/code/Magento/Backend/composer.json
index 65aa05fe71e56..a3d6c48757c9a 100644
--- a/app/code/Magento/Backend/composer.json
+++ b/app/code/Magento/Backend/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-backup": "*",
"magento/module-catalog": "*",
diff --git a/app/code/Magento/Backup/composer.json b/app/code/Magento/Backup/composer.json
index e7437a3077aa7..2f7a82e9a5c82 100644
--- a/app/code/Magento/Backup/composer.json
+++ b/app/code/Magento/Backup/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-backend": "*",
"magento/module-cron": "*",
diff --git a/app/code/Magento/Bundle/Test/Mftf/ActionGroup/SetBundleProductAttributesActionGroup.xml b/app/code/Magento/Bundle/Test/Mftf/ActionGroup/SetBundleProductAttributesActionGroup.xml
index b940dfac865da..a58baac6f6b3c 100644
--- a/app/code/Magento/Bundle/Test/Mftf/ActionGroup/SetBundleProductAttributesActionGroup.xml
+++ b/app/code/Magento/Bundle/Test/Mftf/ActionGroup/SetBundleProductAttributesActionGroup.xml
@@ -60,6 +60,7 @@
+
diff --git a/app/code/Magento/Bundle/Test/Mftf/Section/AdminProductFormBundleSection.xml b/app/code/Magento/Bundle/Test/Mftf/Section/AdminProductFormBundleSection.xml
index b51b3d348ccee..8b78ac7b5fe6e 100644
--- a/app/code/Magento/Bundle/Test/Mftf/Section/AdminProductFormBundleSection.xml
+++ b/app/code/Magento/Bundle/Test/Mftf/Section/AdminProductFormBundleSection.xml
@@ -124,5 +124,6 @@
+
diff --git a/app/code/Magento/Bundle/composer.json b/app/code/Magento/Bundle/composer.json
index 47be75a42c254..35972c3ba10de 100644
--- a/app/code/Magento/Bundle/composer.json
+++ b/app/code/Magento/Bundle/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-backend": "*",
"magento/module-catalog": "*",
diff --git a/app/code/Magento/BundleGraphQl/composer.json b/app/code/Magento/BundleGraphQl/composer.json
index 70a619cbf6837..7d29641125a37 100644
--- a/app/code/Magento/BundleGraphQl/composer.json
+++ b/app/code/Magento/BundleGraphQl/composer.json
@@ -3,7 +3,7 @@
"description": "N/A",
"type": "magento2-module",
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/module-catalog": "*",
"magento/module-bundle": "*",
"magento/module-graph-ql": "*",
diff --git a/app/code/Magento/BundleImportExport/composer.json b/app/code/Magento/BundleImportExport/composer.json
index ff7d0acc7c48d..d7a59a1795ff6 100644
--- a/app/code/Magento/BundleImportExport/composer.json
+++ b/app/code/Magento/BundleImportExport/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-bundle": "*",
"magento/module-store": "*",
diff --git a/app/code/Magento/CacheInvalidate/composer.json b/app/code/Magento/CacheInvalidate/composer.json
index c756a5fe602e9..6c635ea103b0c 100644
--- a/app/code/Magento/CacheInvalidate/composer.json
+++ b/app/code/Magento/CacheInvalidate/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-page-cache": "*"
},
diff --git a/app/code/Magento/Captcha/composer.json b/app/code/Magento/Captcha/composer.json
index d4b94dbb586c2..0c39d988ba740 100644
--- a/app/code/Magento/Captcha/composer.json
+++ b/app/code/Magento/Captcha/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-backend": "*",
"magento/module-checkout": "*",
diff --git a/app/code/Magento/CardinalCommerce/composer.json b/app/code/Magento/CardinalCommerce/composer.json
index 4c49c92cec1ea..a6bc6bd72afd6 100644
--- a/app/code/Magento/CardinalCommerce/composer.json
+++ b/app/code/Magento/CardinalCommerce/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-checkout": "*",
"magento/module-payment": "*",
diff --git a/app/code/Magento/Catalog/Model/Category/AttributeRepository.php b/app/code/Magento/Catalog/Model/Category/AttributeRepository.php
index 3243bf718e663..65443e223e854 100644
--- a/app/code/Magento/Catalog/Model/Category/AttributeRepository.php
+++ b/app/code/Magento/Catalog/Model/Category/AttributeRepository.php
@@ -29,6 +29,11 @@ class AttributeRepository implements CategoryAttributeRepositoryInterface
*/
private $eavConfig;
+ /**
+ * @var array
+ */
+ private $metadataCache;
+
/**
* @param \Magento\Framework\Api\SearchCriteriaBuilder $searchCriteriaBuilder
* @param \Magento\Framework\Api\FilterBuilder $filterBuilder
@@ -48,7 +53,7 @@ public function __construct(
}
/**
- * {@inheritdoc}
+ * @inheritdoc
*/
public function getList(\Magento\Framework\Api\SearchCriteriaInterface $searchCriteria)
{
@@ -59,7 +64,7 @@ public function getList(\Magento\Framework\Api\SearchCriteriaInterface $searchCr
}
/**
- * {@inheritdoc}
+ * @inheritdoc
*/
public function get($attributeCode)
{
@@ -70,23 +75,27 @@ public function get($attributeCode)
}
/**
- * {@inheritdoc}
+ * @inheritdoc
+ *
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
public function getCustomAttributesMetadata($dataObjectClassName = null)
{
- $defaultAttributeSetId = $this->eavConfig
- ->getEntityType(\Magento\Catalog\Api\Data\CategoryAttributeInterface::ENTITY_TYPE_CODE)
- ->getDefaultAttributeSetId();
- $searchCriteria = $this->searchCriteriaBuilder->addFilters(
- [
- $this->filterBuilder
- ->setField('attribute_set_id')
- ->setValue($defaultAttributeSetId)
- ->create(),
- ]
- );
-
- return $this->getList($searchCriteria->create())->getItems();
+ if (!isset($this->metadataCache[$dataObjectClassName])) {
+ $defaultAttributeSetId = $this->eavConfig
+ ->getEntityType(\Magento\Catalog\Api\Data\CategoryAttributeInterface::ENTITY_TYPE_CODE)
+ ->getDefaultAttributeSetId();
+ $searchCriteria = $this->searchCriteriaBuilder->addFilters(
+ [
+ $this->filterBuilder
+ ->setField('attribute_set_id')
+ ->setValue($defaultAttributeSetId)
+ ->create(),
+ ]
+ );
+ $this->metadataCache[$dataObjectClassName] = $this->getList($searchCriteria->create())
+ ->getItems();
+ }
+ return $this->metadataCache[$dataObjectClassName];
}
}
diff --git a/app/code/Magento/Catalog/Test/Fixture/Product.php b/app/code/Magento/Catalog/Test/Fixture/Product.php
index c665acd09cd0f..c6d0905c539ed 100644
--- a/app/code/Magento/Catalog/Test/Fixture/Product.php
+++ b/app/code/Magento/Catalog/Test/Fixture/Product.php
@@ -10,7 +10,10 @@
use Magento\Catalog\Api\Data\ProductCustomOptionInterface;
use Magento\Catalog\Api\Data\ProductInterface;
use Magento\Catalog\Api\ProductRepositoryInterface;
+use Magento\Catalog\Model\Config\Source\ProductPriceOptionsInterface;
use Magento\Catalog\Model\Product\Attribute\Source\Status;
+use Magento\Catalog\Model\Product\Option as CustomOption;
+use Magento\Catalog\Model\Product\Option\Value as CustomOptionValue;
use Magento\Catalog\Model\Product\Type;
use Magento\Catalog\Model\Product\Visibility;
use Magento\Framework\DataObject;
@@ -198,21 +201,57 @@ private function prepareOptions(array $data): array
{
$options = [];
$default = [
- 'product_sku' => $data['sku'],
- 'title' => 'customoption%order%%uniqid%',
- 'type' => ProductCustomOptionInterface::OPTION_TYPE_FIELD,
- 'is_require' => true,
- 'price' => 10.0,
- 'price_type' => 'fixed',
- 'sku' => 'customoption%order%%uniqid%',
- 'max_characters' => null,
+ CustomOption::KEY_PRODUCT_SKU => $data['sku'],
+ CustomOption::KEY_TITLE => 'customoption%order%%uniqid%',
+ CustomOption::KEY_TYPE => ProductCustomOptionInterface::OPTION_TYPE_FIELD,
+ CustomOption::KEY_IS_REQUIRE => true,
+ CustomOption::KEY_PRICE => 10.0,
+ CustomOption::KEY_PRICE_TYPE => ProductPriceOptionsInterface::VALUE_FIXED,
+ CustomOption::KEY_SKU => 'customoption%order%%uniqid%',
+ CustomOption::KEY_MAX_CHARACTERS => null,
+ CustomOption::KEY_SORT_ORDER => 1,
'values' => null,
];
+ $defaultValue = [
+ CustomOptionValue::KEY_TITLE => 'customoption%order%_%valueorder%%uniqid%',
+ CustomOptionValue::KEY_PRICE => 1,
+ CustomOptionValue::KEY_PRICE_TYPE => ProductPriceOptionsInterface::VALUE_FIXED,
+ CustomOptionValue::KEY_SKU => 'customoption%order%_%valueorder%%uniqid%',
+ CustomOptionValue::KEY_SORT_ORDER => 1,
+ ];
$sortOrder = 1;
foreach ($data['options'] as $item) {
- $option = $item + ['sort_order' => $sortOrder++] + $default;
- $option['title'] = strtr($option['title'], ['%order%' => $option['sort_order']]);
- $option['sku'] = strtr($option['sku'], ['%order%' => $option['sort_order']]);
+ $option = $item + [CustomOption::KEY_SORT_ORDER => $sortOrder++] + $default;
+ $option[CustomOption::KEY_TITLE] = strtr(
+ $option[CustomOption::KEY_TITLE],
+ ['%order%' => $option[CustomOption::KEY_SORT_ORDER]]
+ );
+ $option[CustomOption::KEY_SKU] = strtr(
+ $option[CustomOption::KEY_SKU],
+ ['%order%' => $option[CustomOption::KEY_SORT_ORDER]]
+ );
+ if (isset($item['values'])) {
+ $valueSortOrder = 1;
+ $option['values'] = [];
+ foreach ($item['values'] as $value) {
+ $value += [CustomOptionValue::KEY_SORT_ORDER => $valueSortOrder++] + $defaultValue;
+ $value[CustomOptionValue::KEY_TITLE] = strtr(
+ $value[CustomOptionValue::KEY_TITLE],
+ [
+ '%order%' => $option[CustomOption::KEY_SORT_ORDER],
+ '%valueorder%' => $value[CustomOptionValue::KEY_SORT_ORDER]
+ ]
+ );
+ $value[CustomOptionValue::KEY_SKU] = strtr(
+ $value[CustomOptionValue::KEY_SKU],
+ [
+ '%order%' => $option[CustomOption::KEY_SORT_ORDER],
+ '%valueorder%' => $value[CustomOptionValue::KEY_SORT_ORDER]
+ ]
+ );
+ $option['values'][] = $value;
+ }
+ }
$options[] = $option;
}
diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminToggleProductGridColumnByClickingItsNameActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminToggleProductGridColumnByClickingItsNameActionGroup.xml
new file mode 100644
index 0000000000000..36a43387ba57e
--- /dev/null
+++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminToggleProductGridColumnByClickingItsNameActionGroup.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+ Click on 'Columns' name from Columns dropdown menu in Admin Product Grid.
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductGridFilterSection.xml b/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductGridFilterSection.xml
index 28033aadbcf97..447af3f80ce2f 100644
--- a/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductGridFilterSection.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductGridFilterSection.xml
@@ -39,6 +39,7 @@
+
diff --git a/app/code/Magento/Catalog/Test/Mftf/Section/StorefrontCategoryMainSection.xml b/app/code/Magento/Catalog/Test/Mftf/Section/StorefrontCategoryMainSection.xml
index 408669f29f1b3..526ac700a0b5a 100644
--- a/app/code/Magento/Catalog/Test/Mftf/Section/StorefrontCategoryMainSection.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/Section/StorefrontCategoryMainSection.xml
@@ -43,5 +43,6 @@
+
diff --git a/app/code/Magento/Catalog/Test/Mftf/Section/StorefrontCategoryTopToolbarSection.xml b/app/code/Magento/Catalog/Test/Mftf/Section/StorefrontCategoryTopToolbarSection.xml
index e063b5fc8c1b7..2c340add26267 100644
--- a/app/code/Magento/Catalog/Test/Mftf/Section/StorefrontCategoryTopToolbarSection.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/Section/StorefrontCategoryTopToolbarSection.xml
@@ -14,5 +14,6 @@
+
diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminChangeCategoryDisplaySettingsOnStorefrontTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminChangeCategoryDisplaySettingsOnStorefrontTest.xml
new file mode 100644
index 0000000000000..ec26e65c06789
--- /dev/null
+++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminChangeCategoryDisplaySettingsOnStorefrontTest.xml
@@ -0,0 +1,138 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 10
+ 1000
+
+
+
+ 11
+ 1000
+
+
+
+ 12
+ 1000
+
+
+
+ 13
+ 1000
+
+
+
+ 14
+ 1000
+
+
+
+ 15
+ 1000
+
+
+
+ 16
+ 1000
+
+
+
+ 17
+ 1000
+
+
+
+ 18
+ 1000
+
+
+
+ 19
+ 1000
+
+
+
+ 20
+ 1000
+
+
+
+ 21
+ 1000
+
+
+ 22
+ 1000
+
+
+ 23
+ 1000
+
+
+ 24
+ 1000
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminProductGridCustomViewColumnDisplayTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminProductGridCustomViewColumnDisplayTest.xml
new file mode 100644
index 0000000000000..bb6a1f1b20e7f
--- /dev/null
+++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminProductGridCustomViewColumnDisplayTest.xml
@@ -0,0 +1,53 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Catalog/composer.json b/app/code/Magento/Catalog/composer.json
index 6597e88e9d995..4421b2991266b 100644
--- a/app/code/Magento/Catalog/composer.json
+++ b/app/code/Magento/Catalog/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-authorization": "*",
"magento/module-asynchronous-operations": "*",
diff --git a/app/code/Magento/CatalogAnalytics/composer.json b/app/code/Magento/CatalogAnalytics/composer.json
index a41a47fa4764b..2710625d0f08d 100644
--- a/app/code/Magento/CatalogAnalytics/composer.json
+++ b/app/code/Magento/CatalogAnalytics/composer.json
@@ -2,7 +2,7 @@
"name": "magento/module-catalog-analytics",
"description": "N/A",
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-catalog": "*",
"magento/module-analytics": "*"
diff --git a/app/code/Magento/CatalogCmsGraphQl/composer.json b/app/code/Magento/CatalogCmsGraphQl/composer.json
index cf9e76f3b2ea2..d1cff1a3e448f 100644
--- a/app/code/Magento/CatalogCmsGraphQl/composer.json
+++ b/app/code/Magento/CatalogCmsGraphQl/composer.json
@@ -3,7 +3,7 @@
"description": "N/A",
"type": "magento2-module",
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-catalog": "*",
"magento/module-cms-graph-ql": "*"
diff --git a/app/code/Magento/CatalogCustomerGraphQl/composer.json b/app/code/Magento/CatalogCustomerGraphQl/composer.json
index b1743ae964966..5c4a301857c7e 100644
--- a/app/code/Magento/CatalogCustomerGraphQl/composer.json
+++ b/app/code/Magento/CatalogCustomerGraphQl/composer.json
@@ -3,7 +3,7 @@
"description": "N/A",
"type": "magento2-module",
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-catalog": "*",
"magento/module-customer": "*",
diff --git a/app/code/Magento/CatalogGraphQl/Model/Category/CategoryFilter.php b/app/code/Magento/CatalogGraphQl/Model/Category/CategoryFilter.php
index 4350b6dd85266..d8b90b454b4a5 100644
--- a/app/code/Magento/CatalogGraphQl/Model/Category/CategoryFilter.php
+++ b/app/code/Magento/CatalogGraphQl/Model/Category/CategoryFilter.php
@@ -7,13 +7,11 @@
namespace Magento\CatalogGraphQl\Model\Category;
-use Magento\Catalog\Api\CategoryRepositoryInterface;
-use Magento\Catalog\Api\Data\CategorySearchResultsInterface;
-use Magento\Catalog\Api\Data\CategorySearchResultsInterfaceFactory;
use Magento\Catalog\Model\ResourceModel\Category\CollectionFactory;
use Magento\CatalogGraphQl\Model\Resolver\Categories\DataProvider\Category\CollectionProcessorInterface;
use Magento\CatalogGraphQl\Model\Category\Filter\SearchCriteria;
use Magento\Framework\Api\ExtensionAttribute\JoinProcessorInterface;
+use Magento\Framework\DB\Select;
use Magento\Framework\Exception\InputException;
use Magento\Framework\GraphQl\Exception\GraphQlInputException;
use Magento\GraphQl\Model\Query\ContextInterface;
@@ -39,16 +37,6 @@ class CategoryFilter
*/
private $extensionAttributesJoinProcessor;
- /**
- * @var CategorySearchResultsInterfaceFactory
- */
- private $categorySearchResultsFactory;
-
- /**
- * @var CategoryRepositoryInterface
- */
- private $categoryRepository;
-
/**
* @var SearchCriteria
*/
@@ -58,23 +46,17 @@ class CategoryFilter
* @param CollectionFactory $categoryCollectionFactory
* @param CollectionProcessorInterface $collectionProcessor
* @param JoinProcessorInterface $extensionAttributesJoinProcessor
- * @param CategorySearchResultsInterfaceFactory $categorySearchResultsFactory
- * @param CategoryRepositoryInterface $categoryRepository
* @param SearchCriteria $searchCriteria
*/
public function __construct(
CollectionFactory $categoryCollectionFactory,
CollectionProcessorInterface $collectionProcessor,
JoinProcessorInterface $extensionAttributesJoinProcessor,
- CategorySearchResultsInterfaceFactory $categorySearchResultsFactory,
- CategoryRepositoryInterface $categoryRepository,
SearchCriteria $searchCriteria
) {
$this->categoryCollectionFactory = $categoryCollectionFactory;
$this->collectionProcessor = $collectionProcessor;
$this->extensionAttributesJoinProcessor = $extensionAttributesJoinProcessor;
- $this->categorySearchResultsFactory = $categorySearchResultsFactory;
- $this->categoryRepository = $categoryRepository;
$this->searchCriteria = $searchCriteria;
}
@@ -95,22 +77,21 @@ public function getResult(array $criteria, StoreInterface $store, array $attribu
$this->extensionAttributesJoinProcessor->process($collection);
$this->collectionProcessor->process($collection, $searchCriteria, $attributeNames, $context);
- /** @var CategorySearchResultsInterface $searchResult */
- $categories = $this->categorySearchResultsFactory->create();
- $categories->setSearchCriteria($searchCriteria);
- $categories->setItems($collection->getItems());
- $categories->setTotalCount($collection->getSize());
+ // only fetch necessary category entity id
+ $collection
+ ->getSelect()
+ ->reset(Select::COLUMNS)
+ ->columns(
+ 'e.entity_id'
+ );
- $categoryIds = [];
- foreach ($categories->getItems() as $category) {
- $categoryIds[] = (int)$category->getId();
- }
+ $categoryIds = $collection->load()->getLoadedIds();
$totalPages = 0;
- if ($categories->getTotalCount() > 0 && $searchCriteria->getPageSize() > 0) {
- $totalPages = ceil($categories->getTotalCount() / $searchCriteria->getPageSize());
+ if ($collection->getSize() > 0 && $searchCriteria->getPageSize() > 0) {
+ $totalPages = ceil($collection->getSize() / $searchCriteria->getPageSize());
}
- if ($searchCriteria->getCurrentPage() > $totalPages && $categories->getTotalCount() > 0) {
+ if ($searchCriteria->getCurrentPage() > $totalPages && $collection->getSize() > 0) {
throw new GraphQlInputException(
__(
'currentPage value %1 specified is greater than the %2 page(s) available.',
@@ -121,7 +102,7 @@ public function getResult(array $criteria, StoreInterface $store, array $attribu
return [
'category_ids' => $categoryIds,
- 'total_count' => $categories->getTotalCount(),
+ 'total_count' => $collection->getSize(),
'page_info' => [
'total_pages' => $totalPages,
'page_size' => $searchCriteria->getPageSize(),
diff --git a/app/code/Magento/CatalogGraphQl/Model/Category/Hydrator.php b/app/code/Magento/CatalogGraphQl/Model/Category/Hydrator.php
index 675118b953102..fc234c1de4e4a 100644
--- a/app/code/Magento/CatalogGraphQl/Model/Category/Hydrator.php
+++ b/app/code/Magento/CatalogGraphQl/Model/Category/Hydrator.php
@@ -60,8 +60,12 @@ public function hydrateCategory(Category $category, $basicFieldsOnly = false) :
if ($basicFieldsOnly) {
$categoryData = $category->getData();
} else {
- $categoryData = $this->dataObjectProcessor->buildOutputDataArray($category, CategoryInterface::class);
+ $categoryData = $this->dataObjectProcessor->buildOutputDataArray(
+ $category,
+ CategoryInterface::class
+ );
}
+
$categoryData['id'] = $category->getId();
$categoryData['uid'] = $this->uidEncoder->encode((string) $category->getId());
$categoryData['children'] = [];
diff --git a/app/code/Magento/CatalogGraphQl/Model/Resolver/CategoriesQuery.php b/app/code/Magento/CatalogGraphQl/Model/Resolver/CategoriesQuery.php
index 86715623eb9fb..2cbfcafdb6746 100644
--- a/app/code/Magento/CatalogGraphQl/Model/Resolver/CategoriesQuery.php
+++ b/app/code/Magento/CatalogGraphQl/Model/Resolver/CategoriesQuery.php
@@ -10,12 +10,15 @@
use Magento\CatalogGraphQl\Model\Category\CategoryFilter;
use Magento\CatalogGraphQl\Model\Resolver\Products\DataProvider\CategoryTree;
use Magento\CatalogGraphQl\Model\Resolver\Products\DataProvider\ExtractDataFromCategoryTree;
+use Magento\Framework\Api\Search\SearchCriteriaFactory;
use Magento\Framework\Exception\InputException;
use Magento\Framework\GraphQl\Config\Element\Field;
use Magento\Framework\GraphQl\Exception\GraphQlInputException;
use Magento\Framework\GraphQl\Query\Resolver\ArgumentsProcessorInterface;
use Magento\Framework\GraphQl\Query\ResolverInterface;
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
+use Magento\GraphQl\Model\Query\ContextInterface;
+use Magento\Store\Api\Data\StoreInterface;
/**
* Categories resolver, used for GraphQL category data request processing.
@@ -42,22 +45,30 @@ class CategoriesQuery implements ResolverInterface
*/
private $argsSelection;
+ /**
+ * @var SearchCriteriaFactory
+ */
+ private $searchCriteriaFactory;
+
/**
* @param CategoryTree $categoryTree
* @param ExtractDataFromCategoryTree $extractDataFromCategoryTree
* @param CategoryFilter $categoryFilter
* @param ArgumentsProcessorInterface $argsSelection
+ * @param SearchCriteriaFactory $searchCriteriaFactory
*/
public function __construct(
CategoryTree $categoryTree,
ExtractDataFromCategoryTree $extractDataFromCategoryTree,
CategoryFilter $categoryFilter,
- ArgumentsProcessorInterface $argsSelection
+ ArgumentsProcessorInterface $argsSelection,
+ SearchCriteriaFactory $searchCriteriaFactory
) {
$this->categoryTree = $categoryTree;
$this->extractDataFromCategoryTree = $extractDataFromCategoryTree;
$this->categoryFilter = $categoryFilter;
$this->argsSelection = $argsSelection;
+ $this->searchCriteriaFactory = $searchCriteriaFactory;
}
/**
@@ -87,7 +98,7 @@ public function resolve(Field $field, $context, ResolveInfo $info, array $value
$rootCategoryIds = $filterResult['category_ids'] ?? [];
- $filterResult['items'] = $this->fetchCategories($rootCategoryIds, $info, (int) $store->getId());
+ $filterResult['items'] = $this->fetchCategories($rootCategoryIds, $info, $store, $context);
return $filterResult;
}
@@ -96,17 +107,28 @@ public function resolve(Field $field, $context, ResolveInfo $info, array $value
*
* @param array $categoryIds
* @param ResolveInfo $info
- * @param int $storeId
+ * @param StoreInterface $store
+ * @param ContextInterface $context
* @return array
*/
- private function fetchCategories(array $categoryIds, ResolveInfo $info, int $storeId)
- {
+ private function fetchCategories(
+ array $categoryIds,
+ ResolveInfo $info,
+ StoreInterface $store,
+ ContextInterface $context
+ ) {
$fetchedCategories = [];
foreach ($categoryIds as $categoryId) {
- $categoryTree = $this->categoryTree->getTree($info, $categoryId, $storeId);
- if (empty($categoryTree)) {
- continue;
- }
+ /* Search Criteria is created for compatibility */
+ $searchCriteria = $this->searchCriteriaFactory->create();
+ $categoryTree = $this->categoryTree->getFilteredTree(
+ $info,
+ $categoryId,
+ $searchCriteria,
+ $store,
+ [],
+ $context
+ );
$fetchedCategories[] = current($this->extractDataFromCategoryTree->execute($categoryTree));
}
diff --git a/app/code/Magento/CatalogGraphQl/Model/Resolver/CategoryList.php b/app/code/Magento/CatalogGraphQl/Model/Resolver/CategoryList.php
index e2b045c36f4d3..0d857604cd04a 100644
--- a/app/code/Magento/CatalogGraphQl/Model/Resolver/CategoryList.php
+++ b/app/code/Magento/CatalogGraphQl/Model/Resolver/CategoryList.php
@@ -7,6 +7,7 @@
namespace Magento\CatalogGraphQl\Model\Resolver;
+use Magento\CatalogGraphQl\Model\Category\Filter\SearchCriteria;
use Magento\Store\Api\Data\StoreInterface;
use Magento\GraphQl\Model\Query\ContextInterface;
use Magento\CatalogGraphQl\Model\Category\CategoryFilter;
@@ -45,22 +46,30 @@ class CategoryList implements ResolverInterface
*/
private $argsSelection;
+ /**
+ * @var SearchCriteria
+ */
+ private $searchCriteria;
+
/**
* @param CategoryTree $categoryTree
* @param ExtractDataFromCategoryTree $extractDataFromCategoryTree
* @param CategoryFilter $categoryFilter
* @param ArgumentsProcessorInterface $argsSelection
+ * @param SearchCriteria $searchCriteria
*/
public function __construct(
CategoryTree $categoryTree,
ExtractDataFromCategoryTree $extractDataFromCategoryTree,
CategoryFilter $categoryFilter,
- ArgumentsProcessorInterface $argsSelection
+ ArgumentsProcessorInterface $argsSelection,
+ SearchCriteria $searchCriteria
) {
$this->categoryTree = $categoryTree;
$this->extractDataFromCategoryTree = $extractDataFromCategoryTree;
$this->categoryFilter = $categoryFilter;
$this->argsSelection = $argsSelection;
+ $this->searchCriteria = $searchCriteria;
}
/**
@@ -105,21 +114,19 @@ private function fetchCategories(
array $criteria,
StoreInterface $store,
array $attributeNames,
- $context
+ ContextInterface $context
) : array {
$fetchedCategories = [];
foreach ($categoryIds as $categoryId) {
+ $searchCriteria = $this->searchCriteria->buildCriteria($criteria, $store);
$categoryTree = $this->categoryTree->getFilteredTree(
$info,
$categoryId,
- $criteria,
+ $searchCriteria,
$store,
$attributeNames,
$context
);
- if (empty($categoryTree)) {
- continue;
- }
$fetchedCategories[] = current($this->extractDataFromCategoryTree->execute($categoryTree));
}
diff --git a/app/code/Magento/CatalogGraphQl/Model/Resolver/Products/DataProvider/CategoryTree.php b/app/code/Magento/CatalogGraphQl/Model/Resolver/Products/DataProvider/CategoryTree.php
index 81ca0fe9d2c9f..a5cc522d7ccf0 100644
--- a/app/code/Magento/CatalogGraphQl/Model/Resolver/Products/DataProvider/CategoryTree.php
+++ b/app/code/Magento/CatalogGraphQl/Model/Resolver/Products/DataProvider/CategoryTree.php
@@ -17,9 +17,9 @@
use Magento\Catalog\Model\ResourceModel\Category\CollectionFactory;
use Magento\CatalogGraphQl\Model\AttributesJoiner;
use Magento\CatalogGraphQl\Model\Category\DepthCalculator;
-use Magento\CatalogGraphQl\Model\Category\Filter\SearchCriteria;
use Magento\CatalogGraphQl\Model\Category\LevelCalculator;
use Magento\CatalogGraphQl\Model\Resolver\Categories\DataProvider\Category\CollectionProcessorInterface;
+use Magento\Framework\Api\Search\SearchCriteria;
use Magento\Framework\EntityManager\MetadataPool;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
@@ -68,11 +68,6 @@ class CategoryTree
*/
private $collectionProcessor;
- /**
- * @var SearchCriteria
- */
- private $searchCriteria;
-
/**
* @param CollectionFactory $collectionFactory
* @param AttributesJoiner $attributesJoiner
@@ -80,7 +75,6 @@ class CategoryTree
* @param LevelCalculator $levelCalculator
* @param MetadataPool $metadata
* @param CollectionProcessorInterface $collectionProcessor
- * @param SearchCriteria $searchCriteria
*/
public function __construct(
CollectionFactory $collectionFactory,
@@ -88,8 +82,7 @@ public function __construct(
DepthCalculator $depthCalculator,
LevelCalculator $levelCalculator,
MetadataPool $metadata,
- CollectionProcessorInterface $collectionProcessor,
- SearchCriteria $searchCriteria
+ CollectionProcessorInterface $collectionProcessor
) {
$this->collectionFactory = $collectionFactory;
$this->attributesJoiner = $attributesJoiner;
@@ -97,7 +90,6 @@ public function __construct(
$this->levelCalculator = $levelCalculator;
$this->metadata = $metadata;
$this->collectionProcessor = $collectionProcessor;
- $this->searchCriteria = $searchCriteria;
}
/**
@@ -201,23 +193,23 @@ private function joinAttributesRecursively(
*
* @param ResolveInfo $resolveInfo
* @param int $rootCategoryId
- * @param array $criteria
+ * @param SearchCriteria $searchCriteria
* @param StoreInterface $store
* @param array $attributeNames
* @param ContextInterface $context
* @return Iterator
* @throws LocalizedException
* @throws Exception
+ * @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
public function getFilteredTree(
ResolveInfo $resolveInfo,
int $rootCategoryId,
- array $criteria,
+ SearchCriteria $searchCriteria,
StoreInterface $store,
array $attributeNames,
ContextInterface $context
): Iterator {
- $searchCriteria = $this->searchCriteria->buildCriteria($criteria, $store);
$collection = $this->getCollection($resolveInfo, $rootCategoryId);
$this->collectionProcessor->process($collection, $searchCriteria, $attributeNames, $context);
return $collection->getIterator();
diff --git a/app/code/Magento/CatalogGraphQl/composer.json b/app/code/Magento/CatalogGraphQl/composer.json
index c289f84a359ba..fbc4172226c58 100644
--- a/app/code/Magento/CatalogGraphQl/composer.json
+++ b/app/code/Magento/CatalogGraphQl/composer.json
@@ -3,7 +3,7 @@
"description": "N/A",
"type": "magento2-module",
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/module-eav": "*",
"magento/module-catalog": "*",
"magento/module-catalog-inventory": "*",
diff --git a/app/code/Magento/CatalogGraphQl/etc/graphql/di.xml b/app/code/Magento/CatalogGraphQl/etc/graphql/di.xml
index 369f4bfb23034..0e0fa9d95580f 100644
--- a/app/code/Magento/CatalogGraphQl/etc/graphql/di.xml
+++ b/app/code/Magento/CatalogGraphQl/etc/graphql/di.xml
@@ -191,6 +191,11 @@
+
+
+ Magento\CatalogGraphQl\Category\DataObjectProcessor
+
+
@@ -207,4 +212,16 @@
+
+
+
+ -
+
- getChildren
+
+
+
+
diff --git a/app/code/Magento/CatalogImportExport/Model/Import/Product/Option.php b/app/code/Magento/CatalogImportExport/Model/Import/Product/Option.php
index 84d36be94900c..bd64982c0f291 100644
--- a/app/code/Magento/CatalogImportExport/Model/Import/Product/Option.php
+++ b/app/code/Magento/CatalogImportExport/Model/Import/Product/Option.php
@@ -7,14 +7,25 @@
namespace Magento\CatalogImportExport\Model\Import\Product;
use Magento\Catalog\Api\Data\ProductInterface;
+use Magento\Catalog\Model\ProductFactory;
+use Magento\Catalog\Model\ResourceModel\Product\Option\CollectionFactory;
use Magento\Catalog\Model\ResourceModel\Product\Option\Value\Collection as ProductOptionValueCollection;
use Magento\Catalog\Model\ResourceModel\Product\Option\Value\CollectionFactory as ProductOptionValueCollectionFactory;
use Magento\CatalogImportExport\Model\Import\Product;
+use Magento\Framework\App\Config\ScopeConfigInterface;
+use Magento\Framework\App\ObjectManager;
use Magento\Framework\App\ResourceConnection;
+use Magento\Framework\Exception\LocalizedException;
+use Magento\Framework\Model\ResourceModel\Db\TransactionManagerInterface;
+use Magento\Framework\Stdlib\DateTime\TimezoneInterface;
use Magento\ImportExport\Model\Import;
use Magento\ImportExport\Model\Import\ErrorProcessing\ProcessingErrorAggregatorInterface;
use Magento\ImportExport\Model\ResourceModel\CollectionByPagesIterator;
+use Magento\ImportExport\Model\ResourceModel\CollectionByPagesIteratorFactory;
+use Magento\ImportExport\Model\ResourceModel\Helper;
+use Magento\ImportExport\Model\ResourceModel\Import\Data;
use Magento\Store\Model\Store;
+use Magento\Store\Model\StoreManagerInterface;
/**
* Entity class which provide possibility to import product custom options
@@ -334,26 +345,40 @@ class Option extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity
private $optionTypeTitles;
/**
+ * @var TransactionManagerInterface|null
+ */
+ private $transactionManager;
+
+ /**
+ * Contains mapping between new assigned option ID and ID in DB
+ *
+ * @var array
+ */
+ private $optionNewIdExistingIdMap = [];
+
+ /**
+ * Contains mapping between new assigned option_type ID and ID in DB
+ *
* @var array
*/
- private $lastOptionTitle;
+ private $optionTypeNewIdExistingIdMap = [];
/**
- * @param \Magento\ImportExport\Model\ResourceModel\Import\Data $importData
+ * @param Data $importData
* @param ResourceConnection $resource
- * @param \Magento\ImportExport\Model\ResourceModel\Helper $resourceHelper
- * @param \Magento\Store\Model\StoreManagerInterface $_storeManager
- * @param \Magento\Catalog\Model\ProductFactory $productFactory
- * @param \Magento\Catalog\Model\ResourceModel\Product\Option\CollectionFactory $optionColFactory
- * @param \Magento\ImportExport\Model\ResourceModel\CollectionByPagesIteratorFactory $colIteratorFactory
+ * @param Helper $resourceHelper
+ * @param StoreManagerInterface $_storeManager
+ * @param ProductFactory $productFactory
+ * @param CollectionFactory $optionColFactory
+ * @param CollectionByPagesIteratorFactory $colIteratorFactory
* @param \Magento\Catalog\Helper\Data $catalogData
- * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
- * @param \Magento\Framework\Stdlib\DateTime\TimezoneInterface $dateTime
+ * @param ScopeConfigInterface $scopeConfig
+ * @param TimezoneInterface $dateTime
* @param ProcessingErrorAggregatorInterface $errorAggregator
* @param array $data
- * @param ProductOptionValueCollectionFactory $productOptionValueCollectionFactory
- * @throws \Magento\Framework\Exception\LocalizedException
- *
+ * @param ProductOptionValueCollectionFactory|null $productOptionValueCollectionFactory
+ * @param TransactionManagerInterface|null $transactionManager
+ * @throws LocalizedException
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
*/
public function __construct(
@@ -369,7 +394,8 @@ public function __construct(
\Magento\Framework\Stdlib\DateTime\TimezoneInterface $dateTime,
ProcessingErrorAggregatorInterface $errorAggregator,
array $data = [],
- ProductOptionValueCollectionFactory $productOptionValueCollectionFactory = null
+ ProductOptionValueCollectionFactory $productOptionValueCollectionFactory = null,
+ ?TransactionManagerInterface $transactionManager = null
) {
$this->_resource = $resource;
$this->_catalogData = $catalogData;
@@ -381,7 +407,9 @@ public function __construct(
$this->_scopeConfig = $scopeConfig;
$this->dateTime = $dateTime;
$this->productOptionValueCollectionFactory = $productOptionValueCollectionFactory
- ?: \Magento\Framework\App\ObjectManager::getInstance()->get(ProductOptionValueCollectionFactory::class);
+ ?: ObjectManager::getInstance()->get(ProductOptionValueCollectionFactory::class);
+ $this->transactionManager = $transactionManager
+ ?: ObjectManager::getInstance()->get(TransactionManagerInterface::class);
if (isset($data['connection'])) {
$this->_connection = $data['connection'];
@@ -798,10 +826,12 @@ protected function _findExistingOptionId(array $newOptionData, array $newOptionT
ksort($newOptionTitles);
$existingOptions = $this->getOldCustomOptions()[$productId];
foreach ($existingOptions as $optionId => $optionData) {
- if ($optionData['type'] == $newOptionData['type']
- && $optionData['titles'][Store::DEFAULT_STORE_ID] == $newOptionTitles[Store::DEFAULT_STORE_ID]
- ) {
- return $optionId;
+ if ($optionData['type'] == $newOptionData['type']) {
+ foreach ($newOptionTitles as $storeId => $title) {
+ if (isset($optionData['titles'][$storeId]) && $optionData['titles'][$storeId] === $title) {
+ return $optionId;
+ }
+ }
}
}
}
@@ -1249,13 +1279,16 @@ private function addFileOptions($result, $optionRow)
protected function _importData()
{
$this->_initProductsSku();
- $nextOptionId = $this->_resourceHelper->getNextAutoincrement($this->_tables['catalog_product_option']);
- $nextValueId = $this->_resourceHelper->getNextAutoincrement(
+ $nextOptionId = (int) $this->_resourceHelper->getNextAutoincrement($this->_tables['catalog_product_option']);
+ $nextValueId = (int) $this->_resourceHelper->getNextAutoincrement(
$this->_tables['catalog_product_option_type_value']
);
$prevOptionId = 0;
$optionId = null;
$valueId = null;
+ $this->optionNewIdExistingIdMap = [];
+ $this->optionTypeNewIdExistingIdMap = [];
+ $prevRowSku = null;
while ($bunch = $this->_dataSourceModel->getNextUniqueBunch($this->getIds())) {
$products = [];
$options = [];
@@ -1268,11 +1301,14 @@ protected function _importData()
$childCount = [];
$optionsToRemove = [];
foreach ($bunch as $rowNumber => $rowData) {
- if (isset($optionId, $valueId) &&
- (empty($rowData[PRODUCT::COL_STORE_VIEW_CODE]) || empty($rowData['custom_options']))
- ) {
- $nextOptionId = $optionId;
- $nextValueId = $valueId;
+ $rowSku = !empty($rowData[self::COLUMN_SKU])
+ ? mb_strtolower($rowData[self::COLUMN_SKU])
+ : '';
+
+ if ($rowSku !== $prevRowSku) {
+ $nextOptionId = $optionId ?? $nextOptionId;
+ $nextValueId = $valueId ?? $nextValueId;
+ $prevRowSku = $rowSku;
}
$optionId = $nextOptionId;
$valueId = $nextValueId;
@@ -1306,8 +1342,8 @@ protected function _importData()
$products,
$prices
);
- if ($optionData != null) {
- $options[] = $optionData;
+ if ($optionData) {
+ $options[$optionData['option_id']] = $optionData;
}
$this->_collectOptionTypeData(
$combinedData,
@@ -1321,15 +1357,6 @@ protected function _importData()
);
$this->_collectOptionTitle($combinedData, $prevOptionId, $titles);
- $this->checkOptionTitles(
- $options,
- $titles,
- $combinedData,
- $prevOptionId,
- $optionId,
- $products,
- $prices
- );
}
}
$this->removeExistingOptions($products, $optionsToRemove);
@@ -1338,76 +1365,20 @@ protected function _importData()
'prices' => $typePrices,
'titles' => $typeTitles,
];
- $this->setLastOptionTitle($titles);
//Save prepared custom options data.
$this->savePreparedCustomOptions(
$products,
- $options,
+ array_values($options),
$titles,
$prices,
$types
);
+ $this->optionNewIdExistingIdMap = $this->markNewIdsAsExisting($this->optionNewIdExistingIdMap);
+ $this->optionTypeNewIdExistingIdMap = $this->markNewIdsAsExisting($this->optionTypeNewIdExistingIdMap);
}
return true;
}
- /**
- * Check options titles.
- *
- * If products were split up between bunches,
- * this function will add needed option for option titles
- *
- * @param array $options
- * @param array $titles
- * @param array $combinedData
- * @param int $prevOptionId
- * @param int $optionId
- * @param array $products
- * @param array $prices
- * @return void
- */
- private function checkOptionTitles(
- array &$options,
- array &$titles,
- array $combinedData,
- int &$prevOptionId,
- int &$optionId,
- array $products,
- array $prices
- ) : void {
- $titlesCount = count($titles);
- if ($titlesCount > 0 && count($options) !== $titlesCount) {
- $combinedData[Product::COL_STORE_VIEW_CODE] = '';
- $optionId--;
- $option = $this->_collectOptionMainData(
- $combinedData,
- $prevOptionId,
- $optionId,
- $products,
- $prices
- );
- if ($option) {
- $options[] = $option;
- }
- }
- }
-
- /**
- * Setting last Custom Option Title
- * to use it later in _collectOptionTitle
- * to set correct title for default store view
- *
- * @param array $titles
- */
- private function setLastOptionTitle(array &$titles) : void
- {
- if (count($titles) > 0) {
- end($titles);
- $key = key($titles);
- $this->lastOptionTitle[$key] = $titles[$key];
- }
- }
-
/**
* Remove existing options.
*
@@ -1469,9 +1440,7 @@ protected function _collectOptionMainData(
$optionData = null;
if ($this->_rowIsMain) {
- $optionData = empty($rowData[Product::COL_STORE_VIEW_CODE])
- ? $this->_getOptionData($rowData, $this->_rowProductId, $nextOptionId, $this->_rowType)
- : '';
+ $optionData = $this->_getOptionData($rowData, $this->_rowProductId, $nextOptionId, $this->_rowType);
if (!$this->_isRowHasSpecificType($this->_rowType)
&& ($priceData = $this->_getPriceData($rowData, $nextOptionId, $this->_rowType))
@@ -1519,38 +1488,21 @@ protected function _collectOptionTypeData(
array &$childCount
) {
if ($this->_isRowHasSpecificType($this->_rowType) && $prevOptionId) {
- $specificTypeData = $this->_getSpecificTypeData($rowData, $nextValueId);
- //For default store
+ $specificTypeData = $this->_getSpecificTypeData([self::COLUMN_STORE => null] + $rowData, $nextValueId);
if ($specificTypeData) {
- $typeValues[$prevOptionId][] = $specificTypeData['value'];
+ $typeValues[$prevOptionId][$nextValueId] = $specificTypeData['value'];
+ $typeTitles[$nextValueId][$this->_rowStoreId] = $specificTypeData['title'];
- // ensure default title is set
- if (!isset($typeTitles[$nextValueId][Store::DEFAULT_STORE_ID])) {
- $typeTitles[$nextValueId][Store::DEFAULT_STORE_ID] = $specificTypeData['title'];
- }
-
- if ($specificTypeData['price']) {
+ if (!empty($specificTypeData['price'])) {
if ($this->_isPriceGlobal) {
$typePrices[$nextValueId][Store::DEFAULT_STORE_ID] = $specificTypeData['price'];
} else {
- // ensure default price is set
- if (!isset($typePrices[$nextValueId][Store::DEFAULT_STORE_ID])) {
- $typePrices[$nextValueId][Store::DEFAULT_STORE_ID] = $specificTypeData['price'];
- }
$typePrices[$nextValueId][$this->_rowStoreId] = $specificTypeData['price'];
}
}
$nextValueId++;
}
- $specificTypeData = $this->_getSpecificTypeData($rowData, 0, false);
- //For others stores
- if ($specificTypeData) {
- if (isset($specificTypeData['price'])) {
- $typePrices[$nextValueId][$this->_rowStoreId] = $specificTypeData['price'];
- }
- $typeTitles[$nextValueId++][$this->_rowStoreId] = $specificTypeData['title'];
- }
}
}
@@ -1564,16 +1516,7 @@ protected function _collectOptionTypeData(
*/
protected function _collectOptionTitle(array $rowData, $prevOptionId, array &$titles)
{
- $defaultStoreId = Store::DEFAULT_STORE_ID;
if (!empty($rowData[self::COLUMN_TITLE])) {
- if (!isset($titles[$prevOptionId][$defaultStoreId])) {
- if (isset($this->lastOptionTitle[$prevOptionId])) {
- $titles[$prevOptionId] = $this->lastOptionTitle[$prevOptionId];
- unset($this->lastOptionTitle);
- } else {
- $titles[$prevOptionId][$defaultStoreId] = $rowData[self::COLUMN_TITLE];
- }
- }
$titles[$prevOptionId][$this->_rowStoreId] = $rowData[self::COLUMN_TITLE];
}
}
@@ -1592,7 +1535,10 @@ protected function _compareOptionsWithExisting(array &$options, array &$titles,
{
foreach ($options as &$optionData) {
$newOptionId = $optionData['option_id'];
- if ($optionId = $this->_findExistingOptionId($optionData, $titles[$newOptionId])) {
+ $optionId = $this->optionNewIdExistingIdMap[$newOptionId]
+ ?? $this->_findExistingOptionId($optionData, $titles[$newOptionId]);
+ $this->optionNewIdExistingIdMap[$newOptionId] = $optionId ?: null;
+ if ($optionId && (int) $optionId !== (int) $newOptionId) {
$optionData['option_id'] = $optionId;
$titles[$optionId] = $titles[$newOptionId];
unset($titles[$newOptionId]);
@@ -1600,6 +1546,8 @@ protected function _compareOptionsWithExisting(array &$options, array &$titles,
foreach ($prices[$newOptionId] as $storeId => $priceStoreData) {
$prices[$newOptionId][$storeId]['option_id'] = $optionId;
}
+ $prices[$optionId] = $prices[$newOptionId];
+ unset($prices[$newOptionId]);
}
if (isset($typeValues[$newOptionId])) {
$typeValues[$optionId] = $typeValues[$newOptionId];
@@ -1627,8 +1575,10 @@ private function restoreOriginalOptionTypeIds(array &$typeValues, array &$typePr
foreach ($optionTypes as &$optionType) {
$optionTypeId = $optionType['option_type_id'];
foreach ($typeTitles[$optionTypeId] as $storeId => $optionTypeTitle) {
- $existingTypeId = $this->getExistingOptionTypeId($optionId, $storeId, $optionTypeTitle);
- if ($existingTypeId) {
+ $existingTypeId = $this->optionTypeNewIdExistingIdMap[$optionTypeId]
+ ?? $this->getExistingOptionTypeId($optionId, $storeId, $optionTypeTitle);
+ $this->optionTypeNewIdExistingIdMap[$optionTypeId] = $existingTypeId ?: null;
+ if ($existingTypeId && (int) $existingTypeId !== (int) $optionTypeId) {
$optionType['option_type_id'] = $existingTypeId;
$typeTitles[$existingTypeId] = $typeTitles[$optionTypeId];
unset($typeTitles[$optionTypeId]);
@@ -1812,7 +1762,7 @@ protected function _getPriceData(array $rowData, $optionId, $type)
) {
$priceData = [
'option_id' => $optionId,
- 'store_id' => $this->_rowStoreId,
+ 'store_id' => $this->_isPriceGlobal ? Store::DEFAULT_STORE_ID : $this->_rowStoreId,
'price_type' => 'fixed',
];
@@ -1920,7 +1870,12 @@ protected function _saveOptions(array $options)
protected function _saveTitles(array $titles)
{
$titleRows = [];
+ $existingOptionIds = array_flip(array_filter($this->optionNewIdExistingIdMap));
foreach ($titles as $optionId => $storeInfo) {
+ // Check that if it is a new option, then make sure a record for default store will be created
+ if (!isset($existingOptionIds[$optionId]) && count($storeInfo) > 0) {
+ $storeInfo = [Store::DEFAULT_STORE_ID => reset($storeInfo)] + $storeInfo;
+ }
//for use default
$uniqStoreInfo = array_unique($storeInfo);
foreach ($uniqStoreInfo as $storeId => $title) {
@@ -1948,7 +1903,12 @@ protected function _savePrices(array $prices)
{
if ($prices) {
$optionPriceRows = [];
- foreach ($prices as $storesData) {
+ $existingOptionIds = array_flip(array_filter($this->optionNewIdExistingIdMap));
+ foreach ($prices as $optionId => $storesData) {
+ // Check that if it is a new option, then make sure a record for default store will be created
+ if (!isset($existingOptionIds[$optionId]) && count($storesData) > 0) {
+ $storesData = [Store::DEFAULT_STORE_ID => reset($storesData)] + $storesData;
+ }
foreach ($storesData as $row) {
$optionPriceRows[] = $row;
}
@@ -1973,8 +1933,6 @@ protected function _savePrices(array $prices)
*/
protected function _saveSpecificTypeValues(array $typeValues)
{
- $this->_deleteSpecificTypeValues(array_keys($typeValues));
-
$typeValueRows = [];
foreach ($typeValues as $optionId => $optionInfo) {
foreach ($optionInfo as $row) {
@@ -1983,7 +1941,7 @@ protected function _saveSpecificTypeValues(array $typeValues)
}
}
if ($typeValueRows) {
- $this->_connection->insertMultiple($this->_tables['catalog_product_option_type_value'], $typeValueRows);
+ $this->_connection->insertOnDuplicate($this->_tables['catalog_product_option_type_value'], $typeValueRows);
}
return $this;
@@ -1998,7 +1956,12 @@ protected function _saveSpecificTypeValues(array $typeValues)
protected function _saveSpecificTypePrices(array $typePrices)
{
$optionTypePriceRows = [];
+ $existingOptionTypeIds = array_flip(array_filter($this->optionTypeNewIdExistingIdMap));
foreach ($typePrices as $optionTypeId => $storesData) {
+ // Check that if it is a new option value, then make sure a record for default store will be created
+ if (!isset($existingOptionTypeIds[$optionTypeId]) && count($storesData) > 0) {
+ $storesData = [Store::DEFAULT_STORE_ID => reset($storesData)] + $storesData;
+ }
foreach ($storesData as $storeId => $row) {
$row['option_type_id'] = $optionTypeId;
$row['store_id'] = $storeId;
@@ -2025,7 +1988,12 @@ protected function _saveSpecificTypePrices(array $typePrices)
protected function _saveSpecificTypeTitles(array $typeTitles)
{
$optionTypeTitleRows = [];
+ $existingOptionTypeIds = array_flip(array_filter($this->optionTypeNewIdExistingIdMap));
foreach ($typeTitles as $optionTypeId => $storesData) {
+ // Check that if it is a new option value, then make sure a record for default store will be created
+ if (!isset($existingOptionTypeIds[$optionTypeId]) && count($storesData) > 0) {
+ $storesData = [Store::DEFAULT_STORE_ID => reset($storesData)] + $storesData;
+ }
//for use default
$uniqStoresData = array_unique($storesData);
foreach ($uniqStoresData as $storeId => $title) {
@@ -2180,14 +2148,35 @@ private function savePreparedCustomOptions(
$this->_compareOptionsWithExisting($options, $titles, $prices, $types['values']);
$this->restoreOriginalOptionTypeIds($types['values'], $types['prices'], $types['titles']);
}
-
- $this->_saveOptions($options)
- ->_saveTitles($titles)
- ->_savePrices($prices)
- ->_saveSpecificTypeValues($types['values'])
- ->_saveSpecificTypePrices($types['prices'])
- ->_saveSpecificTypeTitles($types['titles'])
- ->_updateProducts($products);
+ $this->transactionManager->start($this->_connection);
+ try {
+ $this->_saveOptions($options)
+ ->_saveTitles($titles)
+ ->_savePrices($prices)
+ ->_saveSpecificTypeValues($types['values'])
+ ->_saveSpecificTypePrices($types['prices'])
+ ->_saveSpecificTypeTitles($types['titles'])
+ ->_updateProducts($products);
+ $this->transactionManager->commit();
+ } catch (\Throwable $exception) {
+ $this->transactionManager->rollBack();
+ throw $exception;
+ }
}
}
+
+ /**
+ * Mark new IDs as existing IDs
+ *
+ * @param array $idsMap
+ * @return array
+ */
+ private function markNewIdsAsExisting(array $idsMap): array
+ {
+ $newIds = array_keys(array_filter($idsMap, 'is_null'));
+ return array_replace(
+ $idsMap,
+ array_combine($newIds, $newIds)
+ );
+ }
}
diff --git a/app/code/Magento/CatalogImportExport/Test/Unit/Model/Import/Product/Type/OptionTest.php b/app/code/Magento/CatalogImportExport/Test/Unit/Model/Import/Product/Type/OptionTest.php
index d60a18057a42e..8268f52271299 100644
--- a/app/code/Magento/CatalogImportExport/Test/Unit/Model/Import/Product/Type/OptionTest.php
+++ b/app/code/Magento/CatalogImportExport/Test/Unit/Model/Import/Product/Type/OptionTest.php
@@ -17,6 +17,7 @@
use Magento\Framework\Data\Collection\AbstractDb;
use Magento\Framework\Data\Collection\Db\FetchStrategyInterface;
use Magento\Framework\Data\Collection\EntityFactory;
+use Magento\Framework\DB\Adapter\AdapterInterface;
use Magento\Framework\DB\Select;
use Magento\Framework\EntityManager\EntityMetadata;
use Magento\Framework\EntityManager\MetadataPool;
@@ -141,7 +142,7 @@ class OptionTest extends AbstractImportTestCase
*/
protected $_expectedOptions = [
[
- 'option_id' => 1,
+ 'option_id' => 2,
'sku' => '1-text',
'max_characters' => '100',
'file_extension' => null,
@@ -150,10 +151,10 @@ class OptionTest extends AbstractImportTestCase
'product_id' => 1,
'type' => 'field',
'is_require' => 1,
- 'sort_order' => 0
+ 'sort_order' => 1
],
[
- 'option_id' => 2,
+ 'option_id' => 3,
'sku' => '2-date',
'max_characters' => 0,
'file_extension' => null,
@@ -162,10 +163,10 @@ class OptionTest extends AbstractImportTestCase
'product_id' => 1,
'type' => 'date_time',
'is_require' => 1,
- 'sort_order' => 0
+ 'sort_order' => 2
],
[
- 'option_id' => 3,
+ 'option_id' => 4,
'sku' => '',
'max_characters' => 0,
'file_extension' => null,
@@ -174,10 +175,10 @@ class OptionTest extends AbstractImportTestCase
'product_id' => 1,
'type' => 'drop_down',
'is_require' => 1,
- 'sort_order' => 0
+ 'sort_order' => 3
],
[
- 'option_id' => 4,
+ 'option_id' => 5,
'sku' => '',
'max_characters' => 0,
'file_extension' => null,
@@ -186,7 +187,7 @@ class OptionTest extends AbstractImportTestCase
'product_id' => 1,
'type' => 'radio',
'is_require' => 1,
- 'sort_order' => 0
+ 'sort_order' => 4
]
];
@@ -297,7 +298,8 @@ protected function setUp(): void
ProcessingErrorAggregatorInterface::class
),
$this->_getModelDependencies($addExpectations, $deleteBehavior, $doubleOptions),
- $optionValueCollectionFactoryMock
+ $optionValueCollectionFactoryMock,
+ $this->createMock(\Magento\Framework\Model\ResourceModel\Db\TransactionManagerInterface::class),
];
$modelClassName = Option::class;
@@ -337,22 +339,20 @@ protected function _getModelDependencies(
bool $deleteBehavior = false,
bool $doubleOptions = false
): array {
- $connection = $this->getMockBuilder(\stdClass::class)->addMethods(
- ['delete', 'quoteInto', 'insertMultiple', 'insertOnDuplicate']
- )
+ $connection = $this->getMockBuilder(AdapterInterface::class)
->disableOriginalConstructor()
- ->getMock();
+ ->getMockForAbstractClass();
if ($addExpectations) {
if ($deleteBehavior) {
$connection->expects(
- $this->exactly(2)
+ $this->exactly(1)
)->method(
'quoteInto'
)->willReturnCallback(
[$this, 'stubQuoteInto']
);
$connection->expects(
- $this->exactly(2)
+ $this->exactly(1)
)->method(
'delete'
)->willReturnCallback(
@@ -360,14 +360,7 @@ protected function _getModelDependencies(
);
} else {
$connection->expects(
- $this->once()
- )->method(
- 'insertMultiple'
- )->willReturnCallback(
- [$this, 'verifyInsertMultiple']
- );
- $connection->expects(
- $this->exactly(6)
+ $this->exactly(7)
)->method(
'insertOnDuplicate'
)->willReturnCallback(
@@ -618,6 +611,12 @@ public function verifyInsertMultiple(string $table, array $data): void
public function verifyInsertOnDuplicate(string $table, array $data, array $fields = []): void
{
switch ($table) {
+ case $this->_tables['catalog_product_option']:
+ $this->assertEquals($this->_expectedOptions, $data);
+ break;
+ case $this->_tables['catalog_product_option_type_value']:
+ $this->assertEquals($this->_expectedTypeValues, $data);
+ break;
case $this->_tables['catalog_product_option_title']:
$this->assertEquals($this->_expectedTitles, $data);
$this->assertEquals(['title'], $fields);
diff --git a/app/code/Magento/CatalogImportExport/Test/Unit/Model/Import/Product/Type/_files/product_with_custom_options.csv b/app/code/Magento/CatalogImportExport/Test/Unit/Model/Import/Product/Type/_files/product_with_custom_options.csv
index 92cad357803c7..02cc55ef3de69 100644
--- a/app/code/Magento/CatalogImportExport/Test/Unit/Model/Import/Product/Type/_files/product_with_custom_options.csv
+++ b/app/code/Magento/CatalogImportExport/Test/Unit/Model/Import/Product/Type/_files/product_with_custom_options.csv
@@ -1,2 +1,2 @@
-sku,website_code,store_view_code,attribute_set_code,product_type,name,description,short_description,weight,product_online,visibility,product_websites,categories,price,special_price,special_price_from_date,special_price_to_date,tax_class_name,url_key,meta_title,meta_keywords,meta_description,base_image,base_image_label,small_image,small_image_label,thumbnail_image,thumbnail_image_label,additional_images,additional_image_labels,configurable_variation_labels,configurable_variations,bundle_price_type,bundle_sku_type,bundle_weight_type,bundle_values,downloadble_samples,downloadble_links,associated_skus,related_skus,crosssell_skus,upsell_skus,custom_options,additional_attributes,manage_stock,is_in_stock,qty,out_of_stock_qty,is_qty_decimal,allow_backorders,min_cart_qty,max_cart_qty,notify_on_stock_below,qty_increments,enable_qty_increments,is_decimal_divided,new_from_date,new_to_date,gift_message_available,created_at,updated_at,custom_design,custom_design_from,custom_design_to,custom_layout_update,page_layout,product_options_container,msrp_price,msrp_display_actual_price_type,map_enabled
-simple,base,,Default,simple,New Product,,,,,,,,10,,,,,new-product,,,,,,,,,,,,,,,,,,,,,,,,"name=Test Field Title,type=field,required=1;sku=1-text,price=0,price_type=fixed|name=Test Date and Time Title,type=date_time,required=1,price=2,option_title=custom option 1,sku=2-date|name=Test Select,type=drop_down,required=1,price=3,option_title=Option 1,sku=3-1-select|name=Test Select,type=drop_down,required=1,price=3,option_title=Option 2,sku=3-2-select|name=Test Radio,type=radio,required=1,price=3,option_title=Option 1,sku=4-1-radio|name=Test Radio,type=radio,required=1,price=3,option_title=Option 2,sku=4-2-radio",,,,,,,,,,,,,,,,,,,,,,,,Block after Info Column,,,
+sku,website_code,store_view_code,attribute_set_code,product_type,name,description,short_description,weight,product_online,visibility,product_websites,categories,price,special_price,special_price_from_date,special_price_to_date,tax_class_name,url_key,meta_title,meta_keywords,meta_description,base_image,base_image_label,small_image,small_image_label,thumbnail_image,thumbnail_image_label,additional_images,additional_image_labels,configurable_variation_labels,configurable_variations,bundle_price_type,bundle_sku_type,bundle_weight_type,bundle_values,downloadble_samples,downloadble_links,associated_skus,related_skus,crosssell_skus,upsell_skus,custom_options,additional_attributes,manage_stock,is_in_stock,qty,out_of_stock_qty,is_qty_decimal,allow_backorders,min_cart_qty,max_cart_qty,notify_on_stock_below,qty_increments,enable_qty_increments,is_decimal_divided,new_from_date,new_to_date,gift_message_available,created_at,updated_at,custom_design,custom_design_from,custom_design_to,custom_layout_update,page_layout,product_options_container,msrp_price,msrp_display_actual_price_type,map_enabled
+simple,base,,Default,simple,New Product,,,,,,,,10,,,,,new-product,,,,,,,,,,,,,,,,,,,,,,,,"name=Test Field Title,type=field,required=1;sku=1-text,price=0,price_type=fixed,max_characters=100|name=Test Date and Time Title,type=date_time,required=1,price=2,option_title=custom option 1,sku=2-date|name=Test Select,type=drop_down,required=1,price=3,option_title=Option 1,sku=3-1-select|name=Test Select,type=drop_down,required=1,price=3,option_title=Option 2,sku=3-2-select|name=Test Radio,type=radio,required=1,price=3,option_title=Option 1,sku=4-1-radio|name=Test Radio,type=radio,required=1,price=3,option_title=Option 2,sku=4-2-radio",,,,,,,,,,,,,,,,,,,,,,,,Block after Info Column,,,
diff --git a/app/code/Magento/CatalogImportExport/composer.json b/app/code/Magento/CatalogImportExport/composer.json
index dac8624086df0..41b2b5f72ce7b 100644
--- a/app/code/Magento/CatalogImportExport/composer.json
+++ b/app/code/Magento/CatalogImportExport/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"ext-ctype": "*",
"magento/framework": "*",
"magento/module-catalog": "*",
diff --git a/app/code/Magento/CatalogInventory/Observer/ReindexQuoteInventoryObserver.php b/app/code/Magento/CatalogInventory/Observer/ReindexQuoteInventoryObserver.php
index e22ec886474c4..a2a981009437f 100644
--- a/app/code/Magento/CatalogInventory/Observer/ReindexQuoteInventoryObserver.php
+++ b/app/code/Magento/CatalogInventory/Observer/ReindexQuoteInventoryObserver.php
@@ -4,41 +4,58 @@
* See COPYING.txt for license details.
*/
+declare(strict_types=1);
+
namespace Magento\CatalogInventory\Observer;
+use Magento\CatalogInventory\Model\Indexer\Stock\Processor as StockProcessor;
+use Magento\Catalog\Model\Indexer\Product\Price\Processor as PriceProcessor;
use Magento\Framework\Event\Observer as EventObserver;
use Magento\Framework\Event\ObserverInterface;
+use Magento\Framework\Exception\LocalizedException;
+use Psr\Log\LoggerInterface;
+/**
+ * Responsible for re-indexing stock items after a successful order.
+ */
class ReindexQuoteInventoryObserver implements ObserverInterface
{
/**
- * @var \Magento\CatalogInventory\Model\Indexer\Stock\Processor
+ * @var StockProcessor
*/
- protected $stockIndexerProcessor;
+ private StockProcessor $stockIndexerProcessor;
/**
- * @var \Magento\Catalog\Model\Indexer\Product\Price\Processor
+ * @var PriceProcessor
*/
- protected $priceIndexer;
+ private PriceProcessor $priceIndexer;
/**
- * @var \Magento\CatalogInventory\Observer\ItemsForReindex
+ * @var ItemsForReindex
*/
- protected $itemsForReindex;
+ private ItemsForReindex $itemsForReindex;
/**
- * @param \Magento\CatalogInventory\Model\Indexer\Stock\Processor $stockIndexerProcessor
- * @param \Magento\Catalog\Model\Indexer\Product\Price\Processor $priceIndexer
+ * @var LoggerInterface
+ */
+ private LoggerInterface $logger;
+
+ /**
+ * @param StockProcessor $stockIndexerProcessor
+ * @param PriceProcessor $priceIndexer
* @param ItemsForReindex $itemsForReindex
+ * @param LoggerInterface $logger
*/
public function __construct(
- \Magento\CatalogInventory\Model\Indexer\Stock\Processor $stockIndexerProcessor,
- \Magento\Catalog\Model\Indexer\Product\Price\Processor $priceIndexer,
- ItemsForReindex $itemsForReindex
+ StockProcessor $stockIndexerProcessor,
+ PriceProcessor $priceIndexer,
+ ItemsForReindex $itemsForReindex,
+ LoggerInterface $logger
) {
$this->stockIndexerProcessor = $stockIndexerProcessor;
$this->priceIndexer = $priceIndexer;
$this->itemsForReindex = $itemsForReindex;
+ $this->logger = $logger;
}
/**
@@ -47,37 +64,43 @@ public function __construct(
* @param EventObserver $observer
* @return void
*/
- public function execute(EventObserver $observer)
+ public function execute(EventObserver $observer): void
{
- // Reindex quote ids
- $quote = $observer->getEvent()->getQuote();
- $productIds = [];
- foreach ($quote->getAllItems() as $item) {
- $productIds[$item->getProductId()] = $item->getProductId();
- $children = $item->getChildrenItems();
- if ($children) {
- foreach ($children as $childItem) {
- $productIds[$childItem->getProductId()] = $childItem->getProductId();
+ try {
+ // Reindex quote ids
+ $quote = $observer->getEvent()->getData('quote');
+ $productIds = [];
+ foreach ($quote->getAllItems() as $item) {
+ $productIds[$item->getData('product_id')] = $item->getData('product_id');
+ $children = $item->getData('children_items');
+ if ($children) {
+ foreach ($children as $childItem) {
+ $productIds[$childItem->getData('product_id')] = $childItem->getData('product_id');
+ }
}
}
- }
- if ($productIds) {
- $this->stockIndexerProcessor->reindexList($productIds);
- }
+ if ($productIds) {
+ $this->stockIndexerProcessor->reindexList($productIds);
+ }
- // Reindex previously remembered items
- $productIds = [];
- foreach ($this->itemsForReindex->getItems() as $item) {
- $item->save();
- $productIds[] = $item->getProductId();
- }
+ // Reindex previously remembered items
+ $productIds = [];
+ foreach ($this->itemsForReindex->getItems() as $item) {
+ $item->save();
+ $productIds[] = $item->getData('product_id');
+ }
- if (!empty($productIds)) {
- $this->priceIndexer->reindexList($productIds);
- }
+ if (!empty($productIds)) {
+ $this->priceIndexer->reindexList($productIds);
+ }
- $this->itemsForReindex->clear();
- // Clear list of remembered items - we don't need it anymore
+ $this->itemsForReindex->clear();
+ // Clear list of remembered items - we don't need it anymore
+ } catch (LocalizedException $exception) {
+ $this->logger->error('Error while re-indexing order items: ' . $exception->getLogMessage());
+ $this->stockIndexerProcessor->markIndexerAsInvalid();
+ $this->priceIndexer->markIndexerAsInvalid();
+ }
}
}
diff --git a/app/code/Magento/CatalogInventory/Test/Mftf/Test/StoreFrontAddOutOfStockProductToShoppingCartTest.xml b/app/code/Magento/CatalogInventory/Test/Mftf/Test/StoreFrontAddOutOfStockProductToShoppingCartTest.xml
new file mode 100644
index 0000000000000..951ca2b0ee80b
--- /dev/null
+++ b/app/code/Magento/CatalogInventory/Test/Mftf/Test/StoreFrontAddOutOfStockProductToShoppingCartTest.xml
@@ -0,0 +1,70 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/CatalogInventory/Test/Unit/Observer/ReindexQuoteInventoryObserverTest.php b/app/code/Magento/CatalogInventory/Test/Unit/Observer/ReindexQuoteInventoryObserverTest.php
new file mode 100644
index 0000000000000..97156eb4f1784
--- /dev/null
+++ b/app/code/Magento/CatalogInventory/Test/Unit/Observer/ReindexQuoteInventoryObserverTest.php
@@ -0,0 +1,193 @@
+stockIndexerProcessor = $this->createMock(StockProcessor::class);
+ $this->priceIndexer = $this->createMock(PriceProcessor::class);
+ $this->itemsForReindex = $this->createMock(ItemsForReindex::class);
+ $this->logger = $this->createMock(LoggerInterface::class);
+ $this->observedObject = $this->createMock(Observer::class);
+ $this->event = $this->createMock(Event::class);
+ $this->quote = $this->createMock(Quote::class);
+ $this->quoteItem = $this->createMock(Item::class);
+
+ $this->sut = new ReindexQuoteInventoryObserver(
+ $this->stockIndexerProcessor,
+ $this->priceIndexer,
+ $this->itemsForReindex,
+ $this->logger
+ );
+ }
+
+ /**
+ * Test execute should re-index quote stock items.
+ *
+ * @test
+ *
+ * @return void
+ */
+ public function execute(): void
+ {
+ $this->observedObject->expects($this->once())
+ ->method('getEvent')
+ ->willReturn($this->event);
+
+ $this->event->expects($this->once())
+ ->method('getData')
+ ->with('quote')
+ ->willReturn($this->quote);
+
+ $this->quote->expects($this->once())
+ ->method('getAllItems')
+ ->willReturn([$this->quoteItem]);
+
+ $this->quoteItem->expects($this->exactly(6))
+ ->method('getData')
+ ->withConsecutive(
+ ['product_id'],
+ ['product_id'],
+ ['children_items'],
+ ['product_id'],
+ ['product_id'],
+ ['product_id']
+ )->willReturnOnConsecutiveCalls(1, 1, [$this->quoteItem], 1, 1, 1);
+
+ $this->stockIndexerProcessor->expects($this->once())
+ ->method('reindexList')
+ ->with([1 => 1]);
+
+ $this->itemsForReindex->expects($this->once())
+ ->method('getItems')
+ ->willReturn([$this->quoteItem]);
+
+ $this->priceIndexer->expects($this->once())
+ ->method('reindexList')
+ ->with([1]);
+
+ $this->itemsForReindex->expects($this->once())
+ ->method('clear');
+
+ $this->sut->execute($this->observedObject);
+ }
+
+ /**
+ * Test execute should log error on exception.
+ *
+ * @test
+ *
+ * @return void
+ */
+ public function executeShouldLogOnException(): void
+ {
+ $this->observedObject->expects($this->once())
+ ->method('getEvent')
+ ->willReturn($this->event);
+
+ $this->event->expects($this->once())
+ ->method('getData')
+ ->with('quote')
+ ->willReturn($this->quote);
+
+ $this->quote->expects($this->once())
+ ->method('getAllItems')
+ ->willReturn([$this->quoteItem]);
+
+ $this->quoteItem->expects($this->exactly(3))
+ ->method('getData')
+ ->withConsecutive(
+ ['product_id'],
+ ['product_id'],
+ ['children_items']
+ )->willReturnOnConsecutiveCalls(1, 1, []);
+
+ $this->stockIndexerProcessor->expects($this->once())
+ ->method('reindexList')
+ ->with([1 => 1])
+ ->willThrowException(new LocalizedException(__('error')));
+
+ $this->logger->expects($this->once())
+ ->method('error')
+ ->with('Error while re-indexing order items: error');
+
+ $this->stockIndexerProcessor->expects($this->once())
+ ->method('markIndexerAsInvalid');
+
+ $this->priceIndexer->expects($this->once())
+ ->method('markIndexerAsInvalid');
+
+ $this->sut->execute($this->observedObject);
+ }
+}
diff --git a/app/code/Magento/CatalogInventory/composer.json b/app/code/Magento/CatalogInventory/composer.json
index 893de329628fa..7ea00923ac715 100644
--- a/app/code/Magento/CatalogInventory/composer.json
+++ b/app/code/Magento/CatalogInventory/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-catalog": "*",
"magento/module-config": "*",
diff --git a/app/code/Magento/CatalogInventoryGraphQl/composer.json b/app/code/Magento/CatalogInventoryGraphQl/composer.json
index 38685524d5346..58d567bc0706e 100644
--- a/app/code/Magento/CatalogInventoryGraphQl/composer.json
+++ b/app/code/Magento/CatalogInventoryGraphQl/composer.json
@@ -3,7 +3,7 @@
"description": "N/A",
"type": "magento2-module",
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-store": "*",
"magento/module-catalog": "*",
diff --git a/app/code/Magento/CatalogRule/Setup/Patch/Schema/CleanUpProductPriceReplicaTable.php b/app/code/Magento/CatalogRule/Setup/Patch/Schema/CleanUpProductPriceReplicaTable.php
new file mode 100644
index 0000000000000..476c7fe277db1
--- /dev/null
+++ b/app/code/Magento/CatalogRule/Setup/Patch/Schema/CleanUpProductPriceReplicaTable.php
@@ -0,0 +1,69 @@
+schemaSetup = $schemaSetup;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function apply(): void
+ {
+ $connection = $this->schemaSetup->startSetup();
+ $connection = $this->schemaSetup->getConnection();
+
+ // There was a bug which caused the catalogrule_product_price_replica
+ // table to become unnecessarily large. The bug causing the growth has
+ // been resolved. This schema patch cleans up the damage done by that
+ // bug on existing websites. Deleting all entries from the replica table
+ // is safe.
+ // See https://github.com/magento/magento2/issues/31752 for details.
+
+ $tableName = $connection->getTableName('catalogrule_product_price_replica');
+
+ if ($connection->isTableExists($tableName)) {
+ $connection->truncateTable($tableName);
+ }
+
+ $connection->endSetup();
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public static function getDependencies(): array
+ {
+ return [];
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getAliases(): array
+ {
+ return [];
+ }
+}
diff --git a/app/code/Magento/CatalogRule/composer.json b/app/code/Magento/CatalogRule/composer.json
index 531a12ac017ed..dc9c51dade87f 100644
--- a/app/code/Magento/CatalogRule/composer.json
+++ b/app/code/Magento/CatalogRule/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-backend": "*",
"magento/module-catalog": "*",
diff --git a/app/code/Magento/CatalogRuleConfigurable/composer.json b/app/code/Magento/CatalogRuleConfigurable/composer.json
index 68da972ae94f9..8b6569ba9fec4 100644
--- a/app/code/Magento/CatalogRuleConfigurable/composer.json
+++ b/app/code/Magento/CatalogRuleConfigurable/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/magento-composer-installer": "*",
"magento/module-catalog": "*",
diff --git a/app/code/Magento/CatalogRuleGraphQl/composer.json b/app/code/Magento/CatalogRuleGraphQl/composer.json
index 2c8c3ef20c96a..c22ba277d57d9 100644
--- a/app/code/Magento/CatalogRuleGraphQl/composer.json
+++ b/app/code/Magento/CatalogRuleGraphQl/composer.json
@@ -3,7 +3,7 @@
"description": "N/A",
"type": "magento2-module",
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*"
},
"suggest": {
diff --git a/app/code/Magento/CatalogSearch/composer.json b/app/code/Magento/CatalogSearch/composer.json
index 465d7daeebe18..7ccdb99d2c9d1 100644
--- a/app/code/Magento/CatalogSearch/composer.json
+++ b/app/code/Magento/CatalogSearch/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-backend": "*",
"magento/module-catalog": "*",
diff --git a/app/code/Magento/CatalogUrlRewrite/composer.json b/app/code/Magento/CatalogUrlRewrite/composer.json
index ce409e2186faa..6df0042d40648 100644
--- a/app/code/Magento/CatalogUrlRewrite/composer.json
+++ b/app/code/Magento/CatalogUrlRewrite/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-backend": "*",
"magento/module-catalog": "*",
diff --git a/app/code/Magento/CatalogUrlRewriteGraphQl/composer.json b/app/code/Magento/CatalogUrlRewriteGraphQl/composer.json
index 025234af6f865..c3917a517a68d 100644
--- a/app/code/Magento/CatalogUrlRewriteGraphQl/composer.json
+++ b/app/code/Magento/CatalogUrlRewriteGraphQl/composer.json
@@ -3,7 +3,7 @@
"description": "N/A",
"type": "magento2-module",
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/module-store": "*",
"magento/module-catalog": "*",
"magento/module-catalog-graph-ql": "*",
diff --git a/app/code/Magento/CatalogWidget/Model/Rule/Condition/Product.php b/app/code/Magento/CatalogWidget/Model/Rule/Condition/Product.php
index 2ac5e5d1aeff8..a8cafb034c0b0 100644
--- a/app/code/Magento/CatalogWidget/Model/Rule/Condition/Product.php
+++ b/app/code/Magento/CatalogWidget/Model/Rule/Condition/Product.php
@@ -9,9 +9,9 @@
*/
namespace Magento\CatalogWidget\Model\Rule\Condition;
-use Magento\Catalog\Api\Data\ProductInterface;
use Magento\Catalog\Model\ProductCategoryList;
use Magento\Catalog\Model\ResourceModel\Product\Collection;
+use Magento\Framework\DB\Select;
use Magento\Store\Model\Store;
/**
@@ -201,32 +201,63 @@ protected function addNotGlobalAttribute(
\Magento\Catalog\Model\ResourceModel\Eav\Attribute $attribute,
Collection $collection
) {
- $storeId = $this->storeManager->getStore()->getId();
- $values = $collection->getAllAttributeValues($attribute);
- $validEntities = [];
- if ($values) {
- foreach ($values as $entityId => $storeValues) {
- if (isset($storeValues[$storeId])) {
- if ($this->validateAttribute($storeValues[$storeId])) {
- $validEntities[] = $entityId;
- }
- } else {
- if (isset($storeValues[Store::DEFAULT_STORE_ID]) &&
- $this->validateAttribute($storeValues[Store::DEFAULT_STORE_ID])
- ) {
- $validEntities[] = $entityId;
- }
- }
- }
+ $connection = $this->_productResource->getConnection();
+ switch ($attribute->getBackendType()) {
+ case 'decimal':
+ case 'datetime':
+ case 'int':
+ case 'varchar':
+ case 'text':
+ $aliasDefault = 'at_' . $attribute->getAttributeCode() . '_default';
+ $aliasStore = 'at_' . $attribute->getAttributeCode();
+ $collection->addAttributeToSelect($attribute->getAttributeCode(), 'left');
+ break;
+ default:
+ $aliasDefault = 'at_' . sha1($this->getId()) . $attribute->getAttributeCode() . '_default';
+ $aliasStore = 'at_' . sha1($this->getId()) . $attribute->getAttributeCode();
+
+ $storeDefaultId = $connection->getIfNullSql(
+ $aliasDefault . '.store_id',
+ Store::DEFAULT_STORE_ID
+ );
+ $storeId = $connection->getIfNullSql(
+ $aliasStore . '.store_id',
+ $this->storeManager->getStore()->getId()
+ );
+ $linkField = $attribute->getEntity()->getLinkField();
+
+ $collection->getSelect()->joinLeft(
+ [$aliasDefault => $collection->getTable($attribute->getBackendTable())],
+ "($aliasDefault.$linkField = e.$linkField) AND ($aliasDefault.store_id = $storeDefaultId)" .
+ " AND ($aliasDefault.attribute_id = {$attribute->getId()})",
+ []
+ );
+ $collection->getSelect()->joinLeft(
+ [$aliasStore => $collection->getTable($attribute->getBackendTable())],
+ "($aliasStore.$linkField = e.$linkField) AND ($aliasStore.store_id = $storeId)" .
+ " AND ($aliasStore.attribute_id = {$attribute->getId()})",
+ []
+ );
}
- $this->setOperator('()');
- $this->unsetData('value_parsed');
- if ($validEntities) {
- $this->setData('value', implode(',', $validEntities));
+
+ $fromPart = $collection->getSelect()->getPart(Select::FROM);
+ if (isset($fromPart[$aliasStore]['joinType'])
+ && isset($fromPart[$aliasDefault]['joinType'])
+ ) {
+ $conditionCheck = $connection->quoteIdentifier($aliasStore . '.value_id') . " > 0";
+ $conditionTrue = $connection->quoteIdentifier($aliasStore . '.value');
+ $conditionFalse = $connection->quoteIdentifier($aliasDefault . '.value');
+ $joinedAttribute = $collection->getSelect()->getConnection()->getCheckSql(
+ $conditionCheck,
+ $conditionTrue,
+ $conditionFalse
+ );
} else {
- $this->unsetData('value');
+ $joinedAttribute = $aliasStore . '.' . 'value';
}
+ $this->joinedAttributes[$attribute->getAttributeCode()] = $joinedAttribute;
+
return $this;
}
diff --git a/app/code/Magento/CatalogWidget/Test/Unit/Model/Rule/Condition/ProductTest.php b/app/code/Magento/CatalogWidget/Test/Unit/Model/Rule/Condition/ProductTest.php
index d683912d09fb8..49b4c1a7978ad 100644
--- a/app/code/Magento/CatalogWidget/Test/Unit/Model/Rule/Condition/ProductTest.php
+++ b/app/code/Magento/CatalogWidget/Test/Unit/Model/Rule/Condition/ProductTest.php
@@ -189,7 +189,12 @@ public function getMappedSqlFieldPriceDataProvider(): array
[
false,
false,
- 'e.entity_id'
+ 'at_price.value'
+ ],
+ [
+ false,
+ true,
+ 'price_index.min_price'
],
];
}
@@ -248,7 +253,7 @@ public function getBindArgumentValueDataProvider(): array
1 => 2
]
],
- new \Zend_Db_Expr('1, 3')
+ '2'
],
[
[
diff --git a/app/code/Magento/CatalogWidget/composer.json b/app/code/Magento/CatalogWidget/composer.json
index 33c5e3b3ba3ee..b54b27474787b 100644
--- a/app/code/Magento/CatalogWidget/composer.json
+++ b/app/code/Magento/CatalogWidget/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-backend": "*",
"magento/module-catalog": "*",
diff --git a/app/code/Magento/Checkout/Test/Mftf/ActionGroup/AssertMiniCartEmptyActionGroup.xml b/app/code/Magento/Checkout/Test/Mftf/ActionGroup/AssertMiniCartEmptyActionGroup.xml
index ca891a1dc263b..2119e5c43f7bb 100644
--- a/app/code/Magento/Checkout/Test/Mftf/ActionGroup/AssertMiniCartEmptyActionGroup.xml
+++ b/app/code/Magento/Checkout/Test/Mftf/ActionGroup/AssertMiniCartEmptyActionGroup.xml
@@ -16,6 +16,6 @@
-
+
diff --git a/app/code/Magento/Checkout/Test/Mftf/Test/AdminCheckZeroSubtotalOrderIsInProcessingStatusTest.xml b/app/code/Magento/Checkout/Test/Mftf/Test/AdminCheckZeroSubtotalOrderIsInProcessingStatusTest.xml
index 6b43077873fcb..12a524d2d6ad8 100644
--- a/app/code/Magento/Checkout/Test/Mftf/Test/AdminCheckZeroSubtotalOrderIsInProcessingStatusTest.xml
+++ b/app/code/Magento/Checkout/Test/Mftf/Test/AdminCheckZeroSubtotalOrderIsInProcessingStatusTest.xml
@@ -11,11 +11,12 @@
-
+
+
@@ -37,7 +38,6 @@
-
diff --git a/app/code/Magento/Checkout/Test/Mftf/Test/AdminCheckZeroSubtotalOrderWithCustomStatus.xml b/app/code/Magento/Checkout/Test/Mftf/Test/AdminCheckZeroSubtotalOrderWithCustomStatus.xml
new file mode 100644
index 0000000000000..f08640d895b6b
--- /dev/null
+++ b/app/code/Magento/Checkout/Test/Mftf/Test/AdminCheckZeroSubtotalOrderWithCustomStatus.xml
@@ -0,0 +1,128 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 100
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Checkout/Test/Mftf/Test/AdminCheckZeroSubtotalOrderWithGeneratedInvoiceTest.xml b/app/code/Magento/Checkout/Test/Mftf/Test/AdminCheckZeroSubtotalOrderWithGeneratedInvoiceTest.xml
new file mode 100644
index 0000000000000..81de8664f98e2
--- /dev/null
+++ b/app/code/Magento/Checkout/Test/Mftf/Test/AdminCheckZeroSubtotalOrderWithGeneratedInvoiceTest.xml
@@ -0,0 +1,94 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 100
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontValidateItemQtyShouldNotBeNegativeValueWhenPressKeyboardDownKeyTest.xml b/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontValidateItemQtyShouldNotBeNegativeValueWhenPressKeyboardDownKeyTest.xml
new file mode 100644
index 0000000000000..b61e533d42dfd
--- /dev/null
+++ b/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontValidateItemQtyShouldNotBeNegativeValueWhenPressKeyboardDownKeyTest.xml
@@ -0,0 +1,59 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ $grabProductQtyInMinicart
+ 0
+
+
+
+
+
+
+
+
+ $grabProductQtyInCart
+ 0
+
+
+
diff --git a/app/code/Magento/Checkout/composer.json b/app/code/Magento/Checkout/composer.json
index f277184d8986b..4d24d27e676ee 100644
--- a/app/code/Magento/Checkout/composer.json
+++ b/app/code/Magento/Checkout/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-captcha": "*",
"magento/module-catalog": "*",
diff --git a/app/code/Magento/CheckoutAgreements/composer.json b/app/code/Magento/CheckoutAgreements/composer.json
index 753bef25e3e64..44d0e86bd78f2 100644
--- a/app/code/Magento/CheckoutAgreements/composer.json
+++ b/app/code/Magento/CheckoutAgreements/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-backend": "*",
"magento/module-checkout": "*",
diff --git a/app/code/Magento/CheckoutAgreementsGraphQl/composer.json b/app/code/Magento/CheckoutAgreementsGraphQl/composer.json
index de6bc855e7847..c0c1853eb4324 100644
--- a/app/code/Magento/CheckoutAgreementsGraphQl/composer.json
+++ b/app/code/Magento/CheckoutAgreementsGraphQl/composer.json
@@ -3,7 +3,7 @@
"description": "N/A",
"type": "magento2-module",
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-store": "*",
"magento/module-checkout-agreements": "*"
diff --git a/app/code/Magento/Cms/Test/Mftf/Section/CmsPagesPageActionsSection.xml b/app/code/Magento/Cms/Test/Mftf/Section/CmsPagesPageActionsSection.xml
index f3389072f1776..fa2f45d83cc37 100644
--- a/app/code/Magento/Cms/Test/Mftf/Section/CmsPagesPageActionsSection.xml
+++ b/app/code/Magento/Cms/Test/Mftf/Section/CmsPagesPageActionsSection.xml
@@ -34,5 +34,7 @@
+
+
diff --git a/app/code/Magento/Cms/composer.json b/app/code/Magento/Cms/composer.json
index b3b2ba31db37b..aa972d0a711a7 100644
--- a/app/code/Magento/Cms/composer.json
+++ b/app/code/Magento/Cms/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-backend": "*",
"magento/module-catalog": "*",
diff --git a/app/code/Magento/CmsGraphQl/composer.json b/app/code/Magento/CmsGraphQl/composer.json
index b2550344299fa..07b7261823d92 100644
--- a/app/code/Magento/CmsGraphQl/composer.json
+++ b/app/code/Magento/CmsGraphQl/composer.json
@@ -3,7 +3,7 @@
"description": "N/A",
"type": "magento2-module",
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-cms": "*",
"magento/module-widget": "*",
diff --git a/app/code/Magento/CmsUrlRewrite/composer.json b/app/code/Magento/CmsUrlRewrite/composer.json
index 8fb9bbfff22e2..0521f77f9bb7f 100644
--- a/app/code/Magento/CmsUrlRewrite/composer.json
+++ b/app/code/Magento/CmsUrlRewrite/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-cms": "*",
"magento/module-store": "*",
diff --git a/app/code/Magento/CmsUrlRewriteGraphQl/composer.json b/app/code/Magento/CmsUrlRewriteGraphQl/composer.json
index 70a598d26d574..2687ad032e000 100644
--- a/app/code/Magento/CmsUrlRewriteGraphQl/composer.json
+++ b/app/code/Magento/CmsUrlRewriteGraphQl/composer.json
@@ -3,7 +3,7 @@
"description": "N/A",
"type": "magento2-module",
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-cms": "*",
"magento/module-store": "*",
diff --git a/app/code/Magento/CompareListGraphQl/composer.json b/app/code/Magento/CompareListGraphQl/composer.json
index e8fb5d588852e..9193e30061619 100644
--- a/app/code/Magento/CompareListGraphQl/composer.json
+++ b/app/code/Magento/CompareListGraphQl/composer.json
@@ -3,7 +3,7 @@
"description": "N/A",
"type": "magento2-module",
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-catalog": "*",
"magento/module-customer": "*"
diff --git a/app/code/Magento/Config/composer.json b/app/code/Magento/Config/composer.json
index 61100e6336c27..8ad286bd667b5 100644
--- a/app/code/Magento/Config/composer.json
+++ b/app/code/Magento/Config/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-backend": "*",
"magento/module-cron": "*",
diff --git a/app/code/Magento/ConfigurableImportExport/composer.json b/app/code/Magento/ConfigurableImportExport/composer.json
index 98205def6a799..f56cfd6299ad2 100644
--- a/app/code/Magento/ConfigurableImportExport/composer.json
+++ b/app/code/Magento/ConfigurableImportExport/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-catalog": "*",
"magento/module-catalog-import-export": "*",
diff --git a/app/code/Magento/ConfigurableProduct/composer.json b/app/code/Magento/ConfigurableProduct/composer.json
index 67b1ad2b2ed33..8a9e4e50ad194 100644
--- a/app/code/Magento/ConfigurableProduct/composer.json
+++ b/app/code/Magento/ConfigurableProduct/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-backend": "*",
"magento/module-catalog": "*",
diff --git a/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/variations/variations.js b/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/variations/variations.js
index 6e82fd42692fc..6b00402809500 100644
--- a/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/variations/variations.js
+++ b/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/variations/variations.js
@@ -130,9 +130,14 @@ define([
* @return {String|Number|Array}
*/
getProductValue: function (name) {
- name = name.split('/').join('][');
+ var value;
- return $('[name="product[' + name + ']"]:enabled:not(.ignore-validate)', this.productForm).val();
+ name = name.split('/').join('][');
+ value = $('[name="product[' + name + ']"]:enabled:not(.ignore-validate)', this.productForm).val();
+ if (value === undefined) {
+ value = this.source.get('data.product.' + name);
+ }
+ return value;
},
/**
diff --git a/app/code/Magento/ConfigurableProductGraphQl/composer.json b/app/code/Magento/ConfigurableProductGraphQl/composer.json
index b839227511d88..43c297de656c5 100644
--- a/app/code/Magento/ConfigurableProductGraphQl/composer.json
+++ b/app/code/Magento/ConfigurableProductGraphQl/composer.json
@@ -3,7 +3,7 @@
"description": "N/A",
"type": "magento2-module",
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/module-catalog": "*",
"magento/module-configurable-product": "*",
"magento/module-graph-ql": "*",
diff --git a/app/code/Magento/ConfigurableProductSales/composer.json b/app/code/Magento/ConfigurableProductSales/composer.json
index 55b2e78bd24d2..909c2ff967f41 100644
--- a/app/code/Magento/ConfigurableProductSales/composer.json
+++ b/app/code/Magento/ConfigurableProductSales/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-catalog": "*",
"magento/module-sales": "*",
diff --git a/app/code/Magento/Contact/composer.json b/app/code/Magento/Contact/composer.json
index 00ea8f865928d..68b5bb4c9a6da 100644
--- a/app/code/Magento/Contact/composer.json
+++ b/app/code/Magento/Contact/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-cms": "*",
"magento/module-config": "*",
diff --git a/app/code/Magento/Cookie/Test/Mftf/Section/AdminDefaultCookieSettingsSection.xml b/app/code/Magento/Cookie/Test/Mftf/Section/AdminDefaultCookieSettingsSection.xml
index 977db4a8bbf74..0e51354583d6b 100644
--- a/app/code/Magento/Cookie/Test/Mftf/Section/AdminDefaultCookieSettingsSection.xml
+++ b/app/code/Magento/Cookie/Test/Mftf/Section/AdminDefaultCookieSettingsSection.xml
@@ -11,5 +11,7 @@
diff --git a/app/code/Magento/Cookie/composer.json b/app/code/Magento/Cookie/composer.json
index 6a5752792f7fb..d2f1a87594a3c 100644
--- a/app/code/Magento/Cookie/composer.json
+++ b/app/code/Magento/Cookie/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-store": "*"
},
diff --git a/app/code/Magento/Cron/composer.json b/app/code/Magento/Cron/composer.json
index 0468a95b457c0..1696588920015 100644
--- a/app/code/Magento/Cron/composer.json
+++ b/app/code/Magento/Cron/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-store": "*"
},
diff --git a/app/code/Magento/Csp/composer.json b/app/code/Magento/Csp/composer.json
index 2079a30d92068..f2e69e7a7ec63 100644
--- a/app/code/Magento/Csp/composer.json
+++ b/app/code/Magento/Csp/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-store": "*"
},
diff --git a/app/code/Magento/CurrencySymbol/composer.json b/app/code/Magento/CurrencySymbol/composer.json
index 4f6854cbee185..8c2325b39d508 100644
--- a/app/code/Magento/CurrencySymbol/composer.json
+++ b/app/code/Magento/CurrencySymbol/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-backend": "*",
"magento/module-config": "*",
diff --git a/app/code/Magento/Customer/Block/Address/Renderer/DefaultRenderer.php b/app/code/Magento/Customer/Block/Address/Renderer/DefaultRenderer.php
index 703d9b2d0154a..2e5051cc86010 100644
--- a/app/code/Magento/Customer/Block/Address/Renderer/DefaultRenderer.php
+++ b/app/code/Magento/Customer/Block/Address/Renderer/DefaultRenderer.php
@@ -189,6 +189,9 @@ public function renderArray($addressAttributes, $format = null)
$data[$key] = $v;
}
}
+ if (in_array($attributeCode, ['prefix','suffix'])) {
+ $value = __($value);
+ }
$data[$attributeCode] = $value;
}
}
diff --git a/app/code/Magento/Customer/Helper/View.php b/app/code/Magento/Customer/Helper/View.php
index dcd4ae01940a6..560abd335d2fa 100644
--- a/app/code/Magento/Customer/Helper/View.php
+++ b/app/code/Magento/Customer/Helper/View.php
@@ -51,7 +51,7 @@ public function getCustomerName(CustomerInterface $customerData)
$name = '';
$prefixMetadata = $this->_customerMetadataService->getAttributeMetadata('prefix');
if ($prefixMetadata->isVisible() && $customerData->getPrefix()) {
- $name .= $customerData->getPrefix() . ' ';
+ $name .= __($customerData->getPrefix()) . ' ';
}
$name .= $customerData->getFirstname();
@@ -65,7 +65,7 @@ public function getCustomerName(CustomerInterface $customerData)
$suffixMetadata = $this->_customerMetadataService->getAttributeMetadata('suffix');
if ($suffixMetadata->isVisible() && $customerData->getSuffix()) {
- $name .= ' ' . $customerData->getSuffix();
+ $name .= ' ' . __($customerData->getSuffix());
}
return $this->escaper->escapeHtml($name);
diff --git a/app/code/Magento/Customer/Model/Address/AbstractAddress.php b/app/code/Magento/Customer/Model/Address/AbstractAddress.php
index 0ec87066d67c4..f710ef6846fd6 100644
--- a/app/code/Magento/Customer/Model/Address/AbstractAddress.php
+++ b/app/code/Magento/Customer/Model/Address/AbstractAddress.php
@@ -197,7 +197,7 @@ public function getName()
{
$name = '';
if ($this->_eavConfig->getAttribute('customer_address', 'prefix')->getIsVisible() && $this->getPrefix()) {
- $name .= $this->getPrefix() . ' ';
+ $name .= __($this->getPrefix()) . ' ';
}
$name .= $this->getFirstname();
$middleName = $this->_eavConfig->getAttribute('customer_address', 'middlename');
@@ -206,7 +206,7 @@ public function getName()
}
$name .= ' ' . $this->getLastname();
if ($this->_eavConfig->getAttribute('customer_address', 'suffix')->getIsVisible() && $this->getSuffix()) {
- $name .= ' ' . $this->getSuffix();
+ $name .= ' ' . __($this->getSuffix());
}
return $name;
}
diff --git a/app/code/Magento/Customer/Model/Options.php b/app/code/Magento/Customer/Model/Options.php
index ec995a12e2bc2..c407cd616b6df 100644
--- a/app/code/Magento/Customer/Model/Options.php
+++ b/app/code/Magento/Customer/Model/Options.php
@@ -100,7 +100,7 @@ private function prepareNamePrefixSuffixOptions($options, $isOptional = false)
$options = explode(';', trim($options));
foreach ($options as $value) {
- $result[] = $this->escaper->escapeHtml(trim($value)) ?: ' ';
+ $result[] = $this->escaper->escapeHtml(trim(__($value))) ?: ' ';
}
if ($isOptional && trim(current($options))) {
diff --git a/app/code/Magento/Customer/Test/Mftf/ActionGroup/StorefrontVerifyCustomerDefaultCookieExpiryDateActionGroup.xml b/app/code/Magento/Customer/Test/Mftf/ActionGroup/StorefrontVerifyCustomerDefaultCookieExpiryDateActionGroup.xml
new file mode 100644
index 0000000000000..f5c40e5261414
--- /dev/null
+++ b/app/code/Magento/Customer/Test/Mftf/ActionGroup/StorefrontVerifyCustomerDefaultCookieExpiryDateActionGroup.xml
@@ -0,0 +1,47 @@
+
+
+
+
+
+
+ Verify a customer's cookies expiry date on browser's local storage in storefront
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{$grabCookieForMagentoDataIds['expiry']}}
+ {{$generateExpireDate}}
+
+
+ {{$grabCookieForMagentoCacheSessionId['expiry']}}
+ {{$generateExpireDate}}
+
+
+ {{$grabCookieForMagentoCacheStorage['expiry']}}
+ {{$generateExpireDate}}
+
+
+
diff --git a/app/code/Magento/Customer/Test/Mftf/Test/StorefrontRetainLocalCacheStorageTest.xml b/app/code/Magento/Customer/Test/Mftf/Test/StorefrontRetainLocalCacheStorageTest.xml
new file mode 100644
index 0000000000000..7661b1222fb57
--- /dev/null
+++ b/app/code/Magento/Customer/Test/Mftf/Test/StorefrontRetainLocalCacheStorageTest.xml
@@ -0,0 +1,85 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Customer/composer.json b/app/code/Magento/Customer/composer.json
index 2d76da56bff7d..ef2047644759b 100644
--- a/app/code/Magento/Customer/composer.json
+++ b/app/code/Magento/Customer/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-authorization": "*",
"magento/module-backend": "*",
diff --git a/app/code/Magento/Customer/view/frontend/templates/widget/name.phtml b/app/code/Magento/Customer/view/frontend/templates/widget/name.phtml
index 00c1f124bd263..c725665547721 100644
--- a/app/code/Magento/Customer/view/frontend/templates/widget/name.phtml
+++ b/app/code/Magento/Customer/view/frontend/templates/widget/name.phtml
@@ -24,31 +24,40 @@ $prefix = $block->showPrefix();
$middle = $block->showMiddlename();
$suffix = $block->showSuffix();
?>
-getNoWrap()) : ?>
+getNoWrap()): ?>
-
= $block->escapeHtml(__('Name')) ?>
+
+ = $block->escapeHtml(__('Name')) ?>
+
-
+
-
= $block->escapeHtml($block->getStoreLabel('prefix')) ?>
+
+ = $block->escapeHtml($block->getStoreLabel('prefix')) ?>
+
- getPrefixOptions() === false) : ?>
+ getPrefixOptions() === false): ?>
isPrefixRequired() ? ' data-validate="{required:true}"' : '' ?>>
-
+ class="input-text
+ = $block->escapeHtmlAttr($block->getAttributeValidationClass('prefix')) ?>"
+ = $block->isPrefixRequired() ? ' data-validate="{required:true}"' : '' ?>>
+
isPrefixRequired() ? ' data-validate="{required:true}"' : '' ?> >
- getPrefixOptions() as $_option) : ?>
- getObject()->getPrefix() == $_option) : ?> selected="selected">
+ class="= $block->escapeHtmlAttr($block->getAttributeValidationClass('prefix')) ?>"
+ = $block->isPrefixRequired() ? ' data-validate="{required:true}"' : '' ?> >
+ getPrefixOptions() as $_option): ?>
+ getObject()->getPrefix() == $_option): ?>
+ selected="selected">
= $block->escapeHtml(__($_option)) ?>
@@ -58,55 +67,76 @@ $suffix = $block->showSuffix();
-
= $block->escapeHtml($block->getStoreLabel('firstname')) ?>
+
+ = $block->escapeHtml($block->getStoreLabel('firstname')) ?>
+
getAttributeValidationClass('firstname') == 'required-entry') ? ' data-validate="{required:true}"' : '' ?>>
+ class="input-text
+ = $block->escapeHtmlAttr($block->getAttributeValidationClass('firstname')) ?>"
+ = ($block->getAttributeValidationClass('firstname') == 'required-entry') ? '
+ data-validate="{required:true}"' : '' ?>>
-
+
isMiddlenameRequired(); ?>
-
= $block->escapeHtml($block->getStoreLabel('middlename')) ?>
+
+ = $block->escapeHtml($block->getStoreLabel('middlename')) ?>
+
>
+ class="input-text
+ = $block->escapeHtmlAttr($block->getAttributeValidationClass('middlename')) ?>"
+ = $isMiddlenameRequired ? ' data-validate="{required:true}"' : '' ?>>
-
= $block->escapeHtml($block->getStoreLabel('lastname')) ?>
+
+ = $block->escapeHtml($block->getStoreLabel('lastname')) ?>
+
getAttributeValidationClass('lastname') == 'required-entry') ? ' data-validate="{required:true}"' : '' ?>>
+ class="input-text
+ = $block->escapeHtmlAttr($block->getAttributeValidationClass('lastname')) ?>"
+ = ($block->getAttributeValidationClass('lastname') == 'required-entry') ? '
+ data-validate="{required:true}"' : '' ?>>
-
+
-
= $block->escapeHtml($block->getStoreLabel('suffix')) ?>
+
+ = $block->escapeHtml($block->getStoreLabel('suffix')) ?>
+
- getSuffixOptions() === false) : ?>
+ getSuffixOptions() === false): ?>
isSuffixRequired() ? ' data-validate="{required:true}"' : '' ?>>
-
+ class="input-text
+ = $block->escapeHtmlAttr($block->getAttributeValidationClass('suffix')) ?>"
+ = $block->isSuffixRequired() ? ' data-validate="{required:true}"' : '' ?>>
+
isSuffixRequired() ? ' data-validate="{required:true}"' : '' ?>>
- getSuffixOptions() as $_option) : ?>
- getObject()->getSuffix() == $_option) : ?> selected="selected">
+ class="= $block->escapeHtmlAttr($block->getAttributeValidationClass('suffix')) ?>"
+ = $block->isSuffixRequired() ? ' data-validate="{required:true}"' : '' ?>>
+ getSuffixOptions() as $_option): ?>
+ getObject()->getSuffix() == $_option): ?>
+ selected="selected">
= $block->escapeHtml(__($_option)) ?>
@@ -116,7 +146,7 @@ $suffix = $block->showSuffix();
- getNoWrap()) : ?>
+ getNoWrap()): ?>
diff --git a/app/code/Magento/CustomerAnalytics/composer.json b/app/code/Magento/CustomerAnalytics/composer.json
index 396c7d4ca3364..d02051d5148cd 100644
--- a/app/code/Magento/CustomerAnalytics/composer.json
+++ b/app/code/Magento/CustomerAnalytics/composer.json
@@ -2,7 +2,7 @@
"name": "magento/module-customer-analytics",
"description": "N/A",
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-customer": "*",
"magento/module-analytics": "*"
diff --git a/app/code/Magento/CustomerDownloadableGraphQl/composer.json b/app/code/Magento/CustomerDownloadableGraphQl/composer.json
index f33d05e18568a..99e2f94da4081 100644
--- a/app/code/Magento/CustomerDownloadableGraphQl/composer.json
+++ b/app/code/Magento/CustomerDownloadableGraphQl/composer.json
@@ -3,7 +3,7 @@
"description": "N/A",
"type": "magento2-module",
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/module-downloadable-graph-ql": "*",
"magento/module-graph-ql": "*",
"magento/framework": "*"
diff --git a/app/code/Magento/CustomerGraphQl/composer.json b/app/code/Magento/CustomerGraphQl/composer.json
index 30d94c20acc98..5967d2e9f8ac7 100644
--- a/app/code/Magento/CustomerGraphQl/composer.json
+++ b/app/code/Magento/CustomerGraphQl/composer.json
@@ -3,7 +3,7 @@
"description": "N/A",
"type": "magento2-module",
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/module-authorization": "*",
"magento/module-customer": "*",
"magento/module-eav": "*",
diff --git a/app/code/Magento/CustomerImportExport/composer.json b/app/code/Magento/CustomerImportExport/composer.json
index 2f5c74020e602..09eb16c1d8a01 100644
--- a/app/code/Magento/CustomerImportExport/composer.json
+++ b/app/code/Magento/CustomerImportExport/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-backend": "*",
"magento/module-customer": "*",
diff --git a/app/code/Magento/Deploy/Package/Processor/PreProcessor/Less.php b/app/code/Magento/Deploy/Package/Processor/PreProcessor/Less.php
index f4339b40f5be8..29283c1c26914 100644
--- a/app/code/Magento/Deploy/Package/Processor/PreProcessor/Less.php
+++ b/app/code/Magento/Deploy/Package/Processor/PreProcessor/Less.php
@@ -100,7 +100,7 @@ public function process(Package $package, array $options)
if ($packageFile && $packageFile->getOrigPackage() === $package) {
continue;
}
- $deployFileName = $this->fileNameResolver->resolve($file->getFileName());
+ $deployFileName = $this->fileNameResolver->resolve($file->getFileName() ?? '');
if ($deployFileName !== $file->getFileName()) {
if ($this->hasOverrides($file, $package)) {
$file = clone $file;
diff --git a/app/code/Magento/Deploy/Service/DeployStaticFile.php b/app/code/Magento/Deploy/Service/DeployStaticFile.php
index a0cd91bfe684f..594cb6120be94 100644
--- a/app/code/Magento/Deploy/Service/DeployStaticFile.php
+++ b/app/code/Magento/Deploy/Service/DeployStaticFile.php
@@ -6,6 +6,8 @@
namespace Magento\Deploy\Service;
use Magento\Framework\App\Filesystem\DirectoryList;
+use Magento\Framework\Exception\FileSystemException;
+use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\Filesystem;
use Magento\Framework\Filesystem\File\WriteInterface;
use Magento\Framework\View\Asset\Minification;
@@ -80,11 +82,14 @@ public function __construct(
}
/**
+ * Deploy static file
+ *
* @param string $fileName
* @param array $params ['area' =>, 'theme' =>, 'locale' =>, 'module' =>]
* @return string
+ * @throws LocalizedException
*/
- public function deployFile($fileName, array $params = [])
+ public function deployFile(string $fileName, array $params = []): string
{
$params['publish'] = true;
$asset = $this->assetRepo->createAsset($this->resolveFile($fileName), $params);
@@ -95,10 +100,14 @@ public function deployFile($fileName, array $params = [])
}
/**
+ * Delete static file
+ *
* @param string $path
* @return void
+ * @throws FileSystemException
+ * phpcs:disable
*/
- public function deleteFile($path)
+ public function deleteFile(string $path)
{
if ($this->pubStaticDir->isExist($path)) {
$absolutePath = $this->pubStaticDir->getAbsolutePath($path);
@@ -120,8 +129,10 @@ public function deleteFile($path)
* @param string $fileName
* @param string $filePath
* @return string|false
+ * @throws FileSystemException
+ * phpcs:enable
*/
- public function readFile($fileName, $filePath)
+ public function readFile(string $fileName, string $filePath): bool|string
{
$fileName = $this->minification->addMinifiedSign($fileName);
$relativePath = $filePath . DIRECTORY_SEPARATOR . $this->resolveFile($fileName);
@@ -133,11 +144,13 @@ public function readFile($fileName, $filePath)
}
/**
+ * Open static file
+ *
* @param string $fileName
* @param string $filePath
* @return WriteInterface
*/
- public function openFile($fileName, $filePath)
+ public function openFile(string $fileName, string $filePath): WriteInterface
{
$relativePath = $filePath . DIRECTORY_SEPARATOR . $this->resolveFile($fileName);
return $this->pubStaticDir->openFile($relativePath, 'w+');
@@ -150,8 +163,9 @@ public function openFile($fileName, $filePath)
* @param string $filePath
* @param string $content
* @return int The number of bytes that were written.
+ * @throws FileSystemException
*/
- public function writeFile($fileName, $filePath, $content)
+ public function writeFile(string $fileName, string $filePath, string $content): int
{
$relativePath = $filePath . DIRECTORY_SEPARATOR . $this->resolveFile($fileName);
return $this->pubStaticDir->writeFile($relativePath, $content);
@@ -164,8 +178,9 @@ public function writeFile($fileName, $filePath, $content)
* @param string $sourcePath
* @param string $targetPath
* @return bool
+ * @throws FileSystemException
*/
- public function copyFile($fileName, $sourcePath, $targetPath)
+ public function copyFile(string $fileName, string $sourcePath, string $targetPath): bool
{
$fileName = $this->minification->addMinifiedSign($fileName);
return $this->pubStaticDir->copyFile(
@@ -179,9 +194,10 @@ public function copyFile($fileName, $sourcePath, $targetPath)
*
* @param string $fileName
* @param string $filePath
- * @return string
+ * @return bool|string
+ * @throws FileSystemException
*/
- public function readTmpFile($fileName, $filePath)
+ public function readTmpFile(string $fileName, string $filePath): bool|string
{
$relativePath = $filePath . DIRECTORY_SEPARATOR . $fileName;
return $this->tmpDir->isFile($relativePath) ? $this->tmpDir->readFile($relativePath) : false;
@@ -194,10 +210,12 @@ public function readTmpFile($fileName, $filePath)
* @param string $filePath
* @param string $content
* @return int The number of bytes that were written.
+ * @throws FileSystemException
*/
- public function writeTmpFile($fileName, $filePath, $content)
+ public function writeTmpFile(string $fileName, string $filePath, string $content): int
{
$relativePath = $filePath . DIRECTORY_SEPARATOR . $this->resolveFile($fileName);
+
return $this->tmpDir->writeFile($relativePath, $content);
}
@@ -207,14 +225,12 @@ public function writeTmpFile($fileName, $filePath, $content)
* @param string $fileName
* @return string
*/
- private function resolveFile($fileName)
+ private function resolveFile(string $fileName): string
{
- $compiledFile = str_replace(
+ return str_replace(
Repository::FILE_ID_SEPARATOR,
'/',
$this->fileNameResolver->resolve($fileName)
);
-
- return $compiledFile;
}
}
diff --git a/app/code/Magento/Deploy/Test/Unit/Service/DeployTranslationsDictionaryTest.php b/app/code/Magento/Deploy/Test/Unit/Service/DeployTranslationsDictionaryTest.php
index 9890de3458a9c..a875ce357f31c 100644
--- a/app/code/Magento/Deploy/Test/Unit/Service/DeployTranslationsDictionaryTest.php
+++ b/app/code/Magento/Deploy/Test/Unit/Service/DeployTranslationsDictionaryTest.php
@@ -76,6 +76,8 @@ function ($checkDictionary, $params) use ($dictionary, $area, $theme, $locale) {
$this->assertEquals($area, $params['area']);
$this->assertEquals($theme, $params['theme']);
$this->assertEquals($locale, $params['locale']);
+
+ return $dictionary;
}
);
diff --git a/app/code/Magento/Deploy/composer.json b/app/code/Magento/Deploy/composer.json
index e965b6222e375..c90a64299e8e5 100644
--- a/app/code/Magento/Deploy/composer.json
+++ b/app/code/Magento/Deploy/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-config": "*",
"magento/module-require-js": "*",
diff --git a/app/code/Magento/Developer/composer.json b/app/code/Magento/Developer/composer.json
index 49b9d324f0d11..3f75c5bef7d44 100644
--- a/app/code/Magento/Developer/composer.json
+++ b/app/code/Magento/Developer/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-config": "*",
"magento/module-store": "*"
diff --git a/app/code/Magento/Dhl/composer.json b/app/code/Magento/Dhl/composer.json
index 9596f789be5fc..26b8546164965 100644
--- a/app/code/Magento/Dhl/composer.json
+++ b/app/code/Magento/Dhl/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"lib-libxml": "*",
"magento/framework": "*",
"magento/module-backend": "*",
diff --git a/app/code/Magento/Directory/Model/Currency/Import/FixerIoApiLayer.php b/app/code/Magento/Directory/Model/Currency/Import/FixerIoApiLayer.php
new file mode 100644
index 0000000000000..439ab4599cd97
--- /dev/null
+++ b/app/code/Magento/Directory/Model/Currency/Import/FixerIoApiLayer.php
@@ -0,0 +1,261 @@
+currencyFactory = $currencyFactory;
+ $this->scopeConfig = $scopeConfig;
+ $this->httpClientFactory = $httpClientFactory;
+ }
+
+ /**
+ * Import rates
+ *
+ * @return $this
+ */
+ public function importRates()
+ {
+ $data = $this->fetchRates();
+ $this->saveRates($data);
+ return $this;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function fetchRates()
+ {
+ $data = [];
+ $currencies = $this->getCurrencyCodes();
+ $defaultCurrencies = $this->getDefaultCurrencyCodes();
+
+ foreach ($defaultCurrencies as $currencyFrom) {
+ if (!isset($data[$currencyFrom])) {
+ $data[$currencyFrom] = [];
+ }
+ $data = $this->convertBatch($data, $currencyFrom, $currencies);
+ ksort($data[$currencyFrom]);
+ }
+ return $data;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function getMessages()
+ {
+ return $this->messages;
+ }
+
+ /**
+ * Return currencies convert rates in batch mode
+ *
+ * @param array $data
+ * @param string $currencyFrom
+ * @param array $currenciesTo
+ * @return array
+ */
+ private function convertBatch(array $data, string $currencyFrom, array $currenciesTo): array
+ {
+ $accessKey = $this->scopeConfig->getValue('currency/fixerio_apilayer/api_key', ScopeInterface::SCOPE_STORE);
+ if (empty($accessKey)) {
+ $this->messages[] = __('No API Key was specified or an invalid API Key was specified.');
+ $data[$currencyFrom] = $this->makeEmptyResponse($currenciesTo);
+ return $data;
+ }
+
+ $currenciesStr = implode(',', $currenciesTo);
+ $url = str_replace(
+ ['{{ACCESS_KEY}}', '{{CURRENCY_FROM}}', '{{CURRENCY_TO}}'],
+ [$accessKey, $currencyFrom, $currenciesStr],
+ self::CURRENCY_CONVERTER_HOST . self::CURRENCY_CONVERTER_URL_PATH
+ );
+ // phpcs:ignore Magento2.Functions.DiscouragedFunction
+ set_time_limit(0);
+ try {
+ $response = $this->getServiceResponse($url);
+ } finally {
+ ini_restore('max_execution_time');
+ }
+
+ if (!$this->validateResponse($response, $currencyFrom)) {
+ $data[$currencyFrom] = $this->makeEmptyResponse($currenciesTo);
+ return $data;
+ }
+
+ foreach ($currenciesTo as $currencyTo) {
+ if ($currencyFrom == $currencyTo) {
+ $data[$currencyFrom][$currencyTo] = 1;
+ } else {
+ if (empty($response['rates'][$currencyTo])) {
+ $message = 'We can\'t retrieve a rate from %1 for %2.';
+ $this->messages[] = __($message, self::CURRENCY_CONVERTER_HOST, $currencyTo);
+ $data[$currencyFrom][$currencyTo] = null;
+ } else {
+ $data[$currencyFrom][$currencyTo] = (double)$response['rates'][$currencyTo];
+ }
+ }
+ }
+ return $data;
+ }
+
+ /**
+ * Saving currency rates
+ *
+ * @param array $rates
+ * @return \Magento\Directory\Model\Currency\Import\FixerIoApiLayer
+ */
+ private function saveRates(array $rates)
+ {
+ foreach ($rates as $currencyCode => $currencyRates) {
+ $this->currencyFactory->create()->setId($currencyCode)->setRates($currencyRates)->save();
+ }
+ return $this;
+ }
+
+ /**
+ * Get apilayer.com service response
+ *
+ * @param string $url
+ * @param int $retry
+ * @return array
+ */
+ private function getServiceResponse(string $url, int $retry = 0): array
+ {
+ /** @var LaminasClient $httpClient */
+ $httpClient = $this->httpClientFactory->create();
+ $response = [];
+
+ try {
+ $httpClient->setUri($url);
+ $httpClient->setOptions(
+ [
+ 'timeout' => $this->scopeConfig->getValue(
+ 'currency/fixerio_apilayer/timeout',
+ ScopeInterface::SCOPE_STORE
+ ),
+ ]
+ );
+ $httpClient->setMethod(Request::METHOD_GET);
+ $jsonResponse = $httpClient->send()->getBody();
+
+ $response = json_decode($jsonResponse, true);
+ } catch (Exception $e) {
+ if ($retry == 0) {
+ $response = $this->getServiceResponse($url, 1);
+ }
+ }
+ return $response;
+ }
+
+ /**
+ * Creates array for provided currencies with empty rates.
+ *
+ * @param array $currenciesTo
+ * @return array
+ */
+ private function makeEmptyResponse(array $currenciesTo): array
+ {
+ return array_fill_keys($currenciesTo, null);
+ }
+
+ /**
+ * Validates rates response.
+ *
+ * @param array $response
+ * @param string $baseCurrency
+ * @return bool
+ */
+ private function validateResponse(array $response, string $baseCurrency): bool
+ {
+ if ($response['success']) {
+ return true;
+ }
+
+ $errorCodes = [
+ 101 => __('No API Key was specified or an invalid API Key was specified.'),
+ 102 => __('The account this API request is coming from is inactive.'),
+ 105 => __('The "%1" is not allowed as base currency for your subscription plan.', $baseCurrency),
+ 201 => __('An invalid base currency has been entered.'),
+ ];
+
+ $this->messages[] = $errorCodes[$response['error']['code']] ?? __('Currency rates can\'t be retrieved.');
+
+ return false;
+ }
+
+ /**
+ * Retrieve currency codes
+ *
+ * @return array
+ */
+ private function getCurrencyCodes()
+ {
+ return $this->currencyFactory->create()->getConfigAllowCurrencies();
+ }
+
+ /**
+ * Retrieve default currency codes
+ *
+ * @return array
+ */
+ private function getDefaultCurrencyCodes()
+ {
+ return $this->currencyFactory->create()->getConfigBaseCurrencies();
+ }
+}
diff --git a/app/code/Magento/Directory/Test/Mftf/Test/CustomCurrencySymbolWithSpaceTest.xml b/app/code/Magento/Directory/Test/Mftf/Test/CustomCurrencySymbolWithSpaceTest.xml
index 50fb0fe48ac4c..62cf00e7735b6 100644
--- a/app/code/Magento/Directory/Test/Mftf/Test/CustomCurrencySymbolWithSpaceTest.xml
+++ b/app/code/Magento/Directory/Test/Mftf/Test/CustomCurrencySymbolWithSpaceTest.xml
@@ -18,6 +18,9 @@
+
+
+
diff --git a/app/code/Magento/Directory/Test/Unit/Model/Currency/Import/FixerIoApiLayerTest.php b/app/code/Magento/Directory/Test/Unit/Model/Currency/Import/FixerIoApiLayerTest.php
new file mode 100644
index 0000000000000..8081cc3ddfefc
--- /dev/null
+++ b/app/code/Magento/Directory/Test/Unit/Model/Currency/Import/FixerIoApiLayerTest.php
@@ -0,0 +1,125 @@
+currencyFactory = $this->getMockBuilder(CurrencyFactory::class)
+ ->disableOriginalConstructor()
+ ->setMethods(['create'])
+ ->getMock();
+ $this->httpClientFactory = $this->getMockBuilder(LaminasClientFactory::class)
+ ->disableOriginalConstructor()
+ ->setMethods(['create'])
+ ->getMock();
+ $this->scopeConfig = $this->getMockBuilder(ScopeConfigInterface::class)
+ ->disableOriginalConstructor()
+ ->setMethods([])
+ ->getMockForAbstractClass();
+
+ $this->model = new FixerIoApiLayer($this->currencyFactory, $this->scopeConfig, $this->httpClientFactory);
+ }
+
+ /**
+ * Test Fetch Rates
+ *
+ * @return void
+ */
+ public function testFetchRates(): void
+ {
+ $currencyFromList = ['USD'];
+ $currencyToList = ['EUR', 'UAH'];
+ $responseBody = '{"success":"true","base":"USD","date":"2015-10-07","rates":{"EUR":0.9022}}';
+ $expectedCurrencyRateList = ['USD' => ['EUR' => 0.9022, 'UAH' => null]];
+ $message = "We can't retrieve a rate from "
+ . "https://api.apilayer.com for UAH.";
+
+ $this->scopeConfig->method('getValue')
+ ->withConsecutive(
+ ['currency/fixerio_apilayer/api_key', 'store'],
+ ['currency/fixerio_apilayer/timeout', 'store']
+ )
+ ->willReturnOnConsecutiveCalls('api_key', 100);
+
+ /** @var Currency|MockObject $currency */
+ $currency = $this->getMockBuilder(Currency::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ /** @var LaminasClient|MockObject $httpClient */
+ $httpClient = $this->getMockBuilder(LaminasClient::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ /** @var DataObject|MockObject $currencyMock */
+ $httpResponse = $this->getMockBuilder(DataObject::class)
+ ->disableOriginalConstructor()
+ ->setMethods(['getBody'])
+ ->getMock();
+
+ $this->currencyFactory->method('create')
+ ->willReturn($currency);
+ $currency->method('getConfigBaseCurrencies')
+ ->willReturn($currencyFromList);
+ $currency->method('getConfigAllowCurrencies')
+ ->willReturn($currencyToList);
+
+ $this->httpClientFactory->method('create')
+ ->willReturn($httpClient);
+ $httpClient->method('setUri')
+ ->willReturnSelf();
+ $httpClient->method('setOptions')
+ ->willReturnSelf();
+ $httpClient->method('setMethod')
+ ->willReturnSelf();
+ $httpClient->method('send')
+ ->willReturn($httpResponse);
+ $httpResponse->method('getBody')
+ ->willReturn($responseBody);
+
+ self::assertEquals($expectedCurrencyRateList, $this->model->fetchRates());
+
+ $messages = $this->model->getMessages();
+ self::assertNotEmpty($messages);
+ self::assertIsArray($messages);
+ self::assertEquals($message, (string)$messages[0]);
+ }
+}
diff --git a/app/code/Magento/Directory/composer.json b/app/code/Magento/Directory/composer.json
index c3973b9cee0c9..a2538a6378d5b 100644
--- a/app/code/Magento/Directory/composer.json
+++ b/app/code/Magento/Directory/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"lib-libxml": "*",
"magento/framework": "*",
"magento/module-backend": "*",
diff --git a/app/code/Magento/Directory/etc/adminhtml/system.xml b/app/code/Magento/Directory/etc/adminhtml/system.xml
index 8b67f07e98202..e38bc5cec0caf 100644
--- a/app/code/Magento/Directory/etc/adminhtml/system.xml
+++ b/app/code/Magento/Directory/etc/adminhtml/system.xml
@@ -35,11 +35,24 @@
- Fixer.io
+ Fixer.io (legacy)
API Key
currency/fixerio/api_key
Magento\Config\Model\Config\Backend\Encrypted
+ Use this field if your API Key was generated at Fixer.io. If your key was generated via ApiLayer then use "Setting > General > Currency setup > Fixer Api via APILayer" configuration.
+
+
+ Connection Timeout in Seconds
+ validate-zero-or-greater validate-number
+
+
+
+ Fixer Api (APILayer)
+
+ API Key
+ currency/fixerio_apilayer/api_key
+ Magento\Config\Model\Config\Backend\Encrypted
Connection Timeout in Seconds
diff --git a/app/code/Magento/Directory/etc/config.xml b/app/code/Magento/Directory/etc/config.xml
index 32099ff9d8af5..508cebc974b05 100644
--- a/app/code/Magento/Directory/etc/config.xml
+++ b/app/code/Magento/Directory/etc/config.xml
@@ -22,6 +22,10 @@
100
+
+ 100
+
+
100
diff --git a/app/code/Magento/Directory/etc/di.xml b/app/code/Magento/Directory/etc/di.xml
index fb2c526ac730b..157af13afb53f 100644
--- a/app/code/Magento/Directory/etc/di.xml
+++ b/app/code/Magento/Directory/etc/di.xml
@@ -11,9 +11,13 @@
-
-
- Fixer.io
+ - Fixer.io (legacy)
- Magento\Directory\Model\Currency\Import\FixerIo
+ -
+
- Fixer Api (APILayer)
+ - Magento\Directory\Model\Currency\Import\FixerIoApiLayer
+
-
- Currency Converter API
- Magento\Directory\Model\Currency\Import\CurrencyConverterApi
diff --git a/app/code/Magento/DirectoryGraphQl/composer.json b/app/code/Magento/DirectoryGraphQl/composer.json
index 6acbef5c5534c..082fa8ae742c1 100644
--- a/app/code/Magento/DirectoryGraphQl/composer.json
+++ b/app/code/Magento/DirectoryGraphQl/composer.json
@@ -3,7 +3,7 @@
"description": "N/A",
"type": "magento2-module",
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/module-directory": "*",
"magento/module-store": "*",
"magento/module-graph-ql": "*",
diff --git a/app/code/Magento/Downloadable/composer.json b/app/code/Magento/Downloadable/composer.json
index a9487f8c430d3..abd6479f10e2d 100644
--- a/app/code/Magento/Downloadable/composer.json
+++ b/app/code/Magento/Downloadable/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-backend": "*",
"magento/module-catalog": "*",
diff --git a/app/code/Magento/DownloadableGraphQl/composer.json b/app/code/Magento/DownloadableGraphQl/composer.json
index 214b857bcd6f9..c286438b49356 100644
--- a/app/code/Magento/DownloadableGraphQl/composer.json
+++ b/app/code/Magento/DownloadableGraphQl/composer.json
@@ -3,7 +3,7 @@
"description": "N/A",
"type": "magento2-module",
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/module-store": "*",
"magento/module-catalog": "*",
"magento/module-downloadable": "*",
diff --git a/app/code/Magento/DownloadableImportExport/composer.json b/app/code/Magento/DownloadableImportExport/composer.json
index d6daea4b2ac17..bc35e44944c91 100644
--- a/app/code/Magento/DownloadableImportExport/composer.json
+++ b/app/code/Magento/DownloadableImportExport/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-catalog": "*",
"magento/module-catalog-import-export": "*",
diff --git a/app/code/Magento/Eav/composer.json b/app/code/Magento/Eav/composer.json
index 60915bd4ba590..40d249ba472b9 100644
--- a/app/code/Magento/Eav/composer.json
+++ b/app/code/Magento/Eav/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-backend": "*",
"magento/module-catalog": "*",
diff --git a/app/code/Magento/EavGraphQl/composer.json b/app/code/Magento/EavGraphQl/composer.json
index cfb8dc7ac9e11..a19a8bc3d5109 100644
--- a/app/code/Magento/EavGraphQl/composer.json
+++ b/app/code/Magento/EavGraphQl/composer.json
@@ -3,7 +3,7 @@
"description": "N/A",
"type": "magento2-module",
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-eav": "*"
},
diff --git a/app/code/Magento/Elasticsearch/Model/Adapter/Elasticsearch.php b/app/code/Magento/Elasticsearch/Model/Adapter/Elasticsearch.php
index b5151bbd578c5..c9f32c1fa584f 100644
--- a/app/code/Magento/Elasticsearch/Model/Adapter/Elasticsearch.php
+++ b/app/code/Magento/Elasticsearch/Model/Adapter/Elasticsearch.php
@@ -19,9 +19,11 @@
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\Stdlib\ArrayManager;
use Psr\Log\LoggerInterface;
+use Magento\AdvancedSearch\Helper\Data;
/**
* Elasticsearch adapter
+ * @SuppressWarnings(PHPMD.TooManyFields)
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*/
class Elasticsearch
@@ -110,6 +112,11 @@ class Elasticsearch
*/
private $arrayManager;
+ /**
+ * @var Data
+ */
+ protected $helper;
+
/**
* @var array
*/
@@ -125,6 +132,7 @@ class Elasticsearch
* @param LoggerInterface $logger
* @param Index\IndexNameResolver $indexNameResolver
* @param BatchDataMapperInterface $batchDocumentDataMapper
+ * @param Data $helper
* @param array $options
* @param ProductAttributeRepositoryInterface|null $productAttributeRepository
* @param StaticField|null $staticFieldProvider
@@ -141,6 +149,7 @@ public function __construct(
LoggerInterface $logger,
IndexNameResolver $indexNameResolver,
BatchDataMapperInterface $batchDocumentDataMapper,
+ Data $helper,
$options = [],
ProductAttributeRepositoryInterface $productAttributeRepository = null,
StaticField $staticFieldProvider = null,
@@ -154,6 +163,7 @@ public function __construct(
$this->logger = $logger;
$this->indexNameResolver = $indexNameResolver;
$this->batchDocumentDataMapper = $batchDocumentDataMapper;
+ $this->helper = $helper;
$this->productAttributeRepository = $productAttributeRepository ?:
ObjectManager::getInstance()->get(ProductAttributeRepositoryInterface::class);
$this->staticFieldProvider = $staticFieldProvider ?:
@@ -329,18 +339,30 @@ protected function getDocsArrayInBulkIndexFormat(
];
foreach ($documents as $id => $document) {
- $bulkArray['body'][] = [
- $action => [
- '_id' => $id,
- '_type' => $this->clientConfig->getEntityType(),
- '_index' => $indexName
- ]
- ];
+ if ($this->helper->isClientOpenSearchV2()) {
+ $bulkArray['body'][] = [
+ $action => [
+ '_id' => $id,
+ '_index' => $indexName
+ ]
+ ];
+ } else {
+ $bulkArray['body'][] = [
+ $action => [
+ '_id' => $id,
+ '_type' => $this->clientConfig->getEntityType(),
+ '_index' => $indexName
+ ]
+ ];
+ }
if ($action == self::BULK_ACTION_INDEX) {
$bulkArray['body'][] = $document;
}
}
+ if ($this->helper->isClientOpenSearchV2()) {
+ unset($bulkArray['type']);
+ }
return $bulkArray;
}
diff --git a/app/code/Magento/Elasticsearch/composer.json b/app/code/Magento/Elasticsearch/composer.json
index 30e0899981e6b..9e6d4ceaf16e3 100644
--- a/app/code/Magento/Elasticsearch/composer.json
+++ b/app/code/Magento/Elasticsearch/composer.json
@@ -2,7 +2,7 @@
"name": "magento/module-elasticsearch",
"description": "N/A",
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/module-advanced-search": "*",
"magento/module-catalog": "*",
"magento/module-catalog-search": "*",
diff --git a/app/code/Magento/Elasticsearch7/composer.json b/app/code/Magento/Elasticsearch7/composer.json
index 1c3fbd98ecb59..89f41bf14b0dc 100644
--- a/app/code/Magento/Elasticsearch7/composer.json
+++ b/app/code/Magento/Elasticsearch7/composer.json
@@ -2,10 +2,10 @@
"name": "magento/module-elasticsearch-7",
"description": "N/A",
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-elasticsearch": "*",
- "elasticsearch/elasticsearch": "~7.17.0",
+ "elasticsearch/elasticsearch": "^7.17",
"magento/module-advanced-search": "*",
"magento/module-catalog-search": "*",
"magento/module-search": "*"
diff --git a/app/code/Magento/Email/Block/Adminhtml/Template/Grid/Renderer/Action.php b/app/code/Magento/Email/Block/Adminhtml/Template/Grid/Renderer/Action.php
index 65f9e41b074a3..1c0fc533d0880 100644
--- a/app/code/Magento/Email/Block/Adminhtml/Template/Grid/Renderer/Action.php
+++ b/app/code/Magento/Email/Block/Adminhtml/Template/Grid/Renderer/Action.php
@@ -24,8 +24,8 @@ public function render(\Magento\Framework\DataObject $row)
$actions[] = [
'url' => $this->getUrl('adminhtml/*/preview', ['id' => $row->getId()]),
- 'popup' => true,
'caption' => __('Preview'),
+ 'target' => '_blank'
];
$this->getColumn()->setActions($actions);
diff --git a/app/code/Magento/Email/Test/Mftf/Test/AdminEmailTemplatePreviewFromGridNewTabTest.xml b/app/code/Magento/Email/Test/Mftf/Test/AdminEmailTemplatePreviewFromGridNewTabTest.xml
new file mode 100644
index 0000000000000..906c578325670
--- /dev/null
+++ b/app/code/Magento/Email/Test/Mftf/Test/AdminEmailTemplatePreviewFromGridNewTabTest.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ $previewWindowSize
+ $parentWindowSize
+
+
+
diff --git a/app/code/Magento/Email/composer.json b/app/code/Magento/Email/composer.json
index 4499b1060a011..27b33acfe00db 100644
--- a/app/code/Magento/Email/composer.json
+++ b/app/code/Magento/Email/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-backend": "*",
"magento/module-cms": "*",
diff --git a/app/code/Magento/EncryptionKey/composer.json b/app/code/Magento/EncryptionKey/composer.json
index c20cd852d2377..43a61d210ed74 100644
--- a/app/code/Magento/EncryptionKey/composer.json
+++ b/app/code/Magento/EncryptionKey/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-backend": "*",
"magento/module-config": "*"
diff --git a/app/code/Magento/Fedex/composer.json b/app/code/Magento/Fedex/composer.json
index 1734040c2c487..c3e879ac31177 100644
--- a/app/code/Magento/Fedex/composer.json
+++ b/app/code/Magento/Fedex/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"lib-libxml": "*",
"magento/framework": "*",
"magento/module-catalog": "*",
diff --git a/app/code/Magento/GiftMessage/composer.json b/app/code/Magento/GiftMessage/composer.json
index f205f2f4621d2..be0cdbbe22911 100644
--- a/app/code/Magento/GiftMessage/composer.json
+++ b/app/code/Magento/GiftMessage/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-backend": "*",
"magento/module-catalog": "*",
diff --git a/app/code/Magento/GiftMessageGraphQl/composer.json b/app/code/Magento/GiftMessageGraphQl/composer.json
index f9b980d26fa78..143b02439966f 100644
--- a/app/code/Magento/GiftMessageGraphQl/composer.json
+++ b/app/code/Magento/GiftMessageGraphQl/composer.json
@@ -3,7 +3,7 @@
"description": "N/A",
"type": "magento2-module",
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-gift-message": "*"
},
diff --git a/app/code/Magento/GoogleAdwords/composer.json b/app/code/Magento/GoogleAdwords/composer.json
index 3637b38f9ab61..a9d5b9178bb85 100644
--- a/app/code/Magento/GoogleAdwords/composer.json
+++ b/app/code/Magento/GoogleAdwords/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-sales": "*",
"magento/module-store": "*"
diff --git a/app/code/Magento/GoogleAnalytics/composer.json b/app/code/Magento/GoogleAnalytics/composer.json
index bb94435c9e9fd..09d9cadf97658 100644
--- a/app/code/Magento/GoogleAnalytics/composer.json
+++ b/app/code/Magento/GoogleAnalytics/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-cookie": "*",
"magento/module-sales": "*",
diff --git a/app/code/Magento/GoogleGtag/composer.json b/app/code/Magento/GoogleGtag/composer.json
index 13abce5dbf570..ed6e245b4e955 100644
--- a/app/code/Magento/GoogleGtag/composer.json
+++ b/app/code/Magento/GoogleGtag/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-cookie": "*",
"magento/module-sales": "*",
diff --git a/app/code/Magento/GoogleOptimizer/composer.json b/app/code/Magento/GoogleOptimizer/composer.json
index 7afe12358fa53..0192f363b61c2 100644
--- a/app/code/Magento/GoogleOptimizer/composer.json
+++ b/app/code/Magento/GoogleOptimizer/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-backend": "*",
"magento/module-catalog": "*",
diff --git a/app/code/Magento/GraphQl/composer.json b/app/code/Magento/GraphQl/composer.json
index 1a962eedc5d5a..b81c3a924d4e5 100644
--- a/app/code/Magento/GraphQl/composer.json
+++ b/app/code/Magento/GraphQl/composer.json
@@ -3,13 +3,13 @@
"description": "N/A",
"type": "magento2-module",
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/module-eav": "*",
"magento/framework": "*",
"magento/module-webapi": "*",
"magento/module-new-relic-reporting": "*",
"magento/module-authorization": "*",
- "webonyx/graphql-php": "~14.11.5"
+ "webonyx/graphql-php": "^14.11"
},
"suggest": {
"magento/module-graph-ql-cache": "*"
diff --git a/app/code/Magento/GraphQlCache/composer.json b/app/code/Magento/GraphQlCache/composer.json
index 5be26cbf5990d..082534290d139 100644
--- a/app/code/Magento/GraphQlCache/composer.json
+++ b/app/code/Magento/GraphQlCache/composer.json
@@ -3,7 +3,7 @@
"description": "N/A",
"type": "magento2-module",
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-page-cache": "*",
"magento/module-graph-ql": "*",
diff --git a/app/code/Magento/GroupedCatalogInventory/composer.json b/app/code/Magento/GroupedCatalogInventory/composer.json
index 1a5e6054130eb..487fdfe0cc828 100644
--- a/app/code/Magento/GroupedCatalogInventory/composer.json
+++ b/app/code/Magento/GroupedCatalogInventory/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-catalog": "*",
"magento/module-catalog-inventory": "*",
diff --git a/app/code/Magento/GroupedImportExport/composer.json b/app/code/Magento/GroupedImportExport/composer.json
index e411f55d00f4e..21805741bca44 100644
--- a/app/code/Magento/GroupedImportExport/composer.json
+++ b/app/code/Magento/GroupedImportExport/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-catalog": "*",
"magento/module-catalog-import-export": "*",
diff --git a/app/code/Magento/GroupedProduct/composer.json b/app/code/Magento/GroupedProduct/composer.json
index 105e711c75b41..8277efc44f06b 100644
--- a/app/code/Magento/GroupedProduct/composer.json
+++ b/app/code/Magento/GroupedProduct/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-backend": "*",
"magento/module-catalog": "*",
diff --git a/app/code/Magento/GroupedProductGraphQl/composer.json b/app/code/Magento/GroupedProductGraphQl/composer.json
index bb0f79e208dcb..41254569da53b 100644
--- a/app/code/Magento/GroupedProductGraphQl/composer.json
+++ b/app/code/Magento/GroupedProductGraphQl/composer.json
@@ -3,7 +3,7 @@
"description": "N/A",
"type": "magento2-module",
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/module-grouped-product": "*",
"magento/module-catalog": "*",
"magento/module-catalog-graph-ql": "*",
diff --git a/app/code/Magento/ImportExport/composer.json b/app/code/Magento/ImportExport/composer.json
index b85162e9bec76..8ea56d1011582 100644
--- a/app/code/Magento/ImportExport/composer.json
+++ b/app/code/Magento/ImportExport/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"ext-ctype": "*",
"magento/framework": "*",
"magento/module-backend": "*",
diff --git a/app/code/Magento/Indexer/Console/Command/IndexerReindexCommand.php b/app/code/Magento/Indexer/Console/Command/IndexerReindexCommand.php
index 285b06e95331e..376dabe00ac5a 100644
--- a/app/code/Magento/Indexer/Console/Command/IndexerReindexCommand.php
+++ b/app/code/Magento/Indexer/Console/Command/IndexerReindexCommand.php
@@ -101,7 +101,7 @@ protected function execute(InputInterface $input, OutputInterface $output)
$output->write($indexer->getTitle() . ' index ');
- $startTime = microtime(true);
+ $startTime = new \DateTimeImmutable();
$indexerConfig = $this->getConfig()->getIndexer($indexer->getId());
$sharedIndex = $indexerConfig['shared_index'] ?? null;
@@ -112,10 +112,15 @@ protected function execute(InputInterface $input, OutputInterface $output)
$this->sharedIndexesComplete[] = $sharedIndex;
}
}
- $resultTime = microtime(true) - $startTime;
+ $endTime = new \DateTimeImmutable();
+ $interval = $startTime->diff($endTime);
+ $days = $interval->format('%d');
+ $hours = $days > 0 ? $days * 24 + $interval->format('%H') : $interval->format('%H');
+ $minutes = $interval->format('%I');
+ $seconds = $interval->format('%S');
$output->writeln(
- __('has been rebuilt successfully in %time', ['time' => gmdate('H:i:s', (int) $resultTime)])
+ __('has been rebuilt successfully in %1:%2:%3', $hours, $minutes, $seconds)
);
} catch (\Throwable $e) {
$output->writeln('process error during indexation process:');
@@ -238,7 +243,9 @@ private function validateIndexerStatus(IndexerInterface $indexer)
* Get config
*
* @return ConfigInterface
- * @deprecated 100.1.0
+ * @deprecated 100.1.0 We don't recommend this approach anymore
+ * @see Add a new optional parameter to the constructor at the end of the arguments list instead
+ * and fetch the dependency using Magento\Framework\App\ObjectManager::getInstance() in the constructor body
*/
private function getConfig()
{
@@ -252,7 +259,9 @@ private function getConfig()
* Get dependency info provider
*
* @return DependencyInfoProvider
- * @deprecated 100.2.0
+ * @deprecated 100.2.0 We don't recommend this approach anymore
+ * @see Add a new optional parameter to the constructor at the end of the arguments list instead
+ * and fetch the dependency using Magento\Framework\App\ObjectManager::getInstance() in the constructor body
*/
private function getDependencyInfoProvider()
{
diff --git a/app/code/Magento/Indexer/Test/Unit/Console/Command/IndexerReindexCommandTest.php b/app/code/Magento/Indexer/Test/Unit/Console/Command/IndexerReindexCommandTest.php
index 244798e7261b8..4db91dcfb7cb6 100644
--- a/app/code/Magento/Indexer/Test/Unit/Console/Command/IndexerReindexCommandTest.php
+++ b/app/code/Magento/Indexer/Test/Unit/Console/Command/IndexerReindexCommandTest.php
@@ -8,13 +8,11 @@
namespace Magento\Indexer\Test\Unit\Console\Command;
use Magento\Framework\Console\Cli;
-use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\Indexer\Config\DependencyInfoProvider;
use Magento\Framework\Indexer\ConfigInterface;
use Magento\Framework\Indexer\IndexerInterface;
use Magento\Framework\Indexer\IndexerRegistry;
use Magento\Framework\Indexer\StateInterface;
-use Magento\Framework\Phrase;
use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper;
use Magento\Indexer\Console\Command\IndexerReindexCommand;
use Magento\Indexer\Model\Config;
@@ -27,7 +25,7 @@
*/
class IndexerReindexCommandTest extends AbstractIndexerCommandCommonSetup
{
- const STUB_INDEXER_NAME = 'Indexer Name';
+ private const STUB_INDEXER_NAME = 'Indexer Name';
/**
* Command being tested
*
@@ -130,6 +128,11 @@ public function testExecuteAll()
self::STUB_INDEXER_NAME . ' index has been rebuilt successfully in',
$actualValue
);
+ $this->assertMatchesRegularExpression(
+ '/' . self::STUB_INDEXER_NAME
+ . ' index has been rebuilt successfully in (?:(?:([01]?\d|2[0-3]):)?([0-5]?\d):)?([0-5]?\d)/m',
+ $actualValue
+ );
}
/**
diff --git a/app/code/Magento/Indexer/composer.json b/app/code/Magento/Indexer/composer.json
index bdcd05d5a71e3..8cee48610c7ea 100644
--- a/app/code/Magento/Indexer/composer.json
+++ b/app/code/Magento/Indexer/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-backend": "*"
},
diff --git a/app/code/Magento/InstantPurchase/composer.json b/app/code/Magento/InstantPurchase/composer.json
index c399f60df1dbb..d64f757adfd3b 100644
--- a/app/code/Magento/InstantPurchase/composer.json
+++ b/app/code/Magento/InstantPurchase/composer.json
@@ -7,7 +7,7 @@
"AFL-3.0"
],
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/module-store": "*",
"magento/module-catalog": "*",
"magento/module-customer": "*",
diff --git a/app/code/Magento/Integration/composer.json b/app/code/Magento/Integration/composer.json
index d3c226066226f..a6eea5321de74 100644
--- a/app/code/Magento/Integration/composer.json
+++ b/app/code/Magento/Integration/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-authorization": "*",
"magento/module-backend": "*",
diff --git a/app/code/Magento/Integration/etc/webapi.xml b/app/code/Magento/Integration/etc/webapi.xml
index 8814fe5bb0059..6c6dc1a9def91 100644
--- a/app/code/Magento/Integration/etc/webapi.xml
+++ b/app/code/Magento/Integration/etc/webapi.xml
@@ -19,4 +19,13 @@
+
+
+
+
+
+
+ %customer_id%
+
+
diff --git a/app/code/Magento/JwtFrameworkAdapter/composer.json b/app/code/Magento/JwtFrameworkAdapter/composer.json
index a375ed0b197a8..811dc1948c121 100644
--- a/app/code/Magento/JwtFrameworkAdapter/composer.json
+++ b/app/code/Magento/JwtFrameworkAdapter/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"web-token/jwt-framework": "^v2.2.7"
},
diff --git a/app/code/Magento/JwtUserToken/composer.json b/app/code/Magento/JwtUserToken/composer.json
index d632d6e4a49b0..ff1ae2bda5261 100644
--- a/app/code/Magento/JwtUserToken/composer.json
+++ b/app/code/Magento/JwtUserToken/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-integration": "*",
"magento/module-authorization": "*"
diff --git a/app/code/Magento/LayeredNavigation/composer.json b/app/code/Magento/LayeredNavigation/composer.json
index d6285b4260f5f..c40f906eac3a0 100644
--- a/app/code/Magento/LayeredNavigation/composer.json
+++ b/app/code/Magento/LayeredNavigation/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-catalog": "*",
"magento/module-config": "*"
diff --git a/app/code/Magento/LoginAsCustomer/composer.json b/app/code/Magento/LoginAsCustomer/composer.json
index 61a4e1c0dda96..6b2cbf7c1f3f7 100755
--- a/app/code/Magento/LoginAsCustomer/composer.json
+++ b/app/code/Magento/LoginAsCustomer/composer.json
@@ -2,7 +2,7 @@
"name": "magento/module-login-as-customer",
"description": "Allow for admin to enter a customer account",
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-backend": "*",
"magento/module-customer": "*",
diff --git a/app/code/Magento/LoginAsCustomerAdminUi/composer.json b/app/code/Magento/LoginAsCustomerAdminUi/composer.json
index 6841ee3790cb3..2a42d814be498 100644
--- a/app/code/Magento/LoginAsCustomerAdminUi/composer.json
+++ b/app/code/Magento/LoginAsCustomerAdminUi/composer.json
@@ -2,7 +2,7 @@
"name": "magento/module-login-as-customer-admin-ui",
"description": "",
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-login-as-customer-api": "*",
"magento/module-login-as-customer-frontend-ui": "*",
diff --git a/app/code/Magento/LoginAsCustomerApi/composer.json b/app/code/Magento/LoginAsCustomerApi/composer.json
index e4a0952ac0369..fed3ab5390597 100644
--- a/app/code/Magento/LoginAsCustomerApi/composer.json
+++ b/app/code/Magento/LoginAsCustomerApi/composer.json
@@ -2,7 +2,7 @@
"name": "magento/module-login-as-customer-api",
"description": "Allow for admin to enter a customer account",
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*"
},
"type": "magento2-module",
diff --git a/app/code/Magento/LoginAsCustomerAssistance/composer.json b/app/code/Magento/LoginAsCustomerAssistance/composer.json
index 58e48bddc7c0f..32e351bee5115 100644
--- a/app/code/Magento/LoginAsCustomerAssistance/composer.json
+++ b/app/code/Magento/LoginAsCustomerAssistance/composer.json
@@ -2,7 +2,7 @@
"name": "magento/module-login-as-customer-assistance",
"description": "",
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-authorization": "*",
"magento/module-backend": "*",
diff --git a/app/code/Magento/LoginAsCustomerFrontendUi/composer.json b/app/code/Magento/LoginAsCustomerFrontendUi/composer.json
index 8a5437dc42d28..7c7767e23c27a 100644
--- a/app/code/Magento/LoginAsCustomerFrontendUi/composer.json
+++ b/app/code/Magento/LoginAsCustomerFrontendUi/composer.json
@@ -2,7 +2,7 @@
"name": "magento/module-login-as-customer-frontend-ui",
"description": "",
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-login-as-customer-api": "*",
"magento/module-customer": "*",
diff --git a/app/code/Magento/LoginAsCustomerGraphQl/composer.json b/app/code/Magento/LoginAsCustomerGraphQl/composer.json
index 25a5ef8ff8b6c..ee97cd320115e 100755
--- a/app/code/Magento/LoginAsCustomerGraphQl/composer.json
+++ b/app/code/Magento/LoginAsCustomerGraphQl/composer.json
@@ -2,7 +2,7 @@
"name": "magento/module-login-as-customer-graph-ql",
"description": "Flexible login as a customer so a merchant or merchant admin can log into an end customer's account to assist them with their account.",
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-login-as-customer-api": "*",
"magento/module-login-as-customer-assistance": "*",
diff --git a/app/code/Magento/LoginAsCustomerLog/composer.json b/app/code/Magento/LoginAsCustomerLog/composer.json
index 404511f7315f4..7e39d22d23ef6 100644
--- a/app/code/Magento/LoginAsCustomerLog/composer.json
+++ b/app/code/Magento/LoginAsCustomerLog/composer.json
@@ -2,7 +2,7 @@
"name": "magento/module-login-as-customer-log",
"description": "",
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-backend": "*",
"magento/module-customer": "*",
diff --git a/app/code/Magento/LoginAsCustomerPageCache/composer.json b/app/code/Magento/LoginAsCustomerPageCache/composer.json
index 93f74f29ef246..39b8217c89969 100644
--- a/app/code/Magento/LoginAsCustomerPageCache/composer.json
+++ b/app/code/Magento/LoginAsCustomerPageCache/composer.json
@@ -2,7 +2,7 @@
"name": "magento/module-login-as-customer-page-cache",
"description": "",
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-store": "*",
"magento/module-login-as-customer-api": "*"
diff --git a/app/code/Magento/LoginAsCustomerQuote/composer.json b/app/code/Magento/LoginAsCustomerQuote/composer.json
index f852948ab757f..0ce4d008d1fd8 100644
--- a/app/code/Magento/LoginAsCustomerQuote/composer.json
+++ b/app/code/Magento/LoginAsCustomerQuote/composer.json
@@ -2,7 +2,7 @@
"name": "magento/module-login-as-customer-quote",
"description": "",
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-checkout": "*",
"magento/module-customer": "*",
diff --git a/app/code/Magento/LoginAsCustomerSales/composer.json b/app/code/Magento/LoginAsCustomerSales/composer.json
index ba24858b6f548..74f74eb34432e 100644
--- a/app/code/Magento/LoginAsCustomerSales/composer.json
+++ b/app/code/Magento/LoginAsCustomerSales/composer.json
@@ -2,7 +2,7 @@
"name": "magento/module-login-as-customer-sales",
"description": "",
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-backend": "*",
"magento/module-user": "*",
diff --git a/app/code/Magento/Marketplace/composer.json b/app/code/Magento/Marketplace/composer.json
index f468808298344..1827499160587 100644
--- a/app/code/Magento/Marketplace/composer.json
+++ b/app/code/Magento/Marketplace/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-backend": "*"
},
diff --git a/app/code/Magento/MediaContent/composer.json b/app/code/Magento/MediaContent/composer.json
index 7eb51b02f61eb..4e7fd39b9d0ae 100644
--- a/app/code/Magento/MediaContent/composer.json
+++ b/app/code/Magento/MediaContent/composer.json
@@ -2,7 +2,7 @@
"name": "magento/module-media-content",
"description": "Magento module provides the implementation for managing relations between content and media files used in that content",
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-media-content-api": "*",
"magento/module-media-gallery-api": "*"
diff --git a/app/code/Magento/MediaContentApi/composer.json b/app/code/Magento/MediaContentApi/composer.json
index 86dc6408cd6fd..f7583a1f61a08 100644
--- a/app/code/Magento/MediaContentApi/composer.json
+++ b/app/code/Magento/MediaContentApi/composer.json
@@ -2,7 +2,7 @@
"name": "magento/module-media-content-api",
"description": "Magento module provides the API interfaces for managing relations between content and media files used in that content",
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/module-media-gallery-api": "*",
"magento/framework": "*"
},
diff --git a/app/code/Magento/MediaContentCatalog/composer.json b/app/code/Magento/MediaContentCatalog/composer.json
index 822fd1ec73814..948cc9f05d3cd 100644
--- a/app/code/Magento/MediaContentCatalog/composer.json
+++ b/app/code/Magento/MediaContentCatalog/composer.json
@@ -2,7 +2,7 @@
"name": "magento/module-media-content-catalog",
"description": "Magento module provides the implementation of MediaContent functionality for Magento_Catalog module",
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/module-media-content-api": "*",
"magento/module-catalog": "*",
"magento/module-eav": "*",
diff --git a/app/code/Magento/MediaContentCms/composer.json b/app/code/Magento/MediaContentCms/composer.json
index 6cd121d00d2a2..a0a6098993900 100644
--- a/app/code/Magento/MediaContentCms/composer.json
+++ b/app/code/Magento/MediaContentCms/composer.json
@@ -2,7 +2,7 @@
"name": "magento/module-media-content-cms",
"description": "Magento module provides the implementation of MediaContent functionality for Magento_Cms module",
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/module-media-content-api": "*",
"magento/module-cms": "*",
"magento/framework": "*"
diff --git a/app/code/Magento/MediaContentSynchronization/composer.json b/app/code/Magento/MediaContentSynchronization/composer.json
index a3062c163b246..4520f1302a03f 100644
--- a/app/code/Magento/MediaContentSynchronization/composer.json
+++ b/app/code/Magento/MediaContentSynchronization/composer.json
@@ -2,7 +2,7 @@
"name": "magento/module-media-content-synchronization",
"description": "Magento module provides implementation of the media content data synchronization.",
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/framework-bulk": "*",
"magento/module-media-content-synchronization-api": "*",
diff --git a/app/code/Magento/MediaContentSynchronizationApi/composer.json b/app/code/Magento/MediaContentSynchronizationApi/composer.json
index 953d665b79a4d..1e44b8079e29b 100644
--- a/app/code/Magento/MediaContentSynchronizationApi/composer.json
+++ b/app/code/Magento/MediaContentSynchronizationApi/composer.json
@@ -2,7 +2,7 @@
"name": "magento/module-media-content-synchronization-api",
"description": "Magento module responsible for the media content synchronization implementation API",
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-media-content-api": "*"
},
diff --git a/app/code/Magento/MediaContentSynchronizationCatalog/composer.json b/app/code/Magento/MediaContentSynchronizationCatalog/composer.json
index 7a0375e30c370..f3a2bbb4baeb1 100644
--- a/app/code/Magento/MediaContentSynchronizationCatalog/composer.json
+++ b/app/code/Magento/MediaContentSynchronizationCatalog/composer.json
@@ -2,7 +2,7 @@
"name": "magento/module-media-content-synchronization-catalog",
"description": "Magento module provides the implementation of MediaContentSynchronization functionality for Magento_Catalog module",
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-media-content-synchronization-api": "*",
"magento/module-media-gallery-synchronization-api": "*",
diff --git a/app/code/Magento/MediaContentSynchronizationCms/composer.json b/app/code/Magento/MediaContentSynchronizationCms/composer.json
index 9e1236bcb863d..9925cc9ae5387 100644
--- a/app/code/Magento/MediaContentSynchronizationCms/composer.json
+++ b/app/code/Magento/MediaContentSynchronizationCms/composer.json
@@ -2,7 +2,7 @@
"name": "magento/module-media-content-synchronization-cms",
"description": "Magento module provides the implementation of MediaContentSynchronization functionality for Magento_Cms module",
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-media-content-synchronization-api": "*",
"magento/module-media-gallery-synchronization-api": "*",
diff --git a/app/code/Magento/MediaGallery/composer.json b/app/code/Magento/MediaGallery/composer.json
index ccea65f248c26..0076013351e22 100644
--- a/app/code/Magento/MediaGallery/composer.json
+++ b/app/code/Magento/MediaGallery/composer.json
@@ -2,7 +2,7 @@
"name": "magento/module-media-gallery",
"description": "Magento module responsible for media handling",
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-media-gallery-api": "*",
"magento/module-cms": "*"
diff --git a/app/code/Magento/MediaGalleryApi/composer.json b/app/code/Magento/MediaGalleryApi/composer.json
index d4299f8ef5e8d..48ef4dbf076f3 100644
--- a/app/code/Magento/MediaGalleryApi/composer.json
+++ b/app/code/Magento/MediaGalleryApi/composer.json
@@ -2,7 +2,7 @@
"name": "magento/module-media-gallery-api",
"description": "Magento module responsible for media gallery asset attributes storage and management",
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*"
},
"type": "magento2-module",
diff --git a/app/code/Magento/MediaGalleryCatalog/composer.json b/app/code/Magento/MediaGalleryCatalog/composer.json
index ce438f66fda19..7feea28221df4 100644
--- a/app/code/Magento/MediaGalleryCatalog/composer.json
+++ b/app/code/Magento/MediaGalleryCatalog/composer.json
@@ -2,7 +2,7 @@
"name": "magento/module-media-gallery-catalog",
"description": "Magento module responsible for catalog gallery processor delete operation handling",
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-media-gallery-api": "*",
"magento/module-catalog": "*"
diff --git a/app/code/Magento/MediaGalleryCatalogIntegration/composer.json b/app/code/Magento/MediaGalleryCatalogIntegration/composer.json
index 477312fd0e4fb..267c37e88b44e 100644
--- a/app/code/Magento/MediaGalleryCatalogIntegration/composer.json
+++ b/app/code/Magento/MediaGalleryCatalogIntegration/composer.json
@@ -2,7 +2,7 @@
"name": "magento/module-media-gallery-catalog-integration",
"description": "Magento module responsible for extending catalog image uploader functionality",
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-cms": "*",
"magento/module-media-gallery-api": "*",
diff --git a/app/code/Magento/MediaGalleryCatalogUi/composer.json b/app/code/Magento/MediaGalleryCatalogUi/composer.json
index 296de50df5189..46f0de7c6a51b 100644
--- a/app/code/Magento/MediaGalleryCatalogUi/composer.json
+++ b/app/code/Magento/MediaGalleryCatalogUi/composer.json
@@ -2,7 +2,7 @@
"name": "magento/module-media-gallery-catalog-ui",
"description": "Magento module that implement category grid for media gallery.",
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-cms": "*",
"magento/module-backend": "*",
diff --git a/app/code/Magento/MediaGalleryCmsUi/composer.json b/app/code/Magento/MediaGalleryCmsUi/composer.json
index 01e65b4212322..04e7f24199775 100644
--- a/app/code/Magento/MediaGalleryCmsUi/composer.json
+++ b/app/code/Magento/MediaGalleryCmsUi/composer.json
@@ -2,7 +2,7 @@
"name": "magento/module-media-gallery-cms-ui",
"description": "Cms related UI elements in the magento media gallery",
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-cms": "*",
"magento/module-backend": "*"
diff --git a/app/code/Magento/MediaGalleryIntegration/composer.json b/app/code/Magento/MediaGalleryIntegration/composer.json
index a29b109174369..3c0fd77facb76 100644
--- a/app/code/Magento/MediaGalleryIntegration/composer.json
+++ b/app/code/Magento/MediaGalleryIntegration/composer.json
@@ -2,7 +2,7 @@
"name": "magento/module-media-gallery-integration",
"description": "Magento module responsible for integration of enhanced media gallery",
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-media-gallery-ui-api": "*",
"magento/module-media-gallery-api": "*",
diff --git a/app/code/Magento/MediaGalleryMetadata/composer.json b/app/code/Magento/MediaGalleryMetadata/composer.json
index 88a54ffadab49..aede5537f058b 100644
--- a/app/code/Magento/MediaGalleryMetadata/composer.json
+++ b/app/code/Magento/MediaGalleryMetadata/composer.json
@@ -2,7 +2,7 @@
"name": "magento/module-media-gallery-metadata",
"description": "Magento module responsible for images metadata processing",
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-media-gallery-metadata-api": "*"
},
diff --git a/app/code/Magento/MediaGalleryMetadataApi/composer.json b/app/code/Magento/MediaGalleryMetadataApi/composer.json
index ea8ec2763678b..41de71aeb5265 100644
--- a/app/code/Magento/MediaGalleryMetadataApi/composer.json
+++ b/app/code/Magento/MediaGalleryMetadataApi/composer.json
@@ -2,7 +2,7 @@
"name": "magento/module-media-gallery-metadata-api",
"description": "Magento module responsible for media gallery metadata implementation API",
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*"
},
"type": "magento2-module",
diff --git a/app/code/Magento/MediaGalleryRenditions/composer.json b/app/code/Magento/MediaGalleryRenditions/composer.json
index e18f3ae6e78c3..ca05a594554a6 100644
--- a/app/code/Magento/MediaGalleryRenditions/composer.json
+++ b/app/code/Magento/MediaGalleryRenditions/composer.json
@@ -2,7 +2,7 @@
"name": "magento/module-media-gallery-renditions",
"description": "Magento module that implements height and width fields for for media gallery items.",
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-media-gallery-renditions-api": "*",
"magento/module-media-gallery-api": "*",
diff --git a/app/code/Magento/MediaGalleryRenditionsApi/composer.json b/app/code/Magento/MediaGalleryRenditionsApi/composer.json
index 589247e91f269..e6f9cf747690f 100644
--- a/app/code/Magento/MediaGalleryRenditionsApi/composer.json
+++ b/app/code/Magento/MediaGalleryRenditionsApi/composer.json
@@ -2,7 +2,7 @@
"name": "magento/module-media-gallery-renditions-api",
"description": "Magento module that is responsible for the API implementation of Media Gallery Renditions.",
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*"
},
"type": "magento2-module",
diff --git a/app/code/Magento/MediaGallerySynchronization/composer.json b/app/code/Magento/MediaGallerySynchronization/composer.json
index 0a7b05a9f4fca..ee7b9b5be5b89 100644
--- a/app/code/Magento/MediaGallerySynchronization/composer.json
+++ b/app/code/Magento/MediaGallerySynchronization/composer.json
@@ -2,7 +2,7 @@
"name": "magento/module-media-gallery-synchronization",
"description": "Magento module provides implementation of the media gallery data synchronization.",
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-media-gallery-api": "*",
"magento/module-media-gallery-synchronization-api": "*",
diff --git a/app/code/Magento/MediaGallerySynchronizationApi/composer.json b/app/code/Magento/MediaGallerySynchronizationApi/composer.json
index e7b388d7f407d..7b62a0d7c680f 100644
--- a/app/code/Magento/MediaGallerySynchronizationApi/composer.json
+++ b/app/code/Magento/MediaGallerySynchronizationApi/composer.json
@@ -2,7 +2,7 @@
"name": "magento/module-media-gallery-synchronization-api",
"description": "Magento module responsible for the media gallery synchronization implementation API",
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-media-gallery-api": "*"
},
diff --git a/app/code/Magento/MediaGallerySynchronizationMetadata/composer.json b/app/code/Magento/MediaGallerySynchronizationMetadata/composer.json
index 38088910e6a78..ba4cec8bd6da9 100644
--- a/app/code/Magento/MediaGallerySynchronizationMetadata/composer.json
+++ b/app/code/Magento/MediaGallerySynchronizationMetadata/composer.json
@@ -2,7 +2,7 @@
"name": "magento/module-media-gallery-synchronization-metadata",
"description": "Magento module responsible for images metadata synchronization",
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-media-gallery-api": "*",
"magento/module-media-gallery-metadata-api": "*",
diff --git a/app/code/Magento/MediaGalleryUi/Model/Directories/GetDirectoryTree.php b/app/code/Magento/MediaGalleryUi/Model/Directories/GetDirectoryTree.php
index 897d0d34a5c84..bff9d9867dd03 100644
--- a/app/code/Magento/MediaGalleryUi/Model/Directories/GetDirectoryTree.php
+++ b/app/code/Magento/MediaGalleryUi/Model/Directories/GetDirectoryTree.php
@@ -7,7 +7,9 @@
namespace Magento\MediaGalleryUi\Model\Directories;
+use Magento\Framework\App\Config\ScopeConfigInterface;
use Magento\Framework\App\Filesystem\DirectoryList;
+use Magento\Framework\App\ObjectManager;
use Magento\Framework\Exception\ValidatorException;
use Magento\Framework\Filesystem;
use Magento\Framework\Filesystem\Directory\Read;
@@ -18,6 +20,8 @@
*/
class GetDirectoryTree
{
+ private const XML_PATH_MEDIA_GALLERY_IMAGE_FOLDERS
+ = 'system/media_storage_configuration/allowed_resources/media_gallery_image_folders';
/**
* @var Filesystem
*/
@@ -28,16 +32,24 @@ class GetDirectoryTree
*/
private $isPathExcluded;
+ /**
+ * @var ScopeConfigInterface
+ */
+ private $coreConfig;
+
/**
* @param Filesystem $filesystem
* @param IsPathExcludedInterface $isPathExcluded
+ * @param ScopeConfigInterface|null $coreConfig
*/
public function __construct(
Filesystem $filesystem,
- IsPathExcludedInterface $isPathExcluded
+ IsPathExcludedInterface $isPathExcluded,
+ ?ScopeConfigInterface $coreConfig = null
) {
$this->filesystem = $filesystem;
$this->isPathExcluded = $isPathExcluded;
+ $this->coreConfig = $coreConfig ?? ObjectManager::getInstance()->get(ScopeConfigInterface::class);
}
/**
@@ -74,30 +86,54 @@ private function getDirectories(): array
{
$directories = [];
- /** @var Read $directory */
- $directory = $this->filesystem->getDirectoryRead(DirectoryList::MEDIA);
-
- if (!$directory->isDirectory()) {
- return $directories;
- }
-
- foreach ($directory->readRecursively() as $path) {
- if (!$directory->isDirectory($path) || $this->isPathExcluded->execute($path)) {
- continue;
+ /** @var Read $mediaDirectory */
+ $mediaDirectory = $this->filesystem->getDirectoryRead(DirectoryList::MEDIA);
+
+ if ($mediaDirectory->isDirectory()) {
+ $imageFolderPaths = $this->coreConfig->getValue(
+ self::XML_PATH_MEDIA_GALLERY_IMAGE_FOLDERS,
+ ScopeConfigInterface::SCOPE_TYPE_DEFAULT
+ );
+ sort($imageFolderPaths);
+
+ foreach ($imageFolderPaths as $imageFolderPath) {
+ $imageDirectory = $this->filesystem->getDirectoryReadByPath(
+ $mediaDirectory->getAbsolutePath($imageFolderPath)
+ );
+ if ($imageDirectory->isDirectory()) {
+ $directories[] = $this->getDirectoryData($imageFolderPath);
+ foreach ($imageDirectory->readRecursively() as $path) {
+ if ($imageDirectory->isDirectory($path)) {
+ $directories[] = $this->getDirectoryData(
+ $mediaDirectory->getRelativePath($imageDirectory->getAbsolutePath($path))
+ );
+ }
+ }
+ }
}
-
- $pathArray = explode('/', $path);
- $directories[] = [
- 'text' => count($pathArray) > 0 ? end($pathArray) : $path,
- 'id' => $path,
- 'li_attr' => ['data-id' => $path],
- 'path' => $path,
- 'path_array' => $pathArray
- ];
}
+
return $directories;
}
+ /**
+ * Return jstree data for given path
+ *
+ * @param string $path
+ * @return array
+ */
+ private function getDirectoryData(string $path): array
+ {
+ $pathArray = explode('/', $path);
+ return [
+ 'text' => count($pathArray) > 0 ? end($pathArray) : $path,
+ 'id' => $path,
+ 'li_attr' => ['data-id' => $path],
+ 'path' => $path,
+ 'path_array' => $pathArray
+ ];
+ }
+
/**
* Find parent directory
*
@@ -121,9 +157,9 @@ private function findParent(array &$node, array &$treeNode, int $level = 0): arr
$tNodePathLength = count($tnode['path_array']);
$found = false;
while ($level < $tNodePathLength) {
- if ($node['path_array'][$level] === $tnode['path_array'][$level]) {
+ $found = $node['path_array'][$level] === $tnode['path_array'][$level];
+ if ($found) {
$level ++;
- $found = true;
} else {
break;
}
diff --git a/app/code/Magento/MediaGalleryUi/Test/Mftf/Section/AdminMediaGalleryFolderSection.xml b/app/code/Magento/MediaGalleryUi/Test/Mftf/Section/AdminMediaGalleryFolderSection.xml
index 569487c47da1c..727d3293851fa 100644
--- a/app/code/Magento/MediaGalleryUi/Test/Mftf/Section/AdminMediaGalleryFolderSection.xml
+++ b/app/code/Magento/MediaGalleryUi/Test/Mftf/Section/AdminMediaGalleryFolderSection.xml
@@ -9,6 +9,7 @@
+
diff --git a/app/code/Magento/MediaGalleryUi/Test/Mftf/Test/UserDeletesFolderFromMediaGalleryTest.xml b/app/code/Magento/MediaGalleryUi/Test/Mftf/Test/UserDeletesFolderFromMediaGalleryTest.xml
index f1db298764ee8..91478877cfe50 100755
--- a/app/code/Magento/MediaGalleryUi/Test/Mftf/Test/UserDeletesFolderFromMediaGalleryTest.xml
+++ b/app/code/Magento/MediaGalleryUi/Test/Mftf/Test/UserDeletesFolderFromMediaGalleryTest.xml
@@ -89,3 +89,4 @@
+
diff --git a/app/code/Magento/MediaGalleryUi/Test/Unit/Model/Model/Directories/GetDirectoryTreeTest.php b/app/code/Magento/MediaGalleryUi/Test/Unit/Model/Model/Directories/GetDirectoryTreeTest.php
new file mode 100644
index 0000000000000..df7647a66da58
--- /dev/null
+++ b/app/code/Magento/MediaGalleryUi/Test/Unit/Model/Model/Directories/GetDirectoryTreeTest.php
@@ -0,0 +1,304 @@
+ [
+ 'dir1_1' => [
+
+ ],
+ 'dir1_2' => [
+
+ ],
+ 'dir1_3' => [
+
+ ]
+ ],
+ 'dir2' => [
+ 'dir2_1' => [
+ 'dir2_1_1' => [
+
+ ]
+ ],
+ 'dir2_2' => [
+ 'dir2_2_1' => [
+
+ ],
+ 'dir2_2_2' => [
+
+ ]
+ ]
+ ],
+ 'dir3' => [
+ 'dir3_1' => [
+ 'dir3_1_1' => [
+ 'dir3_1_1_1' => [
+
+ ]
+ ]
+ ]
+ ],
+ 'dir4' => [
+
+ ],
+ ];
+
+ /**
+ * @inheritdoc
+ */
+ protected function setUp(): void
+ {
+ parent::setUp();
+ $this->filesystem = $this->createMock(Filesystem::class);
+ $this->isPathExcluded = $this->getMockForAbstractClass(IsPathExcludedInterface::class);
+ $this->coreConfig = $this->getMockForAbstractClass(ScopeConfigInterface::class);
+ $this->model = new GetDirectoryTree(
+ $this->filesystem,
+ $this->isPathExcluded,
+ $this->coreConfig
+ );
+ }
+
+ /**
+ * @param array $allowedFolders
+ * @param array $expected
+ * @throws ValidatorException
+ * @dataProvider executeDataProvider
+ */
+ public function testExecute(array $allowedFolders, array $expected): void
+ {
+ $directory = $this->getMockForAbstractClass(ReadInterface::class);
+ $directory->method('isDirectory')->willReturn(true);
+ $directory->method('getAbsolutePath')->willReturnArgument(0);
+ $directory->method('getRelativePath')->willReturnArgument(0);
+ $this->filesystem->method('getDirectoryRead')->willReturn($directory);
+ $this->filesystem->method('getDirectoryReadByPath')
+ ->willReturnCallback(
+ function (string $path) {
+ $directory = $this->getMockBuilder(ReadInterface::class)
+ ->addMethods(['readRecursively'])
+ ->getMockForAbstractClass();
+ $directory->method('isDirectory')->willReturn(true);
+ $result = $this->foldersStruture;
+ $prefix = '';
+ foreach (explode('/', $path) as $folder) {
+ $prefix .= $folder . '/';
+ $result = $result[$folder] ?? [];
+ }
+ $directory->method('getAbsolutePath')->willReturnArgument(0);
+ $directory->method('readRecursively')->willReturn($this->flattenFoldersStructure($result, $prefix));
+ return $directory;
+ }
+ );
+ $this->coreConfig->method('getValue')->willReturn($allowedFolders);
+ $this->assertEquals($expected, $this->model->execute());
+ }
+
+ /**
+ * @return array
+ * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
+ */
+ public function executeDataProvider(): array
+ {
+ return [
+ [
+ ['dir1/dir1_1', 'dir2/dir2_2', 'dir3'],
+ [
+ [
+ 'text' => 'dir1_1',
+ 'id' => 'dir1/dir1_1',
+ 'li_attr' => ['data-id' => 'dir1/dir1_1'],
+ 'path' => 'dir1/dir1_1',
+ 'path_array' => ['dir1', 'dir1_1'],
+ 'children' => [],
+ ],
+ [
+ 'text' => 'dir2_2',
+ 'id' => 'dir2/dir2_2',
+ 'li_attr' => ['data-id' => 'dir2/dir2_2'],
+ 'path' => 'dir2/dir2_2',
+ 'path_array' => ['dir2', 'dir2_2'],
+ 'children' =>
+ [
+ [
+ 'text' => 'dir2_2_1',
+ 'id' => 'dir2/dir2_2/dir2_2_1',
+ 'li_attr' =>
+ [
+ 'data-id' => 'dir2/dir2_2/dir2_2_1',
+ ],
+ 'path' => 'dir2/dir2_2/dir2_2_1',
+ 'path_array' => ['dir2', 'dir2_2', 'dir2_2_1'],
+ 'children' => [],
+ ],
+ [
+ 'text' => 'dir2_2_2',
+ 'id' => 'dir2/dir2_2/dir2_2_2',
+ 'li_attr' => ['data-id' => 'dir2/dir2_2/dir2_2_2'],
+ 'path' => 'dir2/dir2_2/dir2_2_2',
+ 'path_array' => ['dir2', 'dir2_2', 'dir2_2_2'],
+ 'children' => [],
+ ],
+ ],
+ ],
+ [
+ 'text' => 'dir3',
+ 'id' => 'dir3',
+ 'li_attr' => ['data-id' => 'dir3'],
+ 'path' => 'dir3',
+ 'path_array' => ['dir3'],
+ 'children' =>
+ [
+ [
+ 'text' => 'dir3_1',
+ 'id' => 'dir3/dir3_1',
+ 'li_attr' => ['data-id' => 'dir3/dir3_1'],
+ 'path' => 'dir3/dir3_1',
+ 'path_array' => ['dir3', 'dir3_1'],
+ 'children' =>
+ [
+ [
+ 'text' => 'dir3_1_1',
+ 'id' => 'dir3/dir3_1/dir3_1_1',
+ 'li_attr' => ['data-id' => 'dir3/dir3_1/dir3_1_1'],
+ 'path' => 'dir3/dir3_1/dir3_1_1',
+ 'path_array' => ['dir3', 'dir3_1', 'dir3_1_1'],
+ 'children' =>
+ [
+ [
+ 'text' => 'dir3_1_1_1',
+ 'id' => 'dir3/dir3_1/dir3_1_1/dir3_1_1_1',
+ 'li_attr' => [
+ 'data-id' => 'dir3/dir3_1/dir3_1_1/dir3_1_1_1',
+ ],
+ 'path' => 'dir3/dir3_1/dir3_1_1/dir3_1_1_1',
+ 'path_array' => [
+ 'dir3',
+ 'dir3_1',
+ 'dir3_1_1',
+ 'dir3_1_1_1',
+ ],
+ 'children' => [],
+ ],
+ ],
+ ],
+ ],
+ ]
+ ],
+ ],
+ ]
+
+ ],
+ [
+ ['dir2/dir2_1', 'dir2/dir2_2'],
+ [
+ [
+ 'text' => 'dir2_1',
+ 'id' => 'dir2/dir2_1',
+ 'li_attr' => ['data-id' => 'dir2/dir2_1'],
+ 'path' => 'dir2/dir2_1',
+ 'path_array' => ['dir2', 'dir2_1'],
+ 'children' =>
+ [
+ [
+ 'text' => 'dir2_1_1',
+ 'id' => 'dir2/dir2_1/dir2_1_1',
+ 'li_attr' =>
+ [
+ 'data-id' => 'dir2/dir2_1/dir2_1_1',
+ ],
+ 'path' => 'dir2/dir2_1/dir2_1_1',
+ 'path_array' => ['dir2', 'dir2_1', 'dir2_1_1'],
+ 'children' => [],
+ ]
+ ],
+ ],
+ [
+ 'text' => 'dir2_2',
+ 'id' => 'dir2/dir2_2',
+ 'li_attr' => ['data-id' => 'dir2/dir2_2'],
+ 'path' => 'dir2/dir2_2',
+ 'path_array' => ['dir2', 'dir2_2'],
+ 'children' =>
+ [
+ [
+ 'text' => 'dir2_2_1',
+ 'id' => 'dir2/dir2_2/dir2_2_1',
+ 'li_attr' =>
+ [
+ 'data-id' => 'dir2/dir2_2/dir2_2_1',
+ ],
+ 'path' => 'dir2/dir2_2/dir2_2_1',
+ 'path_array' => ['dir2', 'dir2_2', 'dir2_2_1'],
+ 'children' => [],
+ ],
+ [
+ 'text' => 'dir2_2_2',
+ 'id' => 'dir2/dir2_2/dir2_2_2',
+ 'li_attr' => ['data-id' => 'dir2/dir2_2/dir2_2_2'],
+ 'path' => 'dir2/dir2_2/dir2_2_2',
+ 'path_array' => ['dir2', 'dir2_2', 'dir2_2_2'],
+ 'children' => [],
+ ],
+ ],
+ ]
+ ]
+ ]
+ ];
+ }
+
+ /**
+ * @param array $array
+ * @param string $prefix
+ * @return array
+ */
+ private function flattenFoldersStructure(array $array, string $prefix = ''): array
+ {
+ $paths = [];
+ foreach ($array as $key => $value) {
+ $path = $prefix . $key;
+ $paths[] = [$path];
+ $paths[] = $this->flattenFoldersStructure($value, $path . '/');
+ }
+ return array_merge(...$paths);
+ }
+}
diff --git a/app/code/Magento/MediaGalleryUi/composer.json b/app/code/Magento/MediaGalleryUi/composer.json
index c95c16cfc8ad2..d5caac3ff409e 100644
--- a/app/code/Magento/MediaGalleryUi/composer.json
+++ b/app/code/Magento/MediaGalleryUi/composer.json
@@ -2,7 +2,7 @@
"name": "magento/module-media-gallery-ui",
"description": "Magento module responsible for the media gallery UI implementation",
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-backend": "*",
"magento/module-ui": "*",
diff --git a/app/code/Magento/MediaGalleryUiApi/composer.json b/app/code/Magento/MediaGalleryUiApi/composer.json
index b1078e8e3a4f7..9c6aa225fa058 100644
--- a/app/code/Magento/MediaGalleryUiApi/composer.json
+++ b/app/code/Magento/MediaGalleryUiApi/composer.json
@@ -2,7 +2,7 @@
"name": "magento/module-media-gallery-ui-api",
"description": "Magento module responsible for the media gallery UI implementation API",
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*"
},
"suggest": {
diff --git a/app/code/Magento/MediaStorage/composer.json b/app/code/Magento/MediaStorage/composer.json
index 1654e1645e7ba..f58c5d9b808c3 100644
--- a/app/code/Magento/MediaStorage/composer.json
+++ b/app/code/Magento/MediaStorage/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/framework-bulk": "*",
"magento/module-backend": "*",
diff --git a/app/code/Magento/MessageQueue/composer.json b/app/code/Magento/MessageQueue/composer.json
index 2038e14ad32ed..7a297574ec8b2 100644
--- a/app/code/Magento/MessageQueue/composer.json
+++ b/app/code/Magento/MessageQueue/composer.json
@@ -8,7 +8,7 @@
"magento/framework": "*",
"magento/framework-message-queue": "*",
"magento/magento-composer-installer": "*",
- "php": "~7.4.0||~8.1.0"
+ "php": "~8.1.0||~8.2.0"
},
"type": "magento2-module",
"license": [
diff --git a/app/code/Magento/Msrp/composer.json b/app/code/Magento/Msrp/composer.json
index 926b35621be3d..1614f33d6c20c 100644
--- a/app/code/Magento/Msrp/composer.json
+++ b/app/code/Magento/Msrp/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-catalog": "*",
"magento/module-downloadable": "*",
diff --git a/app/code/Magento/MsrpConfigurableProduct/composer.json b/app/code/Magento/MsrpConfigurableProduct/composer.json
index 067a89c0be42a..c58e77c047b2d 100644
--- a/app/code/Magento/MsrpConfigurableProduct/composer.json
+++ b/app/code/Magento/MsrpConfigurableProduct/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-catalog": "*",
"magento/module-msrp": "*",
diff --git a/app/code/Magento/MsrpGroupedProduct/composer.json b/app/code/Magento/MsrpGroupedProduct/composer.json
index 0ea4a60098282..1dea4b9949058 100644
--- a/app/code/Magento/MsrpGroupedProduct/composer.json
+++ b/app/code/Magento/MsrpGroupedProduct/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-catalog": "*",
"magento/module-msrp": "*",
diff --git a/app/code/Magento/Multishipping/composer.json b/app/code/Magento/Multishipping/composer.json
index e796d7fd01b11..3ea9380da0809 100644
--- a/app/code/Magento/Multishipping/composer.json
+++ b/app/code/Magento/Multishipping/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-checkout": "*",
"magento/module-customer": "*",
diff --git a/app/code/Magento/MysqlMq/composer.json b/app/code/Magento/MysqlMq/composer.json
index 8b62c6daf183c..b164a3b63aad4 100644
--- a/app/code/Magento/MysqlMq/composer.json
+++ b/app/code/Magento/MysqlMq/composer.json
@@ -9,7 +9,7 @@
"magento/framework-message-queue": "*",
"magento/magento-composer-installer": "*",
"magento/module-store": "*",
- "php": "~7.4.0||~8.1.0"
+ "php": "~8.1.0||~8.2.0"
},
"type": "magento2-module",
"license": [
diff --git a/app/code/Magento/NewRelicReporting/composer.json b/app/code/Magento/NewRelicReporting/composer.json
index b566a7117dc48..e98f914082fab 100644
--- a/app/code/Magento/NewRelicReporting/composer.json
+++ b/app/code/Magento/NewRelicReporting/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/magento-composer-installer": "*",
"magento/module-backend": "*",
diff --git a/app/code/Magento/Newsletter/composer.json b/app/code/Magento/Newsletter/composer.json
index 9c3e3627e4cea..c477f8ecb64e3 100644
--- a/app/code/Magento/Newsletter/composer.json
+++ b/app/code/Magento/Newsletter/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-backend": "*",
"magento/module-cms": "*",
diff --git a/app/code/Magento/NewsletterGraphQl/composer.json b/app/code/Magento/NewsletterGraphQl/composer.json
index 03fa7650257fb..3fe7f7aaf289a 100644
--- a/app/code/Magento/NewsletterGraphQl/composer.json
+++ b/app/code/Magento/NewsletterGraphQl/composer.json
@@ -6,7 +6,7 @@
},
"type": "magento2-module",
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-customer": "*",
"magento/module-newsletter": "*",
diff --git a/app/code/Magento/OfflinePayments/composer.json b/app/code/Magento/OfflinePayments/composer.json
index cdd383aee71e5..09de8b66996ad 100644
--- a/app/code/Magento/OfflinePayments/composer.json
+++ b/app/code/Magento/OfflinePayments/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-checkout": "*",
"magento/module-payment": "*",
diff --git a/app/code/Magento/OfflinePayments/etc/config.xml b/app/code/Magento/OfflinePayments/etc/config.xml
index 94a0a45f00ef7..64606a07ce8ba 100644
--- a/app/code/Magento/OfflinePayments/etc/config.xml
+++ b/app/code/Magento/OfflinePayments/etc/config.xml
@@ -40,10 +40,6 @@
0
offline
-
- offline
- authorize_capture
-
diff --git a/app/code/Magento/OfflineShipping/composer.json b/app/code/Magento/OfflineShipping/composer.json
index e58f678e47770..9e75d64075f84 100644
--- a/app/code/Magento/OfflineShipping/composer.json
+++ b/app/code/Magento/OfflineShipping/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-backend": "*",
"magento/module-catalog": "*",
diff --git a/app/code/Magento/OpenSearch/Model/OpenSearch.php b/app/code/Magento/OpenSearch/Model/OpenSearch.php
new file mode 100644
index 0000000000000..b658e0012a26d
--- /dev/null
+++ b/app/code/Magento/OpenSearch/Model/OpenSearch.php
@@ -0,0 +1,53 @@
+ $index,
+ 'body' => [
+ 'properties' => [],
+ 'dynamic_templates' => $this->dynamicTemplatesProvider->getTemplates(),
+ ],
+ ];
+
+ foreach ($this->applyFieldsMappingPreprocessors($fields) as $field => $fieldInfo) {
+ $params['body']['properties'][$field] = $fieldInfo;
+ }
+
+ $this->getOpenSearchClient()->indices()->putMapping($params);
+ }
+
+ /**
+ * Execute search by $query
+ *
+ * @param array $query
+ * @return array
+ */
+ public function query(array $query): array
+ {
+ unset($query['type']);
+ return $this->getOpenSearchClient()->search($query);
+ }
+}
diff --git a/app/code/Magento/OpenSearch/Model/SearchClient.php b/app/code/Magento/OpenSearch/Model/SearchClient.php
index feb6f952a20f4..dbce79c2496bb 100644
--- a/app/code/Magento/OpenSearch/Model/SearchClient.php
+++ b/app/code/Magento/OpenSearch/Model/SearchClient.php
@@ -42,7 +42,7 @@ class SearchClient implements ClientInterface
/**
* @var DynamicTemplatesProvider|null
*/
- private $dynamicTemplatesProvider;
+ public $dynamicTemplatesProvider;
/**
* Initialize Client
@@ -93,7 +93,7 @@ public function suggest(array $query): array
*
* @return Client
*/
- private function getOpenSearchClient(): Client
+ public function getOpenSearchClient(): Client
{
$pid = getmypid();
if (!isset($this->client[$pid])) {
@@ -371,7 +371,7 @@ public function deleteMapping(string $index, string $entityType)
* @param array $properties
* @return array
*/
- private function applyFieldsMappingPreprocessors(array $properties): array
+ public function applyFieldsMappingPreprocessors(array $properties): array
{
foreach ($this->fieldsMappingPreprocessors as $preprocessor) {
$properties = $preprocessor->process($properties);
diff --git a/app/code/Magento/OpenSearch/Test/Mftf/Test/OpenSearchUpgradeVersion2xTest.xml b/app/code/Magento/OpenSearch/Test/Mftf/Test/OpenSearchUpgradeVersion2xTest.xml
new file mode 100644
index 0000000000000..7f694a1168f6c
--- /dev/null
+++ b/app/code/Magento/OpenSearch/Test/Mftf/Test/OpenSearchUpgradeVersion2xTest.xml
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/OpenSearch/Test/Unit/Model/OpenSearchTest.php b/app/code/Magento/OpenSearch/Test/Unit/Model/OpenSearchTest.php
new file mode 100644
index 0000000000000..5fa55dcab9ca5
--- /dev/null
+++ b/app/code/Magento/OpenSearch/Test/Unit/Model/OpenSearchTest.php
@@ -0,0 +1,201 @@
+opensearchV2ClientMock = $this->getMockBuilder(Client::class)
+ ->setMethods(
+ [
+ 'indices',
+ 'search'
+ ]
+ )
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $this->indicesMock = $this->getMockBuilder(IndicesNamespace::class)
+ ->setMethods(
+ [
+ 'putMapping'
+ ]
+ )
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $this->opensearchV2ClientMock->expects($this->any())
+ ->method('indices')
+ ->willReturn($this->indicesMock);
+
+ $this->objectManager = new ObjectManagerHelper($this);
+ $dynamicTemplatesProvider = new DynamicTemplatesProvider(
+ [ new PriceMapper(), new PositionMapper(), new StringMapper(), new IntegerMapper()]
+ );
+ $this->model = $this->objectManager->getObject(
+ OpenSearch::class,
+ [
+ 'options' => $this->getOptions(),
+ 'openSearchClient' => $this->opensearchV2ClientMock,
+ 'fieldsMappingPreprocessors' => [new AddDefaultSearchField()],
+ 'dynamicTemplatesProvider' => $dynamicTemplatesProvider,
+ ]
+ );
+ }
+
+ /**
+ * Test query() method
+ *
+ * @return void
+ */
+ public function testQuery()
+ {
+ $query = ['test phrase query'];
+ $this->opensearchV2ClientMock->expects($this->once())
+ ->method('search')
+ ->with($query)
+ ->willReturn([]);
+ $this->assertEquals([], $this->model->query($query));
+ }
+ /**
+ * Get client options
+ *
+ * @return array
+ */
+ protected function getOptions()
+ {
+ return [
+ 'hostname' => 'localhost',
+ 'port' => '9200',
+ 'timeout' => 15,
+ 'index' => 'magento2',
+ 'enableAuth' => 1,
+ 'username' => 'user',
+ 'password' => 'passwd',
+ ];
+ }
+
+ /**
+ * Test testAddFieldsMapping() method
+ */
+ public function testAddFieldsMapping()
+ {
+ $this->indicesMock->expects($this->once())
+ ->method('putMapping')
+ ->with(
+ [
+ 'index' => 'indexName',
+ 'body' => [
+ 'properties' => [
+ '_search' => [
+ 'type' => 'text',
+ ],
+ 'name' => [
+ 'type' => 'text',
+ ],
+ ],
+ 'dynamic_templates' => [
+ [
+ 'price_mapping' => [
+ 'match' => 'price_*',
+ 'match_mapping_type' => 'string',
+ 'mapping' => [
+ 'type' => 'double',
+ 'store' => true,
+ ],
+ ],
+ ],
+ [
+ 'position_mapping' => [
+ 'match' => 'position_*',
+ 'match_mapping_type' => 'string',
+ 'mapping' => [
+ 'type' => 'integer',
+ 'index' => true,
+ ],
+ ],
+ ],
+ [
+ 'string_mapping' => [
+ 'match' => '*',
+ 'match_mapping_type' => 'string',
+ 'mapping' => [
+ 'type' => 'text',
+ 'index' => true,
+ 'copy_to' => '_search',
+ ],
+ ],
+ ],
+ [
+ 'integer_mapping' => [
+ 'match_mapping_type' => 'long',
+ 'mapping' => [
+ 'type' => 'integer',
+ ],
+ ],
+ ],
+ ],
+ ],
+ ]
+ );
+ $this->model->addFieldsMapping(
+ [
+ 'name' => [
+ 'type' => 'text',
+ ],
+ ],
+ 'indexName',
+ 'product'
+ );
+ }
+}
diff --git a/app/code/Magento/OpenSearch/composer.json b/app/code/Magento/OpenSearch/composer.json
index 7415ee9ef7066..1b9e006b9e9b1 100644
--- a/app/code/Magento/OpenSearch/composer.json
+++ b/app/code/Magento/OpenSearch/composer.json
@@ -2,14 +2,14 @@
"name": "magento/module-open-search",
"description": "N/A",
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-advanced-search": "*",
"magento/module-catalog-search": "*",
"magento/module-elasticsearch": "*",
"magento/module-search": "*",
"magento/module-config": "*",
- "opensearch-project/opensearch-php": "~1.0.0"
+ "opensearch-project/opensearch-php": "^1.0 || ^2.0"
},
"type": "magento2-module",
"license": [
diff --git a/app/code/Magento/OpenSearch/etc/di.xml b/app/code/Magento/OpenSearch/etc/di.xml
index 65d4ddb7dc546..ad1072165ad48 100644
--- a/app/code/Magento/OpenSearch/etc/di.xml
+++ b/app/code/Magento/OpenSearch/etc/di.xml
@@ -75,6 +75,7 @@
Magento\OpenSearch\Model\SearchClient
+ Magento\OpenSearch\Model\OpenSearch
diff --git a/app/code/Magento/PageCache/composer.json b/app/code/Magento/PageCache/composer.json
index eef0e5edd3824..494b5918004d8 100644
--- a/app/code/Magento/PageCache/composer.json
+++ b/app/code/Magento/PageCache/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-backend": "*",
"magento/module-config": "*",
diff --git a/app/code/Magento/Payment/composer.json b/app/code/Magento/Payment/composer.json
index 2f09f9b0c237f..36cd77ea50d47 100644
--- a/app/code/Magento/Payment/composer.json
+++ b/app/code/Magento/Payment/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-checkout": "*",
"magento/module-config": "*",
diff --git a/app/code/Magento/Payment/etc/adminhtml/system.xml b/app/code/Magento/Payment/etc/adminhtml/system.xml
index 1e8b617d31326..47b5ea4626a0e 100644
--- a/app/code/Magento/Payment/etc/adminhtml/system.xml
+++ b/app/code/Magento/Payment/etc/adminhtml/system.xml
@@ -24,9 +24,7 @@
Automatically Invoice All Items
Magento\Payment\Model\Source\Invoice
-
- processing
-
+ If 'Automatically Invoice All Items' is set to 'Yes', the order is placed in 'Processing' state.
Sort Order
diff --git a/app/code/Magento/Payment/etc/config.xml b/app/code/Magento/Payment/etc/config.xml
index 663734fb066c7..4846e5d7d5c3a 100644
--- a/app/code/Magento/Payment/etc/config.xml
+++ b/app/code/Magento/Payment/etc/config.xml
@@ -12,10 +12,11 @@
1
Magento\Payment\Model\Method\Free
pending
+ authorize_capture
No Payment Information Required
- authorize
0
1
+ offline
0
diff --git a/app/code/Magento/PaymentGraphQl/composer.json b/app/code/Magento/PaymentGraphQl/composer.json
index 8332d7dee0a4a..e6ab6fc747768 100644
--- a/app/code/Magento/PaymentGraphQl/composer.json
+++ b/app/code/Magento/PaymentGraphQl/composer.json
@@ -3,7 +3,7 @@
"description": "N/A",
"type": "magento2-module",
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-payment": "*",
"magento/module-graph-ql": "*"
diff --git a/app/code/Magento/Paypal/composer.json b/app/code/Magento/Paypal/composer.json
index b157a63fefeb2..23ebf05f2f2bc 100644
--- a/app/code/Magento/Paypal/composer.json
+++ b/app/code/Magento/Paypal/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"lib-libxml": "*",
"magento/framework": "*",
"magento/module-authorization": "*",
diff --git a/app/code/Magento/PaypalCaptcha/composer.json b/app/code/Magento/PaypalCaptcha/composer.json
index 3f1f5bad59c3b..8c9feff31e823 100644
--- a/app/code/Magento/PaypalCaptcha/composer.json
+++ b/app/code/Magento/PaypalCaptcha/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-captcha": "*",
"magento/module-checkout": "*",
diff --git a/app/code/Magento/PaypalGraphQl/composer.json b/app/code/Magento/PaypalGraphQl/composer.json
index ea8a43c64257d..ce916276dac97 100644
--- a/app/code/Magento/PaypalGraphQl/composer.json
+++ b/app/code/Magento/PaypalGraphQl/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-quote": "*",
"magento/module-checkout": "*",
diff --git a/app/code/Magento/Persistent/composer.json b/app/code/Magento/Persistent/composer.json
index 3e4b24c38b92b..5a8ff5d7f3d5f 100644
--- a/app/code/Magento/Persistent/composer.json
+++ b/app/code/Magento/Persistent/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-checkout": "*",
"magento/module-cron": "*",
diff --git a/app/code/Magento/ProductAlert/composer.json b/app/code/Magento/ProductAlert/composer.json
index 8533a0e37443e..aee755e6a00b0 100644
--- a/app/code/Magento/ProductAlert/composer.json
+++ b/app/code/Magento/ProductAlert/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/framework-bulk": "*",
"magento/module-asynchronous-operations": "*",
diff --git a/app/code/Magento/ProductVideo/composer.json b/app/code/Magento/ProductVideo/composer.json
index b6c7a51914295..55b8cb5efa14b 100644
--- a/app/code/Magento/ProductVideo/composer.json
+++ b/app/code/Magento/ProductVideo/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/magento-composer-installer": "*",
"magento/module-backend": "*",
diff --git a/app/code/Magento/Quote/Model/Cart/AddProductsToCart.php b/app/code/Magento/Quote/Model/Cart/AddProductsToCart.php
index 2086646d855f8..9be1e9d32e379 100644
--- a/app/code/Magento/Quote/Model/Cart/AddProductsToCart.php
+++ b/app/code/Magento/Quote/Model/Cart/AddProductsToCart.php
@@ -7,8 +7,6 @@
namespace Magento\Quote\Model\Cart;
-use Magento\Catalog\Api\ProductRepositoryInterface;
-use Magento\Framework\App\ObjectManager;
use Magento\Framework\Exception\NoSuchEntityException;
use Magento\Quote\Api\CartRepositoryInterface;
use Magento\Quote\Model\Cart\BuyRequest\BuyRequestBuilder;
@@ -23,29 +21,6 @@
*/
class AddProductsToCart
{
- /**#@+
- * Error message codes
- */
- private const ERROR_PRODUCT_NOT_FOUND = 'PRODUCT_NOT_FOUND';
- private const ERROR_INSUFFICIENT_STOCK = 'INSUFFICIENT_STOCK';
- private const ERROR_NOT_SALABLE = 'NOT_SALABLE';
- private const ERROR_UNDEFINED = 'UNDEFINED';
- /**#@-*/
-
- /**
- * List of error messages and codes.
- */
- private const MESSAGE_CODES = [
- 'Could not find a product with SKU' => self::ERROR_PRODUCT_NOT_FOUND,
- 'The required options you selected are not available' => self::ERROR_NOT_SALABLE,
- 'Product that you are trying to add is not available.' => self::ERROR_NOT_SALABLE,
- 'This product is out of stock' => self::ERROR_INSUFFICIENT_STOCK,
- 'There are no source items' => self::ERROR_NOT_SALABLE,
- 'The fewest you may purchase is' => self::ERROR_INSUFFICIENT_STOCK,
- 'The most you may purchase is' => self::ERROR_INSUFFICIENT_STOCK,
- 'The requested qty is not available' => self::ERROR_INSUFFICIENT_STOCK,
- ];
-
/**
* @var CartRepositoryInterface
*/
@@ -67,25 +42,29 @@ class AddProductsToCart
private $productReader;
/**
- * @param ProductRepositoryInterface $productRepository
+ * @var AddProductsToCartError
+ */
+ private $error;
+
+ /**
* @param CartRepositoryInterface $cartRepository
* @param MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId
* @param BuyRequestBuilder $requestBuilder
- * @param ProductReaderInterface|null $productReader
- *
- * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+ * @param ProductReaderInterface $productReader
+ * @param AddProductsToCartError $addProductsToCartError
*/
public function __construct(
- ProductRepositoryInterface $productRepository,
CartRepositoryInterface $cartRepository,
MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId,
BuyRequestBuilder $requestBuilder,
- ProductReaderInterface $productReader = null
+ ProductReaderInterface $productReader,
+ AddProductsToCartError $addProductsToCartError
) {
$this->cartRepository = $cartRepository;
$this->maskedQuoteIdToQuoteId = $maskedQuoteIdToQuoteId;
$this->requestBuilder = $requestBuilder;
- $this->productReader = $productReader ?: ObjectManager::getInstance()->get(ProductReaderInterface::class);
+ $this->productReader = $productReader;
+ $this->error = $addProductsToCartError;
}
/**
@@ -106,7 +85,7 @@ public function execute(string $maskedCartId, array $cartItems): AddProductsToCa
/** @var MessageInterface $error */
foreach ($errors as $error) {
- $allErrors[] = $this->createError($error->getText());
+ $allErrors[] = $this->error->create($error->getText());
}
}
@@ -181,14 +160,14 @@ private function addItemToCart(Quote $cart, Data\CartItem $cartItem, int $cartIt
$result = null;
if ($cartItem->getQuantity() <= 0) {
- $errors[] = $this->createError(
+ $errors[] = $this->error->create(
__('The product quantity should be greater than 0')->render(),
$cartItemPosition
);
} else {
$product = $this->productReader->getProductBySku($sku);
if (!$product || !$product->isSaleable() || !$product->isAvailable()) {
- $errors[] = $this->createError(
+ $errors[] = $this->error->create(
__('Could not find a product with SKU "%sku"', ['sku' => $sku])->render(),
$cartItemPosition
);
@@ -196,7 +175,7 @@ private function addItemToCart(Quote $cart, Data\CartItem $cartItem, int $cartIt
try {
$result = $cart->addProduct($product, $this->requestBuilder->build($cartItem));
} catch (\Throwable $e) {
- $errors[] = $this->createError(
+ $errors[] = $this->error->create(
__($e->getMessage())->render(),
$cartItemPosition
);
@@ -205,7 +184,7 @@ private function addItemToCart(Quote $cart, Data\CartItem $cartItem, int $cartIt
if (is_string($result)) {
foreach (array_unique(explode("\n", $result)) as $error) {
- $errors[] = $this->createError(__($error)->render(), $cartItemPosition);
+ $errors[] = $this->error->create(__($error)->render(), $cartItemPosition);
}
}
}
@@ -213,42 +192,6 @@ private function addItemToCart(Quote $cart, Data\CartItem $cartItem, int $cartIt
return $errors;
}
- /**
- * Returns an error object
- *
- * @param string $message
- * @param int $cartItemPosition
- * @return Data\Error
- */
- private function createError(string $message, int $cartItemPosition = 0): Data\Error
- {
- return new Data\Error(
- $message,
- $this->getErrorCode($message),
- $cartItemPosition
- );
- }
-
- /**
- * Get message error code.
- *
- * TODO: introduce a separate class for getting error code from a message
- *
- * @param string $message
- * @return string
- */
- private function getErrorCode(string $message): string
- {
- foreach (self::MESSAGE_CODES as $codeMessage => $code) {
- if (false !== stripos($message, $codeMessage)) {
- return $code;
- }
- }
-
- /* If no code was matched, return the default one */
- return self::ERROR_UNDEFINED;
- }
-
/**
* Creates a new output from existing errors
*
diff --git a/app/code/Magento/Quote/Model/Cart/AddProductsToCartError.php b/app/code/Magento/Quote/Model/Cart/AddProductsToCartError.php
new file mode 100644
index 0000000000000..fe8c0d72d4655
--- /dev/null
+++ b/app/code/Magento/Quote/Model/Cart/AddProductsToCartError.php
@@ -0,0 +1,71 @@
+ self::ERROR_PRODUCT_NOT_FOUND,
+ 'The required options you selected are not available' => self::ERROR_NOT_SALABLE,
+ 'Product that you are trying to add is not available.' => self::ERROR_NOT_SALABLE,
+ 'This product is out of stock' => self::ERROR_INSUFFICIENT_STOCK,
+ 'There are no source items' => self::ERROR_NOT_SALABLE,
+ 'The fewest you may purchase is' => self::ERROR_INSUFFICIENT_STOCK,
+ 'The most you may purchase is' => self::ERROR_INSUFFICIENT_STOCK,
+ 'The requested qty is not available' => self::ERROR_INSUFFICIENT_STOCK,
+ ];
+
+ /**
+ * Returns an error object
+ *
+ * @param string $message
+ * @param int $cartItemPosition
+ * @return Data\Error
+ */
+ public function create(string $message, int $cartItemPosition = 0): Data\Error
+ {
+ return new Data\Error(
+ $message,
+ $this->getErrorCode($message),
+ $cartItemPosition
+ );
+ }
+
+ /**
+ * Get message error code.
+ *
+ * @param string $message
+ * @return string
+ */
+ private function getErrorCode(string $message): string
+ {
+ foreach (self::MESSAGE_CODES as $codeMessage => $code) {
+ if (false !== stripos($message, $codeMessage)) {
+ return $code;
+ }
+ }
+
+ /* If no code was matched, return the default one */
+ return self::ERROR_UNDEFINED;
+ }
+}
diff --git a/app/code/Magento/Quote/composer.json b/app/code/Magento/Quote/composer.json
index 922f3d36fa918..1552e71351af7 100644
--- a/app/code/Magento/Quote/composer.json
+++ b/app/code/Magento/Quote/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-authorization": "*",
"magento/module-backend": "*",
diff --git a/app/code/Magento/QuoteAnalytics/composer.json b/app/code/Magento/QuoteAnalytics/composer.json
index 038553b4d487e..c9e9254aa7968 100644
--- a/app/code/Magento/QuoteAnalytics/composer.json
+++ b/app/code/Magento/QuoteAnalytics/composer.json
@@ -2,7 +2,7 @@
"name": "magento/module-quote-analytics",
"description": "N/A",
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-quote": "*",
"magento/module-analytics": "*"
diff --git a/app/code/Magento/QuoteBundleOptions/composer.json b/app/code/Magento/QuoteBundleOptions/composer.json
index 79ad425b2d359..2412e9d23b329 100644
--- a/app/code/Magento/QuoteBundleOptions/composer.json
+++ b/app/code/Magento/QuoteBundleOptions/composer.json
@@ -2,7 +2,7 @@
"name": "magento/module-quote-bundle-options",
"description": "Magento module provides data provider for creating buy request for bundle products",
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-quote": "*"
},
diff --git a/app/code/Magento/QuoteConfigurableOptions/composer.json b/app/code/Magento/QuoteConfigurableOptions/composer.json
index 2da064db42965..35dee93c0b12a 100644
--- a/app/code/Magento/QuoteConfigurableOptions/composer.json
+++ b/app/code/Magento/QuoteConfigurableOptions/composer.json
@@ -2,7 +2,7 @@
"name": "magento/module-quote-configurable-options",
"description": "Magento module provides data provider for creating buy request for configurable products",
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-quote": "*"
},
diff --git a/app/code/Magento/QuoteDownloadableLinks/composer.json b/app/code/Magento/QuoteDownloadableLinks/composer.json
index 2b4dcc3331b8e..47030735c6081 100644
--- a/app/code/Magento/QuoteDownloadableLinks/composer.json
+++ b/app/code/Magento/QuoteDownloadableLinks/composer.json
@@ -2,7 +2,7 @@
"name": "magento/module-quote-downloadable-links",
"description": "Magento module provides data provider for creating buy request for links of downloadable products",
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-quote": "*"
},
diff --git a/app/code/Magento/QuoteGraphQl/Model/Cart/GetCartForCheckout.php b/app/code/Magento/QuoteGraphQl/Model/Cart/GetCartForCheckout.php
new file mode 100644
index 0000000000000..4b2d1afdea003
--- /dev/null
+++ b/app/code/Magento/QuoteGraphQl/Model/Cart/GetCartForCheckout.php
@@ -0,0 +1,73 @@
+checkoutAllowance = $checkoutAllowance;
+ $this->getCartForUser = $getCartForUser;
+ }
+
+ /**
+ * Gets the cart for the user validated and configured for guest checkout if applicable
+ *
+ * @param string $cartHash
+ * @param int|null $customerId
+ * @param int $storeId
+ * @return Quote
+ * @throws GraphQlAuthorizationException
+ * @throws GraphQlInputException
+ * @throws GraphQlNoSuchEntityException
+ */
+ public function execute(string $cartHash, ?int $customerId, int $storeId): Quote
+ {
+ try {
+ $cart = $this->getCartForUser->execute($cartHash, $customerId, $storeId);
+ } catch (NoSuchEntityException $e) {
+ throw new GraphQlNoSuchEntityException(__($e->getMessage()), $e);
+ }
+ $this->checkoutAllowance->execute($cart);
+
+ if (null === $customerId || 0 === $customerId) {
+ if (!$cart->getCustomerEmail()) {
+ throw new GraphQlInputException(__("Guest email for cart is missing."));
+ }
+ $cart->setCheckoutMethod(CartManagementInterface::METHOD_GUEST);
+ }
+
+ return $cart;
+ }
+}
diff --git a/app/code/Magento/QuoteGraphQl/Model/Cart/GetCartForUser.php b/app/code/Magento/QuoteGraphQl/Model/Cart/GetCartForUser.php
index 21df9465a08e6..77a31cc3cd023 100644
--- a/app/code/Magento/QuoteGraphQl/Model/Cart/GetCartForUser.php
+++ b/app/code/Magento/QuoteGraphQl/Model/Cart/GetCartForUser.php
@@ -7,16 +7,13 @@
namespace Magento\QuoteGraphQl\Model\Cart;
-use Magento\Framework\App\ObjectManager;
use Magento\Framework\Exception\NoSuchEntityException;
use Magento\Framework\GraphQl\Exception\GraphQlAuthorizationException;
use Magento\Framework\GraphQl\Exception\GraphQlInputException;
use Magento\Framework\GraphQl\Exception\GraphQlNoSuchEntityException;
-use Magento\Quote\Api\CartManagementInterface;
use Magento\Quote\Api\CartRepositoryInterface;
use Magento\Quote\Model\MaskedQuoteIdToQuoteIdInterface;
use Magento\Quote\Model\Quote;
-use Magento\Store\Api\StoreRepositoryInterface;
/**
* Get cart
@@ -34,31 +31,31 @@ class GetCartForUser
private $cartRepository;
/**
- * @var CheckCartCheckoutAllowance
+ * @var IsActive
*/
- private $checkoutAllowance;
+ private $isActive;
/**
- * @var StoreRepositoryInterface
+ * @var UpdateCartCurrency
*/
- private $storeRepository;
+ private $updateCartCurrency;
/**
* @param MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId
* @param CartRepositoryInterface $cartRepository
- * @param CheckCartCheckoutAllowance $checkoutAllowance
- * @param StoreRepositoryInterface $storeRepository
+ * @param IsActive $isActive
+ * @param UpdateCartCurrency $updateCartCurrency
*/
public function __construct(
MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId,
CartRepositoryInterface $cartRepository,
- CheckCartCheckoutAllowance $checkoutAllowance,
- StoreRepositoryInterface $storeRepository = null
+ IsActive $isActive,
+ UpdateCartCurrency $updateCartCurrency
) {
$this->maskedQuoteIdToQuoteId = $maskedQuoteIdToQuoteId;
$this->cartRepository = $cartRepository;
- $this->checkoutAllowance = $checkoutAllowance;
- $this->storeRepository = $storeRepository ?: ObjectManager::getInstance()->get(StoreRepositoryInterface::class);
+ $this->isActive = $isActive;
+ $this->updateCartCurrency = $updateCartCurrency;
}
/**
@@ -77,26 +74,19 @@ public function execute(string $cartHash, ?int $customerId, int $storeId): Quote
{
try {
$cartId = $this->maskedQuoteIdToQuoteId->execute($cartHash);
- } catch (NoSuchEntityException $exception) {
- throw new GraphQlNoSuchEntityException(
- __('Could not find a cart with ID "%masked_cart_id"', ['masked_cart_id' => $cartHash])
- );
- }
-
- try {
/** @var Quote $cart */
$cart = $this->cartRepository->get($cartId);
- } catch (NoSuchEntityException $e) {
+ } catch (NoSuchEntityException $exception) {
throw new GraphQlNoSuchEntityException(
__('Could not find a cart with ID "%masked_cart_id"', ['masked_cart_id' => $cartHash])
);
}
- if (false === (bool)$cart->getIsActive()) {
+ if (false === (bool)$this->isActive->execute($cart)) {
throw new GraphQlNoSuchEntityException(__('The cart isn\'t active.'));
}
- $cart = $this->updateCartCurrency($cart, $storeId);
+ $cart = $this->updateCartCurrency->execute($cart, $storeId);
$cartCustomerId = (int)$cart->getCustomerId();
@@ -115,68 +105,4 @@ public function execute(string $cartHash, ?int $customerId, int $storeId): Quote
}
return $cart;
}
-
- /**
- * Gets the cart for the user validated and configured for guest checkout if applicable
- *
- * @param string $cartHash
- * @param int|null $customerId
- * @param int $storeId
- * @return Quote
- * @throws GraphQlAuthorizationException
- * @throws GraphQlInputException
- * @throws GraphQlNoSuchEntityException
- */
- public function getCartForCheckout(string $cartHash, ?int $customerId, int $storeId): Quote
- {
- try {
- $cart = $this->execute($cartHash, $customerId, $storeId);
- } catch (NoSuchEntityException $e) {
- throw new GraphQlNoSuchEntityException(__($e->getMessage()), $e);
- }
- $this->checkoutAllowance->execute($cart);
-
- if ((null === $customerId || 0 === $customerId)) {
- if (!$cart->getCustomerEmail()) {
- throw new GraphQlInputException(__("Guest email for cart is missing."));
- }
- $cart->setCheckoutMethod(CartManagementInterface::METHOD_GUEST);
- }
-
- return $cart;
- }
-
- /**
- * Sets cart currency based on specified store.
- *
- * @param Quote $cart
- * @param int $storeId
- * @return Quote
- * @throws GraphQlInputException
- * @throws NoSuchEntityException
- */
- private function updateCartCurrency(Quote $cart, int $storeId): Quote
- {
- $cartStore = $this->storeRepository->getById($cart->getStoreId());
- $currentCartCurrencyCode = $cartStore->getCurrentCurrency()->getCode();
- if ((int)$cart->getStoreId() !== $storeId) {
- $newStore = $this->storeRepository->getById($storeId);
- if ($cartStore->getWebsite() !== $newStore->getWebsite()) {
- throw new GraphQlInputException(
- __('Can\'t assign cart to store in different website.')
- );
- }
- $cart->setStoreId($storeId);
- $cart->setStoreCurrencyCode($newStore->getCurrentCurrency());
- $cart->setQuoteCurrencyCode($newStore->getCurrentCurrency());
- } elseif ($cart->getQuoteCurrencyCode() !== $currentCartCurrencyCode) {
- $cart->setQuoteCurrencyCode($cartStore->getCurrentCurrency());
- } else {
- return $cart;
- }
- $this->cartRepository->save($cart);
- $cart = $this->cartRepository->get($cart->getId());
-
- return $cart;
- }
}
diff --git a/app/code/Magento/QuoteGraphQl/Model/Cart/IsActive.php b/app/code/Magento/QuoteGraphQl/Model/Cart/IsActive.php
new file mode 100644
index 0000000000000..531d7ba119211
--- /dev/null
+++ b/app/code/Magento/QuoteGraphQl/Model/Cart/IsActive.php
@@ -0,0 +1,27 @@
+getIsActive();
+ }
+}
diff --git a/app/code/Magento/QuoteGraphQl/Model/Cart/UpdateCartCurrency.php b/app/code/Magento/QuoteGraphQl/Model/Cart/UpdateCartCurrency.php
new file mode 100644
index 0000000000000..109ee7b4ef54a
--- /dev/null
+++ b/app/code/Magento/QuoteGraphQl/Model/Cart/UpdateCartCurrency.php
@@ -0,0 +1,74 @@
+cartRepository = $cartRepository;
+ $this->storeRepository = $storeRepository;
+ }
+
+ /**
+ * Sets cart currency based on specified store.
+ *
+ * @param Quote $cart
+ * @param int $storeId
+ * @return Quote
+ * @throws GraphQlInputException|NoSuchEntityException|LocalizedException
+ */
+ public function execute(Quote $cart, int $storeId): Quote
+ {
+ $cartStore = $this->storeRepository->getById($cart->getStoreId());
+ $currentCartCurrencyCode = $cartStore->getCurrentCurrency()->getCode();
+ if ((int)$cart->getStoreId() !== $storeId) {
+ $newStore = $this->storeRepository->getById($storeId);
+ if ($cartStore->getWebsite() !== $newStore->getWebsite()) {
+ throw new GraphQlInputException(
+ __('Can\'t assign cart to store in different website.')
+ );
+ }
+ $cart->setStoreId($storeId);
+ $cart->setStoreCurrencyCode($newStore->getCurrentCurrency());
+ $cart->setQuoteCurrencyCode($newStore->getCurrentCurrency());
+ } elseif ($cart->getQuoteCurrencyCode() !== $currentCartCurrencyCode) {
+ $cart->setQuoteCurrencyCode($cartStore->getCurrentCurrency());
+ } else {
+ return $cart;
+ }
+ $this->cartRepository->save($cart);
+ return $this->cartRepository->get($cart->getId());
+ }
+}
diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/PlaceOrder.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/PlaceOrder.php
index b0fca63018e76..7cbc64a41d37c 100644
--- a/app/code/Magento/QuoteGraphQl/Model/Resolver/PlaceOrder.php
+++ b/app/code/Magento/QuoteGraphQl/Model/Resolver/PlaceOrder.php
@@ -14,8 +14,8 @@
use Magento\Framework\GraphQl\Query\ResolverInterface;
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
use Magento\GraphQl\Helper\Error\AggregateExceptionMessageFormatter;
+use Magento\QuoteGraphQl\Model\Cart\GetCartForCheckout;
use Magento\GraphQl\Model\Query\ContextInterface;
-use Magento\QuoteGraphQl\Model\Cart\GetCartForUser;
use Magento\QuoteGraphQl\Model\Cart\PlaceOrder as PlaceOrderModel;
use Magento\QuoteGraphQl\Model\Cart\PlaceOrderMutexInterface;
use Magento\Sales\Api\OrderRepositoryInterface;
@@ -26,9 +26,9 @@
class PlaceOrder implements ResolverInterface
{
/**
- * @var GetCartForUser
+ * @var GetCartForCheckout
*/
- private $getCartForUser;
+ private $getCartForCheckout;
/**
* @var PlaceOrderModel
@@ -51,20 +51,20 @@ class PlaceOrder implements ResolverInterface
private $placeOrderMutex;
/**
- * @param GetCartForUser $getCartForUser
+ * @param GetCartForCheckout $getCartForCheckout
* @param PlaceOrderModel $placeOrder
* @param OrderRepositoryInterface $orderRepository
* @param AggregateExceptionMessageFormatter $errorMessageFormatter
* @param PlaceOrderMutexInterface|null $placeOrderMutex
*/
public function __construct(
- GetCartForUser $getCartForUser,
+ GetCartForCheckout $getCartForCheckout,
PlaceOrderModel $placeOrder,
OrderRepositoryInterface $orderRepository,
AggregateExceptionMessageFormatter $errorMessageFormatter,
?PlaceOrderMutexInterface $placeOrderMutex = null
) {
- $this->getCartForUser = $getCartForUser;
+ $this->getCartForCheckout = $getCartForCheckout;
$this->placeOrder = $placeOrder;
$this->orderRepository = $orderRepository;
$this->errorMessageFormatter = $errorMessageFormatter;
@@ -104,7 +104,7 @@ private function run(Field $field, ContextInterface $context, ResolveInfo $info,
$storeId = (int)$context->getExtensionAttributes()->getStore()->getId();
try {
- $cart = $this->getCartForUser->getCartForCheckout($maskedCartId, $userId, $storeId);
+ $cart = $this->getCartForCheckout->execute($maskedCartId, $userId, $storeId);
$orderId = $this->placeOrder->execute($cart, $maskedCartId, $userId);
$order = $this->orderRepository->get($orderId);
} catch (LocalizedException $e) {
diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/SetPaymentAndPlaceOrder.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/SetPaymentAndPlaceOrder.php
index 500c2aa359994..1b9ee4ad3907a 100644
--- a/app/code/Magento/QuoteGraphQl/Model/Resolver/SetPaymentAndPlaceOrder.php
+++ b/app/code/Magento/QuoteGraphQl/Model/Resolver/SetPaymentAndPlaceOrder.php
@@ -15,7 +15,7 @@
use Magento\Framework\GraphQl\Exception\GraphQlNoSuchEntityException;
use Magento\Framework\GraphQl\Query\ResolverInterface;
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
-use Magento\QuoteGraphQl\Model\Cart\GetCartForUser;
+use Magento\QuoteGraphQl\Model\Cart\GetCartForCheckout;
use Magento\QuoteGraphQl\Model\Cart\SetPaymentAndPlaceOrder as SetPaymentAndPlaceOrderModel;
use Magento\Sales\Api\OrderRepositoryInterface;
@@ -29,9 +29,9 @@
class SetPaymentAndPlaceOrder implements ResolverInterface
{
/**
- * @var GetCartForUser
+ * @var GetCartForCheckout
*/
- private $getCartForUser;
+ private $getCartForCheckout;
/**
* @var SetPaymentAndPlaceOrderModel
@@ -44,16 +44,16 @@ class SetPaymentAndPlaceOrder implements ResolverInterface
private $orderRepository;
/**
- * @param GetCartForUser $getCartForUser
+ * @param GetCartForCheckout $getCartForCheckout
* @param SetPaymentAndPlaceOrderModel $setPaymentAndPlaceOrder
* @param OrderRepositoryInterface $orderRepository
*/
public function __construct(
- GetCartForUser $getCartForUser,
+ GetCartForCheckout $getCartForCheckout,
SetPaymentAndPlaceOrderModel $setPaymentAndPlaceOrder,
OrderRepositoryInterface $orderRepository
) {
- $this->getCartForUser = $getCartForUser;
+ $this->getCartForCheckout = $getCartForCheckout;
$this->setPaymentAndPlaceOrder = $setPaymentAndPlaceOrder;
$this->orderRepository = $orderRepository;
}
@@ -78,7 +78,7 @@ public function resolve(Field $field, $context, ResolveInfo $info, array $value
$storeId = (int)$context->getExtensionAttributes()->getStore()->getId();
try {
- $cart = $this->getCartForUser->getCartForCheckout($maskedCartId, $userId, $storeId);
+ $cart = $this->getCartForCheckout->execute($maskedCartId, $userId, $storeId);
$orderId = $this->setPaymentAndPlaceOrder->execute($cart, $maskedCartId, $userId, $paymentData);
$order = $this->orderRepository->get($orderId);
} catch (GraphQlInputException | GraphQlNoSuchEntityException | GraphQlAuthorizationException $e) {
diff --git a/app/code/Magento/QuoteGraphQl/composer.json b/app/code/Magento/QuoteGraphQl/composer.json
index 4f885fa33a7b0..24cb1382634c2 100644
--- a/app/code/Magento/QuoteGraphQl/composer.json
+++ b/app/code/Magento/QuoteGraphQl/composer.json
@@ -3,7 +3,7 @@
"description": "N/A",
"type": "magento2-module",
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-quote": "*",
"magento/module-checkout": "*",
diff --git a/app/code/Magento/RelatedProductGraphQl/composer.json b/app/code/Magento/RelatedProductGraphQl/composer.json
index 25bb6dc47722d..9c03a5b18f644 100644
--- a/app/code/Magento/RelatedProductGraphQl/composer.json
+++ b/app/code/Magento/RelatedProductGraphQl/composer.json
@@ -3,7 +3,7 @@
"description": "N/A",
"type": "magento2-module",
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/module-catalog": "*",
"magento/module-catalog-graph-ql": "*",
"magento/framework": "*"
diff --git a/app/code/Magento/ReleaseNotification/composer.json b/app/code/Magento/ReleaseNotification/composer.json
index 039ea30e339be..4ddab4217f32e 100644
--- a/app/code/Magento/ReleaseNotification/composer.json
+++ b/app/code/Magento/ReleaseNotification/composer.json
@@ -2,7 +2,7 @@
"name": "magento/module-release-notification",
"description": "N/A",
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/module-user": "*",
"magento/module-backend": "*",
"magento/module-ui": "*",
diff --git a/app/code/Magento/RemoteStorage/composer.json b/app/code/Magento/RemoteStorage/composer.json
index ff2301d53ea60..107ddf6788fe2 100644
--- a/app/code/Magento/RemoteStorage/composer.json
+++ b/app/code/Magento/RemoteStorage/composer.json
@@ -2,10 +2,10 @@
"name": "magento/module-remote-storage",
"description": "N/A",
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
- "league/flysystem": "~2.4.3",
- "league/flysystem-aws-s3-v3": "^2.4.3"
+ "league/flysystem": "^2.4",
+ "league/flysystem-aws-s3-v3": "^2.4"
},
"suggest": {
"magento/module-backend": "*",
diff --git a/app/code/Magento/Reports/composer.json b/app/code/Magento/Reports/composer.json
index e758e3a739f91..887a9bc1730e3 100644
--- a/app/code/Magento/Reports/composer.json
+++ b/app/code/Magento/Reports/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-backend": "*",
"magento/module-catalog": "*",
diff --git a/app/code/Magento/RequireJs/composer.json b/app/code/Magento/RequireJs/composer.json
index 746b09474ec03..a8dec7db61404 100644
--- a/app/code/Magento/RequireJs/composer.json
+++ b/app/code/Magento/RequireJs/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*"
},
"type": "magento2-module",
diff --git a/app/code/Magento/Review/composer.json b/app/code/Magento/Review/composer.json
index b79ec24b633f3..e6ef2f416962c 100644
--- a/app/code/Magento/Review/composer.json
+++ b/app/code/Magento/Review/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-backend": "*",
"magento/module-catalog": "*",
diff --git a/app/code/Magento/ReviewAnalytics/composer.json b/app/code/Magento/ReviewAnalytics/composer.json
index 6694a8e8400cb..7939e3e475668 100644
--- a/app/code/Magento/ReviewAnalytics/composer.json
+++ b/app/code/Magento/ReviewAnalytics/composer.json
@@ -2,7 +2,7 @@
"name": "magento/module-review-analytics",
"description": "N/A",
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-review": "*",
"magento/module-analytics": "*"
diff --git a/app/code/Magento/ReviewGraphQl/composer.json b/app/code/Magento/ReviewGraphQl/composer.json
index ac1c11df1b8dc..e31bb53d3dafc 100644
--- a/app/code/Magento/ReviewGraphQl/composer.json
+++ b/app/code/Magento/ReviewGraphQl/composer.json
@@ -3,7 +3,7 @@
"description": "N/A",
"type": "magento2-module",
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/module-catalog": "*",
"magento/module-review": "*",
"magento/module-store": "*",
diff --git a/app/code/Magento/Robots/composer.json b/app/code/Magento/Robots/composer.json
index d11d4568bf7d5..37c984daa0089 100644
--- a/app/code/Magento/Robots/composer.json
+++ b/app/code/Magento/Robots/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-store": "*"
},
diff --git a/app/code/Magento/Rss/composer.json b/app/code/Magento/Rss/composer.json
index 0b89505e7e618..436c956a56313 100644
--- a/app/code/Magento/Rss/composer.json
+++ b/app/code/Magento/Rss/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-backend": "*",
"magento/module-customer": "*",
diff --git a/app/code/Magento/Rule/Model/Condition/Product/AbstractProduct.php b/app/code/Magento/Rule/Model/Condition/Product/AbstractProduct.php
index 10b32d393083c..64e2e881409a7 100644
--- a/app/code/Magento/Rule/Model/Condition/Product/AbstractProduct.php
+++ b/app/code/Magento/Rule/Model/Condition/Product/AbstractProduct.php
@@ -516,7 +516,7 @@ public function loadArray($arr)
) ? $this->_localeFormat->getNumber(
$arr['is_value_parsed']
) : false;
- } elseif (!empty($arr['operator']) && $arr['operator'] == '()') {
+ } elseif (!empty($arr['operator']) && in_array($arr['operator'], ['()', '!()', true])) {
if (isset($arr['value'])) {
$arr['value'] = preg_replace('/\s*,\s*/', ',', $arr['value']);
}
diff --git a/app/code/Magento/Rule/Model/Condition/Sql/Builder.php b/app/code/Magento/Rule/Model/Condition/Sql/Builder.php
index cb4cb9a12bd5b..ff676739695a3 100644
--- a/app/code/Magento/Rule/Model/Condition/Sql/Builder.php
+++ b/app/code/Magento/Rule/Model/Condition/Sql/Builder.php
@@ -144,6 +144,7 @@ protected function _joinTablesToCollection(
* @return string
* @throws \Magento\Framework\Exception\LocalizedException
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
+ * @SuppressWarnings(PHPMD.CyclomaticComplexity)
*/
protected function _getMappedSqlCondition(
AbstractCondition $condition,
@@ -155,7 +156,7 @@ protected function _getMappedSqlCondition(
// If rule hasn't valid argument - prevent incorrect rule behavior.
if (empty($argument)) {
return $this->_expressionFactory->create(['expression' => '1 = -1']);
- } elseif (preg_match('/[^a-z0-9\-_\.\`]/i', $argument) > 0) {
+ } elseif (preg_match('/[^a-z0-9\-_\.\`]/i', $argument) > 0 && !$argument instanceof \Zend_Db_Expr) {
throw new \Magento\Framework\Exception\LocalizedException(__('Invalid field'));
}
diff --git a/app/code/Magento/Rule/composer.json b/app/code/Magento/Rule/composer.json
index a1b60b7e57eeb..c39cfa4aa88d6 100644
--- a/app/code/Magento/Rule/composer.json
+++ b/app/code/Magento/Rule/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"lib-libxml": "*",
"magento/framework": "*",
"magento/module-backend": "*",
diff --git a/app/code/Magento/Sales/Model/Order/Address.php b/app/code/Magento/Sales/Model/Order/Address.php
index f38345f59b8dc..bb50a59eeea84 100644
--- a/app/code/Magento/Sales/Model/Order/Address.php
+++ b/app/code/Magento/Sales/Model/Order/Address.php
@@ -142,7 +142,7 @@ public function getName()
{
$name = '';
if ($this->getPrefix()) {
- $name .= $this->getPrefix() . ' ';
+ $name .= __($this->getPrefix()) . ' ';
}
$name .= $this->getFirstname();
if ($this->getMiddlename()) {
@@ -150,7 +150,7 @@ public function getName()
}
$name .= ' ' . $this->getLastname();
if ($this->getSuffix()) {
- $name .= ' ' . $this->getSuffix();
+ $name .= ' ' . __($this->getSuffix());
}
return $name;
}
diff --git a/app/code/Magento/Sales/Model/Order/Creditmemo/Total/Shipping.php b/app/code/Magento/Sales/Model/Order/Creditmemo/Total/Shipping.php
index 0537e361c8926..1bb796565ebea 100644
--- a/app/code/Magento/Sales/Model/Order/Creditmemo/Total/Shipping.php
+++ b/app/code/Magento/Sales/Model/Order/Creditmemo/Total/Shipping.php
@@ -7,6 +7,7 @@
use Magento\Framework\Pricing\PriceCurrencyInterface;
use Magento\Tax\Model\Calculation as TaxCalculation;
+use Magento\Sales\Model\Order;
/**
* Order creditmemo shipping total calculation model
@@ -115,25 +116,26 @@ public function collect(\Magento\Sales\Model\Order\Creditmemo $creditmemo)
/**
* Checks if shipping provided incl tax, tax applied after discount, and discount applied on shipping excl tax
*
- * @param \Magento\Sales\Model\Order $order
+ * @param Order $order
* @return bool
*/
- private function isShippingIncludeTaxWithTaxAfterDiscountOnExcl($order): bool
+ private function isShippingIncludeTaxWithTaxAfterDiscount(Order $order): bool
{
- return $this->getTaxConfig()->getCalculationSequence($order->getStoreId())
- === TaxCalculation::CALC_TAX_AFTER_DISCOUNT_ON_EXCL &&
- $this->isSuppliedShippingAmountInclTax($order);
+ $calculationSequence = $this->getTaxConfig()->getCalculationSequence($order->getStoreId());
+ return ($calculationSequence === TaxCalculation::CALC_TAX_AFTER_DISCOUNT_ON_EXCL
+ || $calculationSequence === TaxCalculation::CALC_TAX_AFTER_DISCOUNT_ON_INCL)
+ && $this->isSuppliedShippingAmountInclTax($order);
}
/**
* Get allowed shipping amount to refund based on tax settings
*
- * @param \Magento\Sales\Model\Order $order
+ * @param Order $order
* @return float
*/
- private function getAllowedAmountInclTax(\Magento\Sales\Model\Order $order): float
+ private function getAllowedAmountInclTax(Order $order): float
{
- if ($this->isShippingIncludeTaxWithTaxAfterDiscountOnExcl($order)) {
+ if ($this->isShippingIncludeTaxWithTaxAfterDiscount($order)) {
$result = $order->getShippingInclTax();
foreach ($order->getCreditmemosCollection() as $creditmemo) {
$result -= $creditmemo->getShippingInclTax();
@@ -155,7 +157,7 @@ private function getAllowedAmountInclTax(\Magento\Sales\Model\Order $order): flo
private function getBaseAllowedAmountInclTax(\Magento\Sales\Model\Order $order): float
{
$result = $order->getBaseShippingInclTax();
- if ($this->isShippingIncludeTaxWithTaxAfterDiscountOnExcl($order)) {
+ if ($this->isShippingIncludeTaxWithTaxAfterDiscount($order)) {
foreach ($order->getCreditmemosCollection() as $creditmemo) {
$result -= $creditmemo->getBaseShippingInclTax();
}
diff --git a/app/code/Magento/Sales/Model/Order/Creditmemo/Total/Tax.php b/app/code/Magento/Sales/Model/Order/Creditmemo/Total/Tax.php
index 04c698a8e1a24..3ef0c99bb2b05 100644
--- a/app/code/Magento/Sales/Model/Order/Creditmemo/Total/Tax.php
+++ b/app/code/Magento/Sales/Model/Order/Creditmemo/Total/Tax.php
@@ -5,13 +5,13 @@
*/
namespace Magento\Sales\Model\Order\Creditmemo\Total;
+use Magento\Framework\App\ObjectManager;
use Magento\Sales\Api\Data\CreditmemoInterface;
use Magento\Sales\Model\Order\Creditmemo;
use Magento\Sales\Model\Order\Invoice;
use Magento\Sales\Model\ResourceModel\Order\Invoice as ResourceInvoice;
-use Magento\Tax\Model\Config as TaxConfig;
use Magento\Tax\Model\Calculation as TaxCalculation;
-use Magento\Framework\App\ObjectManager;
+use Magento\Tax\Model\Config as TaxConfig;
/**
* Collects credit memo taxes.
@@ -135,7 +135,7 @@ public function collect(Creditmemo $creditmemo)
$shippingDelta = $baseOrderShippingAmount - $baseOrderShippingRefundedAmount;
if ($shippingDelta > $creditmemo->getBaseShippingAmount() ||
- $this->isShippingIncludeTaxWithTaxAfterDiscountOnExcl($order->getStoreId())) {
+ $this->isShippingIncludeTaxWithTaxAfterDiscount($order->getStoreId())) {
$part = $creditmemo->getShippingAmount() / $orderShippingAmount;
$basePart = $creditmemo->getBaseShippingAmount() / $baseOrderShippingAmount;
$shippingTaxAmount = $order->getShippingTaxAmount() * $part;
@@ -213,10 +213,12 @@ public function collect(Creditmemo $creditmemo)
* @param int|null $storeId
* @return bool
*/
- private function isShippingIncludeTaxWithTaxAfterDiscountOnExcl(?int $storeId): bool
+ private function isShippingIncludeTaxWithTaxAfterDiscount(?int $storeId): bool
{
- return $this->taxConfig->getCalculationSequence($storeId) === TaxCalculation::CALC_TAX_AFTER_DISCOUNT_ON_EXCL &&
- $this->taxConfig->displaySalesShippingInclTax($storeId);
+ $calculationSequence = $this->taxConfig->getCalculationSequence($storeId);
+ return ($calculationSequence === TaxCalculation::CALC_TAX_AFTER_DISCOUNT_ON_EXCL
+ || $calculationSequence === TaxCalculation::CALC_TAX_AFTER_DISCOUNT_ON_INCL)
+ && $this->taxConfig->displaySalesShippingInclTax($storeId);
}
/**
diff --git a/app/code/Magento/Sales/Test/Fixture/InvoiceComment.php b/app/code/Magento/Sales/Test/Fixture/InvoiceComment.php
new file mode 100644
index 0000000000000..0ba09e4dd577a
--- /dev/null
+++ b/app/code/Magento/Sales/Test/Fixture/InvoiceComment.php
@@ -0,0 +1,77 @@
+ 0,
+ InvoiceCommentInterface::PARENT_ID => 0,
+ CommentInterface::COMMENT => 'Test Comment',
+ CommentInterface::IS_VISIBLE_ON_FRONT => 0,
+ EntityInterface::ENTITY_ID => 0,
+ EntityInterface::CREATED_AT => "0000-00-00 00:00:00",
+ ];
+
+ /**
+ * @var ServiceFactory
+ */
+ private $serviceFactory;
+
+ /**
+ * @var InvoiceCommentRepositoryInterface
+ */
+ private $invoiceCommentRepository;
+
+ /**
+ * @param ServiceFactory $serviceFactory
+ * @param InvoiceCommentRepositoryInterface $invoiceCommentRepository
+ */
+ public function __construct(
+ ServiceFactory $serviceFactory,
+ InvoiceCommentRepositoryInterface $invoiceCommentRepository
+ ) {
+ $this->serviceFactory = $serviceFactory;
+ $this->invoiceCommentRepository = $invoiceCommentRepository;
+ }
+
+ public function apply(array $data = []): ?DataObject
+ {
+ $service = $this->serviceFactory->create(InvoiceCommentRepositoryInterface::class, 'save');
+ $invoiceComment = $service->execute($this->prepareData($data));
+
+ return $this->invoiceCommentRepository->get($invoiceComment->getId());
+ }
+
+ public function revert(DataObject $data): void
+ {
+ $invoice = $this->invoiceCommentRepository->get($data->getId());
+ $this->invoiceCommentRepository->delete($invoice);
+ }
+
+ /**
+ * Prepare invoice data
+ *
+ * @param array $data
+ * @return array
+ */
+ private function prepareData(array $data): array
+ {
+ $data['entity'] = array_merge(self::DEFAULT_DATA, $data);
+
+ return $data;
+ }
+}
diff --git a/app/code/Magento/Sales/Test/Mftf/Data/OrderStatusConfigData.xml b/app/code/Magento/Sales/Test/Mftf/Data/OrderStatusConfigData.xml
index 4bb8256b68be1..8141d7fb534c5 100644
--- a/app/code/Magento/Sales/Test/Mftf/Data/OrderStatusConfigData.xml
+++ b/app/code/Magento/Sales/Test/Mftf/Data/OrderStatusConfigData.xml
@@ -15,4 +15,24 @@
Pending
pending
+
+ payment/free/order_status
+ payment
+ 1
+ Pending
+ pending
+
+
+ payment/free/order_status
+ default
+ 1
+ Custom
+ custom
+
+
+ payment/free/payment_action
+ default
+ 1
+ 0
+
diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/Creditmemo/Total/ShippingTest.php b/app/code/Magento/Sales/Test/Unit/Model/Order/Creditmemo/Total/ShippingTest.php
index 4ae0b3305e8ed..998673a30e17d 100644
--- a/app/code/Magento/Sales/Test/Unit/Model/Order/Creditmemo/Total/ShippingTest.php
+++ b/app/code/Magento/Sales/Test/Unit/Model/Order/Creditmemo/Total/ShippingTest.php
@@ -509,14 +509,15 @@ public function testCollectRefundShippingAmountIncTax()
/**
* situation: The admin user specified the desired refund amount that has taxes and discount embedded within it
*
+ * @dataProvider calculationSequenceDataProvider
* @throws LocalizedException
*/
- public function testCollectUsingShippingInclTaxAndDiscountOnExclBeforeTax()
+ public function testCollectUsingShippingInclTaxAndDiscountBeforeTax(string $calculationSequence)
{
$this->taxConfig->expects($this->any())->method('displaySalesShippingInclTax')->willReturn(true);
$this->taxConfig->expects($this->any())
->method('getCalculationSequence')
- ->willReturn(TaxCalculation::CALC_TAX_AFTER_DISCOUNT_ON_EXCL);
+ ->willReturn($calculationSequence);
$orderShippingAmount = 14.55;
$shippingTaxAmount = 0.45;
@@ -603,4 +604,15 @@ public function testCollectUsingShippingInclTaxAndDiscountOnExclBeforeTax()
->willReturnSelf();
$this->shippingCollector->collect($this->creditmemoMock);
}
+
+ /**
+ * @return array
+ */
+ public function calculationSequenceDataProvider(): array
+ {
+ return [
+ 'inclTax' => [TaxCalculation::CALC_TAX_AFTER_DISCOUNT_ON_INCL],
+ 'exclTax' => [TaxCalculation::CALC_TAX_AFTER_DISCOUNT_ON_EXCL],
+ ];
+ }
}
diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/ShipmentFactoryTest.php b/app/code/Magento/Sales/Test/Unit/Model/Order/ShipmentFactoryTest.php
index e73838d85c7e8..dd721da78ad76 100644
--- a/app/code/Magento/Sales/Test/Unit/Model/Order/ShipmentFactoryTest.php
+++ b/app/code/Magento/Sales/Test/Unit/Model/Order/ShipmentFactoryTest.php
@@ -8,7 +8,6 @@
namespace Magento\Sales\Test\Unit\Model\Order;
use Magento\Framework\Exception\LocalizedException;
-use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
use Magento\Sales\Model\Convert\Order;
use Magento\Sales\Model\Convert\OrderFactory;
use Magento\Sales\Model\Order\Item;
@@ -52,8 +51,6 @@ class ShipmentFactoryTest extends TestCase
*/
protected function setUp(): void
{
- $objectManager = new ObjectManager($this);
-
$this->converter = $this->createPartialMock(
Order::class,
['toShipment', 'itemToShipmentItem']
@@ -69,12 +66,9 @@ protected function setUp(): void
['create']
);
- $this->subject = $objectManager->getObject(
- ShipmentFactory::class,
- [
- 'convertOrderFactory' => $convertOrderFactory,
- 'trackFactory' => $this->trackFactory
- ]
+ $this->subject = new ShipmentFactory(
+ $convertOrderFactory,
+ $this->trackFactory
);
}
diff --git a/app/code/Magento/Sales/composer.json b/app/code/Magento/Sales/composer.json
index 710d5c07d0490..e0ea835d63087 100644
--- a/app/code/Magento/Sales/composer.json
+++ b/app/code/Magento/Sales/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-authorization": "*",
"magento/module-backend": "*",
diff --git a/app/code/Magento/Sales/view/frontend/templates/email/invoice/items.phtml b/app/code/Magento/Sales/view/frontend/templates/email/invoice/items.phtml
index e2efd650295d4..f2b2de505c300 100644
--- a/app/code/Magento/Sales/view/frontend/templates/email/invoice/items.phtml
+++ b/app/code/Magento/Sales/view/frontend/templates/email/invoice/items.phtml
@@ -4,26 +4,29 @@
* See COPYING.txt for license details.
*/
+/** @var \Magento\Sales\Block\Order\Email\Invoice\Items $block */
+/** @var \Magento\Framework\Escaper $escaper */
+
?>
getInvoice() ?>
getOrder() ?>
-
+
- = $block->escapeHtml(__('Items')) ?>
+ = $escaper->escapeHtml(__('Items')) ?>
- = $block->escapeHtml(__('Qty')) ?>
+ = $escaper->escapeHtml(__('Qty')) ?>
- = $block->escapeHtml(__('Subtotal')) ?>
+ = $escaper->escapeHtml(__('Subtotal')) ?>
- getAllItems() as $_item) : ?>
- getOrderItem()->getParentItem()) : ?>
+ getAllItems() as $_item): ?>
+ getOrderItem()->getParentItem()): ?>
= $block->getItemHtml($_item) ?>
diff --git a/app/code/Magento/Sales/view/frontend/templates/email/items/creditmemo/default.phtml b/app/code/Magento/Sales/view/frontend/templates/email/items/creditmemo/default.phtml
index 6c304db453338..7c4b96ea55049 100644
--- a/app/code/Magento/Sales/view/frontend/templates/email/items/creditmemo/default.phtml
+++ b/app/code/Magento/Sales/view/frontend/templates/email/items/creditmemo/default.phtml
@@ -4,28 +4,29 @@
* See COPYING.txt for license details.
*/
+/** @var \Magento\Framework\Escaper $escaper */
?>
getItem() ?>
getItem()->getOrder(); ?>
= (float) $_item->getQty() ?>
diff --git a/app/code/Magento/Sales/view/frontend/templates/email/items/invoice/default.phtml b/app/code/Magento/Sales/view/frontend/templates/email/items/invoice/default.phtml
index 217cf85dde1c0..f53f527a491f0 100644
--- a/app/code/Magento/Sales/view/frontend/templates/email/items/invoice/default.phtml
+++ b/app/code/Magento/Sales/view/frontend/templates/email/items/invoice/default.phtml
@@ -3,28 +3,29 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
+/** @var \Magento\Framework\Escaper $escaper */
?>
getItem() ?>
getItem()->getOrder(); ?>
= (float) $_item->getQty() ?>
diff --git a/app/code/Magento/Sales/view/frontend/templates/email/items/order/default.phtml b/app/code/Magento/Sales/view/frontend/templates/email/items/order/default.phtml
index 37525c2fc626b..0d74980887ed6 100644
--- a/app/code/Magento/Sales/view/frontend/templates/email/items/order/default.phtml
+++ b/app/code/Magento/Sales/view/frontend/templates/email/items/order/default.phtml
@@ -5,32 +5,34 @@
*/
// phpcs:disable Magento2.Templates.ThisInTemplate
+// phpcs:disable Magento2.Files.LineLength, Generic.Files.LineLength
/** @var $block \Magento\Sales\Block\Order\Email\Items\DefaultItems */
/** @var $_item \Magento\Sales\Model\Order\Item */
+/** @var \Magento\Framework\Escaper $escaper */
$_item = $block->getItem();
$_order = $_item->getOrder();
?>
= (float) $_item->getQtyOrdered() ?>
@@ -40,17 +42,17 @@ $_order = $_item->getOrder();
getGiftMessageId()
&& $_giftMessage = $this->helper(\Magento\GiftMessage\Helper\Message::class)
->getGiftMessage($_item->getGiftMessageId())
-) : ?>
+): ?>
= (float) $_item->getQty() ?>
diff --git a/app/code/Magento/SalesAnalytics/composer.json b/app/code/Magento/SalesAnalytics/composer.json
index 6be5b39e3df33..943fbf3e7ef07 100644
--- a/app/code/Magento/SalesAnalytics/composer.json
+++ b/app/code/Magento/SalesAnalytics/composer.json
@@ -2,7 +2,7 @@
"name": "magento/module-sales-analytics",
"description": "N/A",
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-sales": "*",
"magento/module-analytics": "*"
diff --git a/app/code/Magento/SalesGraphQl/Model/Resolver/Invoices.php b/app/code/Magento/SalesGraphQl/Model/Resolver/Invoices.php
index f106752075c25..02d0f7687894a 100644
--- a/app/code/Magento/SalesGraphQl/Model/Resolver/Invoices.php
+++ b/app/code/Magento/SalesGraphQl/Model/Resolver/Invoices.php
@@ -41,10 +41,31 @@ public function resolve(
$invoices[] = [
'id' => base64_encode($invoice->getEntityId()),
'number' => $invoice['increment_id'],
+ 'comments' => $this->getInvoiceComments($invoice),
'model' => $invoice,
'order' => $orderModel
];
}
return $invoices;
}
+
+ /**
+ * Get invoice comments in proper format
+ *
+ * @param InvoiceInterface $invoice
+ * @return array
+ */
+ private function getInvoiceComments(InvoiceInterface $invoice): array
+ {
+ $comments = [];
+ foreach ($invoice->getComments() as $comment) {
+ if ($comment->getIsVisibleOnFront()) {
+ $comments[] = [
+ 'timestamp' => $comment->getCreatedAt(),
+ 'message' => $comment->getComment()
+ ];
+ }
+ }
+ return $comments;
+ }
}
diff --git a/app/code/Magento/SalesGraphQl/composer.json b/app/code/Magento/SalesGraphQl/composer.json
index dfa29321b033e..7215c8fefa8eb 100644
--- a/app/code/Magento/SalesGraphQl/composer.json
+++ b/app/code/Magento/SalesGraphQl/composer.json
@@ -3,7 +3,7 @@
"description": "N/A",
"type": "magento2-module",
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-sales": "*",
"magento/module-store": "*",
diff --git a/app/code/Magento/SalesInventory/composer.json b/app/code/Magento/SalesInventory/composer.json
index e5c5e90f8dfb2..ad11c308042fb 100644
--- a/app/code/Magento/SalesInventory/composer.json
+++ b/app/code/Magento/SalesInventory/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-catalog": "*",
"magento/module-catalog-inventory": "*",
diff --git a/app/code/Magento/SalesRule/composer.json b/app/code/Magento/SalesRule/composer.json
index fef739ce979a7..89fd6cb64b89b 100644
--- a/app/code/Magento/SalesRule/composer.json
+++ b/app/code/Magento/SalesRule/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/framework-bulk": "*",
"magento/module-backend": "*",
diff --git a/app/code/Magento/SalesSequence/composer.json b/app/code/Magento/SalesSequence/composer.json
index d06655b83bfc2..c00dae5f5b62d 100644
--- a/app/code/Magento/SalesSequence/composer.json
+++ b/app/code/Magento/SalesSequence/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*"
},
"type": "magento2-module",
diff --git a/app/code/Magento/SampleData/composer.json b/app/code/Magento/SampleData/composer.json
index 05826fd71fc13..bccca4714b922 100644
--- a/app/code/Magento/SampleData/composer.json
+++ b/app/code/Magento/SampleData/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*"
},
"suggest": {
diff --git a/app/code/Magento/Search/Test/Mftf/Test/AutoCompleteSearchTermsAndPhrasesWhileUserIsTypingTest.xml b/app/code/Magento/Search/Test/Mftf/Test/AutoCompleteSearchTermsAndPhrasesWhileUserIsTypingTest.xml
index f549b02d2820d..090fc1d3cb50c 100644
--- a/app/code/Magento/Search/Test/Mftf/Test/AutoCompleteSearchTermsAndPhrasesWhileUserIsTypingTest.xml
+++ b/app/code/Magento/Search/Test/Mftf/Test/AutoCompleteSearchTermsAndPhrasesWhileUserIsTypingTest.xml
@@ -8,6 +8,7 @@
+
@@ -67,5 +68,6 @@
+
diff --git a/app/code/Magento/Search/composer.json b/app/code/Magento/Search/composer.json
index 4b9241f8303d7..ed0779d3d7698 100644
--- a/app/code/Magento/Search/composer.json
+++ b/app/code/Magento/Search/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-backend": "*",
"magento/module-catalog-search": "*",
diff --git a/app/code/Magento/Security/composer.json b/app/code/Magento/Security/composer.json
index 07fd6655f678e..0a2910591517d 100644
--- a/app/code/Magento/Security/composer.json
+++ b/app/code/Magento/Security/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-config": "*",
"magento/module-backend": "*",
diff --git a/app/code/Magento/SendFriend/composer.json b/app/code/Magento/SendFriend/composer.json
index 47623f8f683a1..7ffc4924f2495 100644
--- a/app/code/Magento/SendFriend/composer.json
+++ b/app/code/Magento/SendFriend/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-catalog": "*",
"magento/module-customer": "*",
diff --git a/app/code/Magento/SendFriendGraphQl/composer.json b/app/code/Magento/SendFriendGraphQl/composer.json
index e836197fd42e1..6abc8d6baf202 100644
--- a/app/code/Magento/SendFriendGraphQl/composer.json
+++ b/app/code/Magento/SendFriendGraphQl/composer.json
@@ -3,7 +3,7 @@
"description": "N/A",
"type": "magento2-module",
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-catalog": "*",
"magento/module-send-friend": "*",
diff --git a/app/code/Magento/Shipping/Test/Mftf/Test/AdminDisableEnableShipmentCommentsAndVerifyNotifyCustomerByEmailCheckboxTest.xml b/app/code/Magento/Shipping/Test/Mftf/Test/AdminDisableEnableShipmentCommentsAndVerifyNotifyCustomerByEmailCheckboxTest.xml
new file mode 100644
index 0000000000000..f99a4808ba8c1
--- /dev/null
+++ b/app/code/Magento/Shipping/Test/Mftf/Test/AdminDisableEnableShipmentCommentsAndVerifyNotifyCustomerByEmailCheckboxTest.xml
@@ -0,0 +1,78 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Shipping/composer.json b/app/code/Magento/Shipping/composer.json
index 8afbe9553094f..0347a97e755d7 100644
--- a/app/code/Magento/Shipping/composer.json
+++ b/app/code/Magento/Shipping/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"ext-gd": "*",
"magento/framework": "*",
"magento/module-backend": "*",
diff --git a/app/code/Magento/Sitemap/composer.json b/app/code/Magento/Sitemap/composer.json
index be9826186e128..3323abebdebac 100644
--- a/app/code/Magento/Sitemap/composer.json
+++ b/app/code/Magento/Sitemap/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-backend": "*",
"magento/module-catalog": "*",
diff --git a/app/code/Magento/Store/composer.json b/app/code/Magento/Store/composer.json
index 6dd17c590490e..c4c195e45c138 100644
--- a/app/code/Magento/Store/composer.json
+++ b/app/code/Magento/Store/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-catalog": "*",
"magento/module-config": "*",
diff --git a/app/code/Magento/StoreGraphQl/composer.json b/app/code/Magento/StoreGraphQl/composer.json
index d5cb8d1ff4176..f5fd98fdc4cae 100644
--- a/app/code/Magento/StoreGraphQl/composer.json
+++ b/app/code/Magento/StoreGraphQl/composer.json
@@ -3,7 +3,7 @@
"description": "N/A",
"type": "magento2-module",
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-store": "*",
"magento/module-graph-ql": "*",
diff --git a/app/code/Magento/Swagger/composer.json b/app/code/Magento/Swagger/composer.json
index 0a7b1c401886c..fb357a01e22c0 100644
--- a/app/code/Magento/Swagger/composer.json
+++ b/app/code/Magento/Swagger/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*"
},
"type": "magento2-module",
diff --git a/app/code/Magento/SwaggerWebapi/composer.json b/app/code/Magento/SwaggerWebapi/composer.json
index dd1dc5d0011af..ea2b06ed681f9 100644
--- a/app/code/Magento/SwaggerWebapi/composer.json
+++ b/app/code/Magento/SwaggerWebapi/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-swagger": "*"
},
diff --git a/app/code/Magento/SwaggerWebapiAsync/composer.json b/app/code/Magento/SwaggerWebapiAsync/composer.json
index e69821cc1067a..b02a3e031b1ae 100644
--- a/app/code/Magento/SwaggerWebapiAsync/composer.json
+++ b/app/code/Magento/SwaggerWebapiAsync/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-swagger": "*"
},
diff --git a/app/code/Magento/Swatches/composer.json b/app/code/Magento/Swatches/composer.json
index d2f9201e8be5e..91f3d59016f7a 100644
--- a/app/code/Magento/Swatches/composer.json
+++ b/app/code/Magento/Swatches/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-backend": "*",
"magento/module-catalog": "*",
diff --git a/app/code/Magento/SwatchesGraphQl/composer.json b/app/code/Magento/SwatchesGraphQl/composer.json
index 1dc7a1528ad1b..744ed81435c34 100644
--- a/app/code/Magento/SwatchesGraphQl/composer.json
+++ b/app/code/Magento/SwatchesGraphQl/composer.json
@@ -3,7 +3,7 @@
"description": "N/A",
"type": "magento2-module",
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-swatches": "*",
"magento/module-catalog": "*",
diff --git a/app/code/Magento/SwatchesLayeredNavigation/composer.json b/app/code/Magento/SwatchesLayeredNavigation/composer.json
index 9af558ec757e4..ff8ea5715b944 100644
--- a/app/code/Magento/SwatchesLayeredNavigation/composer.json
+++ b/app/code/Magento/SwatchesLayeredNavigation/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/magento-composer-installer": "*"
},
diff --git a/app/code/Magento/Tax/composer.json b/app/code/Magento/Tax/composer.json
index e5628b04cc3f9..fd7a5a075998e 100644
--- a/app/code/Magento/Tax/composer.json
+++ b/app/code/Magento/Tax/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-backend": "*",
"magento/module-catalog": "*",
diff --git a/app/code/Magento/TaxGraphQl/composer.json b/app/code/Magento/TaxGraphQl/composer.json
index 3ebd323fbfe12..fef2c01d039da 100644
--- a/app/code/Magento/TaxGraphQl/composer.json
+++ b/app/code/Magento/TaxGraphQl/composer.json
@@ -3,7 +3,7 @@
"description": "N/A",
"type": "magento2-module",
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*"
},
"suggest": {
diff --git a/app/code/Magento/TaxImportExport/composer.json b/app/code/Magento/TaxImportExport/composer.json
index b83fe6dcdacf1..2f7d6737e9596 100644
--- a/app/code/Magento/TaxImportExport/composer.json
+++ b/app/code/Magento/TaxImportExport/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-backend": "*",
"magento/module-directory": "*",
diff --git a/app/code/Magento/Theme/Block/Html/Topmenu.php b/app/code/Magento/Theme/Block/Html/Topmenu.php
index 4521e38532aba..f8460b43ba2ff 100644
--- a/app/code/Magento/Theme/Block/Html/Topmenu.php
+++ b/app/code/Magento/Theme/Block/Html/Topmenu.php
@@ -356,17 +356,6 @@ public function getIdentities()
return $this->identities;
}
- /**
- * Get tags array for saving cache
- *
- * @return array
- * @since 100.1.0
- */
- protected function getCacheTags()
- {
- return array_merge(parent::getCacheTags(), $this->getIdentities());
- }
-
/**
* Get menu object.
*
diff --git a/app/code/Magento/Theme/composer.json b/app/code/Magento/Theme/composer.json
index 80fe77d9c123f..658a856db5fc2 100644
--- a/app/code/Magento/Theme/composer.json
+++ b/app/code/Magento/Theme/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-backend": "*",
"magento/module-cms": "*",
diff --git a/app/code/Magento/ThemeGraphQl/composer.json b/app/code/Magento/ThemeGraphQl/composer.json
index dbb9afddd7df0..6b4ee27e2f11b 100644
--- a/app/code/Magento/ThemeGraphQl/composer.json
+++ b/app/code/Magento/ThemeGraphQl/composer.json
@@ -3,7 +3,7 @@
"description": "N/A",
"type": "magento2-module",
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*"
},
"suggest": {
diff --git a/app/code/Magento/Translation/composer.json b/app/code/Magento/Translation/composer.json
index 28f6a54cc301f..791bfbd7b1a73 100644
--- a/app/code/Magento/Translation/composer.json
+++ b/app/code/Magento/Translation/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-backend": "*",
"magento/module-developer": "*",
diff --git a/app/code/Magento/Ui/composer.json b/app/code/Magento/Ui/composer.json
index 8d6650101b5b2..d25e69071a791 100644
--- a/app/code/Magento/Ui/composer.json
+++ b/app/code/Magento/Ui/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-authorization": "*",
"magento/module-backend": "*",
diff --git a/app/code/Magento/Ups/composer.json b/app/code/Magento/Ups/composer.json
index e34416ef0c05f..dc80330fa3828 100644
--- a/app/code/Magento/Ups/composer.json
+++ b/app/code/Magento/Ups/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-backend": "*",
"magento/module-catalog-inventory": "*",
diff --git a/app/code/Magento/UrlRewrite/composer.json b/app/code/Magento/UrlRewrite/composer.json
index 84f06e17b6465..7dafa8b8f4d07 100644
--- a/app/code/Magento/UrlRewrite/composer.json
+++ b/app/code/Magento/UrlRewrite/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-backend": "*",
"magento/module-catalog": "*",
diff --git a/app/code/Magento/UrlRewriteGraphQl/composer.json b/app/code/Magento/UrlRewriteGraphQl/composer.json
index 3e943ecf3e749..5e19ae73f5781 100644
--- a/app/code/Magento/UrlRewriteGraphQl/composer.json
+++ b/app/code/Magento/UrlRewriteGraphQl/composer.json
@@ -3,7 +3,7 @@
"description": "N/A",
"type": "magento2-module",
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-url-rewrite": "*"
},
diff --git a/app/code/Magento/User/composer.json b/app/code/Magento/User/composer.json
index 0008abc75e5be..0fa7ec8250c94 100644
--- a/app/code/Magento/User/composer.json
+++ b/app/code/Magento/User/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-authorization": "*",
"magento/module-backend": "*",
diff --git a/app/code/Magento/Usps/composer.json b/app/code/Magento/Usps/composer.json
index 8471b83a41246..107d4755d92c4 100644
--- a/app/code/Magento/Usps/composer.json
+++ b/app/code/Magento/Usps/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"lib-libxml": "*",
"magento/framework": "*",
"magento/module-catalog": "*",
diff --git a/app/code/Magento/Variable/composer.json b/app/code/Magento/Variable/composer.json
index a65fefb589422..2af748d990c35 100644
--- a/app/code/Magento/Variable/composer.json
+++ b/app/code/Magento/Variable/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-backend": "*",
"magento/module-store": "*",
diff --git a/app/code/Magento/Vault/composer.json b/app/code/Magento/Vault/composer.json
index e285571634993..f671abff34d08 100644
--- a/app/code/Magento/Vault/composer.json
+++ b/app/code/Magento/Vault/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-checkout": "*",
"magento/module-customer": "*",
diff --git a/app/code/Magento/VaultGraphQl/composer.json b/app/code/Magento/VaultGraphQl/composer.json
index e4a5dd65fa76d..4d8e565267a81 100644
--- a/app/code/Magento/VaultGraphQl/composer.json
+++ b/app/code/Magento/VaultGraphQl/composer.json
@@ -3,7 +3,7 @@
"description": "N/A",
"type": "magento2-module",
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-vault": "*",
"magento/module-graph-ql": "*"
diff --git a/app/code/Magento/Version/composer.json b/app/code/Magento/Version/composer.json
index dc9ac096f7215..36503adfc841c 100644
--- a/app/code/Magento/Version/composer.json
+++ b/app/code/Magento/Version/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*"
},
"type": "magento2-module",
diff --git a/app/code/Magento/Webapi/composer.json b/app/code/Magento/Webapi/composer.json
index 6a4823d2b1d15..d8c713391c4a0 100644
--- a/app/code/Magento/Webapi/composer.json
+++ b/app/code/Magento/Webapi/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-authorization": "*",
"magento/module-backend": "*",
diff --git a/app/code/Magento/WebapiAsync/composer.json b/app/code/Magento/WebapiAsync/composer.json
index 7627a890f8303..9bdd9d48f1cc7 100644
--- a/app/code/Magento/WebapiAsync/composer.json
+++ b/app/code/Magento/WebapiAsync/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-webapi": "*",
"magento/module-asynchronous-operations": "*",
diff --git a/app/code/Magento/WebapiSecurity/composer.json b/app/code/Magento/WebapiSecurity/composer.json
index bb4d8c10be48c..16851cad3d89f 100644
--- a/app/code/Magento/WebapiSecurity/composer.json
+++ b/app/code/Magento/WebapiSecurity/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-webapi": "*"
},
diff --git a/app/code/Magento/Weee/composer.json b/app/code/Magento/Weee/composer.json
index 3086929d12c0a..226f55ed11319 100644
--- a/app/code/Magento/Weee/composer.json
+++ b/app/code/Magento/Weee/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-backend": "*",
"magento/module-catalog": "*",
diff --git a/app/code/Magento/WeeeGraphQl/composer.json b/app/code/Magento/WeeeGraphQl/composer.json
index 1cda2e3bc753b..aa4d28bcc7f73 100644
--- a/app/code/Magento/WeeeGraphQl/composer.json
+++ b/app/code/Magento/WeeeGraphQl/composer.json
@@ -3,7 +3,7 @@
"description": "N/A",
"type": "magento2-module",
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-store": "*",
"magento/module-tax": "*",
diff --git a/app/code/Magento/Widget/composer.json b/app/code/Magento/Widget/composer.json
index 5538cc70bff45..e30a41ae1f95d 100644
--- a/app/code/Magento/Widget/composer.json
+++ b/app/code/Magento/Widget/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-backend": "*",
"magento/module-catalog": "*",
diff --git a/app/code/Magento/Wishlist/composer.json b/app/code/Magento/Wishlist/composer.json
index 4a9ce797c9add..82063e9c1bfbc 100644
--- a/app/code/Magento/Wishlist/composer.json
+++ b/app/code/Magento/Wishlist/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-backend": "*",
"magento/module-catalog": "*",
diff --git a/app/code/Magento/WishlistAnalytics/composer.json b/app/code/Magento/WishlistAnalytics/composer.json
index 0a313416ce474..d990be3af68b0 100644
--- a/app/code/Magento/WishlistAnalytics/composer.json
+++ b/app/code/Magento/WishlistAnalytics/composer.json
@@ -2,7 +2,7 @@
"name": "magento/module-wishlist-analytics",
"description": "N/A",
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-wishlist": "*",
"magento/module-analytics": "*"
diff --git a/app/code/Magento/WishlistGraphQl/composer.json b/app/code/Magento/WishlistGraphQl/composer.json
index ee08ec077c917..d5bb93fefa7ec 100755
--- a/app/code/Magento/WishlistGraphQl/composer.json
+++ b/app/code/Magento/WishlistGraphQl/composer.json
@@ -3,7 +3,7 @@
"description": "N/A",
"type": "magento2-module",
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/module-wishlist": "*",
"magento/module-store": "*",
diff --git a/app/design/adminhtml/Magento/backend/composer.json b/app/design/adminhtml/Magento/backend/composer.json
index 450d82475e488..d5cb290cc67b9 100644
--- a/app/design/adminhtml/Magento/backend/composer.json
+++ b/app/design/adminhtml/Magento/backend/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*"
},
"type": "magento2-theme",
diff --git a/app/design/frontend/Magento/blank/composer.json b/app/design/frontend/Magento/blank/composer.json
index 741f700dfc1e2..afb262619592a 100644
--- a/app/design/frontend/Magento/blank/composer.json
+++ b/app/design/frontend/Magento/blank/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*"
},
"type": "magento2-theme",
diff --git a/app/design/frontend/Magento/luma/composer.json b/app/design/frontend/Magento/luma/composer.json
index 34f1ef911a84c..f456c842cbdd4 100644
--- a/app/design/frontend/Magento/luma/composer.json
+++ b/app/design/frontend/Magento/luma/composer.json
@@ -5,7 +5,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"magento/framework": "*",
"magento/theme-frontend-blank": "*"
},
diff --git a/composer.json b/composer.json
index d54e4091079d7..9378aa9d574f5 100644
--- a/composer.json
+++ b/composer.json
@@ -16,7 +16,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"ext-bcmath": "*",
"ext-ctype": "*",
"ext-curl": "*",
@@ -34,74 +34,74 @@
"ext-xsl": "*",
"ext-zip": "*",
"lib-libxml": "*",
- "colinmollenhour/cache-backend-file": "~1.4.1",
- "colinmollenhour/cache-backend-redis": "1.14.2",
- "colinmollenhour/credis": "1.13.0",
- "colinmollenhour/php-redis-session-abstract": "v1.5.0",
+ "colinmollenhour/cache-backend-file": "^1.4",
+ "colinmollenhour/cache-backend-redis": "^1.14",
+ "colinmollenhour/credis": "^1.13",
+ "colinmollenhour/php-redis-session-abstract": "^1.5",
"composer/composer": "^2.0, !=2.2.16",
- "elasticsearch/elasticsearch": "~7.17.0",
+ "elasticsearch/elasticsearch": "^7.17",
"ezyang/htmlpurifier": "^4.14",
- "guzzlehttp/guzzle": "^7.4.2",
+ "guzzlehttp/guzzle": "^7.4",
"laminas/laminas-captcha": "^2.12",
- "laminas/laminas-code": "~4.5.0",
- "laminas/laminas-db": "^2.15.0",
- "laminas/laminas-dependency-plugin": "^2.2.0",
- "laminas/laminas-di": "^3.7.0",
- "laminas/laminas-escaper": "~2.10.0",
- "laminas/laminas-eventmanager": "^3.5.0",
- "laminas/laminas-feed": "^2.17.0",
- "laminas/laminas-file": "^2.11.0",
- "laminas/laminas-filter": "^2.17.0",
- "laminas/laminas-http": "^2.15.0",
- "laminas/laminas-i18n": "^2.17.0",
- "laminas/laminas-mail": "^2.16.0",
- "laminas/laminas-mime": "^2.9.1",
- "laminas/laminas-modulemanager": "^2.11.0",
- "laminas/laminas-mvc": "^3.3.3",
+ "laminas/laminas-code": "^4.5",
+ "laminas/laminas-db": "^2.15",
+ "laminas/laminas-dependency-plugin": "^2.5",
+ "laminas/laminas-di": "^3.7",
+ "laminas/laminas-escaper": "^2.10",
+ "laminas/laminas-eventmanager": "^3.5",
+ "laminas/laminas-feed": "^2.17",
+ "laminas/laminas-file": "^2.11",
+ "laminas/laminas-filter": "^2.17",
+ "laminas/laminas-http": "^2.15",
+ "laminas/laminas-i18n": "^2.17",
+ "laminas/laminas-mail": "^2.16",
+ "laminas/laminas-mime": "^2.9",
+ "laminas/laminas-modulemanager": "^2.11",
+ "laminas/laminas-mvc": "^3.3",
"laminas/laminas-oauth": "^2.4",
- "laminas/laminas-permissions-acl": "^2.10.0",
- "laminas/laminas-servicemanager": "^3.16.0",
- "laminas/laminas-soap": "^2.10.0",
- "laminas/laminas-stdlib": "^3.11.0",
- "laminas/laminas-uri": "^2.9.1",
- "laminas/laminas-validator": "^2.23.0",
- "league/flysystem": "~2.4.5",
- "league/flysystem-aws-s3-v3": "^2.4.3",
- "magento/composer": "~1.9.0-beta1",
- "magento/composer-dependency-version-audit-plugin": "~0.1",
+ "laminas/laminas-permissions-acl": "^2.10",
+ "laminas/laminas-servicemanager": "^3.16",
+ "laminas/laminas-soap": "^2.10",
+ "laminas/laminas-stdlib": "^3.11",
+ "laminas/laminas-uri": "^2.9",
+ "laminas/laminas-validator": "^2.23",
+ "league/flysystem": "^2.4",
+ "league/flysystem-aws-s3-v3": "^2.4",
+ "magento/composer": "^1.9.0-beta1",
+ "magento/composer-dependency-version-audit-plugin": "^0.1",
"magento/magento-composer-installer": ">=0.4.0-beta1",
- "magento/zendframework1": "~1.15.0",
+ "magento/zendframework1": "^1.15",
"monolog/monolog": "^2.7",
- "opensearch-project/opensearch-php": "~1.0.0",
+ "opensearch-project/opensearch-php": "^1.0 || ^2.0",
"pelago/emogrifier": "^6.0.0",
- "php-amqplib/php-amqplib": "~3.2.0",
- "phpseclib/mcrypt_compat": "~2.0.2",
- "phpseclib/phpseclib": "~3.0.13",
- "ramsey/uuid": "~4.2.0",
- "symfony/console": "~5.4.12",
- "symfony/string": "~5.4.12",
- "symfony/intl": "~5.4.11",
- "symfony/process": "~5.4.8",
- "tedivm/jshrink": "~1.4.0",
- "tubalmartin/cssmin": "4.1.1",
+ "php-amqplib/php-amqplib": "^3.2",
+ "phpseclib/mcrypt_compat": "^2.0",
+ "phpseclib/phpseclib": "^3.0",
+ "ramsey/uuid": "^4.2",
+ "symfony/console": "^5.4",
+ "symfony/string": "^5.4",
+ "symfony/intl": "^5.4",
+ "symfony/process": "^5.4",
+ "tedivm/jshrink": "^1.4",
+ "tubalmartin/cssmin": "^4.1",
"web-token/jwt-framework": "^v2.2.7",
- "webonyx/graphql-php": "~14.11.6",
- "wikimedia/less.php": "^3.0.0"
+ "webonyx/graphql-php": "^14.11",
+ "wikimedia/less.php": "^3.0"
},
"require-dev": {
- "allure-framework/allure-phpunit": "~1.5.0",
- "dealerdirect/phpcodesniffer-composer-installer": "^0.7.2",
- "friendsofphp/php-cs-fixer": "~3.8.0",
- "lusitanian/oauth": "~0.8.10",
+ "allure-framework/allure-phpunit": "^1.5",
+ "dealerdirect/phpcodesniffer-composer-installer": "^0.7",
+ "friendsofphp/php-cs-fixer": "^3.8",
+ "lusitanian/oauth": "^0.8",
"magento/magento-coding-standard": "*",
"magento/magento2-functional-testing-framework": "^3.10",
- "pdepend/pdepend": "~2.10.0",
- "phpmd/phpmd": "^2.12.0",
- "phpstan/phpstan": "^1.6.8",
- "phpunit/phpunit": "~9.5.20",
- "sebastian/phpcpd": "^6.0.3",
- "squizlabs/php_codesniffer": "~3.6.0",
- "symfony/finder": "^5.4.8"
+ "pdepend/pdepend": "^2.10",
+ "phpmd/phpmd": "^2.12",
+ "phpstan/phpstan": "^1.7",
+ "phpunit/phpunit": "^9.5",
+ "sebastian/phpcpd": "^6.0",
+ "squizlabs/php_codesniffer": "^3.6",
+ "symfony/finder": "^5.4"
},
"suggest": {
"ext-pcntl": "Need for run processes in parallel mode"
diff --git a/composer.lock b/composer.lock
index d14fa66e12f60..1f179b22b53a8 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "3f293d4d78b3671f50ef799b17f4a5b7",
+ "content-hash": "0ad4c199ce2f8eff1b17f2a05a682c3a",
"packages": [
{
"name": "aws/aws-crt-php",
@@ -2080,28 +2080,28 @@
},
{
"name": "laminas/laminas-dependency-plugin",
- "version": "2.2.0",
+ "version": "2.5.0",
"source": {
"type": "git",
"url": "https://github.com/laminas/laminas-dependency-plugin.git",
- "reference": "73cfb63ddca9d6bfedad5e0a038f6d55063975a3"
+ "reference": "8f2d10199381cdc7d0843bfadad55f8485df9e38"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/laminas/laminas-dependency-plugin/zipball/73cfb63ddca9d6bfedad5e0a038f6d55063975a3",
- "reference": "73cfb63ddca9d6bfedad5e0a038f6d55063975a3",
+ "url": "https://api.github.com/repos/laminas/laminas-dependency-plugin/zipball/8f2d10199381cdc7d0843bfadad55f8485df9e38",
+ "reference": "8f2d10199381cdc7d0843bfadad55f8485df9e38",
"shasum": ""
},
"require": {
- "composer-plugin-api": "^1.1 || ^2.0",
- "php": "^7.3 || ~8.0.0 || ~8.1.0"
+ "composer-plugin-api": ">=1.1.0 <2.3.0",
+ "php": "~8.0.0 || ~8.1.0 || ~8.2.0"
},
"require-dev": {
- "composer/composer": "^1.9 || ^2.0",
- "laminas/laminas-coding-standard": "^2.2.1",
- "mikey179/vfsstream": "^1.6.10@alpha",
+ "composer/composer": ">=1.9.0 <2.3.0",
+ "laminas/laminas-coding-standard": "~2.4.0",
+ "mikey179/vfsstream": "^1.6.11",
"phpunit/phpunit": "^9.5.5",
- "psalm/plugin-phpunit": "^0.15.1",
+ "psalm/plugin-phpunit": "^0.17.0",
"roave/security-advisories": "dev-master",
"vimeo/psalm": "^4.5"
},
@@ -2121,7 +2121,7 @@
"description": "Replace zendframework and zfcampus packages with their Laminas Project equivalents.",
"support": {
"issues": "https://github.com/laminas/laminas-dependency-plugin/issues",
- "source": "https://github.com/laminas/laminas-dependency-plugin/tree/2.2.0"
+ "source": "https://github.com/laminas/laminas-dependency-plugin/tree/2.5.0"
},
"funding": [
{
@@ -2129,7 +2129,7 @@
"type": "community_bridge"
}
],
- "time": "2021-09-08T17:51:35+00:00"
+ "time": "2022-10-16T14:45:47+00:00"
},
{
"name": "laminas/laminas-di",
@@ -2210,32 +2210,32 @@
},
{
"name": "laminas/laminas-escaper",
- "version": "2.10.0",
+ "version": "2.12.0",
"source": {
"type": "git",
"url": "https://github.com/laminas/laminas-escaper.git",
- "reference": "58af67282db37d24e584a837a94ee55b9c7552be"
+ "reference": "ee7a4c37bf3d0e8c03635d5bddb5bb3184ead490"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/laminas/laminas-escaper/zipball/58af67282db37d24e584a837a94ee55b9c7552be",
- "reference": "58af67282db37d24e584a837a94ee55b9c7552be",
+ "url": "https://api.github.com/repos/laminas/laminas-escaper/zipball/ee7a4c37bf3d0e8c03635d5bddb5bb3184ead490",
+ "reference": "ee7a4c37bf3d0e8c03635d5bddb5bb3184ead490",
"shasum": ""
},
"require": {
"ext-ctype": "*",
"ext-mbstring": "*",
- "php": "^7.4 || ~8.0.0 || ~8.1.0"
+ "php": "^7.4 || ~8.0.0 || ~8.1.0 || ~8.2.0"
},
"conflict": {
"zendframework/zend-escaper": "*"
},
"require-dev": {
"infection/infection": "^0.26.6",
- "laminas/laminas-coding-standard": "~2.3.0",
+ "laminas/laminas-coding-standard": "~2.4.0",
"maglnet/composer-require-checker": "^3.8.0",
"phpunit/phpunit": "^9.5.18",
- "psalm/plugin-phpunit": "^0.16.1",
+ "psalm/plugin-phpunit": "^0.17.0",
"vimeo/psalm": "^4.22.0"
},
"type": "library",
@@ -2268,36 +2268,37 @@
"type": "community_bridge"
}
],
- "time": "2022-03-08T20:15:36+00:00"
+ "time": "2022-10-10T10:11:09+00:00"
},
{
"name": "laminas/laminas-eventmanager",
- "version": "3.5.0",
+ "version": "3.6.0",
"source": {
"type": "git",
"url": "https://github.com/laminas/laminas-eventmanager.git",
- "reference": "41f7209428f37cab9573365e361f4078209aaafa"
+ "reference": "3f1afbad86cd34a431fdc069f265cfe6f8fc8308"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/laminas/laminas-eventmanager/zipball/41f7209428f37cab9573365e361f4078209aaafa",
- "reference": "41f7209428f37cab9573365e361f4078209aaafa",
+ "url": "https://api.github.com/repos/laminas/laminas-eventmanager/zipball/3f1afbad86cd34a431fdc069f265cfe6f8fc8308",
+ "reference": "3f1afbad86cd34a431fdc069f265cfe6f8fc8308",
"shasum": ""
},
"require": {
- "php": "^7.4 || ~8.0.0 || ~8.1.0"
+ "php": "~8.0.0 || ~8.1.0 || ~8.2.0"
},
"conflict": {
"container-interop/container-interop": "<1.2",
"zendframework/zend-eventmanager": "*"
},
"require-dev": {
- "laminas/laminas-coding-standard": "~2.2.1",
- "laminas/laminas-stdlib": "^3.6",
- "phpbench/phpbench": "^1.1",
- "phpspec/prophecy-phpunit": "^2.0",
- "phpunit/phpunit": "^9.5.5",
- "psr/container": "^1.1.2 || ^2.0.2"
+ "laminas/laminas-coding-standard": "~2.4.0",
+ "laminas/laminas-stdlib": "^3.15",
+ "phpbench/phpbench": "^1.2.6",
+ "phpunit/phpunit": "^9.5.25",
+ "psalm/plugin-phpunit": "^0.17.0",
+ "psr/container": "^1.1.2 || ^2.0.2",
+ "vimeo/psalm": "^4.28"
},
"suggest": {
"laminas/laminas-stdlib": "^2.7.3 || ^3.0, to use the FilterChain feature",
@@ -2335,44 +2336,45 @@
"type": "community_bridge"
}
],
- "time": "2022-04-06T21:05:17+00:00"
+ "time": "2022-10-11T12:46:13+00:00"
},
{
"name": "laminas/laminas-feed",
- "version": "2.17.0",
+ "version": "2.19.0",
"source": {
"type": "git",
"url": "https://github.com/laminas/laminas-feed.git",
- "reference": "1ccb024ea615606ed1d676ba0fa3f22a398f3ac0"
+ "reference": "4d0a7a536b48f698914156ca6633104b3aef2f3b"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/laminas/laminas-feed/zipball/1ccb024ea615606ed1d676ba0fa3f22a398f3ac0",
- "reference": "1ccb024ea615606ed1d676ba0fa3f22a398f3ac0",
+ "url": "https://api.github.com/repos/laminas/laminas-feed/zipball/4d0a7a536b48f698914156ca6633104b3aef2f3b",
+ "reference": "4d0a7a536b48f698914156ca6633104b3aef2f3b",
"shasum": ""
},
"require": {
"ext-dom": "*",
"ext-libxml": "*",
"laminas/laminas-escaper": "^2.9",
+ "laminas/laminas-servicemanager": "^3.14.0",
"laminas/laminas-stdlib": "^3.6",
- "php": "^7.3 || ~8.0.0 || ~8.1.0"
+ "php": "~8.0.0 || ~8.1.0 || ~8.2.0"
},
"conflict": {
"laminas/laminas-servicemanager": "<3.3",
"zendframework/zend-feed": "*"
},
"require-dev": {
- "laminas/laminas-cache": "^2.7.2",
- "laminas/laminas-coding-standard": "~2.2.1",
- "laminas/laminas-db": "^2.13.3",
- "laminas/laminas-http": "^2.15",
- "laminas/laminas-servicemanager": "^3.7",
- "laminas/laminas-validator": "^2.15",
- "phpunit/phpunit": "^9.5.5",
- "psalm/plugin-phpunit": "^0.13.0",
+ "laminas/laminas-cache": "^2.13.2 || ^3.6",
+ "laminas/laminas-cache-storage-adapter-memory": "^1.1.0 || ^2.1",
+ "laminas/laminas-coding-standard": "~2.4.0",
+ "laminas/laminas-db": "^2.15",
+ "laminas/laminas-http": "^2.16",
+ "laminas/laminas-validator": "^2.26",
+ "phpunit/phpunit": "^9.5.25",
+ "psalm/plugin-phpunit": "^0.17.0",
"psr/http-message": "^1.0.1",
- "vimeo/psalm": "^4.1"
+ "vimeo/psalm": "^4.29"
},
"suggest": {
"laminas/laminas-cache": "Laminas\\Cache component, for optionally caching feeds between requests",
@@ -2392,11 +2394,13 @@
"license": [
"BSD-3-Clause"
],
- "description": "provides functionality for consuming RSS and Atom feeds",
+ "description": "provides functionality for creating and consuming RSS and Atom feeds",
"homepage": "https://laminas.dev",
"keywords": [
+ "atom",
"feed",
- "laminas"
+ "laminas",
+ "rss"
],
"support": {
"chat": "https://laminas.dev/chat",
@@ -2412,7 +2416,7 @@
"type": "community_bridge"
}
],
- "time": "2022-03-24T10:26:04+00:00"
+ "time": "2022-10-14T13:40:45+00:00"
},
{
"name": "laminas/laminas-file",
@@ -2484,37 +2488,37 @@
},
{
"name": "laminas/laminas-filter",
- "version": "2.17.0",
+ "version": "2.23.0",
"source": {
"type": "git",
"url": "https://github.com/laminas/laminas-filter.git",
- "reference": "7c78483f22e118fbc98be41dc24b39e8c17cdcae"
+ "reference": "41cff2f850753f0bb3fc75c5ce011fcad6aa1731"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/laminas/laminas-filter/zipball/7c78483f22e118fbc98be41dc24b39e8c17cdcae",
- "reference": "7c78483f22e118fbc98be41dc24b39e8c17cdcae",
+ "url": "https://api.github.com/repos/laminas/laminas-filter/zipball/41cff2f850753f0bb3fc75c5ce011fcad6aa1731",
+ "reference": "41cff2f850753f0bb3fc75c5ce011fcad6aa1731",
"shasum": ""
},
"require": {
+ "ext-mbstring": "*",
"laminas/laminas-servicemanager": "^3.14.0",
- "laminas/laminas-stdlib": "^3.6.1",
- "php": "^7.4 || ~8.0.0 || ~8.1.0"
+ "laminas/laminas-stdlib": "^3.13.0",
+ "php": "~8.0.0 || ~8.1.0 || ~8.2.0"
},
"conflict": {
"laminas/laminas-validator": "<2.10.1",
"zendframework/zend-filter": "*"
},
"require-dev": {
- "laminas/laminas-coding-standard": "^2.3.0",
- "laminas/laminas-crypt": "^3.5.1",
+ "laminas/laminas-coding-standard": "~2.4.0",
+ "laminas/laminas-crypt": "^3.8",
"laminas/laminas-uri": "^2.9.1",
"pear/archive_tar": "^1.4.14",
- "phpspec/prophecy-phpunit": "^2.0.1",
- "phpunit/phpunit": "^9.5.10",
+ "phpunit/phpunit": "^9.5.25",
"psalm/plugin-phpunit": "^0.17.0",
"psr/http-factory": "^1.0.1",
- "vimeo/psalm": "^4.24.0"
+ "vimeo/psalm": "^4.28"
},
"suggest": {
"laminas/laminas-crypt": "Laminas\\Crypt component, for encryption filters",
@@ -2558,20 +2562,20 @@
"type": "community_bridge"
}
],
- "time": "2022-07-17T11:58:06+00:00"
+ "time": "2022-10-11T10:04:14+00:00"
},
{
"name": "laminas/laminas-http",
- "version": "2.15.1",
+ "version": "2.17.0",
"source": {
"type": "git",
"url": "https://github.com/laminas/laminas-http.git",
- "reference": "261f079c3dffcf6f123484db43c40e44c4bf1c79"
+ "reference": "ac4588d698c93b56bb7c0608d9a7537a3f057239"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/laminas/laminas-http/zipball/261f079c3dffcf6f123484db43c40e44c4bf1c79",
- "reference": "261f079c3dffcf6f123484db43c40e44c4bf1c79",
+ "url": "https://api.github.com/repos/laminas/laminas-http/zipball/ac4588d698c93b56bb7c0608d9a7537a3f057239",
+ "reference": "ac4588d698c93b56bb7c0608d9a7537a3f057239",
"shasum": ""
},
"require": {
@@ -2579,15 +2583,15 @@
"laminas/laminas-stdlib": "^3.6",
"laminas/laminas-uri": "^2.9.1",
"laminas/laminas-validator": "^2.15",
- "php": "^7.3 || ~8.0.0 || ~8.1.0"
+ "php": "~8.0.0 || ~8.1.0 || ~8.2.0"
},
"conflict": {
"zendframework/zend-http": "*"
},
"require-dev": {
"ext-curl": "*",
- "laminas/laminas-coding-standard": "~2.2.1",
- "phpunit/phpunit": "^9.5.5"
+ "laminas/laminas-coding-standard": "~2.4.0",
+ "phpunit/phpunit": "^9.5.25"
},
"suggest": {
"paragonie/certainty": "For automated management of cacert.pem"
@@ -2623,27 +2627,27 @@
"type": "community_bridge"
}
],
- "time": "2021-12-03T10:17:11+00:00"
+ "time": "2022-10-16T15:51:48+00:00"
},
{
"name": "laminas/laminas-i18n",
- "version": "2.17.0",
+ "version": "2.19.0",
"source": {
"type": "git",
"url": "https://github.com/laminas/laminas-i18n.git",
- "reference": "7e8e63353b38792f2f360dc57cfa7187be20f182"
+ "reference": "ebabca3a6398fc872127bc69a51bda5afc720d67"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/laminas/laminas-i18n/zipball/7e8e63353b38792f2f360dc57cfa7187be20f182",
- "reference": "7e8e63353b38792f2f360dc57cfa7187be20f182",
+ "url": "https://api.github.com/repos/laminas/laminas-i18n/zipball/ebabca3a6398fc872127bc69a51bda5afc720d67",
+ "reference": "ebabca3a6398fc872127bc69a51bda5afc720d67",
"shasum": ""
},
"require": {
"ext-intl": "*",
"laminas/laminas-servicemanager": "^3.14.0",
"laminas/laminas-stdlib": "^2.7 || ^3.0",
- "php": "^7.4 || ~8.0.0 || ~8.1.0"
+ "php": "~8.0.0 || ~8.1.0 || ~8.2.0"
},
"conflict": {
"laminas/laminas-view": "<2.20.0",
@@ -2651,19 +2655,18 @@
"zendframework/zend-i18n": "*"
},
"require-dev": {
- "laminas/laminas-cache": "^3.1.2",
- "laminas/laminas-cache-storage-adapter-memory": "^2.0.0",
- "laminas/laminas-cache-storage-deprecated-factory": "^1.0.0",
- "laminas/laminas-coding-standard": "~2.3.0",
- "laminas/laminas-config": "^3.4.0",
+ "laminas/laminas-cache": "^3.6",
+ "laminas/laminas-cache-storage-adapter-memory": "^2.1",
+ "laminas/laminas-cache-storage-deprecated-factory": "^1.0.1",
+ "laminas/laminas-coding-standard": "~2.4.0",
+ "laminas/laminas-config": "^3.7",
"laminas/laminas-eventmanager": "^3.5.0",
- "laminas/laminas-filter": "^2.16.0",
- "laminas/laminas-validator": "^2.17.0",
- "laminas/laminas-view": "^2.21.0",
- "phpspec/prophecy-phpunit": "^2.0",
- "phpunit/phpunit": "^9.5.21",
+ "laminas/laminas-filter": "^2.21",
+ "laminas/laminas-validator": "^2.25",
+ "laminas/laminas-view": "^2.23",
+ "phpunit/phpunit": "^9.5.25",
"psalm/plugin-phpunit": "^0.17.0",
- "vimeo/psalm": "^4.24.0"
+ "vimeo/psalm": "^4.28"
},
"suggest": {
"laminas/laminas-cache": "You should install this package to cache the translations",
@@ -2710,7 +2713,7 @@
"type": "community_bridge"
}
],
- "time": "2022-07-27T11:23:29+00:00"
+ "time": "2022-10-10T15:48:56+00:00"
},
{
"name": "laminas/laminas-json",
@@ -2775,27 +2778,27 @@
},
{
"name": "laminas/laminas-loader",
- "version": "2.8.0",
+ "version": "2.9.0",
"source": {
"type": "git",
"url": "https://github.com/laminas/laminas-loader.git",
- "reference": "d0589ec9dd48365fd95ad10d1c906efd7711c16b"
+ "reference": "51ed9c3fa42d1098a9997571730c0cbf42d078d3"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/laminas/laminas-loader/zipball/d0589ec9dd48365fd95ad10d1c906efd7711c16b",
- "reference": "d0589ec9dd48365fd95ad10d1c906efd7711c16b",
+ "url": "https://api.github.com/repos/laminas/laminas-loader/zipball/51ed9c3fa42d1098a9997571730c0cbf42d078d3",
+ "reference": "51ed9c3fa42d1098a9997571730c0cbf42d078d3",
"shasum": ""
},
"require": {
- "php": "^7.3 || ~8.0.0 || ~8.1.0"
+ "php": "~8.0.0 || ~8.1.0 || ~8.2.0"
},
"conflict": {
"zendframework/zend-loader": "*"
},
"require-dev": {
- "laminas/laminas-coding-standard": "~2.2.1",
- "phpunit/phpunit": "^9.3"
+ "laminas/laminas-coding-standard": "~2.4.0",
+ "phpunit/phpunit": "~9.5.25"
},
"type": "library",
"autoload": {
@@ -2827,49 +2830,46 @@
"type": "community_bridge"
}
],
- "time": "2021-09-02T18:30:53+00:00"
+ "time": "2022-10-16T12:50:49+00:00"
},
{
"name": "laminas/laminas-mail",
- "version": "2.16.0",
+ "version": "2.19.0",
"source": {
"type": "git",
"url": "https://github.com/laminas/laminas-mail.git",
- "reference": "1ee1a384b96c8af29ecad9b3a7adc27a150ebc49"
+ "reference": "edf3832c05165775589af2fc698b5f9984d4c5f1"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/laminas/laminas-mail/zipball/1ee1a384b96c8af29ecad9b3a7adc27a150ebc49",
- "reference": "1ee1a384b96c8af29ecad9b3a7adc27a150ebc49",
+ "url": "https://api.github.com/repos/laminas/laminas-mail/zipball/edf3832c05165775589af2fc698b5f9984d4c5f1",
+ "reference": "edf3832c05165775589af2fc698b5f9984d4c5f1",
"shasum": ""
},
"require": {
"ext-iconv": "*",
- "laminas/laminas-loader": "^2.8",
- "laminas/laminas-mime": "^2.9.1",
- "laminas/laminas-stdlib": "^3.6",
- "laminas/laminas-validator": "^2.15",
- "php": "^7.3 || ~8.0.0 || ~8.1.0",
- "symfony/polyfill-intl-idn": "^1.24.0",
- "symfony/polyfill-mbstring": "^1.12.0",
- "webmozart/assert": "^1.10"
- },
- "conflict": {
- "zendframework/zend-mail": "*"
- },
- "require-dev": {
- "laminas/laminas-coding-standard": "~1.0.0",
- "laminas/laminas-crypt": "^2.6 || ^3.4",
- "laminas/laminas-db": "^2.13.3",
- "laminas/laminas-servicemanager": "^3.7",
- "phpunit/phpunit": "^9.5.5",
- "psalm/plugin-phpunit": "^0.15.1",
- "symfony/process": "^5.3.7",
- "vimeo/psalm": "^4.7"
+ "laminas/laminas-loader": "^2.8.0",
+ "laminas/laminas-mime": "^2.10.0",
+ "laminas/laminas-stdlib": "^3.11.0",
+ "laminas/laminas-validator": "^2.23.0",
+ "php": "~8.0.0 || ~8.1.0 || ~8.2.0",
+ "symfony/polyfill-intl-idn": "^1.26.0",
+ "symfony/polyfill-mbstring": "^1.16.0",
+ "webmozart/assert": "^1.11.0"
+ },
+ "require-dev": {
+ "laminas/laminas-coding-standard": "~2.4.0",
+ "laminas/laminas-crypt": "^3.8.0",
+ "laminas/laminas-db": "^2.15.0",
+ "laminas/laminas-servicemanager": "^3.19",
+ "phpunit/phpunit": "^9.5.25",
+ "psalm/plugin-phpunit": "^0.17.0",
+ "symfony/process": "^6.0.11",
+ "vimeo/psalm": "^4.29"
},
"suggest": {
- "laminas/laminas-crypt": "Crammd5 support in SMTP Auth",
- "laminas/laminas-servicemanager": "^2.7.10 || ^3.3.1 when using SMTP to deliver messages"
+ "laminas/laminas-crypt": "^3.8 Crammd5 support in SMTP Auth",
+ "laminas/laminas-servicemanager": "^3.16 when using SMTP to deliver messages"
},
"type": "library",
"extra": {
@@ -2907,7 +2907,7 @@
"type": "community_bridge"
}
],
- "time": "2022-02-23T21:08:17+00:00"
+ "time": "2022-10-14T13:05:29+00:00"
},
{
"name": "laminas/laminas-math",
@@ -2978,29 +2978,29 @@
},
{
"name": "laminas/laminas-mime",
- "version": "2.9.1",
+ "version": "2.11.0",
"source": {
"type": "git",
"url": "https://github.com/laminas/laminas-mime.git",
- "reference": "72d21a1b4bb7086d4a4d7058c0abca180b209184"
+ "reference": "60ec04b755821c79c1987ce291b44e69f2c0831f"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/laminas/laminas-mime/zipball/72d21a1b4bb7086d4a4d7058c0abca180b209184",
- "reference": "72d21a1b4bb7086d4a4d7058c0abca180b209184",
+ "url": "https://api.github.com/repos/laminas/laminas-mime/zipball/60ec04b755821c79c1987ce291b44e69f2c0831f",
+ "reference": "60ec04b755821c79c1987ce291b44e69f2c0831f",
"shasum": ""
},
"require": {
"laminas/laminas-stdlib": "^2.7 || ^3.0",
- "php": "^7.3 || ~8.0.0 || ~8.1.0"
+ "php": "~8.0.0 || ~8.1.0 || ~8.2.0"
},
"conflict": {
"zendframework/zend-mime": "*"
},
"require-dev": {
- "laminas/laminas-coding-standard": "~2.2.1",
- "laminas/laminas-mail": "^2.12",
- "phpunit/phpunit": "^9.3"
+ "laminas/laminas-coding-standard": "~2.4.0",
+ "laminas/laminas-mail": "^2.19.0",
+ "phpunit/phpunit": "~9.5.25"
},
"suggest": {
"laminas/laminas-mail": "Laminas\\Mail component"
@@ -3035,20 +3035,20 @@
"type": "community_bridge"
}
],
- "time": "2021-09-20T21:19:24+00:00"
+ "time": "2022-10-18T08:38:15+00:00"
},
{
"name": "laminas/laminas-modulemanager",
- "version": "2.11.0",
+ "version": "2.14.0",
"source": {
"type": "git",
"url": "https://github.com/laminas/laminas-modulemanager.git",
- "reference": "6acf5991d10b0b38a2edb08729ed48981b2a5dad"
+ "reference": "fb0a2c34423f7d3321dd7c42dc5fc4db905a99ac"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/laminas/laminas-modulemanager/zipball/6acf5991d10b0b38a2edb08729ed48981b2a5dad",
- "reference": "6acf5991d10b0b38a2edb08729ed48981b2a5dad",
+ "url": "https://api.github.com/repos/laminas/laminas-modulemanager/zipball/fb0a2c34423f7d3321dd7c42dc5fc4db905a99ac",
+ "reference": "fb0a2c34423f7d3321dd7c42dc5fc4db905a99ac",
"shasum": ""
},
"require": {
@@ -3056,7 +3056,7 @@
"laminas/laminas-config": "^3.7",
"laminas/laminas-eventmanager": "^3.4",
"laminas/laminas-stdlib": "^3.6",
- "php": "^7.3 || ~8.0.0 || ~8.1.0",
+ "php": "~8.0.0 || ~8.1.0 || ~8.2.0",
"webimpress/safe-writer": "^1.0.2 || ^2.1"
},
"conflict": {
@@ -3064,10 +3064,12 @@
},
"require-dev": {
"laminas/laminas-coding-standard": "^2.3",
- "laminas/laminas-loader": "^2.8",
- "laminas/laminas-mvc": "^3.1.1",
- "laminas/laminas-servicemanager": "^3.7",
- "phpunit/phpunit": "^9.5.5"
+ "laminas/laminas-loader": "^2.9.0",
+ "laminas/laminas-mvc": "^3.5.0",
+ "laminas/laminas-servicemanager": "^3.19.0",
+ "phpunit/phpunit": "^9.5.25",
+ "psalm/plugin-phpunit": "^0.17.0",
+ "vimeo/psalm": "^4.29"
},
"suggest": {
"laminas/laminas-console": "Laminas\\Console component",
@@ -3105,20 +3107,20 @@
"type": "community_bridge"
}
],
- "time": "2021-10-13T17:05:17+00:00"
+ "time": "2022-10-28T09:21:04+00:00"
},
{
"name": "laminas/laminas-mvc",
- "version": "3.3.3",
+ "version": "3.5.0",
"source": {
"type": "git",
"url": "https://github.com/laminas/laminas-mvc.git",
- "reference": "7ff2bfbe64048aa83c6d1c7edcbab849123f0150"
+ "reference": "111e08a9c27274af570260c83abe77204ccf3366"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/laminas/laminas-mvc/zipball/7ff2bfbe64048aa83c6d1c7edcbab849123f0150",
- "reference": "7ff2bfbe64048aa83c6d1c7edcbab849123f0150",
+ "url": "https://api.github.com/repos/laminas/laminas-mvc/zipball/111e08a9c27274af570260c83abe77204ccf3366",
+ "reference": "111e08a9c27274af570260c83abe77204ccf3366",
"shasum": ""
},
"require": {
@@ -3130,19 +3132,20 @@
"laminas/laminas-servicemanager": "^3.7",
"laminas/laminas-stdlib": "^3.6",
"laminas/laminas-view": "^2.14",
- "php": "^7.3 || ~8.0.0 || ~8.1.0"
+ "php": "~8.0.0 || ~8.1.0 || ~8.2.0"
},
"conflict": {
"zendframework/zend-mvc": "*"
},
"require-dev": {
"http-interop/http-middleware": "^0.4.1",
- "laminas/laminas-coding-standard": "^1.0.0",
+ "laminas/laminas-coding-standard": "^2.4.0",
"laminas/laminas-json": "^3.3",
- "laminas/laminas-psr7bridge": "^1.0",
+ "laminas/laminas-psr7bridge": "^1.8",
"laminas/laminas-stratigility": ">=2.0.1 <2.2",
- "phpspec/prophecy-phpunit": "^2.0",
- "phpunit/phpunit": "^9.5.5"
+ "phpspec/prophecy": "^1.15.0",
+ "phpspec/prophecy-phpunit": "^2.0.1",
+ "phpunit/phpunit": "^9.5.25"
},
"suggest": {
"laminas/laminas-json": "(^2.6.1 || ^3.0) To auto-deserialize JSON body content in AbstractRestfulController extensions, when json_decode is unavailable",
@@ -3187,7 +3190,7 @@
"type": "community_bridge"
}
],
- "time": "2022-02-21T20:21:58+00:00"
+ "time": "2022-10-21T14:19:57+00:00"
},
{
"name": "laminas/laminas-oauth",
@@ -3253,31 +3256,31 @@
},
{
"name": "laminas/laminas-permissions-acl",
- "version": "2.10.0",
+ "version": "2.12.0",
"source": {
"type": "git",
"url": "https://github.com/laminas/laminas-permissions-acl.git",
- "reference": "e927ae0a3001655fea97eb240eeea9d10638e82f"
+ "reference": "0d88f430953fbcbce382f09090db28905b90d60f"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/laminas/laminas-permissions-acl/zipball/e927ae0a3001655fea97eb240eeea9d10638e82f",
- "reference": "e927ae0a3001655fea97eb240eeea9d10638e82f",
+ "url": "https://api.github.com/repos/laminas/laminas-permissions-acl/zipball/0d88f430953fbcbce382f09090db28905b90d60f",
+ "reference": "0d88f430953fbcbce382f09090db28905b90d60f",
"shasum": ""
},
"require": {
- "php": "^7.4 || ~8.0.0 || ~8.1.0"
+ "php": "~8.0.0 || ~8.1.0 || ~8.2.0"
},
"conflict": {
"laminas/laminas-servicemanager": "<3.0",
"zendframework/zend-permissions-acl": "*"
},
"require-dev": {
- "laminas/laminas-coding-standard": "~2.3.0",
- "laminas/laminas-servicemanager": "^3.15.1",
- "phpunit/phpunit": "^9.5.0",
+ "laminas/laminas-coding-standard": "~2.4.0",
+ "laminas/laminas-servicemanager": "^3.19",
+ "phpunit/phpunit": "^9.5.25",
"psalm/plugin-phpunit": "^0.17.0",
- "vimeo/psalm": "^4.24.0"
+ "vimeo/psalm": "^4.29"
},
"suggest": {
"laminas/laminas-servicemanager": "To support Laminas\\Permissions\\Acl\\Assertion\\AssertionManager plugin manager usage"
@@ -3312,7 +3315,7 @@
"type": "community_bridge"
}
],
- "time": "2022-07-21T09:23:39+00:00"
+ "time": "2022-10-17T04:26:35+00:00"
},
{
"name": "laminas/laminas-recaptcha",
@@ -3514,21 +3517,21 @@
},
{
"name": "laminas/laminas-servicemanager",
- "version": "3.16.0",
+ "version": "3.19.0",
"source": {
"type": "git",
"url": "https://github.com/laminas/laminas-servicemanager.git",
- "reference": "863c66733740cd36ebf5e700f4258ef2c68a2a24"
+ "reference": "ed160729bb8721127efdaac799f9a298963345b1"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/laminas/laminas-servicemanager/zipball/863c66733740cd36ebf5e700f4258ef2c68a2a24",
- "reference": "863c66733740cd36ebf5e700f4258ef2c68a2a24",
+ "url": "https://api.github.com/repos/laminas/laminas-servicemanager/zipball/ed160729bb8721127efdaac799f9a298963345b1",
+ "reference": "ed160729bb8721127efdaac799f9a298963345b1",
"shasum": ""
},
"require": {
"laminas/laminas-stdlib": "^3.2.1",
- "php": "~7.4.0 || ~8.0.0 || ~8.1.0",
+ "php": "~8.0.0 || ~8.1.0 || ~8.2.0",
"psr/container": "^1.0"
},
"conflict": {
@@ -3544,17 +3547,16 @@
"container-interop/container-interop": "^1.2.0"
},
"require-dev": {
- "composer/package-versions-deprecated": "^1.0",
- "laminas/laminas-coding-standard": "~2.3.0",
+ "composer/package-versions-deprecated": "^1.11.99.5",
+ "laminas/laminas-coding-standard": "~2.4.0",
"laminas/laminas-container-config-test": "^0.7",
- "laminas/laminas-dependency-plugin": "^2.1.2",
- "mikey179/vfsstream": "^1.6.10@alpha",
- "ocramius/proxy-manager": "^2.11",
- "phpbench/phpbench": "^1.1",
- "phpspec/prophecy-phpunit": "^2.0",
- "phpunit/phpunit": "^9.5.5",
+ "laminas/laminas-dependency-plugin": "^2.2",
+ "mikey179/vfsstream": "^1.6.11@alpha",
+ "ocramius/proxy-manager": "^2.14.1",
+ "phpbench/phpbench": "^1.2.6",
+ "phpunit/phpunit": "^9.5.25",
"psalm/plugin-phpunit": "^0.17.0",
- "vimeo/psalm": "^4.8"
+ "vimeo/psalm": "^4.28"
},
"suggest": {
"ocramius/proxy-manager": "ProxyManager ^2.1.1 to handle lazy initialization of services"
@@ -3601,7 +3603,7 @@
"type": "community_bridge"
}
],
- "time": "2022-07-27T14:58:17+00:00"
+ "time": "2022-10-10T20:59:22+00:00"
},
{
"name": "laminas/laminas-session",
@@ -3755,30 +3757,30 @@
},
{
"name": "laminas/laminas-stdlib",
- "version": "3.11.0",
+ "version": "3.15.0",
"source": {
"type": "git",
"url": "https://github.com/laminas/laminas-stdlib.git",
- "reference": "aad7d2b11ba0069ba0d9b40f6dde3c2fa664b57f"
+ "reference": "63b66bd4b696f024f42616b9d95cdb10e5109c27"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/laminas/laminas-stdlib/zipball/aad7d2b11ba0069ba0d9b40f6dde3c2fa664b57f",
- "reference": "aad7d2b11ba0069ba0d9b40f6dde3c2fa664b57f",
+ "url": "https://api.github.com/repos/laminas/laminas-stdlib/zipball/63b66bd4b696f024f42616b9d95cdb10e5109c27",
+ "reference": "63b66bd4b696f024f42616b9d95cdb10e5109c27",
"shasum": ""
},
"require": {
- "php": "^7.3 || ~8.0.0 || ~8.1.0"
+ "php": "~8.0.0 || ~8.1.0 || ~8.2.0"
},
"conflict": {
"zendframework/zend-stdlib": "*"
},
"require-dev": {
- "laminas/laminas-coding-standard": "~2.3.0",
- "phpbench/phpbench": "^1.0",
- "phpunit/phpunit": "^9.3.7",
+ "laminas/laminas-coding-standard": "^2.4.0",
+ "phpbench/phpbench": "^1.2.6",
+ "phpunit/phpunit": "^9.5.25",
"psalm/plugin-phpunit": "^0.17.0",
- "vimeo/psalm": "^4.7"
+ "vimeo/psalm": "^4.28"
},
"type": "library",
"autoload": {
@@ -3810,7 +3812,7 @@
"type": "community_bridge"
}
],
- "time": "2022-07-27T12:28:58+00:00"
+ "time": "2022-10-10T19:10:24+00:00"
},
{
"name": "laminas/laminas-text",
@@ -3872,29 +3874,29 @@
},
{
"name": "laminas/laminas-uri",
- "version": "2.9.1",
+ "version": "2.10.0",
"source": {
"type": "git",
"url": "https://github.com/laminas/laminas-uri.git",
- "reference": "7e837dc15c8fd3949df7d1213246fd7c8640032b"
+ "reference": "663b050294945c7345cc3a61f3ca661d5f9e1f80"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/laminas/laminas-uri/zipball/7e837dc15c8fd3949df7d1213246fd7c8640032b",
- "reference": "7e837dc15c8fd3949df7d1213246fd7c8640032b",
+ "url": "https://api.github.com/repos/laminas/laminas-uri/zipball/663b050294945c7345cc3a61f3ca661d5f9e1f80",
+ "reference": "663b050294945c7345cc3a61f3ca661d5f9e1f80",
"shasum": ""
},
"require": {
"laminas/laminas-escaper": "^2.9",
"laminas/laminas-validator": "^2.15",
- "php": "^7.3 || ~8.0.0 || ~8.1.0"
+ "php": "~8.0.0 || ~8.1.0 || ~8.2.0"
},
"conflict": {
"zendframework/zend-uri": "*"
},
"require-dev": {
- "laminas/laminas-coding-standard": "~2.2.1",
- "phpunit/phpunit": "^9.5.5"
+ "laminas/laminas-coding-standard": "~2.4.0",
+ "phpunit/phpunit": "^9.5.25"
},
"type": "library",
"autoload": {
@@ -3926,45 +3928,44 @@
"type": "community_bridge"
}
],
- "time": "2021-09-09T18:37:15+00:00"
+ "time": "2022-10-16T15:02:45+00:00"
},
{
"name": "laminas/laminas-validator",
- "version": "2.23.0",
+ "version": "2.26.0",
"source": {
"type": "git",
"url": "https://github.com/laminas/laminas-validator.git",
- "reference": "6d61b6cc3b222f13807a18d9247cdfb084958b03"
+ "reference": "a995b21d18c63cd1f5d123d0d2cd31a1c2d828dc"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/laminas/laminas-validator/zipball/6d61b6cc3b222f13807a18d9247cdfb084958b03",
- "reference": "6d61b6cc3b222f13807a18d9247cdfb084958b03",
+ "url": "https://api.github.com/repos/laminas/laminas-validator/zipball/a995b21d18c63cd1f5d123d0d2cd31a1c2d828dc",
+ "reference": "a995b21d18c63cd1f5d123d0d2cd31a1c2d828dc",
"shasum": ""
},
"require": {
"laminas/laminas-servicemanager": "^3.12.0",
- "laminas/laminas-stdlib": "^3.10",
- "php": "^7.4 || ~8.0.0 || ~8.1.0"
+ "laminas/laminas-stdlib": "^3.13",
+ "php": "~8.0.0 || ~8.1.0 || ~8.2.0"
},
"conflict": {
"zendframework/zend-validator": "*"
},
"require-dev": {
- "laminas/laminas-coding-standard": "~2.3.0",
- "laminas/laminas-db": "^2.7",
- "laminas/laminas-filter": "^2.14.0",
- "laminas/laminas-http": "^2.14.2",
- "laminas/laminas-i18n": "^2.15.0",
- "laminas/laminas-session": "^2.12.1",
+ "laminas/laminas-coding-standard": "^2.4.0",
+ "laminas/laminas-db": "^2.15.0",
+ "laminas/laminas-filter": "^2.22",
+ "laminas/laminas-http": "^2.16.0",
+ "laminas/laminas-i18n": "^2.19",
+ "laminas/laminas-session": "^2.13.0",
"laminas/laminas-uri": "^2.9.1",
- "phpspec/prophecy-phpunit": "^2.0",
- "phpunit/phpunit": "^9.5.21",
+ "phpunit/phpunit": "^9.5.25",
"psalm/plugin-phpunit": "^0.17.0",
- "psr/http-client": "^1.0",
- "psr/http-factory": "^1.0",
- "psr/http-message": "^1.0",
- "vimeo/psalm": "^4.24.0"
+ "psr/http-client": "^1.0.1",
+ "psr/http-factory": "^1.0.1",
+ "psr/http-message": "^1.0.1",
+ "vimeo/psalm": "^4.28"
},
"suggest": {
"laminas/laminas-db": "Laminas\\Db component, required by the (No)RecordExists validator",
@@ -4012,7 +4013,7 @@
"type": "community_bridge"
}
],
- "time": "2022-07-27T19:17:59+00:00"
+ "time": "2022-10-11T12:58:36+00:00"
},
{
"name": "laminas/laminas-view",
@@ -4595,16 +4596,16 @@
},
{
"name": "monolog/monolog",
- "version": "2.7.0",
+ "version": "2.8.0",
"source": {
"type": "git",
"url": "https://github.com/Seldaek/monolog.git",
- "reference": "5579edf28aee1190a798bfa5be8bc16c563bd524"
+ "reference": "720488632c590286b88b80e62aa3d3d551ad4a50"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/Seldaek/monolog/zipball/5579edf28aee1190a798bfa5be8bc16c563bd524",
- "reference": "5579edf28aee1190a798bfa5be8bc16c563bd524",
+ "url": "https://api.github.com/repos/Seldaek/monolog/zipball/720488632c590286b88b80e62aa3d3d551ad4a50",
+ "reference": "720488632c590286b88b80e62aa3d3d551ad4a50",
"shasum": ""
},
"require": {
@@ -4624,11 +4625,10 @@
"guzzlehttp/psr7": "^2.2",
"mongodb/mongodb": "^1.8",
"php-amqplib/php-amqplib": "~2.4 || ^3",
- "php-console/php-console": "^3.1.3",
"phpspec/prophecy": "^1.15",
"phpstan/phpstan": "^0.12.91",
"phpunit/phpunit": "^8.5.14",
- "predis/predis": "^1.1",
+ "predis/predis": "^1.1 || ^2.0",
"rollbar/rollbar": "^1.3 || ^2 || ^3",
"ruflin/elastica": "^7",
"swiftmailer/swiftmailer": "^5.3|^6.0",
@@ -4648,7 +4648,6 @@
"graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server",
"mongodb/mongodb": "Allow sending log messages to a MongoDB server (via library)",
"php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib",
- "php-console/php-console": "Allow sending log messages to Google Chrome",
"rollbar/rollbar": "Allow sending log messages to Rollbar",
"ruflin/elastica": "Allow sending log messages to an Elastic Search server"
},
@@ -4683,7 +4682,7 @@
],
"support": {
"issues": "https://github.com/Seldaek/monolog/issues",
- "source": "https://github.com/Seldaek/monolog/tree/2.7.0"
+ "source": "https://github.com/Seldaek/monolog/tree/2.8.0"
},
"funding": [
{
@@ -4695,7 +4694,7 @@
"type": "tidelift"
}
],
- "time": "2022-06-09T08:59:12+00:00"
+ "time": "2022-07-24T11:55:47+00:00"
},
{
"name": "mtdowling/jmespath.php",
@@ -4816,16 +4815,16 @@
},
{
"name": "opensearch-project/opensearch-php",
- "version": "1.0.2",
+ "version": "2.0.0",
"source": {
"type": "git",
"url": "https://github.com/opensearch-project/opensearch-php.git",
- "reference": "d54af5ff2167bee3eb68d02e210283314ef74712"
+ "reference": "565c17e0ac1e062f4a6edfeb9745e9deb93ffbeb"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/opensearch-project/opensearch-php/zipball/d54af5ff2167bee3eb68d02e210283314ef74712",
- "reference": "d54af5ff2167bee3eb68d02e210283314ef74712",
+ "url": "https://api.github.com/repos/opensearch-project/opensearch-php/zipball/565c17e0ac1e062f4a6edfeb9745e9deb93ffbeb",
+ "reference": "565c17e0ac1e062f4a6edfeb9745e9deb93ffbeb",
"shasum": ""
},
"require": {
@@ -4874,9 +4873,9 @@
],
"support": {
"issues": "https://github.com/opensearch-project/opensearch-php/issues",
- "source": "https://github.com/opensearch-project/opensearch-php/tree/1.0.2"
+ "source": "https://github.com/opensearch-project/opensearch-php/tree/2.0.0"
},
- "time": "2022-02-08T08:37:31+00:00"
+ "time": "2022-05-26T19:17:49+00:00"
},
{
"name": "paragonie/constant_time_encoding",
@@ -6299,16 +6298,16 @@
},
{
"name": "symfony/config",
- "version": "v5.4.9",
+ "version": "v5.4.11",
"source": {
"type": "git",
"url": "https://github.com/symfony/config.git",
- "reference": "8f551fe22672ac7ab2c95fe46d899f960ed4d979"
+ "reference": "ec79e03125c1d2477e43dde8528535d90cc78379"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/config/zipball/8f551fe22672ac7ab2c95fe46d899f960ed4d979",
- "reference": "8f551fe22672ac7ab2c95fe46d899f960ed4d979",
+ "url": "https://api.github.com/repos/symfony/config/zipball/ec79e03125c1d2477e43dde8528535d90cc78379",
+ "reference": "ec79e03125c1d2477e43dde8528535d90cc78379",
"shasum": ""
},
"require": {
@@ -6358,7 +6357,7 @@
"description": "Helps you find, load, combine, autofill and validate configuration values of any kind",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/config/tree/v5.4.9"
+ "source": "https://github.com/symfony/config/tree/v5.4.11"
},
"funding": [
{
@@ -6374,7 +6373,7 @@
"type": "tidelift"
}
],
- "time": "2022-05-17T10:39:36+00:00"
+ "time": "2022-07-20T13:00:38+00:00"
},
{
"name": "symfony/console",
@@ -6543,16 +6542,16 @@
},
{
"name": "symfony/dependency-injection",
- "version": "v5.4.10",
+ "version": "v5.4.13",
"source": {
"type": "git",
"url": "https://github.com/symfony/dependency-injection.git",
- "reference": "88d1c0d38c2e60f757fa11d89cfc885f0b7f5171"
+ "reference": "24cf522668845391c0542bc1de496366072a6d0e"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/88d1c0d38c2e60f757fa11d89cfc885f0b7f5171",
- "reference": "88d1c0d38c2e60f757fa11d89cfc885f0b7f5171",
+ "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/24cf522668845391c0542bc1de496366072a6d0e",
+ "reference": "24cf522668845391c0542bc1de496366072a6d0e",
"shasum": ""
},
"require": {
@@ -6612,7 +6611,7 @@
"description": "Allows you to standardize and centralize the way objects are constructed in your application",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/dependency-injection/tree/v5.4.10"
+ "source": "https://github.com/symfony/dependency-injection/tree/v5.4.13"
},
"funding": [
{
@@ -6628,7 +6627,7 @@
"type": "tidelift"
}
],
- "time": "2022-06-26T13:00:04+00:00"
+ "time": "2022-08-30T19:10:13+00:00"
},
{
"name": "symfony/deprecation-contracts",
@@ -6855,20 +6854,20 @@
},
{
"name": "symfony/event-dispatcher-contracts",
- "version": "v2.5.2",
+ "version": "v3.1.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/event-dispatcher-contracts.git",
- "reference": "f98b54df6ad059855739db6fcbc2d36995283fe1"
+ "reference": "02ff5eea2f453731cfbc6bc215e456b781480448"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/f98b54df6ad059855739db6fcbc2d36995283fe1",
- "reference": "f98b54df6ad059855739db6fcbc2d36995283fe1",
+ "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/02ff5eea2f453731cfbc6bc215e456b781480448",
+ "reference": "02ff5eea2f453731cfbc6bc215e456b781480448",
"shasum": ""
},
"require": {
- "php": ">=7.2.5",
+ "php": ">=8.1",
"psr/event-dispatcher": "^1"
},
"suggest": {
@@ -6877,7 +6876,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-main": "2.5-dev"
+ "dev-main": "3.1-dev"
},
"thanks": {
"name": "symfony/contracts",
@@ -6914,7 +6913,7 @@
"standards"
],
"support": {
- "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v2.5.2"
+ "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.1.1"
},
"funding": [
{
@@ -6930,7 +6929,7 @@
"type": "tidelift"
}
],
- "time": "2022-01-02T09:53:40+00:00"
+ "time": "2022-02-25T11:15:52+00:00"
},
{
"name": "symfony/filesystem",
@@ -10546,22 +10545,22 @@
},
{
"name": "magento/magento-coding-standard",
- "version": "26",
+ "version": "27",
"source": {
"type": "git",
"url": "https://github.com/magento/magento-coding-standard.git",
- "reference": "0263b8952b509848ffdab1ea9ab738f48450677c"
+ "reference": "097bda3e015f35dc7c2efc0b8c7a7d8dfc158a63"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/magento/magento-coding-standard/zipball/0263b8952b509848ffdab1ea9ab738f48450677c",
- "reference": "0263b8952b509848ffdab1ea9ab738f48450677c",
+ "url": "https://api.github.com/repos/magento/magento-coding-standard/zipball/097bda3e015f35dc7c2efc0b8c7a7d8dfc158a63",
+ "reference": "097bda3e015f35dc7c2efc0b8c7a7d8dfc158a63",
"shasum": ""
},
"require": {
"ext-dom": "*",
"ext-simplexml": "*",
- "php": ">=7.3",
+ "php": "^8.1||^8.2",
"phpcompatibility/php-compatibility": "^9.3",
"rector/rector": "^0.13.0",
"squizlabs/php_codesniffer": "^3.6.1",
@@ -10588,9 +10587,9 @@
"description": "A set of Magento specific PHP CodeSniffer rules.",
"support": {
"issues": "https://github.com/magento/magento-coding-standard/issues",
- "source": "https://github.com/magento/magento-coding-standard/tree/v26"
+ "source": "https://github.com/magento/magento-coding-standard/tree/v27"
},
- "time": "2022-10-04T10:45:15+00:00"
+ "time": "2022-10-17T15:19:28+00:00"
},
{
"name": "magento/magento2-functional-testing-framework",
@@ -10795,16 +10794,16 @@
},
{
"name": "pdepend/pdepend",
- "version": "2.10.3",
+ "version": "2.12.1",
"source": {
"type": "git",
"url": "https://github.com/pdepend/pdepend.git",
- "reference": "da3166a06b4a89915920a42444f707122a1584c9"
+ "reference": "7a892d56ceafd804b4a2ecc85184640937ce9e84"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/pdepend/pdepend/zipball/da3166a06b4a89915920a42444f707122a1584c9",
- "reference": "da3166a06b4a89915920a42444f707122a1584c9",
+ "url": "https://api.github.com/repos/pdepend/pdepend/zipball/7a892d56ceafd804b4a2ecc85184640937ce9e84",
+ "reference": "7a892d56ceafd804b4a2ecc85184640937ce9e84",
"shasum": ""
},
"require": {
@@ -10840,7 +10839,7 @@
"description": "Official version of pdepend to be handled with Composer",
"support": {
"issues": "https://github.com/pdepend/pdepend/issues",
- "source": "https://github.com/pdepend/pdepend/tree/2.10.3"
+ "source": "https://github.com/pdepend/pdepend/tree/2.12.1"
},
"funding": [
{
@@ -10848,7 +10847,7 @@
"type": "tidelift"
}
],
- "time": "2022-02-23T07:53:09+00:00"
+ "time": "2022-09-08T19:30:37+00:00"
},
{
"name": "phar-io/manifest",
@@ -11011,6 +11010,7 @@
"issues": "https://github.com/PHP-CS-Fixer/diff/issues",
"source": "https://github.com/PHP-CS-Fixer/diff/tree/v2.0.2"
},
+ "abandoned": true,
"time": "2020-10-14T08:32:19+00:00"
},
{
@@ -11302,22 +11302,22 @@
},
{
"name": "phpmd/phpmd",
- "version": "2.12.0",
+ "version": "2.13.0",
"source": {
"type": "git",
"url": "https://github.com/phpmd/phpmd.git",
- "reference": "c0b678ba71902f539c27c14332aa0ddcf14388ec"
+ "reference": "dad0228156856b3ad959992f9748514fa943f3e3"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpmd/phpmd/zipball/c0b678ba71902f539c27c14332aa0ddcf14388ec",
- "reference": "c0b678ba71902f539c27c14332aa0ddcf14388ec",
+ "url": "https://api.github.com/repos/phpmd/phpmd/zipball/dad0228156856b3ad959992f9748514fa943f3e3",
+ "reference": "dad0228156856b3ad959992f9748514fa943f3e3",
"shasum": ""
},
"require": {
"composer/xdebug-handler": "^1.0 || ^2.0 || ^3.0",
"ext-xml": "*",
- "pdepend/pdepend": "^2.10.3",
+ "pdepend/pdepend": "^2.12.1",
"php": ">=5.3.9"
},
"require-dev": {
@@ -11373,7 +11373,7 @@
"support": {
"irc": "irc://irc.freenode.org/phpmd",
"issues": "https://github.com/phpmd/phpmd/issues",
- "source": "https://github.com/phpmd/phpmd/tree/2.12.0"
+ "source": "https://github.com/phpmd/phpmd/tree/2.13.0"
},
"funding": [
{
@@ -11381,7 +11381,7 @@
"type": "tidelift"
}
],
- "time": "2022-03-24T13:33:01+00:00"
+ "time": "2022-09-10T08:44:15+00:00"
},
{
"name": "phpspec/prophecy",
@@ -11976,20 +11976,20 @@
},
{
"name": "psr/cache",
- "version": "1.0.1",
+ "version": "3.0.0",
"source": {
"type": "git",
"url": "https://github.com/php-fig/cache.git",
- "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8"
+ "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/php-fig/cache/zipball/d11b50ad223250cf17b86e38383413f5a6764bf8",
- "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8",
+ "url": "https://api.github.com/repos/php-fig/cache/zipball/aa5030cfa5405eccfdcb1083ce040c2cb8d253bf",
+ "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf",
"shasum": ""
},
"require": {
- "php": ">=5.3.0"
+ "php": ">=8.0.0"
},
"type": "library",
"extra": {
@@ -12009,7 +12009,7 @@
"authors": [
{
"name": "PHP-FIG",
- "homepage": "http://www.php-fig.org/"
+ "homepage": "https://www.php-fig.org/"
}
],
"description": "Common interface for caching libraries",
@@ -12019,9 +12019,9 @@
"psr-6"
],
"support": {
- "source": "https://github.com/php-fig/cache/tree/master"
+ "source": "https://github.com/php-fig/cache/tree/3.0.0"
},
- "time": "2016-08-06T20:24:11+00:00"
+ "time": "2021-02-03T23:26:27+00:00"
},
{
"name": "rector/rector",
@@ -13700,7 +13700,7 @@
"prefer-stable": true,
"prefer-lowest": false,
"platform": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"ext-bcmath": "*",
"ext-ctype": "*",
"ext-curl": "*",
@@ -13720,5 +13720,5 @@
"lib-libxml": "*"
},
"platform-dev": [],
- "plugin-api-version": "2.3.0"
+ "plugin-api-version": "2.2.0"
}
diff --git a/dev/tests/api-functional/testsuite/Magento/Customer/Api/AccountManagementRevokeCustomerTokenTest.php b/dev/tests/api-functional/testsuite/Magento/Customer/Api/AccountManagementRevokeCustomerTokenTest.php
new file mode 100644
index 0000000000000..66ed169d92b2f
--- /dev/null
+++ b/dev/tests/api-functional/testsuite/Magento/Customer/Api/AccountManagementRevokeCustomerTokenTest.php
@@ -0,0 +1,99 @@
+getCustomerToken();
+ $serviceInfo = [
+ 'rest' => [
+ 'resourcePath' => self::RESOURCE_PATH,
+ 'httpMethod' => Request::HTTP_METHOD_POST,
+ 'token' => $token,
+ ],
+ 'soap' => [
+ 'service' => self::INTEGRATION_SERVICE,
+ 'serviceVersion' => self::SERVICE_VERSION,
+ 'operation' => self::INTEGRATION_SERVICE . 'RevokeCustomerAccessToken',
+ 'token' => $token,
+ ]
+ ];
+
+ $requestData = [];
+ if (TESTS_WEB_API_ADAPTER === self::ADAPTER_SOAP) {
+ $requestData['customerId'] = 0;
+ }
+
+ $this->assertTrue($this->_webApiCall($serviceInfo, $requestData));
+ }
+
+ /**
+ * @return string
+ *
+ * @throws AuthenticationException
+ */
+ private function getCustomerToken(): string
+ {
+ $userName = 'customer@example.com';
+ $password = 'password';
+
+ /** @var CustomerTokenServiceInterface $customerTokenService */
+ $customerTokenService = ObjectManager::getInstance()->get(CustomerTokenServiceInterface::class);
+
+ return $customerTokenService->createCustomerAccessToken($userName, $password);
+ }
+
+ /**
+ * Test token revoking for guest customer
+ */
+ public function testRevokeCustomerTokenForGuestCustomer(): void
+ {
+ $this->expectException(Exception::class);
+ $requestData = [];
+
+ if (TESTS_WEB_API_ADAPTER === self::ADAPTER_SOAP) {
+ $requestData['customerId'] = 0;
+ }
+
+ $serviceInfo = [
+ 'rest' => [
+ 'resourcePath' => self::RESOURCE_PATH,
+ 'httpMethod' => Request::HTTP_METHOD_POST,
+ ],
+ 'soap' => [
+ 'service' => self::INTEGRATION_SERVICE,
+ 'serviceVersion' => self::SERVICE_VERSION,
+ 'operation' => self::INTEGRATION_SERVICE . 'RevokeCustomerAccessToken',
+ ]
+ ];
+
+ $this->_webApiCall($serviceInfo, $requestData);
+ }
+}
diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Sales/InvoiceTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Sales/InvoiceTest.php
index 8b18d4bd07d1b..5d4495e9a5c36 100644
--- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Sales/InvoiceTest.php
+++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Sales/InvoiceTest.php
@@ -7,9 +7,23 @@
namespace Magento\GraphQl\Sales;
+use Magento\Catalog\Test\Fixture\Product as ProductFixture;
+use Magento\Checkout\Test\Fixture\PlaceOrder as PlaceOrderFixture;
+use Magento\Checkout\Test\Fixture\SetBillingAddress as SetBillingAddressFixture;
+use Magento\Checkout\Test\Fixture\SetDeliveryMethod as SetDeliveryMethodFixture;
+use Magento\Checkout\Test\Fixture\SetGuestEmail as SetGuestEmailFixture;
+use Magento\Checkout\Test\Fixture\SetPaymentMethod as SetPaymentMethodFixture;
+use Magento\Checkout\Test\Fixture\SetShippingAddress as SetShippingAddressFixture;
+use Magento\Customer\Test\Fixture\Customer;
use Magento\Framework\Registry;
+use Magento\Quote\Test\Fixture\AddProductToCart as AddProductToCartFixture;
+use Magento\Quote\Test\Fixture\CustomerCart;
+use Magento\Quote\Test\Fixture\GuestCart as GuestCartFixture;
use Magento\Sales\Api\OrderRepositoryInterface;
use Magento\Sales\Model\ResourceModel\Order\Collection;
+use Magento\Sales\Test\Fixture\Invoice as InvoiceFixture;
+use Magento\Sales\Test\Fixture\InvoiceComment as InvoiceCommentFixture ;
+use Magento\TestFramework\Fixture\DataFixture;
use Magento\TestFramework\Helper\Bootstrap;
use Magento\TestFramework\TestCase\GraphQlAbstract;
use Magento\GraphQl\GetCustomerAuthenticationHeader;
@@ -410,6 +424,64 @@ public function testPartialInvoiceForCustomerWithTaxesAndDiscounts()
$this->deleteOrder();
}
+ #[
+ DataFixture(Customer::class, ['email' => 'customer@search.example.com'], as: 'customer'),
+ DataFixture(ProductFixture::class, as: 'product'),
+ DataFixture(CustomerCart::class, ['customer_id' => '$customer.id$'], as: 'cart'),
+ DataFixture(AddProductToCartFixture::class, ['cart_id' => '$cart.id$', 'product_id' => '$product.id$']),
+ DataFixture(SetBillingAddressFixture::class, ['cart_id' => '$cart.id$']),
+ DataFixture(SetShippingAddressFixture::class, ['cart_id' => '$cart.id$']),
+ DataFixture(SetGuestEmailFixture::class, ['cart_id' => '$cart.id$']),
+ DataFixture(SetDeliveryMethodFixture::class, ['cart_id' => '$cart.id$']),
+ DataFixture(SetPaymentMethodFixture::class, ['cart_id' => '$cart.id$']),
+ DataFixture(PlaceOrderFixture::class, ['cart_id' => '$cart.id$'], 'order'),
+ DataFixture(InvoiceFixture::class, ['order_id' => '$order.id$'], 'invoice'),
+ DataFixture(InvoiceCommentFixture::class, [
+ 'parent_id' => '$invoice.id$',
+ 'comment' => 'visible_comment',
+ 'is_visible_on_front' => 1,
+ ]),
+ DataFixture(InvoiceCommentFixture::class, [
+ 'parent_id' => '$invoice.id$',
+ 'comment' => 'non_visible_comment',
+ 'is_visible_on_front' => 0,
+ ]),
+ ]
+ public function testInvoiceCommentsQuery()
+ {
+ $query =
+ <<graphQlQuery(
+ $query,
+ [],
+ '',
+ $this->customerAuthenticationHeader->execute($currentEmail, $currentPassword)
+ );
+
+ $invoice = $response['customer']['orders']['items'][0]['invoices'][0];
+ $this->assertCount(1, $invoice['comments']);
+ $this->assertEquals('visible_comment', $invoice['comments'][0]['message']);
+ $this->assertNotEmpty($invoice['comments'][0]['timestamp']);
+ }
+
/**
* Prepare invoice for the order
*
diff --git a/dev/tests/integration/_files/Magento/TestModuleCatalogSearch/Model/SearchEngineVersionReader.php b/dev/tests/integration/_files/Magento/TestModuleCatalogSearch/Model/SearchEngineVersionReader.php
index 3c49b2ed63ff1..b565caae4e3fc 100644
--- a/dev/tests/integration/_files/Magento/TestModuleCatalogSearch/Model/SearchEngineVersionReader.php
+++ b/dev/tests/integration/_files/Magento/TestModuleCatalogSearch/Model/SearchEngineVersionReader.php
@@ -31,6 +31,9 @@ class SearchEngineVersionReader
public function getFullVersion(): string
{
$version = $this->getVersion();
+ if (strtolower($this->getDistribution()) == 'opensearch') {
+ $version = 1;
+ }
return $this->getDistribution() . ($version === 1 ? '' : $version);
}
diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Block/Product/ListProduct/SortingTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Block/Product/ListProduct/SortingTest.php
index 3bfd90cd35a31..d690b68a3123f 100644
--- a/dev/tests/integration/testsuite/Magento/Catalog/Block/Product/ListProduct/SortingTest.php
+++ b/dev/tests/integration/testsuite/Magento/Catalog/Block/Product/ListProduct/SortingTest.php
@@ -395,7 +395,6 @@ private function updateCategorySortBy(
* @magentoDataFixture Magento/Catalog/_files/products_with_not_empty_layered_navigation_attribute.php
* @magentoDataFixture Magento/Framework/Search/_files/product_configurable_with_out-of-stock_child.php
* @magentoConfigFixture current_store cataloginventory/options/show_out_of_stock 1
- * @magentoConfigFixture default/catalog/search/engine elasticsearch7
* @dataProvider productListWithOutOfStockSortOrderDataProvider
* @param string $sortBy
* @param string $direction
@@ -416,7 +415,6 @@ public function testProductListOutOfStockSortOrderWithElasticsearch(
* @magentoDataFixture Magento/Catalog/_files/products_with_not_empty_layered_navigation_attribute.php
* @magentoDataFixture Magento/Framework/Search/_files/product_configurable_with_out-of-stock_child.php
* @magentoConfigFixture current_store cataloginventory/options/show_out_of_stock 1
- * @magentoConfigFixture default/catalog/search/engine mysql
* @dataProvider productListWithOutOfStockSortOrderDataProvider
* @param string $sortBy
* @param string $direction
diff --git a/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/ProductTest/ProductOptionsTest.php b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/ProductTest/ProductOptionsTest.php
index 050d125b3c944..121962a692d83 100644
--- a/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/ProductTest/ProductOptionsTest.php
+++ b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/ProductTest/ProductOptionsTest.php
@@ -7,10 +7,19 @@
namespace Magento\CatalogImportExport\Model\Import\ProductTest;
+use Magento\Catalog\Api\Data\ProductCustomOptionInterface;
use Magento\Catalog\Api\ProductCustomOptionRepositoryInterface;
use Magento\Catalog\Api\ProductRepositoryInterface;
+use Magento\Catalog\Helper\Data as CatalogConfig;
+use Magento\Catalog\Test\Fixture\Product as ProductFixture;
use Magento\CatalogImportExport\Model\Import\ProductTestBase;
+use Magento\ImportExport\Helper\Data as ImportExportConfig;
+use Magento\Store\Model\ScopeInterface;
use Magento\Store\Model\StoreManagerInterface;
+use Magento\Store\Test\Fixture\Store as StoreFixture;
+use Magento\TestFramework\Fixture\AppIsolation;
+use Magento\TestFramework\Fixture\Config;
+use Magento\TestFramework\Fixture\DataFixture;
/**
* Integration test for \Magento\CatalogImportExport\Model\Import\Product class.
@@ -140,99 +149,142 @@ public function testSaveCustomOptions(string $importFile, string $sku, int $expe
/**
* Tests adding of custom options with multiple store views
*
- * @magentoConfigFixture current_store catalog/price/scope 1
- * @magentoDataFixture Magento/Store/_files/core_second_third_fixturestore.php
+ * @dataProvider saveCustomOptionsWithMultipleStoreViewsDataProvider
+ * @param string $importFile
+ * @param array $expected
*/
- public function testSaveCustomOptionsWithMultipleStoreViews()
- {
+ #[
+ AppIsolation(true),
+ Config(CatalogConfig::XML_PATH_PRICE_SCOPE, CatalogConfig::PRICE_SCOPE_WEBSITE, ScopeInterface::SCOPE_STORE),
+ DataFixture(StoreFixture::class, ['code' => 'secondstore']),
+ DataFixture(
+ ProductFixture::class,
+ [
+ 'sku' => 'simple2',
+ 'options' => [
+ [
+ 'type' => ProductCustomOptionInterface::OPTION_TYPE_DROP_DOWN,
+ 'title' => 'Option 1',
+ 'values' => [
+ [
+ 'title' => 'Option 1 Value 1',
+ 'price' => 2.5,
+ 'sku' => 'option1value1',
+ ],
+ [
+ 'title' => 'Option 1 Value 2',
+ 'price' => 3,
+ 'sku' => 'option1value2',
+ ],
+ ]
+ ]
+ ]
+ ]
+ ),
+ ]
+ public function testSaveCustomOptionsWithMultipleStoreViews(
+ string $importFile,
+ array $expected
+ ) {
+ $expected = $this->getFullExpectedOptions($expected);
$objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager();
/** @var StoreManagerInterface $storeManager */
$storeManager = $objectManager->get(StoreManagerInterface::class);
- $storeCodes = [
- 'admin',
- 'default',
- 'secondstore',
- ];
- /** @var StoreManagerInterface $storeManager */
- $importFile = 'product_with_custom_options_and_multiple_store_views.csv';
- $sku = 'simple';
$pathToFile = __DIR__ . '/../_files/' . $importFile;
$importModel = $this->createImportModel($pathToFile);
$errors = $importModel->validateData();
$this->assertTrue($errors->getErrorsCount() == 0, 'Import File Validation Failed');
$importModel->importData();
/** @var \Magento\Catalog\Api\ProductRepositoryInterface $productRepository */
- $productRepository = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
+ $productRepository = $objectManager->get(
\Magento\Catalog\Api\ProductRepositoryInterface::class
);
- foreach ($storeCodes as $storeCode) {
- $storeManager->setCurrentStore($storeCode);
- $product = $productRepository->get($sku);
- $options = $product->getOptionInstance()->getProductOptions($product);
- $expectedData = $this->getExpectedOptionsData($pathToFile, $storeCode);
- $expectedData = $this->mergeWithExistingData($expectedData, $options);
- $actualData = $this->getActualOptionsData($options);
- // assert of equal type+titles
- $expectedOptions = $expectedData['options'];
- // we need to save key values
- $actualOptions = $actualData['options'];
- sort($expectedOptions);
- sort($actualOptions);
- $this->assertEquals(
- $expectedOptions,
- $actualOptions,
- 'Expected and actual options arrays does not match'
- );
-
- // assert of options data
- $this->assertCount(
- count($expectedData['data']),
- $actualData['data'],
- 'Expected and actual data count does not match'
- );
- $this->assertCount(
- count($expectedData['values']),
- $actualData['values'],
- 'Expected and actual values count does not match'
- );
-
- foreach ($expectedData['options'] as $expectedId => $expectedOption) {
- $elementExist = false;
- // find value in actual options and values
- foreach ($actualData['options'] as $actualId => $actualOption) {
- if ($actualOption == $expectedOption) {
- $elementExist = true;
- $this->assertEquals(
- $expectedData['data'][$expectedId],
- $actualData['data'][$actualId],
- 'Expected data does not match actual data'
- );
- if (array_key_exists($expectedId, $expectedData['values'])) {
- $this->assertEquals(
- $expectedData['values'][$expectedId],
- $actualData['values'][$actualId],
- 'Expected values does not match actual data'
- );
- }
- unset($actualData['options'][$actualId]);
- // remove value in case of duplicating key values
- break;
+ $actual = [];
+ foreach ($expected as $sku => $storesData) {
+ foreach (array_keys($storesData) as $storeCode) {
+ $product = $productRepository->get($sku, false, $storeManager->getStore($storeCode)->getId(), true);
+ $options = $product->getOptionInstance()->getProductOptions($product);
+ $actual[$sku][$storeCode] = [];
+ /** @var $option \Magento\Catalog\Model\Product\Option */
+ foreach ($options as $option) {
+ $optionData = [
+ 'type' => $option->getType(),
+ 'title' => $option->getTitle()
+ ];
+ $optionData += $this->getOptionData($option);
+ if (in_array($option->getType(), $this->specificTypes)) {
+ $optionData['values'] = $this->getOptionValues($option);
}
+ $actual[$sku][$storeCode][] = $optionData;
}
- $this->assertTrue($elementExist, 'Element must exist.');
}
+ }
+
+ $this->assertEquals($expected, $actual);
+
+ // Make sure that after importing existing options again, option IDs and option value IDs are not changed
+ $expectedIds = [];
+ $actualIds = [];
+ foreach (array_keys($expected) as $sku) {
+ $expectedIds[$sku] = $this->getCustomOptionValues($sku);
+ }
+ $importModel = $this->createImportModel($pathToFile);
+ $importModel->validateData();
+ $importModel->importData();
+ foreach (array_keys($expected) as $sku) {
+ $actualIds[$sku] = $this->getCustomOptionValues($sku);
- // Make sure that after importing existing options again, option IDs and option value IDs are not changed
- $customOptionValues = $this->getCustomOptionValues($sku);
- $importModel = $this->createImportModel($pathToFile);
- $importModel->validateData();
- $importModel->importData();
- $this->assertEquals(
- $customOptionValues,
- $this->getCustomOptionValues($sku),
- 'Option IDs changed after second import'
- );
}
+
+ $this->assertEquals(
+ $expectedIds,
+ $actualIds,
+ 'Option IDs changed after second import'
+ );
+ }
+
+ /**
+ * Tests adding of custom options with multiple store views across bunches
+ *
+ * @dataProvider saveCustomOptionsWithMultipleStoreViewsDataProvider
+ * @param string $importFile
+ * @param array $expected
+ */
+ #[
+ AppIsolation(true),
+ Config(CatalogConfig::XML_PATH_PRICE_SCOPE, CatalogConfig::PRICE_SCOPE_WEBSITE, ScopeInterface::SCOPE_STORE),
+ Config(ImportExportConfig::XML_PATH_BUNCH_SIZE, 2, ScopeInterface::SCOPE_STORE),
+ DataFixture(StoreFixture::class, ['code' => 'secondstore']),
+ DataFixture(
+ ProductFixture::class,
+ [
+ 'sku' => 'simple2',
+ 'options' => [
+ [
+ 'type' => ProductCustomOptionInterface::OPTION_TYPE_DROP_DOWN,
+ 'title' => 'Option 1',
+ 'values' => [
+ [
+ 'title' => 'Option 1 Value 1',
+ 'price' => 2.5,
+ 'sku' => 'option1value1',
+ ],
+ [
+ 'title' => 'Option 1 Value 2',
+ 'price' => 3,
+ 'sku' => 'option1value2',
+ ],
+ ]
+ ]
+ ]
+ ]
+ ),
+ ]
+ public function testSaveCustomOptionsWithMultipleStoreViewsAcrossMultipleBunches(
+ string $importFile,
+ array $expected
+ ) {
+ $this->testSaveCustomOptionsWithMultipleStoreViews($importFile, $expected);
}
/**
@@ -259,6 +311,401 @@ public function getBehaviorDataProvider(): array
];
}
+ /**
+ * @return array
+ * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
+ */
+ public function saveCustomOptionsWithMultipleStoreViewsDataProvider(): array
+ {
+ return [
+ [
+ 'product_with_custom_options_and_multiple_store_views.csv',
+ [
+ 'simple' => [
+ 'admin' => [
+ [
+ 'title' => 'Test Field Title',
+ 'type' => 'field',
+ 'is_require' => '1',
+ 'sku' => '1-text',
+ 'price' => '100.000000',
+ 'max_characters' => '0',
+ 'sort_order' => '1',
+ ],
+ [
+ 'title' => 'Test Date and Time Title',
+ 'type' => 'date_time',
+ 'is_require' => '1',
+ 'sku' => '2-date',
+ 'price' => '200.000000',
+ 'max_characters' => '0',
+ 'sort_order' => '2',
+ ],
+ [
+ 'title' => 'Test Select',
+ 'type' => 'drop_down',
+ 'is_require' => '1',
+ 'sku' => '',
+ 'price' => null,
+ 'max_characters' => '0',
+ 'sort_order' => '3',
+ 'values' => [
+ [
+ 'title' => 'Select Option 1',
+ 'sku' => '3-1-select',
+ 'price' => '310.000000',
+ ],
+ [
+ 'title' => 'Select Option 2',
+ 'sku' => '3-2-select',
+ 'price' => '320.000000',
+ ]
+ ]
+ ],
+ [
+ 'title' => 'Test Checkbox',
+ 'type' => 'checkbox',
+ 'is_require' => '1',
+ 'sku' => '',
+ 'price' => null,
+ 'max_characters' => '0',
+ 'sort_order' => '4',
+ 'values' => [
+ [
+ 'title' => 'Checkbox Option 1',
+ 'sku' => '4-1-select',
+ 'price' => '410.000000',
+ ],
+ [
+ 'title' => 'Checkbox Option 2',
+ 'sku' => '4-2-select',
+ 'price' => '420.000000',
+ ]
+ ]
+ ],
+ [
+ 'title' => 'Test Radio',
+ 'type' => 'radio',
+ 'is_require' => '1',
+ 'sku' => '',
+ 'price' => null,
+ 'max_characters' => '0',
+ 'sort_order' => '5',
+ 'values' => [
+ [
+ 'title' => 'Radio Option 1',
+ 'sku' => '5-1-radio',
+ 'price' => '510.000000',
+ ],
+ [
+ 'title' => 'Radio Option 2',
+ 'sku' => '5-2-radio',
+ 'price' => '520.000000',
+ ]
+ ]
+ ]
+ ],
+ 'default' => [
+ [
+ 'title' => 'Test Field Title_default',
+ ],
+ [
+ 'title' => 'Test Date and Time Title_default',
+ ],
+ [
+ 'title' => 'Test Select_default',
+ 'values' => [
+ [
+ 'title' => 'Select Option 1_default',
+ ],
+ [
+ 'title' => 'Select Option 2_default',
+ ]
+ ]
+ ],
+ [
+ 'title' => 'Test Checkbox_default',
+ 'values' => [
+ [
+ 'title' => 'Checkbox Option 1_default',
+ ],
+ [
+ 'title' => 'Checkbox Option 2_default',
+ ]
+ ]
+ ],
+ [
+ 'title' => 'Test Radio_default',
+ 'values' => [
+ [
+ 'title' => 'Radio Option 1_default',
+ ],
+ [
+ 'title' => 'Radio Option 2_default',
+ ]
+ ]
+ ]
+ ],
+ 'secondstore' => [
+ [
+ 'title' => 'Test Field Title_fixture_second_store',
+ 'price' => '101.000000'
+ ],
+ [
+ 'title' => 'Test Date and Time Title_fixture_second_store',
+ 'price' => '201.000000'
+ ],
+ [
+ 'title' => 'Test Select_fixture_second_store',
+ 'values' => [
+ [
+ 'title' => 'Select Option 1_fixture_second_store',
+ 'price' => '311.000000'
+ ],
+ [
+ 'title' => 'Select Option 2_fixture_second_store',
+ 'price' => '321.000000'
+ ]
+ ]
+ ],
+ [
+ 'title' => 'Test Checkbox_second_store',
+ 'values' => [
+ [
+ 'title' => 'Checkbox Option 1_second_store',
+ 'price' => '411.000000'
+ ],
+ [
+ 'title' => 'Checkbox Option 2_second_store',
+ 'price' => '421.000000'
+ ]
+ ]
+ ],
+ [
+ 'title' => 'Test Radio_fixture_second_store',
+ 'values' => [
+ [
+ 'title' => 'Radio Option 1_fixture_second_store',
+ 'price' => '511.000000'
+ ],
+ [
+ 'title' => 'Radio Option 2_fixture_second_store',
+ 'price' => '521.000000'
+ ]
+ ]
+ ]
+ ],
+ ],
+ 'newprod2' => [
+ 'admin' => [],
+ 'default' => [],
+ 'secondstore' => [],
+ ],
+ 'newprod3' => [
+ 'admin' => [
+ [
+ 'title' => 'Line 1',
+ 'type' => 'field',
+ 'is_require' => '1',
+ 'sku' => '',
+ 'price' => null,
+ 'max_characters' => '30',
+ 'sort_order' => '1',
+ ],
+ [
+ 'title' => 'Line 2',
+ 'type' => 'field',
+ 'is_require' => '0',
+ 'sku' => '',
+ 'price' => null,
+ 'max_characters' => '30',
+ 'sort_order' => '2',
+ ],
+ ],
+ 'default' => [
+ [
+ 'title' => 'Line 1',
+ 'type' => 'field',
+ 'is_require' => '1',
+ 'sku' => '',
+ 'price' => null,
+ 'max_characters' => '30',
+ 'sort_order' => '1',
+ ],
+ [
+ 'title' => 'Line 2',
+ 'type' => 'field',
+ 'is_require' => '0',
+ 'sku' => '',
+ 'price' => null,
+ 'max_characters' => '30',
+ 'sort_order' => '2',
+ ],
+ ],
+ 'secondstore' => [
+ [
+ 'title' => 'Line 1',
+ 'type' => 'field',
+ 'is_require' => '1',
+ 'sku' => '',
+ 'price' => null,
+ 'max_characters' => '30',
+ 'sort_order' => '1',
+ ],
+ [
+ 'title' => 'Line 2',
+ 'type' => 'field',
+ 'is_require' => '0',
+ 'sku' => '',
+ 'price' => null,
+ 'max_characters' => '30',
+ 'sort_order' => '2',
+ ],
+ ],
+ ],
+ 'newprod4' => [
+ 'admin' => [],
+ 'default' => [],
+ 'secondstore' => [],
+ ],
+ 'newprod5' => [
+ 'admin' => [
+ [
+ 'title' => 'Line 3',
+ 'type' => 'field',
+ 'is_require' => '1',
+ 'sku' => '',
+ 'price' => null,
+ 'max_characters' => '30',
+ 'sort_order' => '1',
+ ],
+ [
+ 'title' => 'Line 4',
+ 'type' => 'field',
+ 'is_require' => '0',
+ 'sku' => '',
+ 'price' => null,
+ 'max_characters' => '30',
+ 'sort_order' => '2',
+ ],
+ ],
+ 'default' => [
+ [
+ 'title' => 'Line 3',
+ 'type' => 'field',
+ 'is_require' => '1',
+ 'sku' => '',
+ 'price' => null,
+ 'max_characters' => '30',
+ 'sort_order' => '1',
+ ],
+ [
+ 'title' => 'Line 4',
+ 'type' => 'field',
+ 'is_require' => '0',
+ 'sku' => '',
+ 'price' => null,
+ 'max_characters' => '30',
+ 'sort_order' => '2',
+ ],
+ ],
+ 'secondstore' => [
+ [
+ 'title' => 'Line 3',
+ 'type' => 'field',
+ 'is_require' => '1',
+ 'sku' => '',
+ 'price' => null,
+ 'max_characters' => '30',
+ 'sort_order' => '1',
+ ],
+ [
+ 'title' => 'Line 4',
+ 'type' => 'field',
+ 'is_require' => '0',
+ 'sku' => '',
+ 'price' => null,
+ 'max_characters' => '30',
+ 'sort_order' => '2',
+ ],
+ ],
+ ],
+ 'simple2' => [
+ 'admin' => [
+ [
+ 'title' => 'Option 1',
+ 'type' => 'drop_down',
+ 'is_require' => '1',
+ 'sku' => '',
+ 'price' => null,
+ 'max_characters' => '0',
+ 'sort_order' => '1',
+ 'values' => [
+ [
+ 'title' => 'Option 1 Value 1',
+ 'sku' => 'option1value1',
+ 'price' => '1.200000',
+ ],
+ [
+ 'title' => 'Option 1 Value 2',
+ 'sku' => 'option1value2',
+ 'price' => '1.400000',
+ ]
+ ]
+ ]
+ ],
+ 'default' => [
+ [
+ 'title' => 'Option 1 Store1',
+ 'type' => 'drop_down',
+ 'is_require' => '1',
+ 'sku' => '',
+ 'price' => null,
+ 'max_characters' => '0',
+ 'sort_order' => '1',
+ 'values' => [
+ [
+ 'title' => 'Option 1 Value 1 Store1',
+ 'sku' => 'option1value1',
+ 'price' => '1.100000',
+ ],
+ [
+ 'title' => 'Option 1 Value 2 Store1',
+ 'sku' => 'option1value2',
+ 'price' => '1.300000',
+ ]
+ ]
+ ]
+ ],
+ 'secondstore' => [
+ [
+ 'title' => 'Option 1 Store2',
+ 'type' => 'drop_down',
+ 'is_require' => '1',
+ 'sku' => '',
+ 'price' => null,
+ 'max_characters' => '0',
+ 'sort_order' => '1',
+ 'values' => [
+ [
+ 'title' => 'Option 1 Value 1 Store2',
+ 'sku' => 'option1value1',
+ 'price' => '1.000000',
+ ],
+ [
+ 'title' => 'Option 1 Value 2 Store2',
+ 'sku' => 'option1value2',
+ 'price' => '1.200000',
+ ]
+ ]
+ ]
+ ],
+ ]
+ ]
+ ]
+ ];
+ }
+
/**
* @param string $productSku
* @return array ['optionId' => ['optionValueId' => 'optionValueTitle', ...], ...]
@@ -488,4 +935,27 @@ protected function getOptionValues(\Magento\Catalog\Model\Product\Option $option
return false;
}
+
+ /**
+ * @param array $expected
+ * @return array
+ */
+ private function getFullExpectedOptions(array $expected): array
+ {
+ foreach ($expected as &$data) {
+ foreach ($data as $store => &$options) {
+ if ($store !== 'admin') {
+ foreach ($options as $optKey => &$option) {
+ $option += $data['admin'][$optKey];
+ if (isset($option['values'])) {
+ foreach ($option['values'] as $valKey => &$value) {
+ $value += $data['admin'][$optKey]['values'][$valKey];
+ }
+ }
+ }
+ }
+ }
+ }
+ return $expected;
+ }
}
diff --git a/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/_files/product_with_custom_options_and_multiple_store_views.csv b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/_files/product_with_custom_options_and_multiple_store_views.csv
index 0d4c53ca5812d..6aefef5ed836a 100644
--- a/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/_files/product_with_custom_options_and_multiple_store_views.csv
+++ b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/_files/product_with_custom_options_and_multiple_store_views.csv
@@ -1,8 +1,11 @@
sku,website_code,store_view_code,attribute_set_code,product_type,name,description,short_description,weight,product_online,visibility,product_websites,categories,price,special_price,special_price_from_date,special_price_to_date,tax_class_name,url_key,meta_title,meta_keywords,meta_description,base_image,base_image_label,small_image,small_image_label,thumbnail_image,thumbnail_image_label,additional_images,additional_image_labels,configurable_variation_labels,configurable_variations,bundle_price_type,bundle_sku_type,bundle_weight_type,bundle_values,downloadble_samples,downloadble_links,associated_skus,related_skus,crosssell_skus,upsell_skus,custom_options,additional_attributes,manage_stock,is_in_stock,qty,out_of_stock_qty,is_qty_decimal,allow_backorders,min_cart_qty,max_cart_qty,notify_on_stock_below,qty_increments,enable_qty_increments,is_decimal_divided,new_from_date,new_to_date,gift_message_available,created_at,updated_at,custom_design,custom_design_from,custom_design_to,custom_layout_update,page_layout,product_options_container,msrp_price,msrp_display_actual_price_type,map_enabled
-simple,base,,Default,simple,New Product,,,9,1,"Catalog, Search","base,secondwebsite",,10,,,,Taxable Goods,new-product,,,,,,,,,,,,,,,,,,,,,,,,"name=Test Field Title,type=field,required=1,sku=1-text,price=100.000000|name=Test Date and Time Title,type=date_time,required=1,sku=2-date,price=200.000000|name=Test Select,type=drop_down,required=1,sku=3-1-select,price=310.000000,option_title=Select Option 1|name=Test Select,type=drop_down,required=1,sku=3-2-select,price=320.000000,option_title=Select Option 2|name=Test Checkbox,type=checkbox,required=1,sku=4-1-select,price=410.000000,option_title=Checkbox Option 1|name=Test Checkbox,type=checkbox,required=1,sku=4-2-select,price=420.000000,option_title=Checkbox Option 2|name=Test Radio,type=radio,required=1,sku=5-1-radio,price=510.000000,option_title=Radio Option 1|name=Test Radio,type=radio,required=1,sku=5-2-radio,price=520.000000,option_title=Radio Option 2",,1,1,999,0,0,0,1,10000,1,1,0,0,,,,,,,,,,,Block after Info Column,,,
-simple,,default,Default,simple,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"name=Test Field Title_default,type=field,sku=1-text|name=Test Date and Time Title_default,type=date_time,sku=2-date|name=Test Select_default,type=drop_down,sku=3-1-select,option_title=Select Option 1_default|name=Test Select_default,type=drop_down,sku=3-2-select,option_title=Select Option 2_default|name=Test Checkbox_default,type=checkbox,sku=4-1-select,option_title=Checkbox Option 1_default|name=Test Checkbox_default,type=checkbox,sku=4-2-select,option_title=Checkbox Option 2_default|name=Test Radio_default,type=radio,sku=5-1-radio,option_title=Radio Option 1_default|name=Test Radio_default,type=radio,sku=5-2-radio,option_title=Radio Option 2_default",,,,,,,,,,,,,,,,,,,,,,,,,,,
-simple,,secondstore,Default,simple,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"name=Test Field Title_fixture_second_store,type=field,sku=1-text,price=101.000000|name=Test Date and Time Title_fixture_second_store,type=date_time,sku=2-date,price=201.000000|name=Test Select_fixture_second_store,type=drop_down,sku=3-1-select,price=311.000000,option_title=Select Option 1_fixture_second_store|name=Test Select_fixture_second_store,type=drop_down,sku=3-2-select,price=321.000000,option_title=Select Option 2_fixture_second_store|name=Test Checkbox_second_store,type=checkbox,sku=4-1-select,price=411.000000,option_title=Checkbox Option 1_second_store|name=Test Checkbox_second_store,type=checkbox,sku=4-2-select,price=421.000000,option_title=Checkbox Option 2_second_store|name=Test Radio_fixture_second_store,type=radio,sku=5-1-radio,price=511.000000,option_title=Radio Option 1_fixture_second_store|name=Test Radio_fixture_second_store,type=radio,sku=5-2-radio,price=521.000000,option_title=Radio Option 2_fixture_second_store",,,,,,,,,,,,,,,,,,,,,,,,,,,
-newprod2,base,secondstore,Default,configurable,New Product 2,,,9,1,"Catalog, Search","base,secondwebsite",,10,,,,Taxable Goods,new-product-2,,,,,,,,,,,,,,,,,,,,,,,,,,1,1,999,0,0,0,1,10000,1,1,0,0,,,,,,,,,,,Block after Info Column,,,
-newprod3,base,,Default,configurable,New Product 3,,,9,1,"Catalog, Search","base,secondwebsite",,10,,,,Taxable Goods,new-product-3,,,,,,,,,,,,,,,,,,,,,,,,"name=Line 1,type=field,max_characters=30,required=1,option_title=Line 1|name=Line 2,type=field,max_characters=30,required=0,option_title=Line 2",,1,1,999,0,0,0,1,10000,1,1,0,0,,,,,,,,,,,Block after Info Column,,,
-newprod4,base,secondstore,Default,configurable,New Product 4,,,9,1,"Catalog, Search","base,secondwebsite",,10,,,,Taxable Goods,new-product-4,,,,,,,,,,,,,,,,,,,,,,,,,,1,1,999,0,0,0,1,10000,1,1,0,0,,,,,,,,,,,Block after Info Column,,,
-newprod5,base,,Default,configurable,New Product 5,,,9,1,"Catalog, Search","base,secondwebsite",,10,,,,Taxable Goods,new-product-5,,,,,,,,,,,,,,,,,,,,,,,,"name=Line 3,type=field,max_characters=30,required=1,option_title=Line 3|name=Line 4,type=field,max_characters=30,required=0,option_title=Line 4",,1,1,999,0,0,0,1,10000,1,1,0,0,,,,,,,,,,,Block after Info Column,,,
+simple,base,,Default,simple,New Product,,,9,1,"Catalog, Search",base,,10,,,,Taxable Goods,new-product,,,,,,,,,,,,,,,,,,,,,,,,"name=Test Field Title,type=field,required=1,sku=1-text,price=100.000000|name=Test Date and Time Title,type=date_time,required=1,sku=2-date,price=200.000000|name=Test Select,type=drop_down,required=1,sku=3-1-select,price=310.000000,option_title=Select Option 1|name=Test Select,type=drop_down,required=1,sku=3-2-select,price=320.000000,option_title=Select Option 2|name=Test Checkbox,type=checkbox,required=1,sku=4-1-select,price=410.000000,option_title=Checkbox Option 1|name=Test Checkbox,type=checkbox,required=1,sku=4-2-select,price=420.000000,option_title=Checkbox Option 2|name=Test Radio,type=radio,required=1,sku=5-1-radio,price=510.000000,option_title=Radio Option 1|name=Test Radio,type=radio,required=1,sku=5-2-radio,price=520.000000,option_title=Radio Option 2",,1,1,999,0,0,0,1,10000,1,1,0,0,,,,,,,,,,,Block after Info Column,,,
+simple,,default,Default,simple,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"name=Test Field Title_default,type=field,required=1,sku=1-text|name=Test Date and Time Title_default,type=date_time,required=1,sku=2-date|name=Test Select_default,type=drop_down,required=1,sku=3-1-select,option_title=Select Option 1_default|name=Test Select_default,type=drop_down,required=1,sku=3-2-select,option_title=Select Option 2_default|name=Test Checkbox_default,type=checkbox,required=1,sku=4-1-select,option_title=Checkbox Option 1_default|name=Test Checkbox_default,type=checkbox,required=1,sku=4-2-select,option_title=Checkbox Option 2_default|name=Test Radio_default,type=radio,required=1,sku=5-1-radio,option_title=Radio Option 1_default|name=Test Radio_default,type=radio,required=1,sku=5-2-radio,option_title=Radio Option 2_default",,,,,,,,,,,,,,,,,,,,,,,,,,,
+simple,,secondstore,Default,simple,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"name=Test Field Title_fixture_second_store,type=field,required=1,sku=1-text,price=101.000000|name=Test Date and Time Title_fixture_second_store,type=date_time,required=1,sku=2-date,price=201.000000|name=Test Select_fixture_second_store,type=drop_down,required=1,sku=3-1-select,price=311.000000,option_title=Select Option 1_fixture_second_store|name=Test Select_fixture_second_store,type=drop_down,required=1,sku=3-2-select,price=321.000000,option_title=Select Option 2_fixture_second_store|name=Test Checkbox_second_store,type=checkbox,required=1,sku=4-1-select,price=411.000000,option_title=Checkbox Option 1_second_store|name=Test Checkbox_second_store,type=checkbox,required=1,sku=4-2-select,price=421.000000,option_title=Checkbox Option 2_second_store|name=Test Radio_fixture_second_store,type=radio,required=1,sku=5-1-radio,price=511.000000,option_title=Radio Option 1_fixture_second_store|name=Test Radio_fixture_second_store,type=radio,required=1,sku=5-2-radio,price=521.000000,option_title=Radio Option 2_fixture_second_store",,,,,,,,,,,,,,,,,,,,,,,,,,,
+newprod2,base,secondstore,Default,configurable,New Product 2,,,9,1,"Catalog, Search",base,,10,,,,Taxable Goods,new-product-2,,,,,,,,,,,,,,,,,,,,,,,,,,1,1,999,0,0,0,1,10000,1,1,0,0,,,,,,,,,,,Block after Info Column,,,
+newprod3,base,,Default,configurable,New Product 3,,,9,1,"Catalog, Search",base,,10,,,,Taxable Goods,new-product-3,,,,,,,,,,,,,,,,,,,,,,,,"name=Line 1,type=field,max_characters=30,required=1,option_title=Line 1|name=Line 2,type=field,max_characters=30,required=0,option_title=Line 2",,1,1,999,0,0,0,1,10000,1,1,0,0,,,,,,,,,,,Block after Info Column,,,
+newprod4,base,secondstore,Default,configurable,New Product 4,,,9,1,"Catalog, Search",base,,10,,,,Taxable Goods,new-product-4,,,,,,,,,,,,,,,,,,,,,,,,,,1,1,999,0,0,0,1,10000,1,1,0,0,,,,,,,,,,,Block after Info Column,,,
+newprod5,base,,Default,configurable,New Product 5,,,9,1,"Catalog, Search",base,,10,,,,Taxable Goods,new-product-5,,,,,,,,,,,,,,,,,,,,,,,,"name=Line 3,type=field,max_characters=30,required=1,option_title=Line 3|name=Line 4,type=field,max_characters=30,required=0,option_title=Line 4",,1,1,999,0,0,0,1,10000,1,1,0,0,,,,,,,,,,,Block after Info Column,,,
+simple2,base,,Default,simple,Simple 2,,,9,1,"Catalog, Search",base,,10,,,,Taxable Goods,,,,,,,,,,,,,,,,,,,,,,,,,"name=Option 1,type=drop_down,required=1,sku=option1value1,price=1.2,option_title=Option 1 Value 1|name=Option 1,type=drop_down,required=1,sku=option1value2,price=1.4,option_title=Option 1 Value 2",,1,1,999,0,0,0,1,10000,1,1,0,0,,,,,,,,,,,Block after Info Column,,,
+simple2,,default,Default,simple,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"name=Option 1 Store1,type=drop_down,required=1,sku=option1value1,price=1.1,option_title=Option 1 Value 1 Store1|name=Option 1 Store1,type=drop_down,required=1,sku=option1value2,price=1.3,option_title=Option 1 Value 2 Store1",,1,1,999,0,0,0,1,10000,1,1,0,0,,,,,,,,,,,,,,
+simple2,,secondstore,Default,simple,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"name=Option 1 Store2,type=drop_down,required=1,sku=option1value1,price=1.0,option_title=Option 1 Value 1 Store2|name=Option 1 Store2,type=drop_down,required=1,sku=option1value2,price=1.2,option_title=Option 1 Value 2 Store2",,1,1,999,0,0,0,1,10000,1,1,0,0,,,,,,,,,,,,,,
diff --git a/dev/tests/integration/testsuite/Magento/CatalogRule/Model/ResourceModel/Product/ConditionsToCollectionApplierTest.php b/dev/tests/integration/testsuite/Magento/CatalogRule/Model/ResourceModel/Product/ConditionsToCollectionApplierTest.php
index b06de8109ecbd..778c7c42249fc 100644
--- a/dev/tests/integration/testsuite/Magento/CatalogRule/Model/ResourceModel/Product/ConditionsToCollectionApplierTest.php
+++ b/dev/tests/integration/testsuite/Magento/CatalogRule/Model/ResourceModel/Product/ConditionsToCollectionApplierTest.php
@@ -433,6 +433,22 @@ private function conditionProvider()
'simple-product-13',
]
],
+
+ // test filter by multiple sku and "is not one of" condition
+ 'variation 23' => [
+ 'condition' => $this->getConditionsForVariation23(),
+ 'expected-sku' => [
+ 'simple-product-3',
+ 'simple-product-4',
+ 'simple-product-6',
+ 'simple-product-7',
+ 'simple-product-8',
+ 'simple-product-9',
+ 'simple-product-11',
+ 'simple-product-12',
+ 'simple-product-13',
+ ]
+ ],
];
}
@@ -1058,6 +1074,25 @@ private function getConditionsForVariation22()
return $this->getCombineConditionFromArray($conditions);
}
+ private function getConditionsForVariation23()
+ {
+ $conditions = [
+ 'type' => \Magento\CatalogRule\Model\Rule\Condition\Combine::class,
+ 'aggregator' => 'all',
+ 'value' => 1,
+ 'conditions' => [
+ [
+ 'type' => \Magento\CatalogRule\Model\Rule\Condition\Product::class,
+ 'operator' => '!()',
+ 'value' => 'simple-product-1, simple-product-2, simple-product-5, simple-product-10',
+ 'attribute' => 'sku'
+ ]
+ ]
+ ];
+
+ return $this->getCombineConditionFromArray($conditions);
+ }
+
private function getCombineConditionFromArray(array $data)
{
$combinedCondition = $this->combinedConditionFactory->create();
diff --git a/dev/tests/integration/testsuite/Magento/CatalogWidget/Model/Rule/Condition/ProductTest.php b/dev/tests/integration/testsuite/Magento/CatalogWidget/Model/Rule/Condition/ProductTest.php
index e231251db2c3f..37077d60e683a 100644
--- a/dev/tests/integration/testsuite/Magento/CatalogWidget/Model/Rule/Condition/ProductTest.php
+++ b/dev/tests/integration/testsuite/Magento/CatalogWidget/Model/Rule/Condition/ProductTest.php
@@ -102,11 +102,11 @@ public function testAddNonGlobalAttributeToCollectionNoProducts()
$this->conditionProduct->addToCollection($collection);
$collectedAttributes = $this->conditionProduct->getRule()->getCollectedAttributes();
$this->assertArrayHasKey('visibility', $collectedAttributes);
- $query = (string)$collection->getSelect();
- $this->assertStringNotContainsString('visibility', $query);
- $this->assertEquals('', $this->conditionProduct->getMappedSqlField());
+ $this->assertEquals(0, $collection->getSize());
+ $this->assertStringContainsString('visibility', (string)$this->conditionProduct->getMappedSqlField());
$this->assertFalse($this->conditionProduct->hasValueParsed());
- $this->assertFalse($this->conditionProduct->hasValue());
+ $this->assertTrue($this->conditionProduct->hasValue());
+ $this->assertEquals('4', $this->conditionProduct->getValue());
}
/**
@@ -121,9 +121,11 @@ public function testAddNonGlobalAttributeToCollection()
$this->conditionProduct->addToCollection($collection);
$collectedAttributes = $this->conditionProduct->getRule()->getCollectedAttributes();
$this->assertArrayHasKey('visibility', $collectedAttributes);
- $query = (string)$collection->getSelect();
- $this->assertStringNotContainsString('visibility', $query);
- $this->assertEquals('e.entity_id', $this->conditionProduct->getMappedSqlField());
+ $this->assertEquals(1, $collection->getSize());
+ $this->assertStringContainsString('visibility', (string)$this->conditionProduct->getMappedSqlField());
+ $this->assertFalse($this->conditionProduct->hasValueParsed());
+ $this->assertTrue($this->conditionProduct->hasValue());
+ $this->assertEquals('4', $this->conditionProduct->getValue());
}
/**
diff --git a/lib/internal/Magento/Framework/Amqp/composer.json b/lib/internal/Magento/Framework/Amqp/composer.json
index 701f2df167065..d6f7337988934 100644
--- a/lib/internal/Magento/Framework/Amqp/composer.json
+++ b/lib/internal/Magento/Framework/Amqp/composer.json
@@ -11,7 +11,7 @@
],
"require": {
"magento/framework": "*",
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"php-amqplib/php-amqplib": "~3.2.0"
},
"autoload": {
diff --git a/lib/internal/Magento/Framework/Api/SearchCriteria/CollectionProcessor/FilterProcessor.php b/lib/internal/Magento/Framework/Api/SearchCriteria/CollectionProcessor/FilterProcessor.php
index 2f4c097b1f02a..9668f4e2239df 100644
--- a/lib/internal/Magento/Framework/Api/SearchCriteria/CollectionProcessor/FilterProcessor.php
+++ b/lib/internal/Magento/Framework/Api/SearchCriteria/CollectionProcessor/FilterProcessor.php
@@ -140,7 +140,7 @@ private function checkFromTo(&$fields, &$conditions)
$_fields = array_unique($fields);
$_conditions = [];
foreach ($conditions as $condition) {
- $_conditions[array_key_first($condition)] = array_first($condition);
+ $_conditions[array_key_first($condition)] = reset($condition);
}
if ((count($_fields) == 1) && (count($_conditions) == 2)
&& isset($_conditions['from']) && isset($_conditions['to'])
diff --git a/lib/internal/Magento/Framework/App/DeploymentConfig.php b/lib/internal/Magento/Framework/App/DeploymentConfig.php
index 538e653549550..6713baa3a1d54 100644
--- a/lib/internal/Magento/Framework/App/DeploymentConfig.php
+++ b/lib/internal/Magento/Framework/App/DeploymentConfig.php
@@ -35,14 +35,14 @@ class DeploymentConfig
*
* @var array
*/
- private $data;
+ private $data = [];
/**
* Flattened data
*
* @var array
*/
- private $flatData;
+ private $flatData = [];
/**
* Injected configuration data
@@ -76,16 +76,18 @@ public function __construct(DeploymentConfig\Reader $reader, $overrideData = [])
*/
public function get($key = null, $defaultValue = null)
{
- $this->load();
if ($key === null) {
+ if (empty($this->flatData)) {
+ $this->reloadData();
+ }
return $this->flatData;
}
-
- if (array_key_exists($key, $this->flatData) && $this->flatData[$key] === null) {
- return '';
+ $result = $this->getByKey($key);
+ if ($result === null) {
+ $this->reloadData();
+ $result = $this->getByKey($key);
}
-
- return $this->flatData[$key] ?? $defaultValue;
+ return $result ?? $defaultValue;
}
/**
@@ -97,27 +99,31 @@ public function get($key = null, $defaultValue = null)
*/
public function isAvailable()
{
- $this->load();
- return isset($this->flatData[ConfigOptionsListConstants::CONFIG_PATH_INSTALL_DATE]);
+ return $this->get(ConfigOptionsListConstants::CONFIG_PATH_INSTALL_DATE) !== null;
}
/**
* Gets a value specified key from config data
*
- * @param string $key
+ * @param string|null $key
* @return null|mixed
* @throws FileSystemException
* @throws RuntimeException
*/
public function getConfigData($key = null)
{
- $this->load();
-
- if ($key !== null && !isset($this->data[$key])) {
- return null;
+ if ($key === null) {
+ if (empty($this->data)) {
+ $this->reloadData();
+ }
+ return $this->data;
}
-
- return $this->data[$key] ?? $this->data;
+ $result = $this->getConfigDataByKey($key);
+ if ($result === null) {
+ $this->reloadData();
+ $result = $this->getConfigDataByKey($key);
+ }
+ return $result;
}
/**
@@ -127,7 +133,8 @@ public function getConfigData($key = null)
*/
public function resetData()
{
- $this->data = null;
+ $this->data = [];
+ $this->flatData = [];
}
/**
@@ -140,8 +147,7 @@ public function resetData()
*/
public function isDbAvailable()
{
- $this->load();
- return isset($this->data['db']);
+ return $this->getConfigData('db') !== null;
}
/**
@@ -164,28 +170,26 @@ private function getEnvOverride() : array
* @throws FileSystemException
* @throws RuntimeException
*/
- private function load()
+ private function reloadData(): void
{
- if (empty($this->data)) {
- $this->data = array_replace(
- $this->reader->load(),
- $this->overrideData ?? [],
- $this->getEnvOverride()
- );
- // flatten data for config retrieval using get()
- $this->flatData = $this->flattenParams($this->data);
-
- // allow reading values from env variables by convention
- // MAGENTO_DC_{path}, like db/connection/default/host =>
- // can be overwritten by MAGENTO_DC_DB__CONNECTION__DEFAULT__HOST
- foreach (getenv() as $key => $value) {
- if (false !== \strpos($key, self::MAGENTO_ENV_PREFIX)
- && $key !== self::OVERRIDE_KEY
- ) {
- // convert MAGENTO_DC_DB__CONNECTION__DEFAULT__HOST into db/connection/default/host
- $flatKey = strtolower(str_replace([self::MAGENTO_ENV_PREFIX, '__'], ['', '/'], $key));
- $this->flatData[$flatKey] = $value;
- }
+ $this->data = array_replace(
+ $this->reader->load(),
+ $this->overrideData ?? [],
+ $this->getEnvOverride()
+ );
+ // flatten data for config retrieval using get()
+ $this->flatData = $this->flattenParams($this->data);
+
+ // allow reading values from env variables by convention
+ // MAGENTO_DC_{path}, like db/connection/default/host =>
+ // can be overwritten by MAGENTO_DC_DB__CONNECTION__DEFAULT__HOST
+ foreach (getenv() as $key => $value) {
+ if (false !== \strpos($key, self::MAGENTO_ENV_PREFIX)
+ && $key !== self::OVERRIDE_KEY
+ ) {
+ // convert MAGENTO_DC_DB__CONNECTION__DEFAULT__HOST into db/connection/default/host
+ $flatKey = strtolower(str_replace([self::MAGENTO_ENV_PREFIX, '__'], ['', '/'], $key));
+ $this->flatData[$flatKey] = $value;
}
}
}
@@ -197,12 +201,12 @@ private function load()
* each level of array is accessible by path key
*
* @param array $params
- * @param string $path
- * @param array $flattenResult
+ * @param string|null $path
+ * @param array|null $flattenResult
* @return array
* @throws RuntimeException
*/
- private function flattenParams(array $params, $path = null, array &$flattenResult = null) : array
+ private function flattenParams(array $params, ?string $path = null, array &$flattenResult = null): array
{
if (null === $flattenResult) {
$flattenResult = [];
@@ -236,4 +240,30 @@ private function flattenParams(array $params, $path = null, array &$flattenResul
return $flattenResult;
}
+
+ /**
+ * Returns flat data by key
+ *
+ * @param string|null $key
+ * @return mixed|null
+ */
+ private function getByKey(?string $key)
+ {
+ if (array_key_exists($key, $this->flatData) && $this->flatData[$key] === null) {
+ return '';
+ }
+
+ return $this->flatData[$key] ?? null;
+ }
+
+ /**
+ * Returns data by key
+ *
+ * @param string|null $key
+ * @return mixed|null
+ */
+ private function getConfigDataByKey(?string $key)
+ {
+ return $this->data[$key] ?? null;
+ }
}
diff --git a/lib/internal/Magento/Framework/App/Test/Unit/DeploymentConfigTest.php b/lib/internal/Magento/Framework/App/Test/Unit/DeploymentConfigTest.php
index 191a86c442f95..42b4d7866c23b 100644
--- a/lib/internal/Magento/Framework/App/Test/Unit/DeploymentConfigTest.php
+++ b/lib/internal/Magento/Framework/App/Test/Unit/DeploymentConfigTest.php
@@ -1,8 +1,10 @@
'scalar_value',
- 'configData2' => [
+ 'configData1' => 'scalar_value',
+ 'configData2' => [
'foo' => 1,
'bar' => ['baz' => 2],
],
- 'configData3' => null,
+ 'configData3' => null,
'test_override' => 'original',
];
@@ -34,16 +38,16 @@ class DeploymentConfigTest extends TestCase
*/
private static $flattenedFixture
= [
- 'configData1' => 'scalar_value',
- 'configData2' => [
+ 'configData1' => 'scalar_value',
+ 'configData2' => [
'foo' => 1,
'bar' => ['baz' => 2],
],
- 'configData2/foo' => 1,
- 'configData2/bar' => ['baz' => 2],
+ 'configData2/foo' => 1,
+ 'configData2/bar' => ['baz' => 2],
'configData2/bar/baz' => 2,
- 'configData3' => null,
- 'test_override' => 'overridden',
+ 'configData3' => null,
+ 'test_override' => 'overridden',
];
/**
@@ -59,7 +63,7 @@ class DeploymentConfigTest extends TestCase
/**
* @var DeploymentConfig
*/
- protected $_deploymentConfig;
+ protected $deploymentConfig;
/**
* @var DeploymentConfig
@@ -69,81 +73,100 @@ class DeploymentConfigTest extends TestCase
/**
* @var MockObject
*/
- private $reader;
+ private $readerMock;
public static function setUpBeforeClass(): void
{
- self::$fixtureConfig = require __DIR__ . '/_files/config.php';
+ self::$fixtureConfig = require __DIR__ . '/_files/config.php';
self::$fixtureConfigMerged = require __DIR__ . '/_files/other/local_developer_merged.php';
}
protected function setUp(): void
{
- $this->reader = $this->createMock(Reader::class);
- $this->_deploymentConfig = new DeploymentConfig(
- $this->reader,
+ $this->readerMock = $this->createMock(Reader::class);
+ $this->deploymentConfig = new DeploymentConfig(
+ $this->readerMock,
['test_override' => 'overridden']
);
$this->_deploymentConfigMerged = new DeploymentConfig(
- $this->reader,
+ $this->readerMock,
require __DIR__ . '/_files/other/local_developer.php'
);
}
+ /**
+ * @return void
+ * @throws FileSystemException
+ * @throws RuntimeException
+ */
public function testGetters(): void
{
- $this->reader->expects($this->once())->method('load')->willReturn(self::$fixture);
- $this->assertSame(self::$flattenedFixture, $this->_deploymentConfig->get());
- // second time to ensure loader will be invoked only once
- $this->assertSame(self::$flattenedFixture, $this->_deploymentConfig->get());
- $this->assertSame('scalar_value', $this->_deploymentConfig->getConfigData('configData1'));
- $this->assertSame(self::$fixture['configData2'], $this->_deploymentConfig->getConfigData('configData2'));
- $this->assertSame(self::$fixture['configData3'], $this->_deploymentConfig->getConfigData('configData3'));
- $this->assertSame('', $this->_deploymentConfig->get('configData3'));
- $this->assertSame('defaultValue', $this->_deploymentConfig->get('invalid_key', 'defaultValue'));
- $this->assertNull($this->_deploymentConfig->getConfigData('invalid_key'));
- $this->assertSame('overridden', $this->_deploymentConfig->get('test_override'));
+ $this->readerMock->expects($this->any())->method('load')->willReturn(self::$fixture);
+ $this->assertSame(self::$flattenedFixture, $this->deploymentConfig->get());
+ $this->assertSame('scalar_value', $this->deploymentConfig->getConfigData('configData1'));
+ $this->assertSame(self::$fixture['configData2'], $this->deploymentConfig->getConfigData('configData2'));
+ $this->assertSame(self::$fixture['configData3'], $this->deploymentConfig->getConfigData('configData3'));
+ $this->assertSame('', $this->deploymentConfig->get('configData3'));
+ $this->assertSame('defaultValue', $this->deploymentConfig->get('invalid_key', 'defaultValue'));
+ $this->assertNull($this->deploymentConfig->getConfigData('invalid_key'));
+ $this->assertSame('overridden', $this->deploymentConfig->get('test_override'));
}
+ /**
+ * @return void
+ * @throws FileSystemException
+ * @throws RuntimeException
+ */
public function testIsAvailable(): void
{
- $this->reader->expects($this->once())->method('load')->willReturn(
+ $this->readerMock->expects($this->once())->method('load')->willReturn(
[
ConfigOptionsListConstants::CONFIG_PATH_INSTALL_DATE => 1,
]
);
- $object = new DeploymentConfig($this->reader);
+ $object = new DeploymentConfig($this->readerMock);
$this->assertTrue($object->isAvailable());
}
+ /**
+ * @return void
+ * @throws FileSystemException
+ * @throws RuntimeException
+ */
public function testNotAvailable(): void
{
- $this->reader->expects($this->once())->method('load')->willReturn([]);
- $object = new DeploymentConfig($this->reader);
+ $this->readerMock->expects($this->once())->method('load')->willReturn([]);
+ $object = new DeploymentConfig($this->readerMock);
$this->assertFalse($object->isAvailable());
}
/**
* test if the configuration changes during the same request, the configuration remain the same
+ *
+ * @return void
+ * @throws FileSystemException
+ * @throws RuntimeException
*/
public function testNotAvailableThenAvailable(): void
{
- $this->reader->expects($this->once())->method('load')->willReturn(['Test']);
- $object = new DeploymentConfig($this->reader);
+ $this->readerMock->expects($this->exactly(2))->method('load')->willReturn(['Test']);
+ $object = new DeploymentConfig($this->readerMock);
$this->assertFalse($object->isAvailable());
$this->assertFalse($object->isAvailable());
}
/**
- * @param array $data
* @dataProvider keyCollisionDataProvider
+ * @param array $data
+ * @throws FileSystemException
+ * @throws RuntimeException
*/
public function testKeyCollision(array $data): void
{
$this->expectException('Exception');
$this->expectExceptionMessage('Key collision');
- $this->reader->expects($this->once())->method('load')->willReturn($data);
- $object = new DeploymentConfig($this->reader);
+ $this->readerMock->expects($this->once())->method('load')->willReturn($data);
+ $object = new DeploymentConfig($this->readerMock);
$object->get();
}
@@ -171,49 +194,71 @@ public function keyCollisionDataProvider(): array
];
}
+ /**
+ * @return void
+ * @throws FileSystemException
+ * @throws RuntimeException
+ */
public function testResetData(): void
{
- $this->reader->expects($this->exactly(2))->method('load')->willReturn(self::$fixture);
- $this->assertSame(self::$flattenedFixture, $this->_deploymentConfig->get());
- $this->_deploymentConfig->resetData();
+ $this->readerMock->expects($this->exactly(2))->method('load')->willReturn(self::$fixture);
+ $this->assertSame(self::$flattenedFixture, $this->deploymentConfig->get());
+ $this->deploymentConfig->resetData();
// second time to ensure loader will be invoked only once after reset
- $this->assertSame(self::$flattenedFixture, $this->_deploymentConfig->get());
- $this->assertSame(self::$flattenedFixture, $this->_deploymentConfig->get());
+ $this->assertSame(self::$flattenedFixture, $this->deploymentConfig->get());
+ $this->assertSame(self::$flattenedFixture, $this->deploymentConfig->get());
}
+ /**
+ * @return void
+ * @throws FileSystemException
+ * @throws RuntimeException
+ */
public function testIsDbAvailable(): void
{
- $this->reader->expects($this->exactly(2))->method('load')->willReturnOnConsecutiveCalls([], ['db' => []]);
- $this->assertFalse($this->_deploymentConfig->isDbAvailable());
- $this->_deploymentConfig->resetData();
- $this->assertTrue($this->_deploymentConfig->isDbAvailable());
+ $this->readerMock->expects($this->exactly(2))->method('load')->willReturnOnConsecutiveCalls([], ['db' => []]);
+ $this->assertFalse($this->deploymentConfig->isDbAvailable());
+ $this->assertTrue($this->deploymentConfig->isDbAvailable());
+ }
+
+ /**
+ * @return void
+ * @throws FileSystemException
+ * @throws RuntimeException
+ */
+ public function testResetDataOnMissingConfig(): void
+ {
+ $this->readerMock->expects($this->once())->method('load')->willReturn(self::$fixture);
+ $defaultValue = 'some_default_value';
+ $result = $this->deploymentConfig->get('missing/key', $defaultValue);
+ $this->assertEquals($defaultValue, $result);
}
- public function testNoEnvVariables()
+ public function testNoEnvVariables(): void
{
- $this->reader->expects($this->once())->method('load')->willReturn(['a'=>'b']);
- $this->assertSame('b', $this->_deploymentConfig->get('a'));
+ $this->readerMock->expects($this->once())->method('load')->willReturn(['a'=>'b']);
+ $this->assertSame('b', $this->deploymentConfig->get('a'));
}
- public function testEnvVariables()
+ public function testEnvVariables(): void
{
- $this->reader->expects($this->once())->method('load')->willReturn([]);
+ $this->readerMock->expects($this->once())->method('load')->willReturn([]);
putenv('MAGENTO_DC__OVERRIDE={"a": "c"}');
- $this->assertSame('c', $this->_deploymentConfig->get('a'));
+ $this->assertSame('c', $this->deploymentConfig->get('a'));
}
- public function testEnvVariablesWithNoBaseConfig()
+ public function testEnvVariablesWithNoBaseConfig(): void
{
- $this->reader->expects($this->once())->method('load')->willReturn(['a'=>'b']);
+ $this->readerMock->expects($this->once())->method('load')->willReturn(['a'=>'b']);
putenv('MAGENTO_DC_A=c');
putenv('MAGENTO_DC_B__B__B=D');
- $this->assertSame('c', $this->_deploymentConfig->get('a'));
- $this->assertSame('D', $this->_deploymentConfig->get('b/b/b'));
+ $this->assertSame('c', $this->deploymentConfig->get('a'));
+ $this->assertSame('D', $this->deploymentConfig->get('b/b/b'));
}
- public function testEnvVariablesSubstitution()
+ public function testEnvVariablesSubstitution(): void
{
- $this->reader->expects($this->once())
+ $this->readerMock->expects($this->once())
->method('load')
->willReturn(
[
@@ -224,8 +269,8 @@ public function testEnvVariablesSubstitution()
);
putenv('MAGENTO_DC____A=c');
putenv('MAGENTO_DC____B=D');
- $this->assertSame('c', $this->_deploymentConfig->get('a'));
- $this->assertSame('D', $this->_deploymentConfig->get('b'), 'return value from env');
- $this->assertSame('e$%^&', $this->_deploymentConfig->get('c'), 'return default value');
+ $this->assertSame('c', $this->deploymentConfig->get('a'));
+ $this->assertSame('D', $this->deploymentConfig->get('b'), 'return value from env');
+ $this->assertSame('e$%^&', $this->deploymentConfig->get('c'), 'return default value');
}
}
diff --git a/lib/internal/Magento/Framework/Async/Code/Generator/ProxyDeferredGenerator.php b/lib/internal/Magento/Framework/Async/Code/Generator/ProxyDeferredGenerator.php
index 859a664470072..dc4e83b9905ec 100644
--- a/lib/internal/Magento/Framework/Async/Code/Generator/ProxyDeferredGenerator.php
+++ b/lib/internal/Magento/Framework/Async/Code/Generator/ProxyDeferredGenerator.php
@@ -9,6 +9,7 @@
use Magento\Framework\Async\DeferredInterface;
use Magento\Framework\Code\Generator\EntityAbstract;
+use Magento\Framework\GetReflectionMethodReturnTypeValueTrait;
use Magento\Framework\ObjectManager\DefinitionFactory;
use Magento\Framework\ObjectManager\NoninterceptableInterface;
@@ -17,6 +18,8 @@
*/
class ProxyDeferredGenerator extends EntityAbstract
{
+ use GetReflectionMethodReturnTypeValueTrait;
+
/**
* Entity type
*/
@@ -234,24 +237,4 @@ protected function _validateData()
return $result;
}
-
- /**
- * Returns return type
- *
- * @param \ReflectionMethod $method
- * @return null|string
- */
- private function getReturnTypeValue(\ReflectionMethod $method): ?string
- {
- $returnTypeValue = null;
- $returnType = $method->getReturnType();
- if ($returnType) {
- $returnTypeValue = ($returnType->allowsNull() && $returnType->getName() !== 'mixed' ? '?' : '');
- $returnTypeValue .= ($returnType->getName() === 'self')
- ? $this->_getFullyQualifiedClassName($method->getDeclaringClass()->getName())
- : $returnType->getName();
- }
-
- return $returnTypeValue;
- }
}
diff --git a/lib/internal/Magento/Framework/Bulk/composer.json b/lib/internal/Magento/Framework/Bulk/composer.json
index 7733ce9fea4c6..7beccb44975b3 100644
--- a/lib/internal/Magento/Framework/Bulk/composer.json
+++ b/lib/internal/Magento/Framework/Bulk/composer.json
@@ -11,7 +11,7 @@
],
"require": {
"magento/framework": "*",
- "php": "~7.4.0||~8.1.0"
+ "php": "~8.1.0||~8.2.0"
},
"autoload": {
"psr-4": {
diff --git a/lib/internal/Magento/Framework/Cache/Backend/RemoteSynchronizedCache.php b/lib/internal/Magento/Framework/Cache/Backend/RemoteSynchronizedCache.php
index 71f67b4aa6034..04efd1c60c4cb 100644
--- a/lib/internal/Magento/Framework/Cache/Backend/RemoteSynchronizedCache.php
+++ b/lib/internal/Magento/Framework/Cache/Backend/RemoteSynchronizedCache.php
@@ -195,14 +195,14 @@ public function load($id, $doNotTestCacheValidity = false)
{
$localData = $this->local->load($id);
- if ($localData) {
+ if ($localData !== false) {
if ($this->getDataVersion($localData) === $this->loadRemoteDataVersion($id)) {
return $localData;
}
}
$remoteData = $this->remote->load($id);
- if ($remoteData) {
+ if ($remoteData !== false) {
$this->local->save($remoteData, $id);
return $remoteData;
@@ -233,10 +233,15 @@ public function save($data, $id, $tags = [], $specificLifetime = false)
{
$dataToSave = $data;
$remHash = $this->loadRemoteDataVersion($id);
-
+ $isRemoteUpToDate = false;
if ($remHash !== false && $this->getDataVersion($data) === $remHash) {
- $dataToSave = $this->remote->load($id);
- } else {
+ $remoteData = $this->remote->load($id);
+ if ($remoteData !== false && $this->getDataVersion($data) === $this->getDataVersion($remoteData)) {
+ $isRemoteUpToDate = true;
+ $dataToSave = $remoteData;
+ }
+ }
+ if (!$isRemoteUpToDate) {
$this->remote->save($data, $id, $tags, $specificLifetime);
$this->saveRemoteDataVersion($data, $id, $tags, $specificLifetime);
}
diff --git a/lib/internal/Magento/Framework/Cache/Test/Unit/Backend/RemoteSynchronizedCacheTest.php b/lib/internal/Magento/Framework/Cache/Test/Unit/Backend/RemoteSynchronizedCacheTest.php
index d4a83180796ee..4b3b57a77b823 100644
--- a/lib/internal/Magento/Framework/Cache/Test/Unit/Backend/RemoteSynchronizedCacheTest.php
+++ b/lib/internal/Magento/Framework/Cache/Test/Unit/Backend/RemoteSynchronizedCacheTest.php
@@ -10,17 +10,11 @@
use Magento\Framework\Cache\Backend\Database;
use Magento\Framework\Cache\Backend\RemoteSynchronizedCache;
use Magento\Framework\DB\Adapter\Pdo\Mysql;
-use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
class RemoteSynchronizedCacheTest extends TestCase
{
- /**
- * @var ObjectManager
- */
- protected $objectManager;
-
/**
* @var \Cm_Cache_Backend_File|MockObject
*/
@@ -41,24 +35,12 @@ class RemoteSynchronizedCacheTest extends TestCase
*/
protected function setUp(): void
{
- $this->objectManager = new ObjectManager($this);
-
- $this->localCacheMockExample = $this->getMockBuilder(\Cm_Cache_Backend_File::class)
- ->disableOriginalConstructor()
- ->getMock();
-
- $this->remoteCacheMockExample = $this->getMockBuilder(Database::class)
- ->disableOriginalConstructor()
- ->getMock();
- /** @var \Magento\Framework\Cache\Backend\Database $databaseCacheInstance */
-
- $this->remoteSyncCacheInstance = $this->objectManager->getObject(
- RemoteSynchronizedCache::class,
+ $this->localCacheMockExample = $this->createMock(\Cm_Cache_Backend_File::class);
+ $this->remoteCacheMockExample = $this->createMock(Database::class);
+ $this->remoteSyncCacheInstance = new RemoteSynchronizedCache(
[
- 'options' => [
- 'remote_backend' => $this->remoteCacheMockExample,
- 'local_backend' => $this->localCacheMockExample
- ]
+ 'remote_backend' => $this->remoteCacheMockExample,
+ 'local_backend' => $this->localCacheMockExample
]
);
}
@@ -67,19 +49,13 @@ protected function setUp(): void
* Test that exception is thrown if cache is not configured.
*
* @param array $options
- *
* @return void
* @dataProvider initializeWithExceptionDataProvider
*/
public function testInitializeWithException($options): void
{
$this->expectException('Zend_Cache_Exception');
- $this->objectManager->getObject(
- RemoteSynchronizedCache::class,
- [
- 'options' => $options
- ]
- );
+ new RemoteSynchronizedCache($options);
}
/**
@@ -119,12 +95,7 @@ public function initializeWithExceptionDataProvider(): array
*/
public function testInitializeWithOutException($options): void
{
- $result = $this->objectManager->getObject(
- RemoteSynchronizedCache::class,
- [
- 'options' => $options
- ]
- );
+ $result = new RemoteSynchronizedCache($options);
$this->assertInstanceOf(RemoteSynchronizedCache::class, $result);
}
@@ -377,6 +348,38 @@ public function testSaveWithEqualRemoteData(): void
$this->remoteSyncCacheInstance->save($remoteData, 1, $tags);
}
+ /**
+ * Test data save when remote data are missed but hash exists.
+ *
+ * @return void
+ */
+ public function testSaveWithEqualHashesAndMissedRemoteData(): void
+ {
+ $cacheKey = 'key';
+ $dataToSave = '2';
+ $remoteData = '1';
+ $tags = ['MAGE'];
+
+ $this->remoteCacheMockExample
+ ->method('load')
+ ->willReturnOnConsecutiveCalls(\hash('sha256', $dataToSave), $remoteData);
+
+ $this->remoteCacheMockExample
+ ->expects($this->exactly(2))
+ ->method('save')
+ ->withConsecutive(
+ [$dataToSave, $cacheKey, $tags],
+ [\hash('sha256', $dataToSave), $cacheKey . ':hash', $tags]
+ )->willReturn(true);
+ $this->localCacheMockExample
+ ->expects($this->once())
+ ->method('save')
+ ->with($dataToSave, $cacheKey, [])
+ ->willReturn(true);
+
+ $this->remoteSyncCacheInstance->save($dataToSave, $cacheKey, $tags);
+ }
+
/**
* @return void
*/
diff --git a/lib/internal/Magento/Framework/Code/Generator/EntityAbstract.php b/lib/internal/Magento/Framework/Code/Generator/EntityAbstract.php
index 8ccf26db333d8..d7f720cc7cb0c 100644
--- a/lib/internal/Magento/Framework/Code/Generator/EntityAbstract.php
+++ b/lib/internal/Magento/Framework/Code/Generator/EntityAbstract.php
@@ -338,6 +338,9 @@ private function extractParameterType(
if ($parameterType instanceof \ReflectionUnionType) {
$parameterType = $parameterType->getTypes();
$parameterType = implode('|', $parameterType);
+ } elseif ($parameterType instanceof \ReflectionIntersectionType) {
+ $parameterType = $parameterType->getTypes();
+ $parameterType = implode('&', $parameterType);
} else {
$parameterType = $parameterType->getName();
}
diff --git a/lib/internal/Magento/Framework/Code/Reader/ArgumentsReader.php b/lib/internal/Magento/Framework/Code/Reader/ArgumentsReader.php
index 93f159a56d4e9..450955084d021 100644
--- a/lib/internal/Magento/Framework/Code/Reader/ArgumentsReader.php
+++ b/lib/internal/Magento/Framework/Code/Reader/ArgumentsReader.php
@@ -137,8 +137,9 @@ private function processType(\ReflectionClass $class, \Laminas\Code\Reflection\P
* @param \ReflectionClass $class
* @param array $classArguments
* @return array|null
+ * @throws \ReflectionException
*/
- public function getParentCall(\ReflectionClass $class, array $classArguments)
+ public function getParentCall(\ReflectionClass $class, array $classArguments): ?array
{
/** Skip native PHP types */
if (!$class->getFileName()) {
@@ -146,7 +147,12 @@ public function getParentCall(\ReflectionClass $class, array $classArguments)
}
$trimFunction = function (&$value) {
- $value = trim($value, PHP_EOL . ' $');
+ $position = strpos($value, ':');
+ if ($position !== false) {
+ $value = trim(substr($value, 0, $position), PHP_EOL . ' ');
+ } else {
+ $value = trim($value, PHP_EOL . ' $');
+ }
};
$method = $class->getMethod('__construct');
@@ -158,10 +164,11 @@ public function getParentCall(\ReflectionClass $class, array $classArguments)
$content = implode('', array_slice($source, $start, $length));
$pattern = '/parent::__construct\(([ ' .
PHP_EOL .
- ']*[$]{1}[a-zA-Z0-9_]*,)*[ ' .
+ ']*' .
+ '([a-zA-Z0-9_]+([ ' . PHP_EOL . '])*:([ ' . PHP_EOL . '])*)*[$][a-zA-Z0-9_]*,)*[ ' .
PHP_EOL .
']*' .
- '([$]{1}[a-zA-Z0-9_]*){1}[' .
+ '([a-zA-Z0-9_]+([ ' . PHP_EOL . '])*:([ ' . PHP_EOL . '])*)*([$][a-zA-Z0-9_]*)[' .
PHP_EOL .
' ]*\);/';
@@ -176,6 +183,10 @@ public function getParentCall(\ReflectionClass $class, array $classArguments)
$arguments = substr(trim($arguments), 20, -2);
$arguments = explode(',', $arguments);
+ $isNamedArgument = [];
+ foreach ($arguments as $argumentPosition => $argumentName) {
+ $isNamedArgument[$argumentPosition] = (bool)strpos($argumentName, ':');
+ }
array_walk($arguments, $trimFunction);
$output = [];
@@ -185,8 +196,10 @@ public function getParentCall(\ReflectionClass $class, array $classArguments)
'name' => $argumentName,
'position' => $argumentPosition,
'type' => $type,
+ 'isNamedArgument' => $isNamedArgument[$argumentPosition],
];
}
+
return $output;
}
diff --git a/lib/internal/Magento/Framework/Code/Test/Unit/Reader/ArgumentsReaderTest.php b/lib/internal/Magento/Framework/Code/Test/Unit/Reader/ArgumentsReaderTest.php
index 9bf8ae3721738..64e1277bb1c1f 100644
--- a/lib/internal/Magento/Framework/Code/Test/Unit/Reader/ArgumentsReaderTest.php
+++ b/lib/internal/Magento/Framework/Code/Test/Unit/Reader/ArgumentsReaderTest.php
@@ -270,8 +270,18 @@ public function testGetParentCallWithRightArgumentsOrder()
]
);
$expectedResult = [
- ['name' => 'stdClassObject', 'position' => 0, 'type' => '\stdClass'],
- ['name' => 'secondClass', 'position' => 1, 'type' => '\ClassExtendsDefaultPhpType'],
+ [
+ 'name' => 'stdClassObject',
+ 'position' => 0,
+ 'type' => '\stdClass',
+ 'isNamedArgument' => false
+ ],
+ [
+ 'name' => 'secondClass',
+ 'position' => 1,
+ 'type' => '\ClassExtendsDefaultPhpType',
+ 'isNamedArgument' => false
+ ],
];
$this->assertEquals($expectedResult, $actualResult);
}
@@ -287,8 +297,17 @@ public function testGetParentCallWithWrongArgumentsOrder()
]
);
$expectedResult = [
- ['name' => 'secondClass', 'position' => 0, 'type' => '\ClassExtendsDefaultPhpType'],
- ['name' => 'stdClassObject', 'position' => 1, 'type' => '\stdClass'],
+ [
+ 'name' => 'secondClass',
+ 'position' => 0,
+ 'type' => '\ClassExtendsDefaultPhpType',
+ 'isNamedArgument' => false],
+ [
+ 'name' => 'stdClassObject',
+ 'position' => 1,
+ 'type' => '\stdClass',
+ 'isNamedArgument' => false
+ ],
];
$this->assertEquals($expectedResult, $actualResult);
}
@@ -304,8 +323,72 @@ public function testGetParentCallWithSeparateLineFormat()
]
);
$expectedResult = [
- ['name' => 'stdClassObject', 'position' => 0, 'type' => '\stdClass'],
- ['name' => 'secondClass', 'position' => 1, 'type' => '\ClassExtendsDefaultPhpType'],
+ [
+ 'name' => 'stdClassObject',
+ 'position' => 0,
+ 'type' => '\stdClass',
+ 'isNamedArgument' => false
+ ],
+ [
+ 'name' => 'secondClass',
+ 'position' => 1,
+ 'type' => '\ClassExtendsDefaultPhpType',
+ 'isNamedArgument' => false
+ ],
+ ];
+ $this->assertEquals($expectedResult, $actualResult);
+ }
+
+ public function testGetParentCallWithNamedArguments()
+ {
+ $class = new \ReflectionClass('ClassWithNamedArgumentsForParentCall');
+ $actualResult = $this->_model->getParentCall(
+ $class,
+ [
+ 'stdClassObject' => ['type' => '\stdClass'],
+ 'runeTimeException' => ['type' => '\ClassExtendsDefaultPhpType']
+ ]
+ );
+ $expectedResult = [
+ [
+ 'name' => 'stdClassObject',
+ 'position' => 0,
+ 'type' => '\stdClass',
+ 'isNamedArgument' => true
+ ],
+ [
+ 'name' => 'runeTimeException',
+ 'position' => 1,
+ 'type' => '\ClassExtendsDefaultPhpType',
+ 'isNamedArgument' => true
+ ],
+ ];
+ $this->assertEquals($expectedResult, $actualResult);
+ }
+
+ public function testGetParentCallWithMixedArguments()
+ {
+ $class = new \ReflectionClass('ClassWithMixedArgumentsForParentCall');
+ $actualResult = $this->_model->getParentCall(
+ $class,
+ [
+ 'stdClassObject' => ['type' => '\stdClass'],
+ 'runeTimeException' => ['type' => '\ClassExtendsDefaultPhpType']
+ ]
+ );
+ $expectedResult = [
+ [
+ 'name' => 'stdClassObject',
+ 'position' => 0,
+ 'type' => '\stdClass',
+ 'isNamedArgument' => false
+ ],
+ [
+ 'name' => 'runeTimeException',
+ 'position' => 1,
+ 'type' => '\ClassExtendsDefaultPhpType',
+ 'isNamedArgument' => true
+ ],
];
$this->assertEquals($expectedResult, $actualResult);
}
diff --git a/lib/internal/Magento/Framework/Code/Test/Unit/Reader/_files/ClassesForArgumentsReader.php b/lib/internal/Magento/Framework/Code/Test/Unit/Reader/_files/ClassesForArgumentsReader.php
index dcc5a7c11e553..88e22176810d1 100644
--- a/lib/internal/Magento/Framework/Code/Test/Unit/Reader/_files/ClassesForArgumentsReader.php
+++ b/lib/internal/Magento/Framework/Code/Test/Unit/Reader/_files/ClassesForArgumentsReader.php
@@ -257,3 +257,50 @@ public function __construct(\stdClass $stdClassObject, \ClassExtendsDefaultPhpTy
$this->argumentTwo = $secondClass;
}
}
+class ClassWithNamedArgumentsForParentCall extends FirstClassForParentCall
+{
+ /**
+ * @var stdClass
+ */
+ protected $_stdClassObject;
+
+ /**
+ * @var ClassExtendsDefaultPhpType
+ */
+ protected $_runeTimeException;
+
+ /**
+ * @param stdClass $stdClassObject
+ * @param ClassExtendsDefaultPhpType $runeTimeException
+ */
+ public function __construct(\stdClass $stdClassObject, \ClassExtendsDefaultPhpType $runeTimeException)
+ {
+ parent::__construct(stdClassObject: $stdClassObject, runeTimeException: $runeTimeException);
+ $this->_stdClassObject = $stdClassObject;
+ $this->_runeTimeException = $runeTimeException;
+ }
+}
+
+class ClassWithMixedArgumentsForParentCall extends FirstClassForParentCall
+{
+ /**
+ * @var stdClass
+ */
+ protected $_stdClassObject;
+
+ /**
+ * @var ClassExtendsDefaultPhpType
+ */
+ protected $_runeTimeException;
+
+ /**
+ * @param stdClass $stdClassObject
+ * @param ClassExtendsDefaultPhpType $runeTimeException
+ */
+ public function __construct(\stdClass $stdClassObject, \ClassExtendsDefaultPhpType $runeTimeException)
+ {
+ parent::__construct($stdClassObject, runeTimeException: $runeTimeException);
+ $this->_stdClassObject = $stdClassObject;
+ $this->_runeTimeException = $runeTimeException;
+ }
+}
diff --git a/lib/internal/Magento/Framework/Code/Test/Unit/Validator/ConstructorIntegrityTest.php b/lib/internal/Magento/Framework/Code/Test/Unit/Validator/ConstructorIntegrityTest.php
index 4c77775602787..340a5fa81a9e2 100644
--- a/lib/internal/Magento/Framework/Code/Test/Unit/Validator/ConstructorIntegrityTest.php
+++ b/lib/internal/Magento/Framework/Code/Test/Unit/Validator/ConstructorIntegrityTest.php
@@ -5,9 +5,10 @@
*/
namespace Magento\Framework\Code\Test\Unit\Validator;
+use Magento\SomeModule\Model\NamedArguments\NamedParametersTest;
+use Magento\SomeModule\Model\NamedArguments\MixedParametersTest;
use PHPUnit\Framework\TestCase;
use Magento\Framework\Code\Validator\ConstructorIntegrity;
-use Magento\SomeModule\Model\One\Test;
use Magento\Framework\Exception\ValidatorException;
require_once __DIR__ . '/../_files/app/code/Magento/SomeModule/Model/Three/Test.php';
@@ -16,6 +17,8 @@
require_once __DIR__ . '/../_files/app/code/Magento/SomeModule/Model/Four/Test.php';
require_once __DIR__ . '/../_files/app/code/Magento/SomeModule/Model/Five/Test.php';
require_once __DIR__ . '/../_files/app/code/Magento/SomeModule/Model/Six/Test.php';
+require_once __DIR__ . '/../_files/app/code/Magento/SomeModule/Model/NamedArguments/NamedParametersTest.php';
+require_once __DIR__ . '/../_files/app/code/Magento/SomeModule/Model/NamedArguments/MixedParametersTest.php';
require_once __DIR__ . '/_files/ClassesForConstructorIntegrity.php';
class ConstructorIntegrityTest extends TestCase
{
@@ -31,7 +34,7 @@ protected function setUp(): void
public function testValidateIfParentClassExist()
{
- $this->assertTrue($this->_model->validate(Test::class));
+ $this->assertTrue($this->_model->validate(\Magento\SomeModule\Model\One\Test::class));
}
public function testValidateIfClassHasParentConstructCall()
@@ -39,6 +42,16 @@ public function testValidateIfClassHasParentConstructCall()
$this->assertTrue($this->_model->validate(\Magento\SomeModule\Model\Two\Test::class));
}
+ public function testValidateIfClassHasParentConstructCallWithNamedArguments()
+ {
+ $this->assertTrue($this->_model->validate(NamedParametersTest::class));
+ }
+
+ public function testValidateIfClassHasParentConstructCallWithMixedArguments()
+ {
+ $this->assertTrue($this->_model->validate(MixedParametersTest::class));
+ }
+
public function testValidateIfClassHasArgumentsQtyEqualToParentClass()
{
$this->assertTrue($this->_model->validate(\Magento\SomeModule\Model\Three\Test::class));
@@ -46,10 +59,6 @@ public function testValidateIfClassHasArgumentsQtyEqualToParentClass()
public function testValidateIfClassHasExtraArgumentInTheParentConstructor()
{
- $fileName = realpath(__DIR__ . '/../_files/app/code/Magento/SomeModule/Model/Four/Test.php');
- $fileName = str_replace('\\', '/', $fileName);
- $this->expectException(ValidatorException::class);
- $this->expectExceptionMessage('Extra parameters passed to parent construct: $factory. File: ' . $fileName);
$this->_model->validate(\Magento\SomeModule\Model\Four\Test::class);
}
diff --git a/lib/internal/Magento/Framework/Code/Test/Unit/_files/app/code/Magento/SomeModule/Model/NamedArguments/MixedParametersTest.php b/lib/internal/Magento/Framework/Code/Test/Unit/_files/app/code/Magento/SomeModule/Model/NamedArguments/MixedParametersTest.php
new file mode 100644
index 0000000000000..720d11b00b9de
--- /dev/null
+++ b/lib/internal/Magento/Framework/Code/Test/Unit/_files/app/code/Magento/SomeModule/Model/NamedArguments/MixedParametersTest.php
@@ -0,0 +1,22 @@
+stdClassObject = $stdClassObject;
+ $this->arrayVariable = $arrayVariable;
+ }
+}
diff --git a/lib/internal/Magento/Framework/Code/Validator/ConstructorIntegrity.php b/lib/internal/Magento/Framework/Code/Validator/ConstructorIntegrity.php
index 59491ee3c9cdc..d12c66c3a595a 100644
--- a/lib/internal/Magento/Framework/Code/Validator/ConstructorIntegrity.php
+++ b/lib/internal/Magento/Framework/Code/Validator/ConstructorIntegrity.php
@@ -1,15 +1,19 @@
_argumentsReader->getConstructorArguments($parent, true, true);
foreach ($parentArguments as $index => $requiredArgument) {
- if (isset($callArguments[$index])) {
- $actualArgument = $callArguments[$index];
- } else {
- if ($requiredArgument['isOptional']) {
+ $reIndexedCallArguments = array_column($callArguments, null, 'name');
+ if (isset($reIndexedCallArguments[$requiredArgument['name']])) {
+ if ($reIndexedCallArguments[$requiredArgument['name']]['isNamedArgument'] === true) {
+ $actualArgument = $reIndexedCallArguments[$requiredArgument['name']];
+ $this->checkCompatibleTypes($requiredArgument['type'], $actualArgument['type'], $class);
continue;
}
+ }
- $classPath = str_replace('\\', '/', $class->getFileName());
- throw new \Magento\Framework\Exception\ValidatorException(
- new Phrase(
- 'Missed required argument %1 in parent::__construct call. File: %2',
- [$requiredArgument['name'], $classPath]
- )
- );
+ if (isset($callArguments[$index]) && $callArguments[$index]['isNamedArgument'] === true) {
+ $this->checkIfRequiredArgumentIsOptional($requiredArgument, $class);
}
- $isCompatibleTypes = $this->_argumentsReader->isCompatibleType(
- $requiredArgument['type'],
- $actualArgument['type']
- );
- if (false == $isCompatibleTypes) {
- $classPath = str_replace('\\', '/', $class->getFileName());
- throw new \Magento\Framework\Exception\ValidatorException(
- new Phrase(
- 'Incompatible argument type: Required type: %1. Actual type: %2; File: %3%4%5',
- [$requiredArgument['type'], $actualArgument['type'], PHP_EOL, $classPath, PHP_EOL]
- )
- );
+ if (isset($callArguments[$index])) {
+ $actualArgument = $callArguments[$index];
+ $this->checkCompatibleTypes($requiredArgument['type'], $actualArgument['type'], $class);
+ } else {
+ $this->checkIfRequiredArgumentIsOptional($requiredArgument, $class);
}
}
- /**
- * Try to detect unused arguments
- * Check whether count of passed parameters less or equal that count of count parent class arguments
- */
- if (count($callArguments) > count($parentArguments)) {
- $extraParameters = array_slice($callArguments, count($parentArguments));
- $names = [];
- foreach ($extraParameters as $param) {
- $names[] = '$' . $param['name'];
- }
+ return true;
+ }
+ /**
+ * Check argument type compatibility
+ *
+ * @param string $requiredArgumentType
+ * @param string $actualArgumentType
+ * @param \ReflectionClass $class
+ * @return void
+ * @throws ValidatorException
+ */
+ private function checkCompatibleTypes(
+ $requiredArgumentType,
+ $actualArgumentType,
+ \ReflectionClass $class
+ ): void {
+ $isCompatibleTypes = $this->_argumentsReader->isCompatibleType(
+ $requiredArgumentType,
+ $actualArgumentType
+ );
+
+ if (!$isCompatibleTypes) {
$classPath = str_replace('\\', '/', $class->getFileName());
- throw new \Magento\Framework\Exception\ValidatorException(
+ throw new ValidatorException(
new Phrase(
- 'Extra parameters passed to parent construct: %1. File: %2',
- [implode(', ', $names), $classPath]
+ 'Incompatible argument type: Required type: %1. Actual type: %2; File: %3%4%5',
+ [$requiredArgumentType, $actualArgumentType, PHP_EOL, $classPath, PHP_EOL]
+ )
+ );
+ }
+ }
+
+ /**
+ * Check if required argument is optional
+ *
+ * @param array $requiredArgument
+ * @param \ReflectionClass $class
+ * @return void
+ * @throws ValidatorException
+ */
+ private function checkIfRequiredArgumentIsOptional(array $requiredArgument, \ReflectionClass $class): void
+ {
+ if (!$requiredArgument['isOptional']) {
+ $classPath = str_replace('\\', '/', $class->getFileName());
+ throw new ValidatorException(
+ new Phrase(
+ 'Missed required argument %1 in parent::__construct call. File: %2',
+ [$requiredArgument['name'], $classPath]
)
);
}
- return true;
}
}
diff --git a/lib/internal/Magento/Framework/GetReflectionMethodReturnTypeValueTrait.php b/lib/internal/Magento/Framework/GetReflectionMethodReturnTypeValueTrait.php
new file mode 100644
index 0000000000000..82bc6d0d3ead9
--- /dev/null
+++ b/lib/internal/Magento/Framework/GetReflectionMethodReturnTypeValueTrait.php
@@ -0,0 +1,61 @@
+getReturnType();
+ if ($returnType) {
+ if ($returnType instanceof \ReflectionUnionType || $returnType instanceof \ReflectionIntersectionType) {
+ return $this->getReturnTypeValues($returnType, $method);
+ }
+
+ $className = $method->getDeclaringClass()->getName();
+ $returnTypeValue = ($returnType->allowsNull() && $returnType->getName() !== 'mixed' ? '?' : '');
+ $returnTypeValue .= ($returnType->getName() === 'self')
+ ? $className ? '\\' . ltrim($className, '\\') : ''
+ : $returnType->getName();
+ }
+
+ return $returnTypeValue;
+ }
+
+ /**
+ * Get return type values for Intersection|Union types
+ *
+ * @param \ReflectionIntersectionType|\ReflectionUnionType $returnType
+ * @param \ReflectionMethod $method
+ * @return string|null
+ */
+ private function getReturnTypeValues(
+ \ReflectionIntersectionType|\ReflectionUnionType $returnType,
+ \ReflectionMethod $method
+ ): ?string {
+ $returnTypeValue = [];
+ foreach ($method->getReturnType()->getTypes() as $type) {
+ $returnTypeValue[] = $type->getName();
+ }
+
+ return implode(
+ $returnType instanceof \ReflectionUnionType ? '|' : '&',
+ $returnTypeValue
+ );
+ }
+}
diff --git a/lib/internal/Magento/Framework/Image/Adapter/Gd2.php b/lib/internal/Magento/Framework/Image/Adapter/Gd2.php
index 442418ecb17fa..037a2eb56d6c1 100644
--- a/lib/internal/Magento/Framework/Image/Adapter/Gd2.php
+++ b/lib/internal/Magento/Framework/Image/Adapter/Gd2.php
@@ -538,8 +538,8 @@ private function createWatermarkBasedOnPosition(
} elseif ($this->getWatermarkPosition() == self::POSITION_STRETCH) {
$watermark = $this->createWaterMark($watermark, $this->_imageSrcWidth, $this->_imageSrcHeight);
} elseif ($this->getWatermarkPosition() == self::POSITION_CENTER) {
- $positionX = $this->_imageSrcWidth / 2 - imagesx($watermark) / 2;
- $positionY = $this->_imageSrcHeight / 2 - imagesy($watermark) / 2;
+ $positionX = (int) ($this->_imageSrcWidth / 2 - imagesx($watermark) / 2);
+ $positionY = (int) ($this->_imageSrcHeight / 2 - imagesy($watermark) / 2);
$this->imagecopymergeWithAlphaFix(
$this->_imageHandler,
$watermark,
diff --git a/lib/internal/Magento/Framework/Image/Adapter/ImageMagick.php b/lib/internal/Magento/Framework/Image/Adapter/ImageMagick.php
index d67fe7799db22..d0b88a34c09d8 100644
--- a/lib/internal/Magento/Framework/Image/Adapter/ImageMagick.php
+++ b/lib/internal/Magento/Framework/Image/Adapter/ImageMagick.php
@@ -334,8 +334,8 @@ public function watermark($imagePath, $positionX = 0, $positionY = 0, $opacity =
$watermark->sampleImage($this->_imageSrcWidth, $this->_imageSrcHeight);
break;
case self::POSITION_CENTER:
- $positionX = ($this->_imageSrcWidth - $watermark->getImageWidth()) / 2;
- $positionY = ($this->_imageSrcHeight - $watermark->getImageHeight()) / 2;
+ $positionX = (int) (($this->_imageSrcWidth - $watermark->getImageWidth()) / 2);
+ $positionY = (int) (($this->_imageSrcHeight - $watermark->getImageHeight()) / 2);
break;
case self::POSITION_TOP_RIGHT:
$positionX = $this->_imageSrcWidth - $watermark->getImageWidth();
diff --git a/lib/internal/Magento/Framework/Interception/Code/Generator/Interceptor.php b/lib/internal/Magento/Framework/Interception/Code/Generator/Interceptor.php
index 4b8685facad7c..f04bea1030ade 100644
--- a/lib/internal/Magento/Framework/Interception/Code/Generator/Interceptor.php
+++ b/lib/internal/Magento/Framework/Interception/Code/Generator/Interceptor.php
@@ -8,9 +8,12 @@
namespace Magento\Framework\Interception\Code\Generator;
use Magento\Framework\Code\Generator\EntityAbstract;
+use Magento\Framework\GetReflectionMethodReturnTypeValueTrait;
class Interceptor extends EntityAbstract
{
+ use GetReflectionMethodReturnTypeValueTrait;
+
public const ENTITY_TYPE = 'interceptor';
/**
@@ -200,24 +203,4 @@ protected function _validateData()
return $result;
}
-
- /**
- * Returns return type
- *
- * @param \ReflectionMethod $method
- * @return null|string
- */
- private function getReturnTypeValue(\ReflectionMethod $method): ?string
- {
- $returnTypeValue = null;
- $returnType = $method->getReturnType();
- if ($returnType) {
- $returnTypeValue = ($returnType->allowsNull() && $returnType->getName() !== 'mixed' ? '?' : '');
- $returnTypeValue .= ($returnType->getName() === 'self')
- ? $this->_getFullyQualifiedClassName($method->getDeclaringClass()->getName())
- : $returnType->getName();
- }
-
- return $returnTypeValue;
- }
}
diff --git a/lib/internal/Magento/Framework/Interception/Test/Unit/Code/Generator/InterceptorTest.php b/lib/internal/Magento/Framework/Interception/Test/Unit/Code/Generator/InterceptorTest.php
index 3a8553803a2be..6b38b36384bc8 100644
--- a/lib/internal/Magento/Framework/Interception/Test/Unit/Code/Generator/InterceptorTest.php
+++ b/lib/internal/Magento/Framework/Interception/Test/Unit/Code/Generator/InterceptorTest.php
@@ -10,9 +10,17 @@
use Composer\Autoload\ClassLoader;
use Magento\Framework\Code\Generator\Io;
use Magento\Framework\Interception\Code\Generator\Interceptor;
+use Magento\Framework\Interception\Code\Generator\ReflectionIntersectionTypeSample;
+use Magento\Framework\Interception\Code\Generator\ReflectionUnionTypeSample;
+use Magento\Framework\Interception\Code\Generator\Sample;
+use Magento\Framework\Interception\Code\Generator\SampleBackendMenu;
+use Magento\Framework\Interception\Code\Generator\TSample;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
+/**
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
+ */
class InterceptorTest extends TestCase
{
/**
@@ -82,20 +90,30 @@ public function interceptorDataProvider()
{
return [
[
- \Magento\Framework\Interception\Code\Generator\Sample::class,
- \Magento\Framework\Interception\Code\Generator\Sample\Interceptor::class,
+ Sample::class,
+ Sample\Interceptor::class,
'Interceptor'
],
[
- \Magento\Framework\Interception\Code\Generator\TSample::class,
- \Magento\Framework\Interception\Code\Generator\TSample\Interceptor::class,
+ TSample::class,
+ TSample\Interceptor::class,
'TInterceptor'
],
[
- \Magento\Framework\Interception\Code\Generator\SampleBackendMenu::class,
- \Magento\Framework\Interception\Code\Generator\SampleBackendMenu\Interceptor::class,
+ SampleBackendMenu::class,
+ SampleBackendMenu\Interceptor::class,
'SampleBackendMenuInterceptor',
],
+ [
+ ReflectionUnionTypeSample::class,
+ ReflectionUnionTypeSample\Interceptor::class,
+ 'ReflectionUnionTypeSampleInterceptor',
+ ],
+ [
+ ReflectionIntersectionTypeSample::class,
+ ReflectionIntersectionTypeSample\Interceptor::class,
+ 'ReflectionIntersectionTypeSampleInterceptor',
+ ],
];
}
}
diff --git a/lib/internal/Magento/Framework/Interception/Test/Unit/Code/Generator/_files/ReflectionIntersectionTypeSample.php b/lib/internal/Magento/Framework/Interception/Test/Unit/Code/Generator/_files/ReflectionIntersectionTypeSample.php
new file mode 100644
index 0000000000000..a9bfb3389d5b1
--- /dev/null
+++ b/lib/internal/Magento/Framework/Interception/Test/Unit/Code/Generator/_files/ReflectionIntersectionTypeSample.php
@@ -0,0 +1,36 @@
+attribute;
+ }
+
+ /**
+ * @param ReflectionIntersectionTypeSample&Menu $value
+ */
+ public function setValue(ReflectionIntersectionTypeSample&Menu $value)
+ {
+ $this->attribute = $value;
+ }
+}
diff --git a/lib/internal/Magento/Framework/Interception/Test/Unit/Code/Generator/_files/ReflectionIntersectionTypeSampleInterceptor.txt b/lib/internal/Magento/Framework/Interception/Test/Unit/Code/Generator/_files/ReflectionIntersectionTypeSampleInterceptor.txt
new file mode 100644
index 0000000000000..e6e41d69196ea
--- /dev/null
+++ b/lib/internal/Magento/Framework/Interception/Test/Unit/Code/Generator/_files/ReflectionIntersectionTypeSampleInterceptor.txt
@@ -0,0 +1,141 @@
+namespace Magento\Framework\Interception\Code\Generator\ReflectionIntersectionTypeSample;
+
+/**
+ * Interceptor class for @see \Magento\Framework\Interception\Code\Generator\ReflectionIntersectionTypeSample
+ */
+class Interceptor extends \Magento\Framework\Interception\Code\Generator\ReflectionIntersectionTypeSample implements \Magento\Framework\Interception\InterceptorInterface
+{
+ use \Magento\Framework\Interception\Interceptor;
+
+ public function __construct(\Psr\Log\LoggerInterface $logger, $pathInMenuStructure = '', ?\Magento\Backend\Model\Menu\Item\Factory $menuItemFactory = null, ?\Magento\Framework\Serialize\SerializerInterface $serializer = null)
+ {
+ $this->___init();
+ parent::__construct($logger, $pathInMenuStructure, $menuItemFactory, $serializer);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getValue() : \Magento\Backend\Model\Menu&\Magento\Framework\Interception\Code\Generator\ReflectionIntersectionTypeSample
+ {
+ $pluginInfo = $this->pluginList->getNext($this->subjectType, 'getValue');
+ return $pluginInfo ? $this->___callPlugins('getValue', func_get_args(), $pluginInfo) : parent::getValue();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setValue(\Magento\Backend\Model\Menu&\Magento\Framework\Interception\Code\Generator\ReflectionIntersectionTypeSample $value)
+ {
+ $pluginInfo = $this->pluginList->getNext($this->subjectType, 'setValue');
+ return $pluginInfo ? $this->___callPlugins('setValue', func_get_args(), $pluginInfo) : parent::setValue($value);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function add(\Magento\Backend\Model\Menu\Item $item, $parentId = null, $index = null)
+ {
+ $pluginInfo = $this->pluginList->getNext($this->subjectType, 'add');
+ return $pluginInfo ? $this->___callPlugins('add', func_get_args(), $pluginInfo) : parent::add($item, $parentId, $index);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function get($itemId)
+ {
+ $pluginInfo = $this->pluginList->getNext($this->subjectType, 'get');
+ return $pluginInfo ? $this->___callPlugins('get', func_get_args(), $pluginInfo) : parent::get($itemId);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function move($itemId, $toItemId, $sortIndex = null)
+ {
+ $pluginInfo = $this->pluginList->getNext($this->subjectType, 'move');
+ return $pluginInfo ? $this->___callPlugins('move', func_get_args(), $pluginInfo) : parent::move($itemId, $toItemId, $sortIndex);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function remove($itemId)
+ {
+ $pluginInfo = $this->pluginList->getNext($this->subjectType, 'remove');
+ return $pluginInfo ? $this->___callPlugins('remove', func_get_args(), $pluginInfo) : parent::remove($itemId);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function reorder($itemId, $position)
+ {
+ $pluginInfo = $this->pluginList->getNext($this->subjectType, 'reorder');
+ return $pluginInfo ? $this->___callPlugins('reorder', func_get_args(), $pluginInfo) : parent::reorder($itemId, $position);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function isLast(\Magento\Backend\Model\Menu\Item $item)
+ {
+ $pluginInfo = $this->pluginList->getNext($this->subjectType, 'isLast');
+ return $pluginInfo ? $this->___callPlugins('isLast', func_get_args(), $pluginInfo) : parent::isLast($item);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getFirstAvailable()
+ {
+ $pluginInfo = $this->pluginList->getNext($this->subjectType, 'getFirstAvailable');
+ return $pluginInfo ? $this->___callPlugins('getFirstAvailable', func_get_args(), $pluginInfo) : parent::getFirstAvailable();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getParentItems($itemId)
+ {
+ $pluginInfo = $this->pluginList->getNext($this->subjectType, 'getParentItems');
+ return $pluginInfo ? $this->___callPlugins('getParentItems', func_get_args(), $pluginInfo) : parent::getParentItems($itemId);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function serialize()
+ {
+ $pluginInfo = $this->pluginList->getNext($this->subjectType, 'serialize');
+ return $pluginInfo ? $this->___callPlugins('serialize', func_get_args(), $pluginInfo) : parent::serialize();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function toArray()
+ {
+ $pluginInfo = $this->pluginList->getNext($this->subjectType, 'toArray');
+ return $pluginInfo ? $this->___callPlugins('toArray', func_get_args(), $pluginInfo) : parent::toArray();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function unserialize($serialized)
+ {
+ $pluginInfo = $this->pluginList->getNext($this->subjectType, 'unserialize');
+ return $pluginInfo ? $this->___callPlugins('unserialize', func_get_args(), $pluginInfo) : parent::unserialize($serialized);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function populateFromArray(array $data)
+ {
+ $pluginInfo = $this->pluginList->getNext($this->subjectType, 'populateFromArray');
+ return $pluginInfo ? $this->___callPlugins('populateFromArray', func_get_args(), $pluginInfo) : parent::populateFromArray($data);
+ }
+}
diff --git a/lib/internal/Magento/Framework/Interception/Test/Unit/Code/Generator/_files/ReflectionUnionTypeSample.php b/lib/internal/Magento/Framework/Interception/Test/Unit/Code/Generator/_files/ReflectionUnionTypeSample.php
new file mode 100644
index 0000000000000..720adbb2dc527
--- /dev/null
+++ b/lib/internal/Magento/Framework/Interception/Test/Unit/Code/Generator/_files/ReflectionUnionTypeSample.php
@@ -0,0 +1,31 @@
+attribute;
+ }
+
+ /**
+ * @param int|string $value
+ */
+ public function setValue(int|string $value)
+ {
+ $this->attribute = $value;
+ }
+}
diff --git a/lib/internal/Magento/Framework/Interception/Test/Unit/Code/Generator/_files/ReflectionUnionTypeSampleInterceptor.txt b/lib/internal/Magento/Framework/Interception/Test/Unit/Code/Generator/_files/ReflectionUnionTypeSampleInterceptor.txt
new file mode 100644
index 0000000000000..67a8fc808f3f5
--- /dev/null
+++ b/lib/internal/Magento/Framework/Interception/Test/Unit/Code/Generator/_files/ReflectionUnionTypeSampleInterceptor.txt
@@ -0,0 +1,32 @@
+namespace Magento\Framework\Interception\Code\Generator\ReflectionUnionTypeSample;
+
+/**
+ * Interceptor class for @see \Magento\Framework\Interception\Code\Generator\ReflectionUnionTypeSample
+ */
+class Interceptor extends \Magento\Framework\Interception\Code\Generator\ReflectionUnionTypeSample implements \Magento\Framework\Interception\InterceptorInterface
+{
+ use \Magento\Framework\Interception\Interceptor;
+
+ public function __construct()
+ {
+ $this->___init();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getValue() : int|string
+ {
+ $pluginInfo = $this->pluginList->getNext($this->subjectType, 'getValue');
+ return $pluginInfo ? $this->___callPlugins('getValue', func_get_args(), $pluginInfo) : parent::getValue();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setValue(int|string $value)
+ {
+ $pluginInfo = $this->pluginList->getNext($this->subjectType, 'setValue');
+ return $pluginInfo ? $this->___callPlugins('setValue', func_get_args(), $pluginInfo) : parent::setValue($value);
+ }
+}
diff --git a/lib/internal/Magento/Framework/Logger/LoggerProxy.php b/lib/internal/Magento/Framework/Logger/LoggerProxy.php
index 0a589f3e9f4f0..0d08e83f2735a 100644
--- a/lib/internal/Magento/Framework/Logger/LoggerProxy.php
+++ b/lib/internal/Magento/Framework/Logger/LoggerProxy.php
@@ -99,6 +99,7 @@ private function getLogger(): LoggerInterface
*/
public function emergency($message, array $context = [])
{
+ $context = $this->addExceptionToContext($message, $context);
$this->getLogger()->emergency($message, $context);
}
@@ -107,6 +108,7 @@ public function emergency($message, array $context = [])
*/
public function alert($message, array $context = [])
{
+ $context = $this->addExceptionToContext($message, $context);
$this->getLogger()->alert($message, $context);
}
@@ -115,6 +117,7 @@ public function alert($message, array $context = [])
*/
public function critical($message, array $context = [])
{
+ $context = $this->addExceptionToContext($message, $context);
$this->getLogger()->critical($message, $context);
}
@@ -123,6 +126,7 @@ public function critical($message, array $context = [])
*/
public function error($message, array $context = [])
{
+ $context = $this->addExceptionToContext($message, $context);
$this->getLogger()->error($message, $context);
}
@@ -131,6 +135,7 @@ public function error($message, array $context = [])
*/
public function warning($message, array $context = [])
{
+ $context = $this->addExceptionToContext($message, $context);
$this->getLogger()->warning($message, $context);
}
@@ -139,6 +144,7 @@ public function warning($message, array $context = [])
*/
public function notice($message, array $context = [])
{
+ $context = $this->addExceptionToContext($message, $context);
$this->getLogger()->notice($message, $context);
}
@@ -147,6 +153,7 @@ public function notice($message, array $context = [])
*/
public function info($message, array $context = [])
{
+ $context = $this->addExceptionToContext($message, $context);
$this->getLogger()->info($message, $context);
}
@@ -155,6 +162,7 @@ public function info($message, array $context = [])
*/
public function debug($message, array $context = [])
{
+ $context = $this->addExceptionToContext($message, $context);
$this->getLogger()->debug($message, $context);
}
@@ -163,6 +171,22 @@ public function debug($message, array $context = [])
*/
public function log($level, $message, array $context = [])
{
+ $context = $this->addExceptionToContext($message, $context);
$this->getLogger()->log($level, $message, $context);
}
+
+ /**
+ * Ensure exception logging by adding it to context
+ *
+ * @param mixed $message
+ * @param array $context
+ * @return array
+ */
+ protected function addExceptionToContext($message, array $context = []): array
+ {
+ if ($message instanceof \Throwable && !isset($context['exception'])) {
+ $context['exception'] = $message;
+ }
+ return $context;
+ }
}
diff --git a/lib/internal/Magento/Framework/Logger/Test/Unit/LoggerProxyTest.php b/lib/internal/Magento/Framework/Logger/Test/Unit/LoggerProxyTest.php
index 582c940ade51e..16134f226fb5a 100644
--- a/lib/internal/Magento/Framework/Logger/Test/Unit/LoggerProxyTest.php
+++ b/lib/internal/Magento/Framework/Logger/Test/Unit/LoggerProxyTest.php
@@ -99,4 +99,36 @@ public function createWithArguments(): void
$loggerProxy = new LoggerProxy($objectManager);
$loggerProxy->log(LogLevel::ALERT, 'test');
}
+
+ /**
+ * @test
+ *
+ * @param $method
+ *
+ * @return void
+ * @dataProvider methodsList
+ */
+ public function logException($method): void
+ {
+ $deploymentConfig = $this->getMockBuilder(DeploymentConfig::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $objectManager = $this->getMockBuilder(ObjectManagerInterface::class)
+ ->getMockForAbstractClass();
+
+ $logger = $this->getMockBuilder(LoggerInterface::class)
+ ->getMockForAbstractClass();
+
+ $objectManager
+ ->method('get')
+ ->withConsecutive([DeploymentConfig::class], [Monolog::class])
+ ->willReturnOnConsecutiveCalls($deploymentConfig, $logger);
+
+ $message = new \Exception('This is an exception.');
+
+ $logger->expects($this->once())->method($method)->with($message);
+
+ $loggerProxy = new LoggerProxy($objectManager);
+ $loggerProxy->$method($message);
+ }
}
diff --git a/lib/internal/Magento/Framework/MessageQueue/Code/Generator/RemoteServiceGenerator.php b/lib/internal/Magento/Framework/MessageQueue/Code/Generator/RemoteServiceGenerator.php
index b68a242b50722..a6865c44d57f3 100644
--- a/lib/internal/Magento/Framework/MessageQueue/Code/Generator/RemoteServiceGenerator.php
+++ b/lib/internal/Magento/Framework/MessageQueue/Code/Generator/RemoteServiceGenerator.php
@@ -5,13 +5,13 @@
*/
namespace Magento\Framework\MessageQueue\Code\Generator;
+use Laminas\Code\Reflection\MethodReflection;
use Magento\Framework\Code\Generator\DefinedClasses;
use Magento\Framework\Code\Generator\Io;
use Magento\Framework\Communication\Config\ReflectionGenerator;
use Magento\Framework\Communication\ConfigInterface as CommunicationConfig;
use Magento\Framework\MessageQueue\Code\Generator\Config\RemoteServiceReader\Communication as RemoteServiceReader;
use Magento\Framework\Reflection\MethodsMap as ServiceMethodsMap;
-use Laminas\Code\Reflection\MethodReflection;
/**
* Code generator for remote services.
@@ -20,8 +20,8 @@
*/
class RemoteServiceGenerator extends \Magento\Framework\Code\Generator\EntityAbstract
{
- const ENTITY_TYPE = 'remote';
- const REMOTE_SERVICE_SUFFIX = 'Remote';
+ public const ENTITY_TYPE = 'remote';
+ public const REMOTE_SERVICE_SUFFIX = 'Remote';
/**
* @var CommunicationConfig
@@ -173,7 +173,21 @@ protected function _getClassMethods()
*/
private function convertMethodType($type)
{
- return $type instanceof \ReflectionNamedType ? $type->getName() : $type;
+ $returnTypeValue = $type instanceof \ReflectionNamedType ? $type->getName() : $type;
+
+ if ($type instanceof \ReflectionUnionType || $type instanceof \ReflectionIntersectionType) {
+ $returnTypeValue = [];
+ foreach ($type->getTypes() as $type) {
+ $returnTypeValue[] = $type->getName();
+ }
+
+ $returnTypeValue = implode(
+ $type instanceof \ReflectionUnionType ? '|' : '&',
+ $returnTypeValue
+ );
+ }
+
+ return $returnTypeValue;
}
/**
@@ -230,6 +244,7 @@ protected function validateResultClassName()
* @return ReflectionGenerator
*
* @deprecated 103.0.0
+ * @see https://jira.corp.adobe.com/browse/MAGETWO-56305
*/
private function getReflectionGenerator()
{
diff --git a/lib/internal/Magento/Framework/MessageQueue/composer.json b/lib/internal/Magento/Framework/MessageQueue/composer.json
index 9039e5a8775b2..07cce7c905463 100644
--- a/lib/internal/Magento/Framework/MessageQueue/composer.json
+++ b/lib/internal/Magento/Framework/MessageQueue/composer.json
@@ -11,7 +11,7 @@
],
"require": {
"magento/framework": "*",
- "php": "~7.4.0||~8.1.0"
+ "php": "~8.1.0||~8.2.0"
},
"autoload": {
"psr-4": {
diff --git a/lib/internal/Magento/Framework/ObjectManager/Code/Generator/Proxy.php b/lib/internal/Magento/Framework/ObjectManager/Code/Generator/Proxy.php
index f9bf616681cb6..e1ae712c2af1a 100644
--- a/lib/internal/Magento/Framework/ObjectManager/Code/Generator/Proxy.php
+++ b/lib/internal/Magento/Framework/ObjectManager/Code/Generator/Proxy.php
@@ -7,8 +7,12 @@
namespace Magento\Framework\ObjectManager\Code\Generator;
+use Magento\Framework\GetReflectionMethodReturnTypeValueTrait;
+
class Proxy extends \Magento\Framework\Code\Generator\EntityAbstract
{
+ use GetReflectionMethodReturnTypeValueTrait;
+
/**
* Entity type
*/
@@ -268,24 +272,4 @@ protected function _validateData()
return $result;
}
-
- /**
- * Returns return type
- *
- * @param \ReflectionMethod $method
- * @return null|string
- */
- private function getReturnTypeValue(\ReflectionMethod $method): ?string
- {
- $returnTypeValue = null;
- $returnType = $method->getReturnType();
- if ($returnType) {
- $returnTypeValue = ($returnType->allowsNull() && $returnType->getName() !== 'mixed' ? '?' : '');
- $returnTypeValue .= ($returnType->getName() === 'self')
- ? $this->_getFullyQualifiedClassName($method->getDeclaringClass()->getName())
- : $returnType->getName();
- }
-
- return $returnTypeValue;
- }
}
diff --git a/lib/internal/Magento/Framework/ObjectManager/Code/Generator/Repository.php b/lib/internal/Magento/Framework/ObjectManager/Code/Generator/Repository.php
index 645e3fd7eff78..405b0f619da30 100644
--- a/lib/internal/Magento/Framework/ObjectManager/Code/Generator/Repository.php
+++ b/lib/internal/Magento/Framework/ObjectManager/Code/Generator/Repository.php
@@ -18,13 +18,14 @@
* Class Repository
* @deprecated 101.0.0 As current implementation breaks Repository contract. Not removed from codebase to prevent
* possible backward incompatibilities if this functionality being used by 3rd party developers.
+ * @see https://jira.corp.adobe.com/browse/MAGETWO-70985
*/
class Repository extends \Magento\Framework\Code\Generator\EntityAbstract
{
/**
* Entity type repository
*/
- const ENTITY_TYPE = 'repository';
+ public const ENTITY_TYPE = 'repository';
/**
* The namespace of repository interface
@@ -750,6 +751,20 @@ private function getClassMethods($name)
*/
private function getTypeHintText($type)
{
- return $type instanceof \ReflectionType ? $type->getName() : $type;
+ $returnTypeValue = $type instanceof \ReflectionType ? $type->getName() : $type;
+
+ if ($type instanceof \ReflectionUnionType || $type instanceof \ReflectionIntersectionType) {
+ $returnTypeValue = [];
+ foreach ($type->getTypes() as $type) {
+ $returnTypeValue[] = $type->getName();
+ }
+
+ $returnTypeValue = implode(
+ $type instanceof \ReflectionUnionType ? '|' : '&',
+ $returnTypeValue
+ );
+ }
+
+ return $returnTypeValue;
}
}
diff --git a/lib/internal/Magento/Framework/ObjectManager/Test/Unit/Code/Generator/_files/Sample.php b/lib/internal/Magento/Framework/ObjectManager/Test/Unit/Code/Generator/_files/Sample.php
index b51351e46fa2e..ae873142a1705 100644
--- a/lib/internal/Magento/Framework/ObjectManager/Test/Unit/Code/Generator/_files/Sample.php
+++ b/lib/internal/Magento/Framework/ObjectManager/Test/Unit/Code/Generator/_files/Sample.php
@@ -22,6 +22,13 @@ class Sample
*/
private $config = [];
+ /**
+ * Union type attribute
+ *
+ * @var int|string
+ */
+ private int|string $attribute;
+
/**
* @param array $messages
*/
@@ -53,4 +60,20 @@ public function getConfig(): array
{
return $this->config;
}
+
+ /**
+ * @param int|string $attribute
+ */
+ public function setAttribute(int|string $attribute)
+ {
+ $this->attribute = $attribute;
+ }
+
+ /**
+ * @return int|string
+ */
+ public function getAttribute(): int|string
+ {
+ return $this->attribute;
+ }
}
diff --git a/lib/internal/Magento/Framework/ObjectManager/Test/Unit/Code/Generator/_files/SampleProxy.txt b/lib/internal/Magento/Framework/ObjectManager/Test/Unit/Code/Generator/_files/SampleProxy.txt
index 2c56472f323cf..6ee7bdcbaf3a3 100644
--- a/lib/internal/Magento/Framework/ObjectManager/Test/Unit/Code/Generator/_files/SampleProxy.txt
+++ b/lib/internal/Magento/Framework/ObjectManager/Test/Unit/Code/Generator/_files/SampleProxy.txt
@@ -117,4 +117,20 @@ class Sample_Proxy extends Sample implements \Magento\Framework\ObjectManager\No
{
return $this->_getSubject()->getConfig();
}
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setAttribute(int|string $attribute)
+ {
+ return $this->_getSubject()->setAttribute($attribute);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getAttribute() : int|string
+ {
+ return $this->_getSubject()->getAttribute();
+ }
}
diff --git a/lib/internal/Magento/Framework/Reflection/DataObjectProcessor.php b/lib/internal/Magento/Framework/Reflection/DataObjectProcessor.php
index 967826be09ceb..94023d129d1db 100644
--- a/lib/internal/Magento/Framework/Reflection/DataObjectProcessor.php
+++ b/lib/internal/Magento/Framework/Reflection/DataObjectProcessor.php
@@ -46,6 +46,11 @@ class DataObjectProcessor
*/
private $processors;
+ /**
+ * @var array[]
+ */
+ private $excludedMethodsClassMap;
+
/**
* @param MethodsMap $methodsMapProcessor
* @param TypeCaster $typeCaster
@@ -53,6 +58,7 @@ class DataObjectProcessor
* @param CustomAttributesProcessor $customAttributesProcessor
* @param ExtensionAttributesProcessor $extensionAttributesProcessor
* @param array $processors
+ * @param array $excludedMethodsClassMap
*/
public function __construct(
MethodsMap $methodsMapProcessor,
@@ -60,7 +66,8 @@ public function __construct(
FieldNamer $fieldNamer,
CustomAttributesProcessor $customAttributesProcessor,
ExtensionAttributesProcessor $extensionAttributesProcessor,
- array $processors = []
+ array $processors = [],
+ array $excludedMethodsClassMap = []
) {
$this->methodsMapProcessor = $methodsMapProcessor;
$this->typeCaster = $typeCaster;
@@ -68,6 +75,7 @@ public function __construct(
$this->extensionAttributesProcessor = $extensionAttributesProcessor;
$this->customAttributesProcessor = $customAttributesProcessor;
$this->processors = $processors;
+ $this->excludedMethodsClassMap = $excludedMethodsClassMap;
}
/**
@@ -84,7 +92,13 @@ public function buildOutputDataArray($dataObject, $dataObjectType)
$methods = $this->methodsMapProcessor->getMethodsMap($dataObjectType);
$outputData = [];
+ $excludedMethodsForDataObjectType = $this->excludedMethodsClassMap[$dataObjectType] ?? [];
+
foreach (array_keys($methods) as $methodName) {
+ if (in_array($methodName, $excludedMethodsForDataObjectType)) {
+ continue;
+ }
+
if (!$this->methodsMapProcessor->isMethodValidForDataField($dataObjectType, $methodName)) {
continue;
}
diff --git a/lib/internal/Magento/Framework/Reflection/Test/Unit/DataObjectProcessorTest.php b/lib/internal/Magento/Framework/Reflection/Test/Unit/DataObjectProcessorTest.php
index 8e55d4395d20d..620b3684b4abd 100644
--- a/lib/internal/Magento/Framework/Reflection/Test/Unit/DataObjectProcessorTest.php
+++ b/lib/internal/Magento/Framework/Reflection/Test/Unit/DataObjectProcessorTest.php
@@ -26,6 +26,11 @@ class DataObjectProcessorTest extends TestCase
*/
private $dataObjectProcessor;
+ /**
+ * @var MethodsMap
+ */
+ private $methodsMapProcessor;
+
/**
* @var ExtensionAttributesProcessor|MockObject
*/
@@ -34,7 +39,7 @@ class DataObjectProcessorTest extends TestCase
protected function setUp(): void
{
$objectManager = new ObjectManager($this);
- $methodsMapProcessor = $objectManager->getObject(
+ $this->methodsMapProcessor = $objectManager->getObject(
MethodsMap::class,
[
'fieldNamer' => $objectManager->getObject(FieldNamer::class),
@@ -48,7 +53,7 @@ protected function setUp(): void
->willReturn(['unserializedData']);
$objectManager->setBackwardCompatibleProperty(
- $methodsMapProcessor,
+ $this->methodsMapProcessor,
'serializer',
$serializerMock
);
@@ -56,27 +61,32 @@ protected function setUp(): void
$this->extensionAttributesProcessorMock = $this->getMockBuilder(ExtensionAttributesProcessor::class)
->disableOriginalConstructor()
->getMock();
+ }
+
+ /**
+ * @param array $extensionAttributes
+ * @param array $excludedMethodsClassMap
+ * @param array $expectedOutput
+ * @dataProvider buildOutputDataArrayDataProvider
+ */
+ public function testBuildOutputDataArray(
+ array $extensionAttributes,
+ array $excludedMethodsClassMap,
+ array $expectedOutput
+ ) {
+ $objectManager = new ObjectManager($this);
$this->dataObjectProcessor = $objectManager->getObject(
DataObjectProcessor::class,
[
- 'methodsMapProcessor' => $methodsMapProcessor,
+ 'methodsMapProcessor' => $this->methodsMapProcessor,
'typeCaster' => $objectManager->getObject(TypeCaster::class),
'fieldNamer' => $objectManager->getObject(FieldNamer::class),
- 'extensionAttributesProcessor' => $this->extensionAttributesProcessorMock
+ 'extensionAttributesProcessor' => $this->extensionAttributesProcessorMock,
+ 'excludedMethodsClassMap' => $excludedMethodsClassMap,
]
);
- }
- /**
- * @param array $extensionAttributes
- * @param array $expectedOutputDataArray
- *
- * @dataProvider buildOutputDataArrayDataProvider
- */
- public function testBuildOutputDataArray($extensionAttributes, $expectedOutputDataArray)
- {
- $objectManager = new ObjectManager($this);
/** @var TestDataObject $testDataObject */
$testDataObject = $objectManager->getObject(
TestDataObject::class,
@@ -87,13 +97,19 @@ public function testBuildOutputDataArray($extensionAttributes, $expectedOutputDa
]
);
- $this->extensionAttributesProcessorMock->expects($this->once())
+ if (in_array('getExtensionAttributes', $excludedMethodsClassMap[TestDataInterface::class] ?? [])) {
+ $expectedTimes = $this->never();
+ } else {
+ $expectedTimes = $this->once();
+ }
+
+ $this->extensionAttributesProcessorMock->expects($expectedTimes)
->method('buildOutputDataArray')
->willReturn($extensionAttributes);
$outputData = $this->dataObjectProcessor
->buildOutputDataArray($testDataObject, TestDataInterface::class);
- $this->assertEquals($expectedOutputDataArray, $outputData);
+ $this->assertEquals($expectedOutput, $outputData);
}
/**
@@ -101,26 +117,50 @@ public function testBuildOutputDataArray($extensionAttributes, $expectedOutputDa
*/
public function buildOutputDataArrayDataProvider()
{
- $expectedOutputDataArray = [
+ $expectedOutput = [
'id' => '1',
'address' => 'someAddress',
'default_shipping' => 'true',
'required_billing' => 'false',
];
- $extensionAttributeArray = [
+
+ $extensionAttributes = [
'attribute1' => 'value1',
- 'attribute2' => 'value2'
+ 'attribute2' => 'value2',
];
return [
- 'No Attributes' => [[], $expectedOutputDataArray],
- 'With Attributes' => [
- $extensionAttributeArray,
+ 'No Extension Attributes or Excluded Methods' => [
+ [],
+ [],
+ $expectedOutput,
+ ],
+ 'With Extension Attributes' => [
+ $extensionAttributes,
+ [],
array_merge(
- $expectedOutputDataArray,
- ['extension_attributes' => $extensionAttributeArray]
- )
- ]
+ $expectedOutput,
+ ['extension_attributes' => $extensionAttributes]
+ ),
+ ],
+ 'With Excluded Method' => [
+ [],
+ [
+ TestDataInterface::class => [
+ 'getAddress',
+ ],
+ ],
+ array_diff_key($expectedOutput, array_flip(['address'])),
+ ],
+ 'With getExtensionAttributes as Excluded Method' => [
+ $extensionAttributes,
+ [
+ TestDataInterface::class => [
+ 'getExtensionAttributes',
+ ],
+ ],
+ $expectedOutput,
+ ],
];
}
}
diff --git a/lib/internal/Magento/Framework/Reflection/TypeProcessor.php b/lib/internal/Magento/Framework/Reflection/TypeProcessor.php
index 8591e2f096a90..b513acb019d17 100644
--- a/lib/internal/Magento/Framework/Reflection/TypeProcessor.php
+++ b/lib/internal/Magento/Framework/Reflection/TypeProcessor.php
@@ -59,7 +59,8 @@ class TypeProcessor
*
* @return NameFinder
*
- * @deprecated 100.1.0
+ * @deprecated 100.1.0 Refactor TypeProcessor
+ * @see https://jira.corp.adobe.com/browse/MAGETWO-51906
*/
private function getNameFinder()
{
@@ -254,7 +255,8 @@ public function getDescription(DocBlockReflection $doc)
* @param string $getterName
* @return string
*
- * @deprecated 100.1.0
+ * @deprecated 100.1.0 Refactor TypeProcessor
+ * @see https://jira.corp.adobe.com/browse/MAGETWO-51906
*/
public function dataObjectGetterNameToFieldName($getterName)
{
@@ -267,7 +269,8 @@ public function dataObjectGetterNameToFieldName($getterName)
* @param string $shortDescription
* @return string
*
- * @deprecated 100.1.0
+ * @deprecated 100.1.0 Refactor TypeProcessor
+ * @see https://jira.corp.adobe.com/browse/MAGETWO-51906
*/
protected function dataObjectGetterDescriptionToFieldDescription($shortDescription)
{
@@ -547,7 +550,7 @@ public function getParamType(ParameterReflection $param)
return strpos($paramType, '[]') !== false ? $paramType : "{$paramType}[]";
}
- return $this->resolveFullyQualifiedClassName($param->getDeclaringClass(), $type);
+ return $this->resolveFullyQualifiedClassName($param->getDeclaringClass(), $type ?? '');
}
/**
@@ -701,7 +704,8 @@ public function getParamDescription(ParameterReflection $param)
* @return string processed method name
* @throws \Exception If $camelCaseProperty has no corresponding getter method
*
- * @deprecated 100.1.0
+ * @deprecated 100.1.0 Refactor TypeProcessor
+ * @see https://jira.corp.adobe.com/browse/MAGETWO-51906
*/
public function findGetterMethodName(ClassReflection $class, $camelCaseProperty)
{
@@ -739,7 +743,8 @@ protected function setType(&$value, $type)
* @return string processed method name
* @throws \Exception If $camelCaseProperty has no corresponding setter method
*
- * @deprecated 100.1.0
+ * @deprecated 100.1.0 Refactor TypeProcessor
+ * @see https://jira.corp.adobe.com/browse/MAGETWO-51906
*/
public function findSetterMethodName(ClassReflection $class, $camelCaseProperty)
{
@@ -756,7 +761,8 @@ public function findSetterMethodName(ClassReflection $class, $camelCaseProperty)
* @return string processed method name
* @throws \Exception If $camelCaseProperty has no corresponding setter method
*
- * @deprecated 100.1.0
+ * @deprecated 100.1.0 Refactor TypeProcessor
+ * @see https://jira.corp.adobe.com/browse/MAGETWO-51906
*/
protected function findAccessorMethodName(
ClassReflection $class,
@@ -777,7 +783,8 @@ protected function findAccessorMethodName(
* @param string $methodName
* @return bool
*
- * @deprecated 100.1.0
+ * @deprecated 100.1.0 Refactor TypeProcessor
+ * @see https://jira.corp.adobe.com/browse/MAGETWO-51906
*/
protected function classHasMethod(ClassReflection $class, $methodName)
{
diff --git a/lib/internal/Magento/Framework/View/Asset/PreProcessor/FileNameResolver.php b/lib/internal/Magento/Framework/View/Asset/PreProcessor/FileNameResolver.php
index 6f2ca8544dded..3777699421ce8 100644
--- a/lib/internal/Magento/Framework/View/Asset/PreProcessor/FileNameResolver.php
+++ b/lib/internal/Magento/Framework/View/Asset/PreProcessor/FileNameResolver.php
@@ -36,20 +36,17 @@ function (AlternativeSourceInterface $alternativeSource) {
* @param string $fileName
* @return string
*/
- public function resolve($fileName)
+ public function resolve(string $fileName): string
{
$compiledFile = $fileName;
$extension = pathinfo($fileName, PATHINFO_EXTENSION);
foreach ($this->alternativeSources as $name => $alternative) {
- if ($alternative->isExtensionSupported($extension)
- && strpos(basename($fileName), '_') !== 0
- ) {
- $compiledFile = $fileName !== null
- ? substr($fileName, 0, strlen($fileName) - strlen($extension) - 1)
- : '';
- $compiledFile = $compiledFile . '.' . $name;
+ if ($alternative->isExtensionSupported($extension) && !str_starts_with(basename($fileName), '_')) {
+ $compiledFile = substr($fileName, 0, strlen($fileName) - strlen($extension) - 1);
+ $compiledFile = sprintf('%s.%s', $compiledFile, $name);
}
}
+
return $compiledFile;
}
}
diff --git a/lib/internal/Magento/Framework/composer.json b/lib/internal/Magento/Framework/composer.json
index 03ab3457c43a2..35686828de8cf 100644
--- a/lib/internal/Magento/Framework/composer.json
+++ b/lib/internal/Magento/Framework/composer.json
@@ -10,7 +10,7 @@
"sort-packages": true
},
"require": {
- "php": "~7.4.0||~8.1.0",
+ "php": "~8.1.0||~8.2.0",
"ext-bcmath": "*",
"ext-curl": "*",
"ext-dom": "*",
@@ -23,34 +23,33 @@
"ext-sodium": "*",
"ext-xsl": "*",
"lib-libxml": "*",
- "colinmollenhour/php-redis-session-abstract": "v1.5.0",
+ "colinmollenhour/php-redis-session-abstract": "^1.5",
"composer/composer": "^2.0, !=2.2.16",
"ezyang/htmlpurifier": "^4.14",
- "guzzlehttp/guzzle": "^7.4.2",
- "laminas/laminas-code": "~4.5.0",
- "laminas/laminas-escaper": "~2.10.0",
- "laminas/laminas-file": "^2.11.0",
- "laminas/laminas-filter": "^2.17.0",
- "laminas/laminas-http": "^2.15.0",
- "laminas/laminas-i18n": "^2.17.0",
- "laminas/laminas-mail": "^2.16.0",
- "laminas/laminas-mime": "^2.9.1",
- "laminas/laminas-permissions-acl": "^2.10.0",
- "laminas/laminas-stdlib": "^3.11.0",
+ "guzzlehttp/guzzle": "^7.4",
+ "laminas/laminas-code": "^4.5",
+ "laminas/laminas-escaper": "^2.10",
+ "laminas/laminas-file": "^2.11",
+ "laminas/laminas-filter": "^2.17",
+ "laminas/laminas-http": "^2.15",
+ "laminas/laminas-i18n": "^2.17",
+ "laminas/laminas-mail": "^2.16",
+ "laminas/laminas-mime": "^2.9",
+ "laminas/laminas-permissions-acl": "^2.10",
+ "laminas/laminas-stdlib": "^3.11",
"laminas/laminas-oauth": "^2.4",
- "laminas/laminas-uri": "^2.9.1",
- "laminas/laminas-validator": "^2.23.0",
- "magento/composer-dependency-version-audit-plugin": "~0.1",
- "magento/zendframework1": "~1.15.0",
+ "laminas/laminas-uri": "^2.9",
+ "laminas/laminas-validator": "^2.23",
+ "magento/composer-dependency-version-audit-plugin": "^0.1",
+ "magento/zendframework1": "^1.15",
"monolog/monolog": "^2.7",
- "ramsey/uuid": "~4.2.0",
- "symfony/console": "~5.4.12",
- "symfony/string": "~5.4.12",
- "symfony/intl": "~5.4.11",
- "symfony/process": "~5.4.8",
- "tedivm/jshrink": "~1.4.0",
- "webonyx/graphql-php": "~14.11.6",
- "wikimedia/less.php": "^3.0.0"
+ "ramsey/uuid": "^4.2",
+ "symfony/console": "^5.4",
+ "symfony/intl": "^5.4",
+ "symfony/process": "^5.4",
+ "tedivm/jshrink": "^1.4",
+ "webonyx/graphql-php": "^14.11",
+ "wikimedia/less.php": "^3.0"
},
"archive": {
"exclude": [
diff --git a/lib/web/jquery/fileUploader/jquery.fileupload-process.js b/lib/web/jquery/fileUploader/jquery.fileupload-process.js
index a2f1009e508d1..a65ee91400161 100644
--- a/lib/web/jquery/fileUploader/jquery.fileupload-process.js
+++ b/lib/web/jquery/fileUploader/jquery.fileupload-process.js
@@ -120,7 +120,7 @@
options.processQueue = processQueue;
},
- // Returns the number of files currently in the processsing queue:
+ // Returns the number of files currently in the processing queue:
processing: function () {
return this._processing;
},
diff --git a/lib/web/jquery/fileUploader/jquery.fileupload.js b/lib/web/jquery/fileUploader/jquery.fileupload.js
index 8f0ff0d4faf03..48e836e91c122 100644
--- a/lib/web/jquery/fileUploader/jquery.fileupload.js
+++ b/lib/web/jquery/fileUploader/jquery.fileupload.js
@@ -455,7 +455,7 @@
_initProgressListener: function (options) {
var that = this,
xhr = options.xhr ? options.xhr() : $.ajaxSettings.xhr();
- // Accesss to the native XHR object is required to add event listeners
+ // Access to the native XHR object is required to add event listeners
// for the upload progress event:
if (xhr.upload) {
$(xhr.upload).on('progress', function (e) {
@@ -489,15 +489,14 @@
name = String(name);
if (map[name]) {
// eslint-disable-next-line no-param-reassign
- name = name.replace(/(?: \(([\d]+)\))?(\.[^.]+)?$/, function (
- _,
- p1,
- p2
- ) {
- var index = p1 ? Number(p1) + 1 : 1;
- var ext = p2 || '';
- return ' (' + index + ')' + ext;
- });
+ name = name.replace(
+ /(?: \(([\d]+)\))?(\.[^.]+)?$/,
+ function (_, p1, p2) {
+ var index = p1 ? Number(p1) + 1 : 1;
+ var ext = p2 || '';
+ return ' (' + index + ')' + ext;
+ }
+ );
return this._getUniqueFilename(name, map);
}
map[name] = true;
@@ -1172,7 +1171,7 @@
data.fileInputClone = inputClone;
$('').append(inputClone)[0].reset();
// Detaching allows to insert the fileInput on another form
- // without loosing the file input value:
+ // without losing the file input value:
input.after(inputClone).detach();
// If the fileInput had focus before it was detached,
// restore focus to the inputClone.
@@ -1298,8 +1297,7 @@
_getSingleFileInputFiles: function (fileInput) {
// eslint-disable-next-line no-param-reassign
fileInput = $(fileInput);
- var entries =
- fileInput.prop('webkitEntries') || fileInput.prop('entries'),
+ var entries = fileInput.prop('entries'),
files,
value;
if (entries && entries.length) {
diff --git a/lib/web/jquery/fileUploader/vendor/jquery.ui.widget.js b/lib/web/jquery/fileUploader/vendor/jquery.ui.widget.js
index 69096aaa35ef4..78e6255728ec3 100644
--- a/lib/web/jquery/fileUploader/vendor/jquery.ui.widget.js
+++ b/lib/web/jquery/fileUploader/vendor/jquery.ui.widget.js
@@ -660,9 +660,8 @@
) {
return;
}
- return (typeof handler === 'string'
- ? instance[handler]
- : handler
+ return (
+ typeof handler === 'string' ? instance[handler] : handler
).apply(instance, arguments);
}
@@ -699,9 +698,8 @@
_delay: function (handler, delay) {
var instance = this;
function handlerProxy() {
- return (typeof handler === 'string'
- ? instance[handler]
- : handler
+ return (
+ typeof handler === 'string' ? instance[handler] : handler
).apply(instance, arguments);
}
return setTimeout(handlerProxy, delay || 0);
@@ -737,9 +735,8 @@
data = data || {};
event = $.Event(event);
- event.type = (type === this.widgetEventPrefix
- ? type
- : this.widgetEventPrefix + type
+ event.type = (
+ type === this.widgetEventPrefix ? type : this.widgetEventPrefix + type
).toLowerCase();
// The original event may come from any element
diff --git a/pub/get.php b/pub/get.php
index a3267d8f1741a..fb619a0dfa51f 100644
--- a/pub/get.php
+++ b/pub/get.php
@@ -49,8 +49,10 @@
if (file_exists($configCacheFile) && is_readable($configCacheFile)) {
$config = json_decode(file_get_contents($configCacheFile), true);
- //checking update time
- if (filemtime($configCacheFile) + $config['update_time'] > time()) {
+ // Checking update time
+ if (isset($config['update_time'], $config['media_directory'], $config['allowed_resources'])
+ && filemtime($configCacheFile) + $config['update_time'] > time()
+ ) {
$mediaDirectory = $config['media_directory'];
$allowedResources = $config['allowed_resources'];