diff --git a/app/code/Magento/AdvancedSearch/Model/Client/ClientResolver.php b/app/code/Magento/AdvancedSearch/Model/Client/ClientResolver.php index fbcaf412e3562..84933c8584bb3 100644 --- a/app/code/Magento/AdvancedSearch/Model/Client/ClientResolver.php +++ b/app/code/Magento/AdvancedSearch/Model/Client/ClientResolver.php @@ -5,8 +5,9 @@ */ namespace Magento\AdvancedSearch\Model\Client; -use \Magento\Framework\ObjectManagerInterface; +use Magento\Framework\ObjectManagerInterface; use Magento\Framework\Search\EngineResolverInterface; +use Magento\Framework\App\Config\ScopeConfigInterface; /** * @api @@ -46,7 +47,7 @@ class ClientResolver private $clientOptionsPool; /** - * @var EngineResolver + * @var EngineResolverInterface */ private $engineResolver; diff --git a/app/code/Magento/AdvancedSearch/Model/Indexer/Fulltext/Plugin/CustomerGroup.php b/app/code/Magento/AdvancedSearch/Model/Indexer/Fulltext/Plugin/CustomerGroup.php index 421c309d3ed06..c63f6bfc8138b 100644 --- a/app/code/Magento/AdvancedSearch/Model/Indexer/Fulltext/Plugin/CustomerGroup.php +++ b/app/code/Magento/AdvancedSearch/Model/Indexer/Fulltext/Plugin/CustomerGroup.php @@ -12,8 +12,6 @@ use Magento\Framework\Model\AbstractModel; use Magento\Catalog\Model\ResourceModel\Attribute; use Magento\AdvancedSearch\Model\Client\ClientOptionsInterface; -use Magento\Framework\Search\EngineResolverInterface; -use Magento\Search\Model\EngineResolver; class CustomerGroup extends AbstractPlugin { @@ -22,24 +20,16 @@ class CustomerGroup extends AbstractPlugin */ protected $clientOptions; - /** - * @var EngineResolverInterface - */ - protected $engineResolver; - /** * @param IndexerRegistry $indexerRegistry * @param ClientOptionsInterface $clientOptions - * @param EngineResolverInterface $engineResolver */ public function __construct( IndexerRegistry $indexerRegistry, - ClientOptionsInterface $clientOptions, - EngineResolverInterface $engineResolver + ClientOptionsInterface $clientOptions ) { parent::__construct($indexerRegistry); $this->clientOptions = $clientOptions; - $this->engineResolver = $engineResolver; } /** @@ -56,9 +46,7 @@ public function aroundSave( \Closure $proceed, AbstractModel $group ) { - $needInvalidation = - ($this->engineResolver->getCurrentSearchEngine() != EngineResolver::CATALOG_SEARCH_MYSQL_ENGINE) - && ($group->isObjectNew() || $group->dataHasChangedFor('tax_class_id')); + $needInvalidation = $group->isObjectNew() || $group->dataHasChangedFor('tax_class_id'); $result = $proceed($group); if ($needInvalidation) { $this->indexerRegistry->get(Fulltext::INDEXER_ID)->invalidate(); diff --git a/app/code/Magento/AdvancedSearch/Test/Unit/Model/Indexer/Fulltext/Plugin/CustomerGroupTest.php b/app/code/Magento/AdvancedSearch/Test/Unit/Model/Indexer/Fulltext/Plugin/CustomerGroupTest.php index 6991ceec93e47..8cfb5e2ac3fbd 100644 --- a/app/code/Magento/AdvancedSearch/Test/Unit/Model/Indexer/Fulltext/Plugin/CustomerGroupTest.php +++ b/app/code/Magento/AdvancedSearch/Test/Unit/Model/Indexer/Fulltext/Plugin/CustomerGroupTest.php @@ -14,8 +14,8 @@ use Magento\Customer\Model\ResourceModel\Group as CustomerGroupResourceModel; use Magento\Framework\Indexer\IndexerInterface; use Magento\Framework\Indexer\IndexerRegistry; -use Magento\Framework\Search\EngineResolverInterface; use PHPUnit\Framework\TestCase; +use PHPUnit\Framework\MockObject\MockObject; /** * @covers \Magento\AdvancedSearch\Model\Indexer\Fulltext\Plugin\CustomerGroup @@ -35,7 +35,7 @@ class CustomerGroupTest extends TestCase private $indexerMock; /** - * @var Group|MockObject + * @var CustomerGroupResourceModel|MockObject */ private $subjectMock; @@ -49,11 +49,6 @@ class CustomerGroupTest extends TestCase */ private $indexerRegistryMock; - /** - * @var EngineResolverInterface|MockObject - */ - private $engineResolverMock; - protected function setUp(): void { $this->subjectMock = $this->createMock(CustomerGroupResourceModel::class); @@ -73,19 +68,13 @@ protected function setUp(): void IndexerRegistry::class, ['get'] ); - $this->engineResolverMock = $this->createPartialMock( - EngineResolverInterface::class, - ['getCurrentSearchEngine'] - ); $this->model = new CustomerGroupPlugin( $this->indexerRegistryMock, - $this->customerOptionsMock, - $this->engineResolverMock + $this->customerOptionsMock ); } /** - * @param string $searchEngine * @param bool $isObjectNew * @param bool $isTaxClassIdChanged * @param int $invalidateCounter @@ -93,15 +82,10 @@ protected function setUp(): void * @dataProvider aroundSaveDataProvider */ public function testAroundSave( - string $searchEngine, bool $isObjectNew, bool $isTaxClassIdChanged, int $invalidateCounter ): void { - $this->engineResolverMock->expects($this->once()) - ->method('getCurrentSearchEngine') - ->willReturn($searchEngine); - $groupMock = $this->createPartialMock( CustomerGroupModel::class, ['dataHasChangedFor', 'isObjectNew', '__wakeup'] @@ -137,14 +121,10 @@ public function testAroundSave( public function aroundSaveDataProvider(): array { return [ - ['mysql', false, false, 0], - ['mysql', false, true, 0], - ['mysql', true, false, 0], - ['mysql', true, true, 0], - ['custom', false, false, 0], - ['custom', false, true, 1], - ['custom', true, false, 1], - ['custom', true, true, 1], + [false, false, 0], + [false, true, 1], + [true, false, 1], + [true, true, 1], ]; } } diff --git a/app/code/Magento/Backend/etc/adminhtml/system.xml b/app/code/Magento/Backend/etc/adminhtml/system.xml index 1e8ec226d6b88..45ed50fd49b7e 100644 --- a/app/code/Magento/Backend/etc/adminhtml/system.xml +++ b/app/code/Magento/Backend/etc/adminhtml/system.xml @@ -341,7 +341,7 @@ - + Magento\Config\Model\Config\Source\Yesno Resize performed via javascript before file upload. @@ -459,9 +459,7 @@ Magento\Config\Model\Config\Source\Yesno Magento\Config\Model\Config\Backend\Store - - Warning! When using Store Code in URLs, in some cases system may not work properly if URLs without Store Codes are specified in the third-party services (e.g. PayPal etc.).]]> - + Warning! When using Store Code in URLs, in some cases system may not work properly if URLs without Store Codes are specified in the third-party services (e.g. PayPal etc.).]]> diff --git a/app/code/Magento/Backend/i18n/en_US.csv b/app/code/Magento/Backend/i18n/en_US.csv index e0643518bde30..59bbe7f69985a 100644 --- a/app/code/Magento/Backend/i18n/en_US.csv +++ b/app/code/Magento/Backend/i18n/en_US.csv @@ -403,11 +403,9 @@ Security,Security Web,Web "Url Options","Url Options" "Add Store Code to Urls","Add Store Code to Urls" -" - Warning! When using Store Code in URLs, in some cases system may not work properly if URLs without Store Codes are specified in the third-party services (e.g. PayPal etc.). - "," - Warning! When using Store Code in URLs, in some cases system may not work properly if URLs without Store Codes are specified in the third-party services (e.g. PayPal etc.). - " +"Warning! When using Store Code in URLs, in some cases system may not work properly if URLs without Store Codes are specified in the third-party services (e.g. PayPal etc.).","Warning! When using Store Code in URLs, in some cases system may not work properly if URLs without Store Codes are specified in the third-party services (e.g. PayPal etc.)." +"Enable Frontend Resize","Enable Frontend Resize" +"Resize performed via javascript before file upload.","Resize performed via javascript before file upload." "Auto-redirect to Base URL","Auto-redirect to Base URL" "Search Engine Optimization","Search Engine Optimization" "Use Web Server Rewrites","Use Web Server Rewrites" diff --git a/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontAdvanceCatalogSearchBundleBySkuWithHyphenTest.xml b/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontAdvanceCatalogSearchBundleBySkuWithHyphenTest.xml index f31c51cf6e8ae..30c784b19a0bf 100644 --- a/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontAdvanceCatalogSearchBundleBySkuWithHyphenTest.xml +++ b/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontAdvanceCatalogSearchBundleBySkuWithHyphenTest.xml @@ -19,7 +19,7 @@ - + diff --git a/app/code/Magento/Captcha/Controller/Refresh/Index.php b/app/code/Magento/Captcha/Controller/Refresh/Index.php index 968f02a87290f..4c205afc256cf 100644 --- a/app/code/Magento/Captcha/Controller/Refresh/Index.php +++ b/app/code/Magento/Captcha/Controller/Refresh/Index.php @@ -8,6 +8,8 @@ namespace Magento\Captcha\Controller\Refresh; use Magento\Captcha\Helper\Data as CaptchaHelper; +use Magento\Framework\App\Action\Action; +use Magento\Framework\App\Action\Context; use Magento\Framework\App\Action\HttpPostActionInterface; use Magento\Framework\App\RequestInterface; use Magento\Framework\Controller\Result\JsonFactory as JsonResultFactory; @@ -18,7 +20,7 @@ * Refreshes captcha and returns JSON encoded URL to image (AJAX action) * Example: {'imgSrc': 'http://example.com/media/captcha/67842gh187612ngf8s.png'} */ -class Index implements HttpPostActionInterface +class Index extends Action implements HttpPostActionInterface { /** * @var CaptchaHelper @@ -46,6 +48,7 @@ class Index implements HttpPostActionInterface private $jsonResultFactory; /** + * @param Context $context * @param RequestInterface $request * @param JsonResultFactory $jsonFactory * @param CaptchaHelper $captchaHelper @@ -53,12 +56,14 @@ class Index implements HttpPostActionInterface * @param JsonSerializer $serializer */ public function __construct( + Context $context, RequestInterface $request, JsonResultFactory $jsonFactory, CaptchaHelper $captchaHelper, LayoutInterface $layout, JsonSerializer $serializer ) { + parent::__construct($context); $this->request = $request; $this->jsonResultFactory = $jsonFactory; $this->captchaHelper = $captchaHelper; diff --git a/app/code/Magento/Captcha/Test/Unit/Controller/Refresh/IndexTest.php b/app/code/Magento/Captcha/Test/Unit/Controller/Refresh/IndexTest.php index c10f774c74993..af3e9033e9596 100644 --- a/app/code/Magento/Captcha/Test/Unit/Controller/Refresh/IndexTest.php +++ b/app/code/Magento/Captcha/Test/Unit/Controller/Refresh/IndexTest.php @@ -10,6 +10,7 @@ use Magento\Captcha\Controller\Refresh\Index; use Magento\Captcha\Helper\Data as CaptchaHelper; use Magento\Captcha\Model\CaptchaInterface; +use Magento\Framework\App\Action\Context; use Magento\Framework\App\RequestInterface; use Magento\Framework\Controller\Result\Json as ResultJson; use Magento\Framework\Controller\Result\JsonFactory as ResultJsonFactory; @@ -45,6 +46,9 @@ class IndexTest extends TestCase /** @var MockObject|JsonSerializer */ private $jsonSerializerMock; + /** @var MockObject|Context */ + private $contextMock; + /** @var Index */ private $refreshAction; @@ -66,6 +70,8 @@ protected function setUp(): void $this->jsonSerializerMock = $this->createMock(JsonSerializer::class); $this->captchaHelperMock = $this->createMock(CaptchaHelper::class); + $this->contextMock = $this->createMock(Context::class); + $this->blockMock->method('setIsAjax') ->willReturnSelf(); @@ -73,6 +79,7 @@ protected function setUp(): void ->willReturn($this->blockMock); $this->refreshAction = new Index( + $this->contextMock, $this->requestMock, $this->jsonResultFactoryMock, $this->captchaHelperMock, diff --git a/app/code/Magento/Catalog/Model/Product/Webapi/Rest/RequestTypeBasedDeserializer.php b/app/code/Magento/Catalog/Model/Product/Webapi/Rest/RequestTypeBasedDeserializer.php new file mode 100644 index 0000000000000..dbc51c0089398 --- /dev/null +++ b/app/code/Magento/Catalog/Model/Product/Webapi/Rest/RequestTypeBasedDeserializer.php @@ -0,0 +1,62 @@ +deserializeFactory = $deserializeFactory; + $this->request = $request; + } + + /** + * @inheritdoc + * + * Parse request body into array of params with identifying request body content type + * to use appropriate instance of deserializer class + * + * @param string $body Posted content from request + * @return array|null Return NULL if content is invalid + * @throws \Magento\Framework\Exception\InputException + * @throws \Magento\Framework\Webapi\Exception + */ + public function deserialize($body) + { + $deserializer = $this->deserializeFactory->get($this->request->getContentType()); + return $deserializer->deserialize($body); + } +} diff --git a/app/code/Magento/Catalog/Test/Mftf/Data/ProductData.xml b/app/code/Magento/Catalog/Test/Mftf/Data/ProductData.xml index d61a05d3418ca..7aabedbf1c3f7 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Data/ProductData.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Data/ProductData.xml @@ -35,6 +35,10 @@ EavStockItem CustomAttributeCategoryIds + + TestFooBar + foobar + Pursuit Lumaflex&trade; Tone Band x&trade; @@ -68,6 +72,9 @@ EavStockItem CustomAttributeCategoryIds + + partialTestSku + SimpleProduct -+~/\\<>\’“:*\$#@()!,.?`=%&^ diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/StorefrontAdvanceCatalogSearchSimpleProductBySkuWithHyphenTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/StorefrontAdvanceCatalogSearchSimpleProductBySkuWithHyphenTest.xml index cb12ce6b524d7..69f78c63e2675 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/StorefrontAdvanceCatalogSearchSimpleProductBySkuWithHyphenTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/StorefrontAdvanceCatalogSearchSimpleProductBySkuWithHyphenTest.xml @@ -19,7 +19,7 @@ - + diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/StorefrontAdvanceCatalogSearchVirtualProductBySkuWithHyphenTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/StorefrontAdvanceCatalogSearchVirtualProductBySkuWithHyphenTest.xml index 4e48e5d5439aa..b87cce398498f 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/StorefrontAdvanceCatalogSearchVirtualProductBySkuWithHyphenTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/StorefrontAdvanceCatalogSearchVirtualProductBySkuWithHyphenTest.xml @@ -19,7 +19,7 @@ - + diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Product/Webapi/Rest/RequestTypeBasedDeserializerTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Product/Webapi/Rest/RequestTypeBasedDeserializerTest.php new file mode 100644 index 0000000000000..a3e44fb7027df --- /dev/null +++ b/app/code/Magento/Catalog/Test/Unit/Model/Product/Webapi/Rest/RequestTypeBasedDeserializerTest.php @@ -0,0 +1,151 @@ +deserializeFactoryMock = $this->createMock(DeserializerFactory::class); + /** @var Request|MockObject $requestMock */ + $this->requestMock = $this->createMock(Request::class); + /** @var requestTypeBasedDeserializer */ + $this->requestTypeBasedDeserializer = new RequestTypeBasedDeserializer( + $this->deserializeFactoryMock, + $this->requestMock + ); + } + + /** + * Test RequestTypeBasedDeserializer::deserializeMethod() + * + * @dataProvider getDeserializerDataProvider + * @param string $body + * @param string $contentType + * @param DeserializerInterface $deserializer + * @param array $expectedResult + * @throws \Magento\Framework\Exception\InputException + * @throws \Magento\Framework\Webapi\Exception + */ + public function testDeserialize( + string $body, + string $contentType, + DeserializerInterface $deserializer, + array $expectedResult + ): void { + $this->requestMock->method('getContentType') + ->willReturn($contentType); + $this->deserializeFactoryMock->expects($this->any()) + ->method('get') + ->with($contentType) + ->willReturn($deserializer); + $this->assertEquals($expectedResult, $this->requestTypeBasedDeserializer->deserialize($body)); + } + + public function getDeserializerDataProvider(): array + { + return [ + 'request body with xml data' => [ + 'body' => ' + + testSku1 + testName1 + 10 + 4 + 1 + + ', + 'content-type' => 'application/xml', + 'deserializer' => $this->prepareXmlDeserializer(), + 'expectedResult' => [ + 'product' => [ + 'sku' => 'testSku1', + 'name' => 'testName1', + 'weight' => '10', + 'attribute_set_id' => '4', + 'status' => '1' + ] + ] + ], + 'request body with json data' => [ + 'body' => '{ + "product": { + "sku": "testSku2", + "name": "testName2", + "weight": 5, + "attribute_set_id": 4, + "status": 0 + } + }', + 'content-type' => 'application/json', + 'deserializer' => $this->prepareJsonDeserializer(), + 'expectedResult' => [ + 'product' => [ + 'sku' => 'testSku2', + 'name' => 'testName2', + 'weight' => 5, + 'attribute_set_id' => 4, + 'status' => 0 + ] + ] + ] + ]; + } + + /** + * Creates Json Deserializer instance with some mocked parameters + * + * @return DeserializerJson + */ + private function prepareJsonDeserializer(): DeserializerJson + { + /** @var Decoder|MockObject $decoder */ + $decoder = $this->createMock(Decoder::class); + /** @var State|MockObject $appStateMock */ + $appStateMock = $this->createMock(State::class); + $serializer = new SerializerJson(); + return new DeserializerJson($decoder, $appStateMock, $serializer); + } + + /** + * Creates XML Deserializer instance with some mocked parameters + * + * @return DeserializerXml + */ + private function prepareXmlDeserializer(): DeserializerXml + { + $parserXml = new ParserXml(); + /** @var State|MockObject $appStateMock */ + $appStateMock = $this->createMock(State::class); + return new DeserializerXml($parserXml, $appStateMock); + } +} diff --git a/app/code/Magento/Catalog/etc/webapi_rest/di.xml b/app/code/Magento/Catalog/etc/webapi_rest/di.xml index 14779245f21af..1fd47fde304ec 100644 --- a/app/code/Magento/Catalog/etc/webapi_rest/di.xml +++ b/app/code/Magento/Catalog/etc/webapi_rest/di.xml @@ -37,7 +37,7 @@ - Magento\Framework\Webapi\Rest\Request\Deserializer\Json + Magento\Catalog\Model\Product\Webapi\Rest\RequestTypeBasedDeserializer diff --git a/app/code/Magento/CatalogCmsGraphQl/Model/Resolver/Category/Block.php b/app/code/Magento/CatalogCmsGraphQl/Model/Resolver/Category/Block.php index 110d03cac7735..9f95c504dbc27 100644 --- a/app/code/Magento/CatalogCmsGraphQl/Model/Resolver/Category/Block.php +++ b/app/code/Magento/CatalogCmsGraphQl/Model/Resolver/Category/Block.php @@ -11,6 +11,7 @@ use Magento\Framework\Exception\LocalizedException; use Magento\Framework\Exception\NoSuchEntityException; use Magento\Framework\GraphQl\Config\Element\Field; +use Magento\Framework\GraphQl\Exception\GraphQlNoSuchEntityException; use Magento\Framework\GraphQl\Query\ResolverInterface; use Magento\Framework\GraphQl\Schema\Type\ResolveInfo; use Magento\CmsGraphQl\Model\Resolver\DataProvider\Block as BlockProvider; @@ -48,18 +49,19 @@ public function resolve( } /** @var Category $category */ $category = $value['model']; - $blockId = $category->getLandingPage(); + $blockId = (int)$category->getLandingPage(); + $storeId = (int)$context->getExtensionAttributes()->getStore()->getId(); if (empty($blockId)) { return null; } try { - $block = $this->blockProvider->getData($blockId); + $blockData = $this->blockProvider->getBlockById($blockId, $storeId); } catch (NoSuchEntityException $e) { - return null; + return new GraphQlNoSuchEntityException(__($e->getMessage()), $e); } - return $block; + return $blockData; } } diff --git a/app/code/Magento/CatalogGraphQl/Model/Category/CategoryFilter.php b/app/code/Magento/CatalogGraphQl/Model/Category/CategoryFilter.php index 09694b7cf1a0c..1fae247c981d2 100644 --- a/app/code/Magento/CatalogGraphQl/Model/Category/CategoryFilter.php +++ b/app/code/Magento/CatalogGraphQl/Model/Category/CategoryFilter.php @@ -13,7 +13,6 @@ use Magento\Framework\Exception\InputException; use Magento\Framework\GraphQl\Exception\GraphQlInputException; use Magento\Framework\GraphQl\Query\Resolver\Argument\SearchCriteria\ArgumentApplier\Filter; -use Magento\Framework\Search\Adapter\Mysql\Query\Builder\Match; use Magento\Search\Model\Query; use Magento\Store\Api\Data\StoreInterface; use Magento\Store\Model\ScopeInterface; @@ -24,6 +23,11 @@ */ class CategoryFilter { + /** + * @var string + */ + private const SPECIAL_CHARACTERS = '-+~/\\<>\'":*$#@()!,.?`=%&^'; + /** * @var ScopeConfigInterface */ @@ -120,7 +124,7 @@ private function formatMatchFilters(array $filters, StoreInterface $store): arra foreach ($filters as $filter => $condition) { $conditionType = current(array_keys($condition)); if ($conditionType === 'match') { - $searchValue = trim(str_replace(Match::SPECIAL_CHARACTERS, '', $condition[$conditionType])); + $searchValue = trim(str_replace(self::SPECIAL_CHARACTERS, '', $condition[$conditionType])); $matchLength = strlen($searchValue); if ($matchLength < $minQueryLength) { throw new InputException(__('Invalid match filter. Minimum length is %1.', $minQueryLength)); diff --git a/app/code/Magento/CatalogGraphQl/Model/Search/Adapter/Mysql/Query/Builder/Match.php b/app/code/Magento/CatalogGraphQl/Model/Search/Adapter/Mysql/Query/Builder/Match.php deleted file mode 100644 index 4490cf031e5e1..0000000000000 --- a/app/code/Magento/CatalogGraphQl/Model/Search/Adapter/Mysql/Query/Builder/Match.php +++ /dev/null @@ -1,78 +0,0 @@ -searchHelper = $searchHelper; - } - - /** - * @inheritdoc - */ - protected function prepareQuery($queryValue, $conditionType) - { - $replaceSymbols = str_split(self::SPECIAL_CHARACTERS, 1); - $queryValue = str_replace($replaceSymbols, ' ', $queryValue); - foreach ($this->preprocessors as $preprocessor) { - $queryValue = $preprocessor->process($queryValue); - } - - $stringPrefix = ''; - if ($conditionType === BoolExpression::QUERY_CONDITION_MUST) { - $stringPrefix = '+'; - } elseif ($conditionType === BoolExpression::QUERY_CONDITION_NOT) { - $stringPrefix = '-'; - } - - $queryValues = explode(' ', $queryValue); - - foreach ($queryValues as $queryKey => $queryValue) { - if (empty($queryValue)) { - unset($queryValues[$queryKey]); - } else { - $stringSuffix = $this->searchHelper->getMinQueryLength() > strlen($queryValue) ? '' : '*'; - $queryValues[$queryKey] = $stringPrefix . $queryValue . $stringSuffix; - } - } - - $queryValue = implode(' ', $queryValues); - - return $queryValue; - } -} diff --git a/app/code/Magento/CatalogGraphQl/etc/graphql/di.xml b/app/code/Magento/CatalogGraphQl/etc/graphql/di.xml index ed548efc896f8..c4f9bc26ee9f3 100644 --- a/app/code/Magento/CatalogGraphQl/etc/graphql/di.xml +++ b/app/code/Magento/CatalogGraphQl/etc/graphql/di.xml @@ -91,8 +91,6 @@ - diff --git a/app/code/Magento/CatalogGraphQl/etc/schema.graphqls b/app/code/Magento/CatalogGraphQl/etc/schema.graphqls index f77b301d61e28..a9720bf17445b 100644 --- a/app/code/Magento/CatalogGraphQl/etc/schema.graphqls +++ b/app/code/Magento/CatalogGraphQl/etc/schema.graphqls @@ -245,7 +245,7 @@ interface CategoryInterface @typeResolver(class: "Magento\\CatalogGraphQl\\Model level: Int @doc(description: "Indicates the depth of the category within the tree.") created_at: String @doc(description: "Timestamp indicating when the category was created.") updated_at: String @doc(description: "Timestamp indicating when the category was updated.") - product_count: Int @doc(description: "The number of products in the category.") @resolver(class: "Magento\\CatalogGraphQl\\Model\\Resolver\\Category\\ProductsCount") + product_count: Int @doc(description: "The number of products in the category that are marked as visible. By default, in complex products, parent products are visible, but their child products are not.") @resolver(class: "Magento\\CatalogGraphQl\\Model\\Resolver\\Category\\ProductsCount") default_sort_by: String @doc(description: "The attribute to use for sorting.") products( pageSize: Int = 20 @doc(description: "Specifies the maximum number of results to return at once. This attribute is optional."), @@ -299,7 +299,7 @@ type SimpleProduct implements ProductInterface, PhysicalProductInterface, Custom type Products @doc(description: "The Products object is the top-level object returned in a product search.") { items: [ProductInterface] @doc(description: "An array of products that match the specified search criteria.") page_info: SearchResultPageInfo @doc(description: "An object that includes the page_info and currentPage values specified in the query.") - total_count: Int @doc(description: "The number of products returned.") + total_count: Int @doc(description: "The number of products that are marked as visible. By default, in complex products, parent products are visible, but their child products are not.") filters: [LayerFilter] @resolver(class: "Magento\\CatalogGraphQl\\Model\\Resolver\\LayerFilters") @doc(description: "Layered navigation filters array.") @deprecated(reason: "Use aggregations instead") aggregations: [Aggregation] @doc(description: "Layered navigation aggregations.") @resolver(class: "Magento\\CatalogGraphQl\\Model\\Resolver\\Aggregations") sort_fields: SortFields @doc(description: "An object that includes the default sort field and all available sort fields.") @resolver(class: "Magento\\CatalogGraphQl\\Model\\Resolver\\Category\\SortFields") @@ -308,7 +308,7 @@ type Products @doc(description: "The Products object is the top-level object ret type CategoryProducts @doc(description: "The category products object returned in the Category query.") { items: [ProductInterface] @doc(description: "An array of products that are assigned to the category.") page_info: SearchResultPageInfo @doc(description: "An object that includes the page_info and currentPage values specified in the query.") - total_count: Int @doc(description: "The number of products returned.") + total_count: Int @doc(description: "The number of products in the category that are marked as visible. By default, in complex products, parent products are visible, but their child products are not.") } input ProductAttributeFilterInput @doc(description: "ProductAttributeFilterInput defines the filters to be used in the search. A filter contains at least one attribute, a comparison operator, and the value that is being searched for.") { diff --git a/app/code/Magento/CatalogGraphQl/etc/search_request.xml b/app/code/Magento/CatalogGraphQl/etc/search_request.xml index ab1eea9eb6fda..5a452a1540cd1 100644 --- a/app/code/Magento/CatalogGraphQl/etc/search_request.xml +++ b/app/code/Magento/CatalogGraphQl/etc/search_request.xml @@ -15,6 +15,7 @@ + @@ -23,6 +24,11 @@ + + + + + @@ -61,6 +67,7 @@ + @@ -69,6 +76,11 @@ + + + + + diff --git a/app/code/Magento/CatalogSearch/Model/Adapter/Mysql/Aggregation/DataProvider.php b/app/code/Magento/CatalogSearch/Model/Adapter/Mysql/Aggregation/DataProvider.php deleted file mode 100644 index 66f5ad7a7192b..0000000000000 --- a/app/code/Magento/CatalogSearch/Model/Adapter/Mysql/Aggregation/DataProvider.php +++ /dev/null @@ -1,123 +0,0 @@ -eavConfig = $eavConfig; - $this->connection = $resource->getConnection(); - $this->scopeResolver = $scopeResolver; - $this->selectBuilderForAttribute = $selectBuilderForAttribute - ?: ObjectManager::getInstance()->get(SelectBuilderForAttribute::class); - $this->eventManager = $eventManager ?: ObjectManager::getInstance()->get(Manager::class); - } - - /** - * @inheritdoc - */ - public function getDataSet( - BucketInterface $bucket, - array $dimensions, - Table $entityIdsTable - ) { - $currentScope = $this->scopeResolver->getScope($dimensions['scope']->getValue())->getId(); - $attribute = $this->eavConfig->getAttribute(Product::ENTITY, $bucket->getField()); - $select = $this->getSelect(); - - $select->joinInner( - ['entities' => $entityIdsTable->getName()], - 'main_table.entity_id = entities.entity_id', - [] - ); - $this->eventManager->dispatch( - 'catalogsearch_query_add_filter_after', - ['bucket' => $bucket, 'select' => $select] - ); - $select = $this->selectBuilderForAttribute->build($select, $attribute, $currentScope); - - return $select; - } - - /** - * @inheritdoc - */ - public function execute(Select $select) - { - return $this->connection->fetchAssoc($select); - } - - /** - * Get select. - * - * @return Select - */ - private function getSelect() - { - return $this->connection->select(); - } -} diff --git a/app/code/Magento/CatalogSearch/Model/Adapter/Mysql/Aggregation/DataProvider/QueryBuilder.php b/app/code/Magento/CatalogSearch/Model/Adapter/Mysql/Aggregation/DataProvider/QueryBuilder.php deleted file mode 100644 index 26837448f2df2..0000000000000 --- a/app/code/Magento/CatalogSearch/Model/Adapter/Mysql/Aggregation/DataProvider/QueryBuilder.php +++ /dev/null @@ -1,187 +0,0 @@ -resource = $resource; - $this->scopeResolver = $scopeResolver; - $this->inventoryConfig = $inventoryConfig; - $this->priceTableResolver = $priceTableResolver - ?: ObjectManager::getInstance()->get(IndexScopeResolverInterface::class); - $this->dimensionFactory = $dimensionFactory ?: ObjectManager::getInstance()->get(DimensionFactory::class); - } - - /** - * Build select. - * - * @param AbstractAttribute $attribute - * @param string $tableName - * @param int $currentScope - * @param int $customerGroupId - * - * @return Select - */ - public function build( - AbstractAttribute $attribute, - string $tableName, - int $currentScope, - int $customerGroupId - ) : Select { - $select = $this->resource->getConnection()->select(); - $select->joinInner( - ['entities' => $tableName], - 'main_table.entity_id = entities.entity_id', - [] - ); - - if ($attribute->getAttributeCode() === 'price') { - return $this->buildQueryForPriceAttribute($currentScope, $customerGroupId, $select); - } - - return $this->buildQueryForAttribute($currentScope, $attribute, $select); - } - - /** - * Build select for price attribute. - * - * @param int $currentScope - * @param int $customerGroupId - * @param Select $select - * - * @return Select - */ - private function buildQueryForPriceAttribute( - int $currentScope, - int $customerGroupId, - Select $select - ) : Select { - /** @var \Magento\Store\Model\Store $store */ - $store = $this->scopeResolver->getScope($currentScope); - if (!$store instanceof \Magento\Store\Model\Store) { - throw new \RuntimeException('Illegal scope resolved'); - } - $websiteId = $store->getWebsiteId(); - - $tableName = $this->priceTableResolver->resolve( - 'catalog_product_index_price', - [ - $this->dimensionFactory->create( - WebsiteDimensionProvider::DIMENSION_NAME, - (string)$websiteId - ), - $this->dimensionFactory->create( - CustomerGroupDimensionProvider::DIMENSION_NAME, - (string)$customerGroupId - ), - ] - ); - $select->from(['main_table' => $tableName], null) - ->columns([BucketInterface::FIELD_VALUE => 'main_table.min_price']) - ->where('main_table.customer_group_id = ?', $customerGroupId) - ->where('main_table.website_id = ?', $websiteId); - - return $select; - } - - /** - * Build select for attribute. - * - * @param int $currentScope - * @param AbstractAttribute $attribute - * @param Select $select - * - * @return Select - */ - private function buildQueryForAttribute( - int $currentScope, - AbstractAttribute $attribute, - Select $select - ) : Select { - $currentScopeId = $this->scopeResolver->getScope($currentScope)->getId(); - $table = $this->resource->getTableName( - 'catalog_product_index_eav' . ($attribute->getBackendType() === 'decimal' ? '_decimal' : '') - ); - $select->from(['main_table' => $table], ['main_table.entity_id', 'main_table.value']) - ->distinct() - ->joinLeft( - ['stock_index' => $this->resource->getTableName('cataloginventory_stock_status')], - 'main_table.source_id = stock_index.product_id', - [] - ) - ->where('main_table.attribute_id = ?', $attribute->getAttributeId()) - ->where('main_table.store_id = ? ', $currentScopeId); - - if (!$this->inventoryConfig->isShowOutOfStock($currentScopeId)) { - $select->where('stock_index.stock_status = ?', Stock::STOCK_IN_STOCK); - } - - $parentSelect = $this->resource->getConnection()->select(); - $parentSelect->from(['main_table' => $select], ['main_table.value']); - return $parentSelect; - } -} diff --git a/app/code/Magento/CatalogSearch/Model/Adapter/Mysql/Aggregation/DataProvider/SelectBuilderForAttribute.php b/app/code/Magento/CatalogSearch/Model/Adapter/Mysql/Aggregation/DataProvider/SelectBuilderForAttribute.php deleted file mode 100644 index 00012a78d1003..0000000000000 --- a/app/code/Magento/CatalogSearch/Model/Adapter/Mysql/Aggregation/DataProvider/SelectBuilderForAttribute.php +++ /dev/null @@ -1,134 +0,0 @@ -resource = $resource; - $this->scopeResolver = $scopeResolver; - $this->applyStockConditionToSelect = $applyStockConditionToSelect; - $this->customerSession = $customerSession; - $this->scopeConfig = $scopeConfig; - } - - /** - * Build select for attribute search - * - * @param Select $select - * @param AbstractAttribute $attribute - * @param int $currentScope - * - * @return Select - */ - public function build(Select $select, AbstractAttribute $attribute, int $currentScope): Select - { - if ($attribute->getAttributeCode() === 'price') { - /** @var Store $store */ - $store = $this->scopeResolver->getScope($currentScope); - if (!$store instanceof Store) { - throw new \RuntimeException('Illegal scope resolved'); - } - $table = $this->resource->getTableName('catalog_product_index_price'); - $select->from(['main_table' => $table], null) - ->columns([BucketInterface::FIELD_VALUE => 'main_table.min_price']) - ->where('main_table.customer_group_id = ?', $this->customerSession->getCustomerGroupId()) - ->where('main_table.website_id = ?', $store->getWebsiteId()); - } else { - $currentScopeId = $this->scopeResolver->getScope($currentScope)->getId(); - $table = $this->resource->getTableName( - 'catalog_product_index_eav' . ($attribute->getBackendType() === 'decimal' ? '_decimal' : '') - ); - $subSelect = $select; - $subSelect->from(['main_table' => $table], ['main_table.entity_id', 'main_table.value']) - ->distinct() - ->where('main_table.attribute_id = ?', (int) $attribute->getAttributeId()) - ->where('main_table.store_id = ? ', $currentScopeId); - if ($this->isAddStockFilter()) { - $subSelect = $this->applyStockConditionToSelect->execute($subSelect); - } - - $parentSelect = $this->resource->getConnection()->select(); - $parentSelect->from(['main_table' => $subSelect], ['main_table.value']); - $select = $parentSelect; - } - - return $select; - } - - /** - * Is add stock filter - * - * @return bool - */ - private function isAddStockFilter() - { - $isShowOutOfStock = $this->scopeConfig->isSetFlag( - 'cataloginventory/options/show_out_of_stock', - ScopeInterface::SCOPE_STORE - ); - - return false === $isShowOutOfStock; - } -} diff --git a/app/code/Magento/CatalogSearch/Model/Adapter/Mysql/Aggregation/DataProvider/SelectBuilderForAttribute/ApplyStockConditionToSelect.php b/app/code/Magento/CatalogSearch/Model/Adapter/Mysql/Aggregation/DataProvider/SelectBuilderForAttribute/ApplyStockConditionToSelect.php deleted file mode 100644 index be572793f1ec3..0000000000000 --- a/app/code/Magento/CatalogSearch/Model/Adapter/Mysql/Aggregation/DataProvider/SelectBuilderForAttribute/ApplyStockConditionToSelect.php +++ /dev/null @@ -1,50 +0,0 @@ -resource = $resource; - } - - /** - * @param Select $select - * @return Select - */ - public function execute(Select $select): Select - { - $select->joinInner( - ['stock_index' => $this->resource->getTableName('cataloginventory_stock_status')], - 'main_table.source_id = stock_index.product_id', - [] - )->where('stock_index.stock_status = ?', Stock::STOCK_IN_STOCK); - - return $select; - } -} diff --git a/app/code/Magento/CatalogSearch/Model/Adapter/Mysql/BaseSelectStrategy/BaseSelectAttributesSearchStrategy.php b/app/code/Magento/CatalogSearch/Model/Adapter/Mysql/BaseSelectStrategy/BaseSelectAttributesSearchStrategy.php deleted file mode 100644 index 27a784f8609bb..0000000000000 --- a/app/code/Magento/CatalogSearch/Model/Adapter/Mysql/BaseSelectStrategy/BaseSelectAttributesSearchStrategy.php +++ /dev/null @@ -1,100 +0,0 @@ -resource = $resource; - $this->storeManager = $storeManager; - $this->scopeResolver = $scopeResolver; - } - - /** - * Creates base select query that can be populated with additional filters - * - * @param SelectContainer $selectContainer - * @return SelectContainer - * @throws \DomainException - */ - public function createBaseSelect(SelectContainer $selectContainer) - { - $select = $this->resource->getConnection()->select(); - $mainTableAlias = $selectContainer->isFullTextSearchRequired() ? 'eav_index' : 'search_index'; - - $select->distinct() - ->from( - [$mainTableAlias => $this->resource->getTableName('catalog_product_index_eav')], - ['entity_id' => 'entity_id'] - )->where( - $this->resource->getConnection()->quoteInto( - sprintf('%s.store_id = ?', $mainTableAlias), - $this->storeManager->getStore()->getId() - ) - ); - - if ($selectContainer->isFullTextSearchRequired()) { - $tableName = $this->scopeResolver->resolve( - $selectContainer->getUsedIndex(), - $selectContainer->getDimensions() - ); - - $select->joinInner( - ['search_index' => $tableName], - 'eav_index.entity_id = search_index.entity_id', - [] - )->joinInner( - ['cea' => $this->resource->getTableName('catalog_eav_attribute')], - 'search_index.attribute_id = cea.attribute_id', - [] - ); - } - - $selectContainer = $selectContainer->updateSelect($select); - return $selectContainer; - } -} diff --git a/app/code/Magento/CatalogSearch/Model/Adapter/Mysql/BaseSelectStrategy/BaseSelectFullTextSearchStrategy.php b/app/code/Magento/CatalogSearch/Model/Adapter/Mysql/BaseSelectStrategy/BaseSelectFullTextSearchStrategy.php deleted file mode 100644 index bff878122c8c4..0000000000000 --- a/app/code/Magento/CatalogSearch/Model/Adapter/Mysql/BaseSelectStrategy/BaseSelectFullTextSearchStrategy.php +++ /dev/null @@ -1,76 +0,0 @@ -resource = $resource; - $this->scopeResolver = $scopeResolver; - } - - /** - * Creates base select query that can be populated with additional filters - * - * @param SelectContainer $selectContainer - * @return SelectContainer - * @throws \DomainException - */ - public function createBaseSelect(SelectContainer $selectContainer) - { - $select = $this->resource->getConnection()->select(); - - $tableName = $this->scopeResolver->resolve( - $selectContainer->getUsedIndex(), - $selectContainer->getDimensions() - ); - - $select->from( - ['search_index' => $tableName], - ['entity_id' => 'entity_id'] - )->joinInner( - ['cea' => $this->resource->getTableName('catalog_eav_attribute')], - 'search_index.attribute_id = cea.attribute_id', - [] - ); - - $selectContainer = $selectContainer->updateSelect($select); - return $selectContainer; - } -} diff --git a/app/code/Magento/CatalogSearch/Model/Adapter/Mysql/Dynamic/DataProvider.php b/app/code/Magento/CatalogSearch/Model/Adapter/Mysql/Dynamic/DataProvider.php deleted file mode 100644 index eb4761adf830c..0000000000000 --- a/app/code/Magento/CatalogSearch/Model/Adapter/Mysql/Dynamic/DataProvider.php +++ /dev/null @@ -1,233 +0,0 @@ -resource = $resource; - $this->connection = $resource->getConnection(); - $this->range = $range; - $this->customerSession = $customerSession; - $this->dataProvider = $dataProvider; - $this->intervalFactory = $intervalFactory; - $this->storeManager = $storeManager ?: ObjectManager::getInstance()->get(StoreManager::class); - $this->priceTableResolver = $priceTableResolver ?: ObjectManager::getInstance()->get( - IndexScopeResolverInterface::class - ); - $this->dimensionFactory = $dimensionFactory ?: ObjectManager::getInstance()->get(DimensionFactory::class); - } - - /** - * {@inheritdoc} - */ - public function getRange() - { - return $this->range->getPriceRange(); - } - - /** - * {@inheritdoc} - */ - public function getAggregations(\Magento\Framework\Search\Dynamic\EntityStorage $entityStorage) - { - $aggregation = [ - 'count' => 'count(main_table.entity_id)', - 'max' => 'MAX(min_price)', - 'min' => 'MIN(min_price)', - 'std' => 'STDDEV_SAMP(min_price)', - ]; - - $select = $this->getSelect(); - $websiteId = $this->storeManager->getStore()->getWebsiteId(); - $customerGroupId = $this->customerSession->getCustomerGroupId(); - - $tableName = $this->priceTableResolver->resolve( - 'catalog_product_index_price', - [ - $this->dimensionFactory->create( - WebsiteDimensionProvider::DIMENSION_NAME, - (string)$websiteId - ), - $this->dimensionFactory->create( - CustomerGroupDimensionProvider::DIMENSION_NAME, - (string)$customerGroupId - ), - ] - ); - /** @var Table $table */ - $table = $entityStorage->getSource(); - $select->from(['main_table' => $tableName], []) - ->where('main_table.entity_id in (select entity_id from ' . $table->getName() . ')') - ->columns($aggregation); - - $select->where('customer_group_id = ?', $customerGroupId); - $select->where('main_table.website_id = ?', $websiteId); - - return $this->connection->fetchRow($select); - } - - /** - * {@inheritdoc} - */ - public function getInterval( - BucketInterface $bucket, - array $dimensions, - \Magento\Framework\Search\Dynamic\EntityStorage $entityStorage - ) { - $select = $this->dataProvider->getDataSet($bucket, $dimensions, $entityStorage->getSource()); - - return $this->intervalFactory->create(['select' => $select]); - } - - /** - * {@inheritdoc} - */ - public function getAggregation( - BucketInterface $bucket, - array $dimensions, - $range, - \Magento\Framework\Search\Dynamic\EntityStorage $entityStorage - ) { - $select = $this->dataProvider->getDataSet($bucket, $dimensions, $entityStorage->getSource()); - $column = $select->getPart(Select::COLUMNS)[0]; - $select->reset(Select::COLUMNS); - $rangeExpr = new \Zend_Db_Expr( - $this->connection->getIfNullSql( - $this->connection->quoteInto('FLOOR(' . $column[1] . ' / ? ) + 1', $range), - 1 - ) - ); - - $select - ->columns(['range' => $rangeExpr]) - ->columns(['metrix' => 'COUNT(*)']) - ->group('range') - ->order('range'); - $result = $this->connection->fetchPairs($select); - - return $result; - } - - /** - * {@inheritdoc} - */ - public function prepareData($range, array $dbRanges) - { - $data = []; - if (!empty($dbRanges)) { - $lastIndex = array_keys($dbRanges); - $lastIndex = $lastIndex[count($lastIndex) - 1]; - - foreach ($dbRanges as $index => $count) { - $fromPrice = $index == 1 ? '' : ($index - 1) * $range; - $toPrice = $index == $lastIndex ? '' : $index * $range; - - $data[] = [ - 'from' => $fromPrice, - 'to' => $toPrice, - 'count' => $count, - ]; - } - } - - return $data; - } - - /** - * @return Select - */ - private function getSelect() - { - return $this->connection->select(); - } -} diff --git a/app/code/Magento/CatalogSearch/Model/Adapter/Mysql/Field/Resolver.php b/app/code/Magento/CatalogSearch/Model/Adapter/Mysql/Field/Resolver.php deleted file mode 100644 index c24acf4610e07..0000000000000 --- a/app/code/Magento/CatalogSearch/Model/Adapter/Mysql/Field/Resolver.php +++ /dev/null @@ -1,73 +0,0 @@ -attributeCollection = $attributeCollection; - $this->fieldFactory = $fieldFactory; - } - - /** - * {@inheritdoc} - */ - public function resolve(array $fields) - { - $resolvedFields = []; - $this->attributeCollection->addFieldToFilter('attribute_code', ['in' => $fields]); - foreach ($fields as $field) { - if ('*' === $field) { - $resolvedFields = [ - $this->fieldFactory->create( - [ - 'attributeId' => null, - 'column' => 'data_index', - 'type' => FieldInterface::TYPE_FULLTEXT - ] - ) - ]; - break; - } - $attribute = $this->attributeCollection->getItemByColumnValue('attribute_code', $field); - $attributeId = $attribute ? $attribute->getId() : 0; - $resolvedFields[$field] = $this->fieldFactory->create( - [ - 'attributeId' => $attributeId, - 'column' => 'data_index', - 'type' => FieldInterface::TYPE_FULLTEXT - ] - ); - } - return $resolvedFields; - } -} diff --git a/app/code/Magento/CatalogSearch/Model/Adapter/Mysql/Filter/AliasResolver.php b/app/code/Magento/CatalogSearch/Model/Adapter/Mysql/Filter/AliasResolver.php deleted file mode 100644 index bf431396cc0c7..0000000000000 --- a/app/code/Magento/CatalogSearch/Model/Adapter/Mysql/Filter/AliasResolver.php +++ /dev/null @@ -1,48 +0,0 @@ -getField(); - switch ($field) { - case 'price': - $alias = 'price_index'; - break; - case 'category_ids': - $alias = 'category_ids_index'; - break; - default: - $alias = $field . RequestGenerator::FILTER_SUFFIX; - break; - } - return $alias; - } -} diff --git a/app/code/Magento/CatalogSearch/Model/Adapter/Mysql/Filter/Preprocessor.php b/app/code/Magento/CatalogSearch/Model/Adapter/Mysql/Filter/Preprocessor.php deleted file mode 100644 index a97d362c5de7f..0000000000000 --- a/app/code/Magento/CatalogSearch/Model/Adapter/Mysql/Filter/Preprocessor.php +++ /dev/null @@ -1,304 +0,0 @@ -conditionManager = $conditionManager; - $this->scopeResolver = $scopeResolver; - $this->config = $config; - $this->resource = $resource; - $this->connection = $resource->getConnection(); - $this->attributePrefix = $attributePrefix; - - if (null === $scopeConfig) { - $scopeConfig = ObjectManager::getInstance()->get(ScopeConfigInterface::class); - } - if (null === $aliasResolver) { - $aliasResolver = ObjectManager::getInstance()->get(AliasResolver::class); - } - if (null === $customerSession) { - $customerSession = ObjectManager::getInstance()->get(Session::class); - } - - $this->scopeConfig = $scopeConfig; - $this->aliasResolver = $aliasResolver; - $this->customerSession = $customerSession; - } - - /** - * @inheritdoc - */ - public function process(FilterInterface $filter, $isNegation, $query) - { - return $this->processQueryWithField($filter, $isNegation, $query); - } - - /** - * Process query with field. - * - * @param FilterInterface $filter - * @param bool $isNegation - * @param string $query - * @return string - * @throws \Magento\Framework\Exception\LocalizedException - */ - private function processQueryWithField(FilterInterface $filter, $isNegation, $query) - { - /** @var Attribute $attribute */ - $attribute = $this->config->getAttribute(Product::ENTITY, $filter->getField()); - $linkIdField = $this->getMetadataPool()->getMetadata(ProductInterface::class)->getLinkField(); - if ($filter->getField() === 'price') { - $resultQuery = str_replace( - $this->connection->quoteIdentifier('price'), - $this->connection->quoteIdentifier('price_index.min_price'), - $query - ); - - $resultQuery .= sprintf( - ' AND %s = %s', - $this->connection->quoteIdentifier('price_index.customer_group_id'), - $this->customerSession->getCustomerGroupId() - ); - } elseif ($filter->getField() === 'category_ids') { - return $this->connection->quoteInto( - 'category_ids_index.category_id in (?)', - $filter->getValue() - ); - } elseif ($attribute->isStatic()) { - $alias = $this->aliasResolver->getAlias($filter); - $resultQuery = str_replace( - $this->connection->quoteIdentifier($attribute->getAttributeCode()), - $this->connection->quoteIdentifier($alias . '.' . $attribute->getAttributeCode()), - $query - ); - } elseif ($filter->getField() === VisibilityFilter::VISIBILITY_FILTER_FIELD) { - return ''; - } elseif ($filter->getType() === FilterInterface::TYPE_TERM && - in_array($attribute->getFrontendInput(), ['select', 'multiselect', 'boolean'], true) - ) { - $resultQuery = $this->processTermSelect($filter, $isNegation); - } elseif ($filter->getType() === FilterInterface::TYPE_RANGE && - in_array($attribute->getBackendType(), ['decimal', 'int'], true) - ) { - $resultQuery = $this->processRangeNumeric($filter, $query, $attribute); - } else { - $table = $attribute->getBackendTable(); - $select = $this->connection->select(); - $ifNullCondition = $this->connection->getIfNullSql('current_store.value', 'main_table.value'); - - $currentStoreId = $this->scopeResolver->getScope()->getId(); - - $select->from(['e' => $this->resource->getTableName('catalog_product_entity')], ['entity_id']) - ->join( - ['main_table' => $table], - "main_table.{$linkIdField} = e.{$linkIdField}", - [] - ) - ->joinLeft( - ['current_store' => $table], - "current_store.{$linkIdField} = main_table.{$linkIdField} AND " - . "current_store.attribute_id = main_table.attribute_id AND current_store.store_id = " - . $currentStoreId, - null - ) - ->columns([$filter->getField() => $ifNullCondition]) - ->where( - 'main_table.attribute_id = ?', - $attribute->getAttributeId() - ) - ->where('main_table.store_id = ?', Store::DEFAULT_STORE_ID) - ->having($query); - - $resultQuery = 'search_index.entity_id IN (' - . 'select entity_id from ' - . $this->conditionManager->wrapBrackets($select) - . ' as filter)'; - } - - return $resultQuery; - } - - /** - * Process range numeric. - * - * @param FilterInterface $filter - * @param string $query - * @param Attribute $attribute - * @return string - * @throws \Exception - */ - private function processRangeNumeric(FilterInterface $filter, $query, $attribute) - { - $tableSuffix = $attribute->getBackendType() === 'decimal' ? '_decimal' : ''; - $table = $this->resource->getTableName("catalog_product_index_eav{$tableSuffix}"); - $select = $this->connection->select(); - $entityField = $this->getMetadataPool()->getMetadata(ProductInterface::class)->getIdentifierField(); - - $currentStoreId = $this->scopeResolver->getScope()->getId(); - - $select->from(['e' => $this->resource->getTableName('catalog_product_entity')], ['entity_id']) - ->join( - ['main_table' => $table], - "main_table.{$entityField} = e.{$entityField}", - [] - ) - ->columns([$filter->getField() => 'main_table.value']) - ->where('main_table.attribute_id = ?', $attribute->getAttributeId()) - ->where('main_table.store_id = ?', $currentStoreId) - ->having($query); - - $resultQuery = 'search_index.entity_id IN (' - . 'select entity_id from ' - . $this->conditionManager->wrapBrackets($select) - . ' as filter)'; - - return $resultQuery; - } - - /** - * Process term select. - * - * @param FilterInterface $filter - * @param bool $isNegation - * @return string - */ - private function processTermSelect(FilterInterface $filter, $isNegation) - { - $alias = $this->aliasResolver->getAlias($filter); - if (is_array($filter->getValue())) { - $value = sprintf( - '%s IN (%s)', - ($isNegation ? 'NOT' : ''), - implode(',', array_map([$this->connection, 'quote'], $filter->getValue())) - ); - } else { - $value = ($isNegation ? '!' : '') . '= ' . $this->connection->quote($filter->getValue()); - } - $resultQuery = sprintf( - '%1$s.value %2$s', - $alias, - $value - ); - - return $resultQuery; - } - - /** - * Get product metadata pool - * - * @return \Magento\Framework\EntityManager\MetadataPool - */ - protected function getMetadataPool() - { - if (!$this->metadataPool) { - $this->metadataPool = \Magento\Framework\App\ObjectManager::getInstance() - ->get(\Magento\Framework\EntityManager\MetadataPool::class); - } - return $this->metadataPool; - } -} diff --git a/app/code/Magento/CatalogSearch/Model/Adapter/Mysql/Plugin/Aggregation/Category/DataProvider.php b/app/code/Magento/CatalogSearch/Model/Adapter/Mysql/Plugin/Aggregation/Category/DataProvider.php deleted file mode 100644 index a5650cac73395..0000000000000 --- a/app/code/Magento/CatalogSearch/Model/Adapter/Mysql/Plugin/Aggregation/Category/DataProvider.php +++ /dev/null @@ -1,124 +0,0 @@ -resource = $resource; - $this->scopeResolver = $scopeResolver; - $this->layer = $layerResolver->get(); - $this->tableResolver = $tableResolver ?: ObjectManager::getInstance()->get(TableResolver::class); - } - - /** - * @param \Magento\CatalogSearch\Model\Adapter\Mysql\Aggregation\DataProvider $subject - * @param callable|\Closure $proceed - * @param BucketInterface $bucket - * @param Dimension[] $dimensions - * - * @param Table $entityIdsTable - * @return Select - * @SuppressWarnings(PHPMD.UnusedFormalParameter) - */ - public function aroundGetDataSet( - \Magento\CatalogSearch\Model\Adapter\Mysql\Aggregation\DataProvider $subject, - \Closure $proceed, - BucketInterface $bucket, - array $dimensions, - Table $entityIdsTable - ) { - if ($bucket->getField() == 'category_ids') { - $currentScopeId = $this->scopeResolver->getScope($dimensions['scope']->getValue())->getId(); - $currentCategory = $this->layer->getCurrentCategory(); - - $catalogCategoryProductDimension = new Dimension(\Magento\Store\Model\Store::ENTITY, $currentScopeId); - - $catalogCategoryProductTableName = $this->tableResolver->resolve( - AbstractAction::MAIN_INDEX_TABLE, - [ - $catalogCategoryProductDimension - ] - ); - - $derivedTable = $this->resource->getConnection()->select(); - $derivedTable->from( - ['main_table' => $catalogCategoryProductTableName], - [ - 'value' => 'category_id' - ] - )->where('main_table.store_id = ?', $currentScopeId); - $derivedTable->joinInner( - ['entities' => $entityIdsTable->getName()], - 'main_table.product_id = entities.entity_id', - [] - ); - - if (!empty($currentCategory)) { - $derivedTable->join( - ['category' => $this->resource->getTableName('catalog_category_entity')], - 'main_table.category_id = category.entity_id', - [] - )->where('`category`.`path` LIKE ?', $currentCategory->getPath() . '%') - ->where('`category`.`level` > ?', $currentCategory->getLevel()); - } - $select = $this->resource->getConnection()->select(); - $select->from(['main_table' => $derivedTable]); - return $select; - } - return $proceed($bucket, $dimensions, $entityIdsTable); - } -} diff --git a/app/code/Magento/CatalogSearch/Model/Fulltext.php b/app/code/Magento/CatalogSearch/Model/Fulltext.php deleted file mode 100644 index 398d6e9dd18dd..0000000000000 --- a/app/code/Magento/CatalogSearch/Model/Fulltext.php +++ /dev/null @@ -1,87 +0,0 @@ -queryFactory = $queryFactory; - $this->_scopeConfig = $scopeConfig; - parent::__construct($context, $registry, $resource, $resourceCollection, $data); - } - - /** - * @return void - */ - protected function _construct() - { - $this->_init(\Magento\CatalogSearch\Model\ResourceModel\Fulltext::class); - } - - /** - * Reset search results cache - * - * @return $this - * @deprecated Not used anymore - * @see \Magento\CatalogSearch\Model\ResourceModel\Fulltext::resetSearchResultsByStore - */ - public function resetSearchResults() - { - $this->getResource()->resetSearchResults(); - return $this; - } -} diff --git a/app/code/Magento/CatalogSearch/Model/Indexer/Fulltext.php b/app/code/Magento/CatalogSearch/Model/Indexer/Fulltext.php index 912dec8666191..ca6ff0720023f 100644 --- a/app/code/Magento/CatalogSearch/Model/Indexer/Fulltext.php +++ b/app/code/Magento/CatalogSearch/Model/Indexer/Fulltext.php @@ -55,11 +55,15 @@ class Fulltext implements /** * @var IndexSwitcherInterface + * @deprecated + * @see \Magento\Elasticsearch */ private $indexSwitcher; /** * @var \Magento\CatalogSearch\Model\Indexer\Scope\State + * @deprecated + * @see \Magento\Elasticsearch */ private $indexScopeState; @@ -136,13 +140,9 @@ public function executeByDimensions(array $dimensions, \Traversable $entityIds = ); if (null === $entityIds) { - $this->indexScopeState->useTemporaryIndex(); $saveHandler->cleanIndex($dimensions); $saveHandler->saveIndex($dimensions, $this->fullAction->rebuildStoreIndex($storeId)); - $this->indexSwitcher->switchIndex($dimensions); - $this->indexScopeState->useRegularIndex(); - $this->fulltextResource->resetSearchResultsByStore($storeId); } else { // internal implementation works only with array diff --git a/app/code/Magento/CatalogSearch/Model/Indexer/Fulltext/Action/DataProvider.php b/app/code/Magento/CatalogSearch/Model/Indexer/Fulltext/Action/DataProvider.php index cd2529a8fd725..28624c667e42b 100644 --- a/app/code/Magento/CatalogSearch/Model/Indexer/Fulltext/Action/DataProvider.php +++ b/app/code/Magento/CatalogSearch/Model/Indexer/Fulltext/Action/DataProvider.php @@ -83,7 +83,7 @@ class DataProvider private $storeManager; /** - * @var \Magento\CatalogSearch\Model\ResourceModel\Engine + * @var \Magento\CatalogSearch\Model\ResourceModel\EngineInterface */ private $engine; @@ -323,7 +323,7 @@ public function getSearchableAttributes($backendType = null) 'catelogsearch_searchable_attributes_load_after', ['engine' => $this->engine, 'attributes' => $attributes] ); - + $this->eventManager->dispatch( 'catalogsearch_searchable_attributes_load_after', ['engine' => $this->engine, 'attributes' => $attributes] diff --git a/app/code/Magento/CatalogSearch/Model/Indexer/Fulltext/Action/Full.php b/app/code/Magento/CatalogSearch/Model/Indexer/Fulltext/Action/Full.php index f56a4fe4d1b76..bd63e1e79989c 100644 --- a/app/code/Magento/CatalogSearch/Model/Indexer/Fulltext/Action/Full.php +++ b/app/code/Magento/CatalogSearch/Model/Indexer/Fulltext/Action/Full.php @@ -125,7 +125,7 @@ class Full protected $storeManager; /** - * @var \Magento\CatalogSearch\Model\ResourceModel\Engine + * @var \Magento\CatalogSearch\Model\ResourceModel\EngineInterface */ protected $engine; @@ -181,13 +181,6 @@ class Full */ protected $connection; - /** - * @var \Magento\CatalogSearch\Model\Indexer\Fulltext\Action\IndexIteratorFactory - * @deprecated 100.1.6 DataProvider used directly without IndexIterator - * @see self::$dataProvider - */ - private $iteratorFactory; - /** * @var \Magento\Framework\EntityManager\MetadataPool */ @@ -223,11 +216,12 @@ class Full * @param \Magento\CatalogSearch\Model\ResourceModel\Fulltext $fulltextResource * @param \Magento\Framework\Search\Request\DimensionFactory $dimensionFactory * @param \Magento\Framework\Indexer\ConfigInterface $indexerConfig - * @param \Magento\CatalogSearch\Model\Indexer\Fulltext\Action\IndexIteratorFactory $indexIteratorFactory - * @param \Magento\Framework\EntityManager\MetadataPool $metadataPool - * @param DataProvider $dataProvider + * @param mixed $indexIteratorFactory + * @param \Magento\Framework\EntityManager\MetadataPool|null $metadataPool + * @param DataProvider|null $dataProvider * @param int $batchSize * @SuppressWarnings(PHPMD.ExcessiveParameterList) + * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ public function __construct( ResourceConnection $resource, @@ -247,7 +241,7 @@ public function __construct( \Magento\CatalogSearch\Model\ResourceModel\Fulltext $fulltextResource, \Magento\Framework\Search\Request\DimensionFactory $dimensionFactory, \Magento\Framework\Indexer\ConfigInterface $indexerConfig, - \Magento\CatalogSearch\Model\Indexer\Fulltext\Action\IndexIteratorFactory $indexIteratorFactory, + $indexIteratorFactory = null, \Magento\Framework\EntityManager\MetadataPool $metadataPool = null, DataProvider $dataProvider = null, $batchSize = 500 @@ -270,7 +264,6 @@ public function __construct( $this->localeDate = $localeDate; $this->fulltextResource = $fulltextResource; $this->dimensionFactory = $dimensionFactory; - $this->iteratorFactory = $indexIteratorFactory; $this->metadataPool = $metadataPool ?: ObjectManager::getInstance() ->get(\Magento\Framework\EntityManager\MetadataPool::class); $this->dataProvider = $dataProvider ?: ObjectManager::getInstance()->get(DataProvider::class); diff --git a/app/code/Magento/CatalogSearch/Model/Indexer/Fulltext/Action/IndexIterator.php b/app/code/Magento/CatalogSearch/Model/Indexer/Fulltext/Action/IndexIterator.php deleted file mode 100644 index a2c39deff1892..0000000000000 --- a/app/code/Magento/CatalogSearch/Model/Indexer/Fulltext/Action/IndexIterator.php +++ /dev/null @@ -1,287 +0,0 @@ -dataProvider = $dataProvider; - $this->storeId = $storeId; - $this->staticFields = $staticFields; - $this->productIds = $productIds; - $this->dynamicFields = $dynamicFields; - $this->visibility = $visibility; - $this->allowedVisibility = $allowedVisibility; - $this->status = $status; - $this->statusIds = $statusIds; - } - - /** - * {@inheritDoc} - * - * @deprecated 100.1.6 Since class is deprecated - * @since 100.0.3 - */ - public function current() - { - return $this->current; - } - - /** - * {@inheritDoc} - * - * @deprecated 100.1.6 Since class is deprecated - * @since 100.0.3 - */ - public function next() - { - \next($this->products); - if (\key($this->products) === null) { - // check if storage has more items to process - $this->products = $this->dataProvider->getSearchableProducts( - $this->storeId, - $this->staticFields, - $this->productIds, - $this->lastProductId - ); - - if (!count($this->products)) { - $this->isValid = false; - return; - } - - $productAttributes = []; - $this->productRelations = []; - foreach ($this->products as $productData) { - $this->lastProductId = $productData['entity_id']; - $productAttributes[$productData['entity_id']] = $productData['entity_id']; - $productChildren = $this->dataProvider->getProductChildIds( - $productData['entity_id'], - $productData['type_id'] - ); - $this->productRelations[$productData['entity_id']] = $productChildren; - if ($productChildren) { - foreach ($productChildren as $productChildId) { - $productAttributes[$productChildId] = $productChildId; - } - } - } - \reset($this->products); - - $this->productAttributes = $this->dataProvider->getProductAttributes( - $this->storeId, - $productAttributes, - $this->dynamicFields - ); - } - - $productData = \current($this->products); - - if (!isset($this->productAttributes[$productData['entity_id']])) { - $this->next(); - return; - } - - $productAttr = $this->productAttributes[$productData['entity_id']]; - if (!isset($productAttr[$this->visibility->getId()]) - || !in_array($productAttr[$this->visibility->getId()], $this->allowedVisibility) - ) { - $this->next(); - return; - } - if (!isset($productAttr[$this->status->getId()]) - || !in_array($productAttr[$this->status->getId()], $this->statusIds) - ) { - $this->next(); - return; - } - - $productIndex = [$productData['entity_id'] => $productAttr]; - - $hasChildren = false; - $productChildren = $this->productRelations[$productData['entity_id']]; - if ($productChildren) { - foreach ($productChildren as $productChildId) { - if (isset($this->productAttributes[$productChildId])) { - $productChildAttr = $this->productAttributes[$productChildId]; - if (!isset($productChildAttr[$this->status->getId()]) - || !in_array($productChildAttr[$this->status->getId()], $this->statusIds) - ) { - continue; - } - - $hasChildren = true; - $productIndex[$productChildId] = $productChildAttr; - } - } - } - if ($productChildren !== null && !$hasChildren) { - $this->next(); - return; - } - - $index = $this->dataProvider->prepareProductIndex($productIndex, $productData, $this->storeId); - - $this->current = $index; - $this->key = $productData['entity_id']; - } - - /** - * {@inheritDoc} - * - * @deprecated 100.1.6 Since class is deprecated - * @since 100.0.3 - */ - public function key() - { - return $this->key; - } - - /** - * {@inheritDoc} - * - * @deprecated 100.1.6 Since class is deprecated - * @since 100.0.3 - */ - public function valid() - { - return $this->isValid; - } - - /** - * {@inheritDoc} - * - * @deprecated 100.1.6 Since class is deprecated - * @since 100.0.3 - */ - public function rewind() - { - $this->lastProductId = 0; - $this->key = null; - $this->current = null; - unset($this->products); - $this->products = []; - $this->next(); - } -} diff --git a/app/code/Magento/CatalogSearch/Model/Indexer/Fulltext/Store.php b/app/code/Magento/CatalogSearch/Model/Indexer/Fulltext/Store.php index 23ab52012f2e5..67ae57e2f3485 100644 --- a/app/code/Magento/CatalogSearch/Model/Indexer/Fulltext/Store.php +++ b/app/code/Magento/CatalogSearch/Model/Indexer/Fulltext/Store.php @@ -58,7 +58,7 @@ private function clearIndex(\Magento\Store\Model\Store $store) $this->dimensionFactory->create(['name' => 'scope', 'value' => $store->getId()]) ]; $configData = $this->indexerConfig->getIndexer(FulltextIndexer::INDEXER_ID); - /** @var \Magento\CatalogSearch\Model\Indexer\IndexerHandler $indexHandler */ + /** @var \Magento\Framework\Indexer\SaveHandler\IndexerInterface $indexHandler */ $indexHandler = $this->indexerHandlerFactory->create(['data' => $configData]); $indexHandler->cleanIndex($dimensions); } diff --git a/app/code/Magento/CatalogSearch/Model/Indexer/IndexStructure.php b/app/code/Magento/CatalogSearch/Model/Indexer/IndexStructure.php index 0d226acdc3d7b..ab75d09bb4cf9 100644 --- a/app/code/Magento/CatalogSearch/Model/Indexer/IndexStructure.php +++ b/app/code/Magento/CatalogSearch/Model/Indexer/IndexStructure.php @@ -6,10 +6,10 @@ namespace Magento\CatalogSearch\Model\Indexer; +use Magento\Framework\App\ObjectManager; use Magento\Framework\App\ResourceConnection; use Magento\Framework\DB\Adapter\AdapterInterface; use Magento\Framework\DB\Ddl\Table; -use Magento\Framework\Search\Request\Dimension; use Magento\Framework\Indexer\IndexStructureInterface; use Magento\Framework\Indexer\ScopeResolver\IndexScopeResolver; use Magento\Framework\Search\Request\IndexScopeResolverInterface; @@ -22,26 +22,44 @@ */ class IndexStructure implements IndexStructureInterface { + /** + * @var IndexStructureInterface + */ + private $indexStructureEntity; + + /** + * @var IndexStructureFactory + */ + private $indexStructureFactory; + /** * @var Resource + * @deprecated + * @see \Magento\Elasticsearch */ private $resource; /** * @var IndexScopeResolver + * @deprecated + * @see \Magento\Elasticsearch */ private $indexScopeResolver; /** * @param ResourceConnection $resource * @param IndexScopeResolverInterface $indexScopeResolver + * @param IndexStructureFactory|null $indexStructureFactory */ public function __construct( ResourceConnection $resource, - IndexScopeResolverInterface $indexScopeResolver + IndexScopeResolverInterface $indexScopeResolver, + IndexStructureFactory $indexStructureFactory = null ) { $this->resource = $resource; $this->indexScopeResolver = $indexScopeResolver; + $this->indexStructureFactory = $indexStructureFactory ? : ObjectManager::getInstance() + ->get(IndexStructureFactory::class); } /** @@ -49,10 +67,7 @@ public function __construct( */ public function delete($index, array $dimensions = []) { - $tableName = $this->indexScopeResolver->resolve($index, $dimensions); - if ($this->resource->getConnection()->isTableExists($tableName)) { - $this->resource->getConnection()->dropTable($tableName); - } + return $this->getEntity()->delete($index, $dimensions); } /** @@ -60,7 +75,20 @@ public function delete($index, array $dimensions = []) */ public function create($index, array $fields, array $dimensions = []) { - $this->createFulltextIndex($this->indexScopeResolver->resolve($index, $dimensions)); + return $this->getEntity()->create($index, $fields, $dimensions); + } + + /** + * Get instance of current index structure + * + * @return IndexStructureInterface + */ + private function getEntity() + { + if (empty($this->indexStructureEntity)) { + $this->indexStructureEntity = $this->indexStructureFactory->create(); + } + return $this->indexStructureEntity; } /** @@ -69,6 +97,8 @@ public function create($index, array $fields, array $dimensions = []) * @param string $tableName * @throws \Zend_Db_Exception * @return void + * @deprecated + * @see \Magento\ElasticSearch */ protected function createFulltextIndex($tableName) { diff --git a/app/code/Magento/CatalogSearch/Model/Indexer/IndexStructureProxy.php b/app/code/Magento/CatalogSearch/Model/Indexer/IndexStructureProxy.php index c62d2a033565f..e2077dda815ba 100644 --- a/app/code/Magento/CatalogSearch/Model/Indexer/IndexStructureProxy.php +++ b/app/code/Magento/CatalogSearch/Model/Indexer/IndexStructureProxy.php @@ -9,6 +9,9 @@ /** * Catalog search index structure proxy. + * + * @deprecated mysql search engine has been removed + * @see \Magento\Elasticsearch */ class IndexStructureProxy implements IndexStructureInterface { diff --git a/app/code/Magento/CatalogSearch/Model/Indexer/IndexSwitcherInterface.php b/app/code/Magento/CatalogSearch/Model/Indexer/IndexSwitcherInterface.php index f45ef11a86389..59c22fa60052f 100644 --- a/app/code/Magento/CatalogSearch/Model/Indexer/IndexSwitcherInterface.php +++ b/app/code/Magento/CatalogSearch/Model/Indexer/IndexSwitcherInterface.php @@ -10,6 +10,8 @@ * * @api * @since 100.2.0 + * @deprecated mysql search engine has been removed + * @see \Magento\Elasticsearch */ interface IndexSwitcherInterface { diff --git a/app/code/Magento/CatalogSearch/Model/Indexer/IndexSwitcherProxy.php b/app/code/Magento/CatalogSearch/Model/Indexer/IndexSwitcherProxy.php index e4a20cc188fbd..634da0ed3228f 100644 --- a/app/code/Magento/CatalogSearch/Model/Indexer/IndexSwitcherProxy.php +++ b/app/code/Magento/CatalogSearch/Model/Indexer/IndexSwitcherProxy.php @@ -11,6 +11,9 @@ /** * Proxy for adapter-specific index switcher + * + * @deprecated mysql search engine has been removed + * @see \Magento\Elasticsearch */ class IndexSwitcherProxy implements IndexSwitcherInterface { diff --git a/app/code/Magento/CatalogSearch/Model/Indexer/IndexerHandler.php b/app/code/Magento/CatalogSearch/Model/Indexer/IndexerHandler.php deleted file mode 100644 index 9f105bd3ea462..0000000000000 --- a/app/code/Magento/CatalogSearch/Model/Indexer/IndexerHandler.php +++ /dev/null @@ -1,212 +0,0 @@ -indexScopeResolver = $indexScopeResolver; - $this->indexStructure = $indexStructure; - $this->resource = $resource; - $this->batch = $batch; - $this->eavConfig = $eavConfig; - $this->data = $data; - $this->fields = []; - - $this->prepareFields(); - $this->batchSize = $batchSize; - } - - /** - * @inheritdoc - */ - public function saveIndex($dimensions, \Traversable $documents) - { - foreach ($this->batch->getItems($documents, $this->batchSize) as $batchDocuments) { - $this->insertDocuments($batchDocuments, $dimensions); - } - } - - /** - * @inheritdoc - */ - public function deleteIndex($dimensions, \Traversable $documents) - { - foreach ($this->batch->getItems($documents, $this->batchSize) as $batchDocuments) { - $this->resource->getConnection() - ->delete($this->getTableName($dimensions), ['entity_id in (?)' => $batchDocuments]); - } - } - - /** - * @inheritdoc - */ - public function cleanIndex($dimensions) - { - $this->indexStructure->delete($this->getIndexName(), $dimensions); - $this->indexStructure->create($this->getIndexName(), [], $dimensions); - } - - /** - * @inheritdoc - */ - public function isAvailable($dimensions = []) - { - if (empty($dimensions)) { - return true; - } - - return $this->resource->getConnection()->isTableExists($this->getTableName($dimensions)); - } - - /** - * Returns table name. - * - * @param Dimension[] $dimensions - * @return string - */ - private function getTableName($dimensions) - { - return $this->indexScopeResolver->resolve($this->getIndexName(), $dimensions); - } - - /** - * Returns index name. - * - * @return string - */ - private function getIndexName() - { - return $this->data['indexer_id']; - } - - /** - * Add documents to storage. - * - * @param array $documents - * @param Dimension[] $dimensions - * @return void - */ - private function insertDocuments(array $documents, array $dimensions) - { - $documents = $this->prepareSearchableFields($documents); - if (empty($documents)) { - return; - } - $this->resource->getConnection()->insertOnDuplicate( - $this->getTableName($dimensions), - $documents, - ['data_index'] - ); - } - - /** - * Searchable filter preparation. - * - * @param array $documents - * @return array - */ - private function prepareSearchableFields(array $documents) - { - $insertDocuments = []; - foreach ($documents as $entityId => $document) { - foreach ($document as $attributeId => $fieldValue) { - $insertDocuments[$entityId . '_' . $attributeId] = [ - 'entity_id' => $entityId, - 'attribute_id' => $attributeId, - 'data_index' => $fieldValue, - ]; - } - } - - return $insertDocuments; - } - - /** - * Prepare fields. - * - * @return void - */ - private function prepareFields() - { - foreach ($this->data['fieldsets'] as $fieldset) { - $this->fields = array_merge($this->fields, $fieldset['fields']); - } - } -} diff --git a/app/code/Magento/CatalogSearch/Model/Indexer/ProductFieldset.php b/app/code/Magento/CatalogSearch/Model/Indexer/ProductFieldset.php deleted file mode 100644 index 6db063bde7d1e..0000000000000 --- a/app/code/Magento/CatalogSearch/Model/Indexer/ProductFieldset.php +++ /dev/null @@ -1,151 +0,0 @@ -eavConfig = $eavConfig; - $this->collectionFactory = $collectionFactory; - } - - /** - * {@inheritdoc} - */ - public function addDynamicData(array $data) - { - $searchableAttributes = $this->getSearchableAttributes(); - - $defaultSource = isset($data['source']) ? $data['source'] : null; - $additionalFields = $this->convert($searchableAttributes, $defaultSource, null); - - $data['fields'] = $this->merge($data['fields'], $additionalFields); - - return $data; - } - - /** - * Retrieve searchable attributes - * - * @return Attribute[] - */ - private function getSearchableAttributes() - { - if ($this->searchableAttributes === null) { - $this->searchableAttributes = []; - - /** @var \Magento\Catalog\Model\ResourceModel\Product\Attribute\Collection $productAttributes */ - $productAttributes = $this->collectionFactory->create(); - $productAttributes->addToIndexFilter(true); - - /** @var \Magento\Eav\Model\Entity\Attribute[] $attributes */ - $attributes = $productAttributes->getItems(); - - $entity = $this->eavConfig->getEntityType(Product::ENTITY) - ->getEntity(); - - foreach ($attributes as $attribute) { - $attribute->setEntity($entity); - } - - $this->searchableAttributes = $attributes; - } - - return $this->searchableAttributes; - } - - /** - * @param array $attributes - * @param string $defaultSource - * @param string $defaultHandler - * @return array - */ - private function convert(array $attributes, $defaultSource, $defaultHandler) - { - $fields = []; - foreach ($attributes as $attribute) { - $fields[] = [ - 'name' => $attribute->getName(), - 'source' => $defaultSource, - 'handler' => $defaultHandler, - 'dataType' => $attribute->getBackendType(), - 'type' => $this->getType($attribute), - 'filters' => [], - ]; - } - - return $fields; - } - - /** - * @param Attribute $attribute - * @return string - */ - private function getType(Attribute $attribute) - { - $type = ''; - $isFilterable = $attribute->getData('is_filterable') || $attribute->getData('is_filterable_in_search'); - $isSearchable = $attribute->getData('is_searchable'); - if ($isSearchable && $isFilterable) { - $type = 'both'; - } elseif ($isSearchable) { - $type = 'searchable'; - } elseif ($isFilterable) { - $type = 'filterable'; - } - - return $type; - } - - /** - * @param array $dataFields - * @param array $searchableFields - * @return array - */ - private function merge(array $dataFields, array $searchableFields) - { - foreach ($searchableFields as $field) { - if (!isset($dataFields[$field['name']])) { - $dataFields[$field['name']] = $field; - } - } - - return $dataFields; - } -} diff --git a/app/code/Magento/CatalogSearch/Model/Indexer/Scope/IndexSwitcher.php b/app/code/Magento/CatalogSearch/Model/Indexer/Scope/IndexSwitcher.php deleted file mode 100644 index ed2b1be5c7035..0000000000000 --- a/app/code/Magento/CatalogSearch/Model/Indexer/Scope/IndexSwitcher.php +++ /dev/null @@ -1,79 +0,0 @@ -resource = $resource; - $this->resolver = $indexScopeResolver; - $this->state = $state; - } - - /** - * {@inheritdoc} - * @throws IndexTableNotExistException - */ - public function switchIndex(array $dimensions) - { - if (State::USE_TEMPORARY_INDEX === $this->state->getState()) { - $index = \Magento\CatalogSearch\Model\Indexer\Fulltext::INDEXER_ID; - - $temporalIndexTable = $this->resolver->resolve($index, $dimensions); - if (!$this->resource->getConnection()->isTableExists($temporalIndexTable)) { - throw new IndexTableNotExistException( - __( - "Temporary table for index $index doesn't exist," - . " which is inconsistent with state of scope resolver" - ) - ); - } - - $this->state->useRegularIndex(); - $tableName = $this->resolver->resolve($index, $dimensions); - if ($this->resource->getConnection()->isTableExists($tableName)) { - $this->resource->getConnection()->dropTable($tableName); - } - - $this->resource->getConnection()->renameTable($temporalIndexTable, $tableName); - $this->state->useTemporaryIndex(); - } - } -} diff --git a/app/code/Magento/CatalogSearch/Model/Indexer/Scope/IndexTableNotExistException.php b/app/code/Magento/CatalogSearch/Model/Indexer/Scope/IndexTableNotExistException.php deleted file mode 100644 index b01f3c50d5002..0000000000000 --- a/app/code/Magento/CatalogSearch/Model/Indexer/Scope/IndexTableNotExistException.php +++ /dev/null @@ -1,22 +0,0 @@ -indexScopeResolver = $indexScopeResolver; - } - - /** - * @param string $index - * @param Dimension[] $dimensions - * @return string - */ - public function resolve($index, array $dimensions) - { - $tableName = $this->indexScopeResolver->resolve($index, $dimensions); - $tableName .= \Magento\Framework\Indexer\Table\StrategyInterface::TMP_SUFFIX; - - return $tableName; - } -} diff --git a/app/code/Magento/CatalogSearch/Model/ResourceModel/Advanced/Collection.php b/app/code/Magento/CatalogSearch/Model/ResourceModel/Advanced/Collection.php index bbebbc99103a2..291fad1e16ebf 100644 --- a/app/code/Magento/CatalogSearch/Model/ResourceModel/Advanced/Collection.php +++ b/app/code/Magento/CatalogSearch/Model/ResourceModel/Advanced/Collection.php @@ -27,7 +27,6 @@ use Magento\CatalogSearch\Model\ResourceModel\Fulltext\Collection\SearchResultApplierFactory; use Magento\Framework\App\ObjectManager; use Magento\Framework\Api\Search\SearchResultInterface; -use Magento\Search\Model\EngineResolver; /** * Advanced search collection @@ -41,11 +40,6 @@ */ class Collection extends \Magento\Catalog\Model\ResourceModel\Product\Collection { - /** - * Config search engine path. - */ - private const SEARCH_ENGINE_VALUE_PATH = 'catalog/search/engine'; - /** * List Of filters * @var array @@ -57,12 +51,6 @@ class Collection extends \Magento\Catalog\Model\ResourceModel\Product\Collection */ private $search; - /** - * @var \Magento\Framework\Search\Adapter\Mysql\TemporaryStorageFactory - * @deprecated There must be no dependencies on specific adapter in generic search implementation - */ - private $temporaryStorageFactory; - /** * @var SearchCriteriaBuilder */ @@ -140,9 +128,9 @@ class Collection extends \Magento\Catalog\Model\ResourceModel\Product\Collection * @param \Magento\Customer\Model\Session $customerSession * @param \Magento\Framework\Stdlib\DateTime $dateTime * @param \Magento\Customer\Api\GroupManagementInterface $groupManagement - * @param \Magento\CatalogSearch\Model\Advanced\Request\Builder $requestBuilder - * @param \Magento\Search\Model\SearchEngine $searchEngine - * @param \Magento\Framework\Search\Adapter\Mysql\TemporaryStorageFactory $temporaryStorageFactory + * @param mixed $requestBuilder + * @param mixed $searchEngine + * @param mixed $temporaryStorageFactory * @param \Magento\Framework\DB\Adapter\AdapterInterface|null $connection * @param SearchResultFactory|null $searchResultFactory * @param ProductLimitationFactory|null $productLimitationFactory @@ -154,6 +142,7 @@ class Collection extends \Magento\Catalog\Model\ResourceModel\Product\Collection * @param EngineResolverInterface|null $engineResolver * @param DefaultFilterStrategyApplyCheckerInterface|null $defaultFilterStrategyApplyChecker * @SuppressWarnings(PHPMD.ExcessiveParameterList) + * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ public function __construct( \Magento\Framework\Data\Collection\EntityFactory $entityFactory, @@ -175,9 +164,9 @@ public function __construct( \Magento\Customer\Model\Session $customerSession, \Magento\Framework\Stdlib\DateTime $dateTime, \Magento\Customer\Api\GroupManagementInterface $groupManagement, - \Magento\CatalogSearch\Model\Advanced\Request\Builder $requestBuilder, - \Magento\Search\Model\SearchEngine $searchEngine, - \Magento\Framework\Search\Adapter\Mysql\TemporaryStorageFactory $temporaryStorageFactory, + $requestBuilder = null, + $searchEngine = null, + $temporaryStorageFactory = null, \Magento\Framework\DB\Adapter\AdapterInterface $connection = null, SearchResultFactory $searchResultFactory = null, ProductLimitationFactory $productLimitationFactory = null, @@ -189,9 +178,6 @@ public function __construct( EngineResolverInterface $engineResolver = null, DefaultFilterStrategyApplyCheckerInterface $defaultFilterStrategyApplyChecker = null ) { - $this->requestBuilder = $requestBuilder; - $this->searchEngine = $searchEngine; - $this->temporaryStorageFactory = $temporaryStorageFactory; $this->searchRequestName = $searchRequestName; if ($searchResultFactory === null) { $this->searchResultFactory = \Magento\Framework\App\ObjectManager::getInstance() @@ -375,11 +361,6 @@ public function _loadEntities($printQuery = false, $logQuery = false) { $this->getEntity(); - $currentSearchEngine = $this->_scopeConfig->getValue(self::SEARCH_ENGINE_VALUE_PATH); - if ($this->_pageSize && $currentSearchEngine === EngineResolver::CATALOG_SEARCH_MYSQL_ENGINE) { - $this->getSelect()->limitPage($this->getCurPage(), $this->_pageSize); - } - $this->printLogQuery($printQuery, $logQuery); try { diff --git a/app/code/Magento/CatalogSearch/Model/ResourceModel/Engine.php b/app/code/Magento/CatalogSearch/Model/ResourceModel/Engine.php deleted file mode 100644 index 93ae2c94e2105..0000000000000 --- a/app/code/Magento/CatalogSearch/Model/ResourceModel/Engine.php +++ /dev/null @@ -1,147 +0,0 @@ -catalogProductVisibility = $catalogProductVisibility; - $this->indexScopeResolver = $indexScopeResolver; - } - - /** - * Retrieve allowed visibility values for current engine - * - * @return int[] - */ - public function getAllowedVisibility() - { - return $this->catalogProductVisibility->getVisibleInSiteIds(); - } - - /** - * Define if current search engine supports advanced index - * - * @return bool - */ - public function allowAdvancedIndex() - { - return true; - } - - /** - * Is attribute filterable as term cache - * - * @var array - */ - private $termFilterableAttributeAttributeCache = []; - - /** - * Is Attribute Filterable as Term - * - * @param \Magento\Catalog\Model\Entity\Attribute $attribute - * @return bool - */ - private function isTermFilterableAttribute($attribute) - { - $attributeId = $attribute->getAttributeId(); - if (!isset($this->termFilterableAttributeAttributeCache[$attributeId])) { - $this->termFilterableAttributeAttributeCache[$attributeId] = - in_array($attribute->getFrontendInput(), ['select', 'multiselect'], true) - && ($attribute->getIsVisibleInAdvancedSearch() - || $attribute->getIsFilterable() - || $attribute->getIsFilterableInSearch()); - } - - return $this->termFilterableAttributeAttributeCache[$attributeId]; - } - - /** - * @inheritdoc - */ - public function processAttributeValue($attribute, $value) - { - $result = false; - if ($attribute->getIsSearchable() - && in_array($attribute->getFrontendInput(), ['text', 'textarea']) - ) { - $result = $value; - } elseif ($this->isTermFilterableAttribute($attribute) - || ($attribute->getIsSearchable() && in_array($attribute->getFrontendInput(), ['select', 'multiselect'])) - ) { - $result = ''; - } - - return $result; - } - - /** - * Prepare index array as a string glued by separator - * - * Support 2 level array gluing - * - * @param array $index - * @param string $separator - * @return array - */ - public function prepareEntityIndex($index, $separator = ' ') - { - $indexData = []; - foreach ($index as $attributeId => $value) { - $indexData[$attributeId] = is_array($value) ? implode($separator, $value) : $value; - } - return $indexData; - } - - /** - * @inheritdoc - */ - public function isAvailable() - { - return true; - } -} diff --git a/app/code/Magento/CatalogSearch/Model/ResourceModel/EngineInterface.php b/app/code/Magento/CatalogSearch/Model/ResourceModel/EngineInterface.php index 4b9db55105ea9..f90dcc4397c80 100644 --- a/app/code/Magento/CatalogSearch/Model/ResourceModel/EngineInterface.php +++ b/app/code/Magento/CatalogSearch/Model/ResourceModel/EngineInterface.php @@ -13,10 +13,16 @@ */ interface EngineInterface { + /** + * Field prefix constant + * + * @deprecated mysql search engine has been removed + * @see \Magento\Framework\Search\EngineResolverInterface + */ const FIELD_PREFIX = 'attr_'; /** - * Scope identifier + * Scope identifier constant * * @deprecated since using engine resolver * @see \Magento\Framework\Search\EngineResolverInterface diff --git a/app/code/Magento/CatalogSearch/Model/ResourceModel/Fulltext/Collection.php b/app/code/Magento/CatalogSearch/Model/ResourceModel/Fulltext/Collection.php index 30a7c723940e2..e63ed1bd3d72f 100644 --- a/app/code/Magento/CatalogSearch/Model/ResourceModel/Fulltext/Collection.php +++ b/app/code/Magento/CatalogSearch/Model/ResourceModel/Fulltext/Collection.php @@ -20,14 +20,12 @@ use Magento\CatalogSearch\Model\Search\RequestGenerator; use Magento\Framework\EntityManager\MetadataPool; use Magento\Framework\Exception\StateException; -use Magento\Framework\Search\Response\QueryResponse; use Magento\Framework\Search\Request\EmptyRequestDataException; use Magento\Framework\Search\Request\NonExistingRequestNameException; use Magento\Framework\Api\Search\SearchResultFactory; use Magento\Framework\Exception\LocalizedException; use Magento\Framework\App\ObjectManager; use Magento\Catalog\Model\ResourceModel\Product\Collection\ProductLimitationFactory; -use Magento\Search\Model\EngineResolver; /** * Fulltext Collection @@ -42,37 +40,6 @@ */ class Collection extends \Magento\Catalog\Model\ResourceModel\Product\Collection { - /** - * Config search engine path. - */ - private const SEARCH_ENGINE_VALUE_PATH = 'catalog/search/engine'; - - /** - * @var QueryResponse - * @deprecated 100.1.0 - */ - protected $queryResponse; - - /** - * Catalog search data - * - * @var \Magento\Search\Model\QueryFactory - * @deprecated 100.1.0 - */ - protected $queryFactory = null; - - /** - * @var \Magento\Framework\Search\Request\Builder - * @deprecated 100.1.0 - */ - private $requestBuilder; - - /** - * @var \Magento\Search\Model\SearchEngine - * @deprecated 100.1.0 - */ - private $searchEngine; - /** * @var string */ @@ -83,12 +50,6 @@ class Collection extends \Magento\Catalog\Model\ResourceModel\Product\Collection */ private $searchRequestName; - /** - * @var \Magento\Framework\Search\Adapter\Mysql\TemporaryStorageFactory - * @deprecated There must be no dependencies on specific adapter in generic search implementation - */ - private $temporaryStorageFactory; - /** * @var \Magento\Search\Api\SearchInterface */ @@ -140,8 +101,6 @@ class Collection extends \Magento\Catalog\Model\ResourceModel\Product\Collection private $defaultFilterStrategyApplyChecker; /** - * Collection constructor - * * @param \Magento\Framework\Data\Collection\EntityFactory $entityFactory * @param \Psr\Log\LoggerInterface $logger * @param \Magento\Framework\Data\Collection\Db\FetchStrategyInterface $fetchStrategy @@ -161,10 +120,10 @@ class Collection extends \Magento\Catalog\Model\ResourceModel\Product\Collection * @param \Magento\Customer\Model\Session $customerSession * @param \Magento\Framework\Stdlib\DateTime $dateTime * @param \Magento\Customer\Api\GroupManagementInterface $groupManagement - * @param \Magento\Search\Model\QueryFactory $catalogSearchData - * @param \Magento\Framework\Search\Request\Builder $requestBuilder - * @param \Magento\Search\Model\SearchEngine $searchEngine - * @param \Magento\Framework\Search\Adapter\Mysql\TemporaryStorageFactory $temporaryStorageFactory + * @param mixed $catalogSearchData + * @param mixed $requestBuilder + * @param mixed $searchEngine + * @param mixed $temporaryStorageFactory * @param \Magento\Framework\DB\Adapter\AdapterInterface|null $connection * @param string $searchRequestName * @param SearchResultFactory|null $searchResultFactory @@ -179,6 +138,7 @@ class Collection extends \Magento\Catalog\Model\ResourceModel\Product\Collection * @param DefaultFilterStrategyApplyCheckerInterface|null $defaultFilterStrategyApplyChecker * @SuppressWarnings(PHPMD.ExcessiveParameterList) * @SuppressWarnings(PHPMD.NPathComplexity) + * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ public function __construct( \Magento\Framework\Data\Collection\EntityFactory $entityFactory, @@ -200,10 +160,10 @@ public function __construct( \Magento\Customer\Model\Session $customerSession, \Magento\Framework\Stdlib\DateTime $dateTime, \Magento\Customer\Api\GroupManagementInterface $groupManagement, - \Magento\Search\Model\QueryFactory $catalogSearchData, - \Magento\Framework\Search\Request\Builder $requestBuilder, - \Magento\Search\Model\SearchEngine $searchEngine, - \Magento\Framework\Search\Adapter\Mysql\TemporaryStorageFactory $temporaryStorageFactory, + $catalogSearchData = null, + $requestBuilder = null, + $searchEngine = null, + $temporaryStorageFactory = null, \Magento\Framework\DB\Adapter\AdapterInterface $connection = null, $searchRequestName = 'catalog_view_container', SearchResultFactory $searchResultFactory = null, @@ -217,7 +177,6 @@ public function __construct( TotalRecordsResolverFactory $totalRecordsResolverFactory = null, DefaultFilterStrategyApplyCheckerInterface $defaultFilterStrategyApplyChecker = null ) { - $this->queryFactory = $catalogSearchData; $this->searchResultFactory = $searchResultFactory ?? \Magento\Framework\App\ObjectManager::getInstance() ->get(\Magento\Framework\Api\Search\SearchResultFactory::class); parent::__construct( @@ -244,9 +203,6 @@ public function __construct( $productLimitationFactory, $metadataPool ); - $this->requestBuilder = $requestBuilder; - $this->searchEngine = $searchEngine; - $this->temporaryStorageFactory = $temporaryStorageFactory; $this->searchRequestName = $searchRequestName; $this->search = $search ?: ObjectManager::getInstance()->get(\Magento\Search\Api\SearchInterface::class); $this->searchCriteriaBuilder = $searchCriteriaBuilder ?: ObjectManager::getInstance() @@ -408,11 +364,6 @@ public function _loadEntities($printQuery = false, $logQuery = false) { $this->getEntity(); - $currentSearchEngine = $this->_scopeConfig->getValue(self::SEARCH_ENGINE_VALUE_PATH); - if ($this->_pageSize && $currentSearchEngine === EngineResolver::CATALOG_SEARCH_MYSQL_ENGINE) { - $this->getSelect()->limitPage($this->getCurPage(), $this->_pageSize); - } - $this->printLogQuery($printQuery, $logQuery); try { diff --git a/app/code/Magento/CatalogSearch/Model/ResourceModel/Fulltext/Collection/SearchResultApplier.php b/app/code/Magento/CatalogSearch/Model/ResourceModel/Fulltext/Collection/SearchResultApplier.php index c2e2a1ba47f17..2dfc3b78ea821 100644 --- a/app/code/Magento/CatalogSearch/Model/ResourceModel/Fulltext/Collection/SearchResultApplier.php +++ b/app/code/Magento/CatalogSearch/Model/ResourceModel/Fulltext/Collection/SearchResultApplier.php @@ -13,7 +13,9 @@ /** * Resolve specific attributes for search criteria. - * @deprecated @see \Magento\Elasticsearch\Model\ResourceModel\Fulltext\Collection\SearchResultApplier + * + * @deprecated mysql search engine has been removed + * @see \Magento\Elasticsearch\Model\ResourceModel\Fulltext\Collection\SearchResultApplier */ class SearchResultApplier implements SearchResultApplierInterface { diff --git a/app/code/Magento/CatalogSearch/Model/Search/BaseSelectStrategy/BaseSelectStrategyInterface.php b/app/code/Magento/CatalogSearch/Model/Search/BaseSelectStrategy/BaseSelectStrategyInterface.php deleted file mode 100644 index 2d8dfb9222497..0000000000000 --- a/app/code/Magento/CatalogSearch/Model/Search/BaseSelectStrategy/BaseSelectStrategyInterface.php +++ /dev/null @@ -1,26 +0,0 @@ -baseSelectFullTextSearchStrategy = $baseSelectFullTextSearchStrategy; - $this->baseSelectAttributesSearchStrategy = $baseSelectAttributesSearchStrategy; - } - - /** - * Decides which BaseSelectStrategyInterface should be used - * - * @param SelectContainer $selectContainer - * @return BaseSelectStrategyInterface - */ - public function mapSelectContainerToStrategy(SelectContainer $selectContainer) - { - if ($selectContainer->isFullTextSearchRequired() - && !$selectContainer->hasCustomAttributesFilters() - && !$selectContainer->hasVisibilityFilter() - ) { - return $this->baseSelectFullTextSearchStrategy; - } - - return $this->baseSelectAttributesSearchStrategy; - } -} diff --git a/app/code/Magento/CatalogSearch/Model/Search/CustomAttributeFilterCheck.php b/app/code/Magento/CatalogSearch/Model/Search/CustomAttributeFilterCheck.php deleted file mode 100644 index 657c8540d7c68..0000000000000 --- a/app/code/Magento/CatalogSearch/Model/Search/CustomAttributeFilterCheck.php +++ /dev/null @@ -1,61 +0,0 @@ -eavConfig = $eavConfig; - } - - /** - * Checks if FilterInterface is by custom attribute - * - * @param FilterInterface $filter - * @return bool - * @throws \Magento\Framework\Exception\LocalizedException - */ - public function isCustom(FilterInterface $filter) - { - $attribute = $this->getAttributeByCode($filter->getField()); - - return $attribute - && $filter->getType() === FilterInterface::TYPE_TERM - && in_array($attribute->getFrontendInput(), ['select', 'multiselect', 'boolean'], true); - } - - /** - * Return attribute by its code - * - * @param string $field - * @return \Magento\Catalog\Model\ResourceModel\Eav\Attribute - * @throws \Magento\Framework\Exception\LocalizedException - */ - private function getAttributeByCode($field) - { - return $this->eavConfig->getAttribute(Product::ENTITY, $field); - } -} diff --git a/app/code/Magento/CatalogSearch/Model/Search/FilterMapper/CustomAttributeFilter.php b/app/code/Magento/CatalogSearch/Model/Search/FilterMapper/CustomAttributeFilter.php deleted file mode 100644 index 8c796f8770657..0000000000000 --- a/app/code/Magento/CatalogSearch/Model/Search/FilterMapper/CustomAttributeFilter.php +++ /dev/null @@ -1,191 +0,0 @@ -resourceConnection = $resourceConnection; - $this->conditionManager = $conditionManager; - $this->eavConfig = $eavConfig; - $this->storeManager = $storeManager; - $this->aliasResolver = $aliasResolver; - } - - /** - * Applies filters by custom attributes to base select - * - * @param Select $select - * @param FilterInterface[] $filters - * @return Select - * @throws \Magento\Framework\Exception\LocalizedException - * @throws \InvalidArgumentException - * @throws \DomainException - */ - public function apply(Select $select, FilterInterface ...$filters) - { - $select = clone $select; - $mainTableAlias = $this->extractTableAliasFromSelect($select); - $attributes = []; - - foreach ($filters as $filter) { - $filterJoinAlias = $this->aliasResolver->getAlias($filter); - - $attributeId = $this->getAttributeIdByCode($filter->getField()); - - if ($attributeId === null) { - throw new \InvalidArgumentException( - sprintf('Invalid attribute id for field: %s', $filter->getField()) - ); - } - - $attributes[] = $attributeId; - - $select->joinInner( - [$filterJoinAlias => $this->resourceConnection->getTableName('catalog_product_index_eav')], - $this->conditionManager->combineQueries( - $this->getJoinConditions($attributeId, $mainTableAlias, $filterJoinAlias), - Select::SQL_AND - ), - [] - ); - } - - if (count($attributes) === 1) { - // forces usage of PRIMARY key in main table - // is required to boost performance in case when we have just one filter by custom attribute - $attribute = reset($attributes); - $filter = reset($filters); - $select->where( - $this->conditionManager->generateCondition( - sprintf('%s.attribute_id', $mainTableAlias), - '=', - $attribute - ) - )->where( - $this->conditionManager->generateCondition( - sprintf('%s.value', $mainTableAlias), - is_array($filter->getValue()) ? 'in' : '=', - $filter->getValue() - ) - ); - } - - return $select; - } - - /** - * Returns Joins conditions for table catalog_product_index_eav - * - * @param int $attrId - * @param string $mainTable - * @param string $joinTable - * @return array - */ - private function getJoinConditions($attrId, $mainTable, $joinTable) - { - return [ - sprintf('`%s`.`entity_id` = `%s`.`entity_id`', $mainTable, $joinTable), - $this->conditionManager->generateCondition( - sprintf('%s.attribute_id', $joinTable), - '=', - $attrId - ), - $this->conditionManager->generateCondition( - sprintf('%s.store_id', $joinTable), - '=', - (int) $this->storeManager->getStore()->getId() - ) - ]; - } - - /** - * Returns attribute id by code - * - * @param string $field - * @return int|null - * @throws \Magento\Framework\Exception\LocalizedException - */ - private function getAttributeIdByCode($field) - { - $attr = $this->eavConfig->getAttribute(Product::ENTITY, $field); - - return ($attr && $attr->getId()) ? (int) $attr->getId() : null; - } - - /** - * Extracts alias for table that is used in FROM clause in Select - * - * @param Select $select - * @return string|null - * @throws \Zend_Db_Select_Exception - */ - private function extractTableAliasFromSelect(Select $select) - { - $fromArr = array_filter( - $select->getPart(Select::FROM), - function ($fromPart) { - return $fromPart['joinType'] === Select::FROM; - } - ); - - return $fromArr ? array_keys($fromArr)[0] : null; - } -} diff --git a/app/code/Magento/CatalogSearch/Model/Search/FilterMapper/CustomAttributeStockStatusFilter.php b/app/code/Magento/CatalogSearch/Model/Search/FilterMapper/CustomAttributeStockStatusFilter.php deleted file mode 100644 index 28aa3df2d56b4..0000000000000 --- a/app/code/Magento/CatalogSearch/Model/Search/FilterMapper/CustomAttributeStockStatusFilter.php +++ /dev/null @@ -1,100 +0,0 @@ -eavConfig = $eavConfig; - $this->aliasResolver = $aliasResolver; - $this->stockStatusQueryBuilder = $stockStatusQueryBuilder; - } - - /** - * Apply stock status filter to provided filter - * - * @param Select $select - * @param mixed $values - * @param FilterInterface[] $filters - * @return Select - */ - public function apply(Select $select, $values = null, FilterInterface ...$filters): Select - { - $select = clone $select; - foreach ($filters as $filter) { - if ($this->isApplicable($filter)) { - $mainTableAlias = $this->aliasResolver->getAlias($filter); - $stockTableAlias = $mainTableAlias . self::STOCK_STATUS_TABLE_ALIAS_SUFFIX; - $select = $this->stockStatusQueryBuilder->apply( - $select, - $mainTableAlias, - $stockTableAlias, - 'source_id', - $values - ); - } - } - return $select; - } - - /** - * Check if stock status filter is applicable to provided filter - * - * @param FilterInterface $filter - * @return bool - */ - private function isApplicable(FilterInterface $filter): bool - { - $attribute = $this->eavConfig->getAttribute(Product::ENTITY, $filter->getField()); - return $attribute - && $filter->getType() === FilterInterface::TYPE_TERM - && in_array($attribute->getFrontendInput(), self::TARGET_ATTRIBUTE_TYPES, true); - } -} diff --git a/app/code/Magento/CatalogSearch/Model/Search/FilterMapper/DimensionsProcessor.php b/app/code/Magento/CatalogSearch/Model/Search/FilterMapper/DimensionsProcessor.php deleted file mode 100644 index 3d2b9eed03761..0000000000000 --- a/app/code/Magento/CatalogSearch/Model/Search/FilterMapper/DimensionsProcessor.php +++ /dev/null @@ -1,92 +0,0 @@ -conditionManager = $conditionManager; - $this->dimensionScopeResolver = $dimensionScopeResolver; - } - - /** - * Adds dimension conditions to select query - * - * @param SelectContainer $selectContainer - * @return SelectContainer - */ - public function processDimensions(SelectContainer $selectContainer) - { - $query = $this->conditionManager->combineQueries( - $this->prepareDimensions($selectContainer->getDimensions()), - Select::SQL_OR - ); - - if (!empty($query)) { - $select = $selectContainer->getSelect(); - $select->where($this->conditionManager->wrapBrackets($query)); - $selectContainer = $selectContainer->updateSelect($select); - } - - return $selectContainer; - } - - /** - * Prepares where conditions from dimensions - * - * @param Dimension[] $dimensions - * @return string[] - */ - private function prepareDimensions(array $dimensions) - { - $preparedDimensions = []; - - foreach ($dimensions as $dimension) { - if ('scope' === $dimension->getName()) { - continue; - } - $preparedDimensions[] = $this->conditionManager->generateCondition( - $dimension->getName(), - '=', - $this->dimensionScopeResolver->getScope($dimension->getValue())->getId() - ); - } - - return $preparedDimensions; - } -} diff --git a/app/code/Magento/CatalogSearch/Model/Search/FilterMapper/ExclusionStrategy.php b/app/code/Magento/CatalogSearch/Model/Search/FilterMapper/ExclusionStrategy.php deleted file mode 100644 index c382569338e29..0000000000000 --- a/app/code/Magento/CatalogSearch/Model/Search/FilterMapper/ExclusionStrategy.php +++ /dev/null @@ -1,222 +0,0 @@ -resourceConnection = $resourceConnection; - $this->storeManager = $storeManager; - $this->aliasResolver = $aliasResolver; - $this->tableResolver = $tableResolver ?: ObjectManager::getInstance()->get(TableResolver::class); - $this->dimensionFactory = $dimensionFactory ?: ObjectManager::getInstance()->get(DimensionFactory::class); - $this->priceTableResolver = $priceTableResolver ?: ObjectManager::getInstance()->get( - IndexScopeResolverInterface::class - ); - $this->httpContext = $httpContext ?: ObjectManager::getInstance()->get(Context::class); - } - - /** - * {@inheritDoc} - */ - public function apply( - \Magento\Framework\Search\Request\FilterInterface $filter, - \Magento\Framework\DB\Select $select - ) { - if (!in_array($filter->getField(), $this->validFields, true)) { - return false; - } - - if ($filter->getField() === 'price') { - return $this->applyPriceFilter($filter, $select); - } elseif ($filter->getField() === 'category_ids') { - return $this->applyCategoryFilter($filter, $select); - } - } - - /** - * Applies filter bt price field - * - * @param \Magento\Framework\Search\Request\FilterInterface $filter - * @param \Magento\Framework\DB\Select $select - * @return bool - * @throws \DomainException - * @throws \Magento\Framework\Exception\LocalizedException - */ - private function applyPriceFilter( - \Magento\Framework\Search\Request\FilterInterface $filter, - \Magento\Framework\DB\Select $select - ) { - $alias = $this->aliasResolver->getAlias($filter); - $websiteId = $this->storeManager->getWebsite()->getId(); - $tableName = $this->priceTableResolver->resolve( - 'catalog_product_index_price', - [ - $this->dimensionFactory->create(WebsiteDimensionProvider::DIMENSION_NAME, (string)$websiteId), - $this->dimensionFactory->create( - CustomerGroupDimensionProvider::DIMENSION_NAME, - (string)$this->httpContext->getValue(CustomerContext::CONTEXT_GROUP) - ) - ] - ); - $mainTableAlias = $this->extractTableAliasFromSelect($select); - - $select->joinInner( - [ - $alias => $tableName - ], - $this->resourceConnection->getConnection()->quoteInto( - sprintf('%s.entity_id = price_index.entity_id AND price_index.website_id = ?', $mainTableAlias), - $websiteId - ), - [] - ); - - return true; - } - - /** - * Applies filter by category - * - * @param \Magento\Framework\Search\Request\FilterInterface $filter - * @param \Magento\Framework\DB\Select $select - * @return bool - * @throws \DomainException - * @throws \Magento\Framework\Exception\LocalizedException - */ - private function applyCategoryFilter( - \Magento\Framework\Search\Request\FilterInterface $filter, - \Magento\Framework\DB\Select $select - ) { - $alias = $this->aliasResolver->getAlias($filter); - - $catalogCategoryProductDimension = new Dimension( - \Magento\Store\Model\Store::ENTITY, - $this->storeManager->getStore()->getId() - ); - - $tableName = $this->tableResolver->resolve( - AbstractAction::MAIN_INDEX_TABLE, - [ - $catalogCategoryProductDimension - ] - ); - $mainTableAlias = $this->extractTableAliasFromSelect($select); - - $select->joinInner( - [ - $alias => $tableName - ], - $this->resourceConnection->getConnection()->quoteInto( - sprintf( - '%s.entity_id = category_ids_index.product_id AND category_ids_index.store_id = ?', - $mainTableAlias - ), - $this->storeManager->getStore()->getId() - ), - [] - ); - - return true; - } - - /** - * Extracts alias for table that is used in FROM clause in Select - * - * @param \Magento\Framework\DB\Select $select - * @return string|null - */ - private function extractTableAliasFromSelect(\Magento\Framework\DB\Select $select) - { - $fromArr = array_filter( - $select->getPart(\Magento\Framework\DB\Select::FROM), - function ($fromPart) { - return $fromPart['joinType'] === \Magento\Framework\DB\Select::FROM; - } - ); - - return $fromArr ? array_keys($fromArr)[0] : null; - } -} diff --git a/app/code/Magento/CatalogSearch/Model/Search/FilterMapper/FilterContext.php b/app/code/Magento/CatalogSearch/Model/Search/FilterMapper/FilterContext.php deleted file mode 100644 index 67ed66da2a036..0000000000000 --- a/app/code/Magento/CatalogSearch/Model/Search/FilterMapper/FilterContext.php +++ /dev/null @@ -1,92 +0,0 @@ -eavConfig = $eavConfig; - $this->exclusionStrategy = $exclusionStrategy; - $this->staticAttributeStrategy = $staticAttributeStrategy; - } - - /** - * {@inheritDoc} - */ - public function apply( - \Magento\Framework\Search\Request\FilterInterface $filter, - \Magento\Framework\DB\Select $select - ) { - $isApplied = $this->exclusionStrategy->apply($filter, $select); - - if (!$isApplied) { - $attribute = $this->getAttributeByCode($filter->getField()); - if ($attribute) { - if ($filter->getType() === \Magento\Framework\Search\Request\FilterInterface::TYPE_TERM - && in_array($attribute->getFrontendInput(), ['select', 'multiselect'], true) - ) { - $isApplied = false; - } elseif ($attribute->getBackendType() === AbstractAttribute::TYPE_STATIC) { - $isApplied = $this->staticAttributeStrategy->apply($filter, $select); - } - } - } - - return $isApplied; - } - - /** - * @param string $field - * @return \Magento\Catalog\Model\ResourceModel\Eav\Attribute - * @throws \Magento\Framework\Exception\LocalizedException - */ - private function getAttributeByCode($field) - { - return $this->eavConfig->getAttribute(\Magento\Catalog\Model\Product::ENTITY, $field); - } -} diff --git a/app/code/Magento/CatalogSearch/Model/Search/FilterMapper/FilterMapper.php b/app/code/Magento/CatalogSearch/Model/Search/FilterMapper/FilterMapper.php deleted file mode 100644 index 1c4a803c1dd00..0000000000000 --- a/app/code/Magento/CatalogSearch/Model/Search/FilterMapper/FilterMapper.php +++ /dev/null @@ -1,132 +0,0 @@ -aliasResolver = $aliasResolver; - $this->customAttributeFilter = $customAttributeFilter; - $this->filterStrategy = $filterStrategy; - $this->visibilityFilter = $visibilityFilter; - $this->stockStatusFilter = $stockStatusFilter; - $this->customAttributeStockStatusFilter = $customAttributeStockStatusFilter - ?? ObjectManager::getInstance()->get(CustomAttributeStockStatusFilter::class); - } - - /** - * Applies filters to Select query in SelectContainer based on SelectContainer configuration - * - * @param SelectContainer $selectContainer - * @return SelectContainer - * @throws \Magento\Framework\Exception\LocalizedException - * @throws \InvalidArgumentException - * @throws \DomainException - */ - public function applyFilters(SelectContainer $selectContainer) - { - $select = $selectContainer->getSelect(); - - $select = $this->stockStatusFilter->apply( - $select, - Stock::STOCK_IN_STOCK, - StockStatusFilter::FILTER_JUST_ENTITY, - $selectContainer->isShowOutOfStockEnabled() - ); - - if ($selectContainer->hasCustomAttributesFilters()) { - $select = $this->customAttributeFilter->apply($select, ...$selectContainer->getCustomAttributesFilters()); - $select = $this->customAttributeStockStatusFilter->apply( - $select, - $selectContainer->isShowOutOfStockEnabled() ? null : Stock::STOCK_IN_STOCK, - ...$selectContainer->getCustomAttributesFilters() - ); - } - - $appliedFilters = []; - - if ($selectContainer->hasVisibilityFilter()) { - $filterType = VisibilityFilter::FILTER_BY_WHERE; - if ($selectContainer->hasCustomAttributesFilters()) { - $filterType = VisibilityFilter::FILTER_BY_JOIN; - } - - $select = $this->visibilityFilter->apply($select, $selectContainer->getVisibilityFilter(), $filterType); - $appliedFilters[$this->aliasResolver->getAlias($selectContainer->getVisibilityFilter())] = true; - } - - foreach ($selectContainer->getNonCustomAttributesFilters() as $filter) { - $alias = $this->aliasResolver->getAlias($filter); - - if (!array_key_exists($alias, $appliedFilters)) { - $isApplied = $this->filterStrategy->apply($filter, $select); - if ($isApplied) { - $appliedFilters[$alias] = true; - } - } - } - - $selectContainer = $selectContainer->updateSelect($select); - return $selectContainer; - } -} diff --git a/app/code/Magento/CatalogSearch/Model/Search/FilterMapper/FilterStrategyInterface.php b/app/code/Magento/CatalogSearch/Model/Search/FilterMapper/FilterStrategyInterface.php deleted file mode 100644 index a61c691c0d5cd..0000000000000 --- a/app/code/Magento/CatalogSearch/Model/Search/FilterMapper/FilterStrategyInterface.php +++ /dev/null @@ -1,28 +0,0 @@ -resourceConnection = $resourceConnection; - $this->eavConfig = $eavConfig; - $this->aliasResolver = $aliasResolver; - } - - /** - * {@inheritDoc} - */ - public function apply( - \Magento\Framework\Search\Request\FilterInterface $filter, - \Magento\Framework\DB\Select $select - ) { - $attribute = $this->getAttributeByCode($filter->getField()); - $alias = $this->aliasResolver->getAlias($filter); - $mainTableAlias = $this->extractTableAliasFromSelect($select); - - $select->joinInner( - [$alias => $attribute->getBackendTable()], - sprintf('%s.entity_id = ', $mainTableAlias) - . $this->resourceConnection->getConnection()->quoteIdentifier("$alias.entity_id"), - [] - ); - - return true; - } - - /** - * @param string $field - * @return \Magento\Catalog\Model\ResourceModel\Eav\Attribute - * @throws \Magento\Framework\Exception\LocalizedException - */ - private function getAttributeByCode($field) - { - return $this->eavConfig->getAttribute(\Magento\Catalog\Model\Product::ENTITY, $field); - } - - /** - * Extracts alias for table that is used in FROM clause in Select - * - * @param Select $select - * @return string|null - */ - private function extractTableAliasFromSelect(Select $select) - { - $fromArr = array_filter( - $select->getPart(Select::FROM), - function ($fromPart) { - return $fromPart['joinType'] === Select::FROM; - } - ); - - return $fromArr ? array_keys($fromArr)[0] : null; - } -} diff --git a/app/code/Magento/CatalogSearch/Model/Search/FilterMapper/StockStatusFilter.php b/app/code/Magento/CatalogSearch/Model/Search/FilterMapper/StockStatusFilter.php deleted file mode 100644 index 420c69a7325f6..0000000000000 --- a/app/code/Magento/CatalogSearch/Model/Search/FilterMapper/StockStatusFilter.php +++ /dev/null @@ -1,143 +0,0 @@ -resourceConnection = $resourceConnection; - $this->conditionManager = $conditionManager; - $this->stockConfiguration = $stockConfiguration; - $this->stockRegistry = $stockRegistry; - $this->stockStatusQueryBuilder = $stockStatusQueryBuilder - ?? ObjectManager::getInstance()->get(StockStatusQueryBuilder::class); - } - - /** - * Adds filter by stock status to base select - * - * @param Select $select - * @param mixed $stockValues - * @param string $type - * @param bool $showOutOfStockFlag - * @return Select - * @throws \InvalidArgumentException - */ - public function apply(Select $select, $stockValues, $type, $showOutOfStockFlag) - { - if ($type !== self::FILTER_JUST_ENTITY && $type !== self::FILTER_ENTITY_AND_SUB_PRODUCTS) { - throw new \InvalidArgumentException(sprintf('Invalid filter type: %s', $type)); - } - - $select = clone $select; - $mainTableAlias = $this->extractTableAliasFromSelect($select); - - $select = $this->stockStatusQueryBuilder->apply( - $select, - $mainTableAlias, - 'stock_index', - 'entity_id', - $showOutOfStockFlag ? null : $stockValues - ); - - if ($type === self::FILTER_ENTITY_AND_SUB_PRODUCTS) { - $select = $this->stockStatusQueryBuilder->apply( - $select, - $mainTableAlias, - 'sub_products_stock_index', - 'source_id', - $showOutOfStockFlag ? null : $stockValues - ); - } - - return $select; - } - - /** - * Extracts alias for table that is used in FROM clause in Select - * - * @param Select $select - * @return string|null - */ - private function extractTableAliasFromSelect(Select $select) - { - $fromArr = array_filter( - $select->getPart(Select::FROM), - function ($fromPart) { - return $fromPart['joinType'] === Select::FROM; - } - ); - - return $fromArr ? array_keys($fromArr)[0] : null; - } -} diff --git a/app/code/Magento/CatalogSearch/Model/Search/FilterMapper/StockStatusQueryBuilder.php b/app/code/Magento/CatalogSearch/Model/Search/FilterMapper/StockStatusQueryBuilder.php deleted file mode 100644 index 2d0d408875661..0000000000000 --- a/app/code/Magento/CatalogSearch/Model/Search/FilterMapper/StockStatusQueryBuilder.php +++ /dev/null @@ -1,106 +0,0 @@ -stockStatusResourceModel = $stockStatusResourceModel; - $this->conditionManager = $conditionManager; - $this->stockConfiguration = $stockConfiguration; - $this->stockRegistry = $stockRegistry; - } - - /** - * Add stock filter to Select - * - * @param Select $select - * @param string $mainTableAlias - * @param string $stockTableAlias - * @param string $joinField - * @param mixed $values - * @return Select - */ - public function apply( - Select $select, - string $mainTableAlias, - string $stockTableAlias, - string $joinField, - $values = null - ): Select { - $select->joinInner( - [$stockTableAlias => $this->stockStatusResourceModel->getMainTable()], - $this->conditionManager->combineQueries( - [ - sprintf('%s.product_id = %s.%s', $stockTableAlias, $mainTableAlias, $joinField), - $this->conditionManager->generateCondition( - sprintf('%s.website_id', $stockTableAlias), - '=', - $this->stockConfiguration->getDefaultScopeId() - ), - $values === null - ? '' - : $this->conditionManager->generateCondition( - sprintf('%s.stock_status', $stockTableAlias), - is_array($values) ? 'in' : '=', - $values - ), - $this->conditionManager->generateCondition( - sprintf('%s.stock_id', $stockTableAlias), - '=', - (int) $this->stockRegistry->getStock()->getStockId() - ), - ], - Select::SQL_AND - ), - [] - ); - - return $select; - } -} diff --git a/app/code/Magento/CatalogSearch/Model/Search/FilterMapper/TermDropdownStrategy.php b/app/code/Magento/CatalogSearch/Model/Search/FilterMapper/TermDropdownStrategy.php deleted file mode 100644 index 9d7e31ee3b6d1..0000000000000 --- a/app/code/Magento/CatalogSearch/Model/Search/FilterMapper/TermDropdownStrategy.php +++ /dev/null @@ -1,86 +0,0 @@ -eavConfig = $eavConfig; - $this->aliasResolver = $aliasResolver; - $this->selectBuilder = $selectBuilder ?: ObjectManager::getInstance()->get(SelectBuilder::class); - } - - /** - * {@inheritDoc} - * @throws \Magento\Framework\Exception\LocalizedException - */ - public function apply( - \Magento\Framework\Search\Request\FilterInterface $filter, - \Magento\Framework\DB\Select $select - ) { - $alias = $this->aliasResolver->getAlias($filter); - $attribute = $this->getAttributeByCode($filter->getField()); - $this->selectBuilder->execute((int)$attribute->getId(), $alias, $select); - - return true; - } - - /** - * @param string $field - * @return \Magento\Catalog\Model\ResourceModel\Eav\Attribute - * @throws \Magento\Framework\Exception\LocalizedException - */ - private function getAttributeByCode($field) - { - return $this->eavConfig->getAttribute(\Magento\Catalog\Model\Product::ENTITY, $field); - } -} diff --git a/app/code/Magento/CatalogSearch/Model/Search/FilterMapper/TermDropdownStrategy/ApplyStockConditionToSelect.php b/app/code/Magento/CatalogSearch/Model/Search/FilterMapper/TermDropdownStrategy/ApplyStockConditionToSelect.php deleted file mode 100644 index c28bc3485cf49..0000000000000 --- a/app/code/Magento/CatalogSearch/Model/Search/FilterMapper/TermDropdownStrategy/ApplyStockConditionToSelect.php +++ /dev/null @@ -1,59 +0,0 @@ -resourceConnection = $resourceConnection; - } - - /** - * @param string $alias - * @param string $stockAlias - * @param Select $select - * - * @return void - */ - public function execute( - string $alias, - string $stockAlias, - Select $select - ) { - $select->joinInner( - [$stockAlias => $this->resourceConnection->getTableName('cataloginventory_stock_status')], - sprintf( - '%2$s.product_id = %1$s.source_id AND %2$s.stock_status = %3$d', - $alias, - $stockAlias, - Status::STATUS_IN_STOCK - ), - [] - ); - } -} diff --git a/app/code/Magento/CatalogSearch/Model/Search/FilterMapper/TermDropdownStrategy/SelectBuilder.php b/app/code/Magento/CatalogSearch/Model/Search/FilterMapper/TermDropdownStrategy/SelectBuilder.php deleted file mode 100644 index 007647db39b32..0000000000000 --- a/app/code/Magento/CatalogSearch/Model/Search/FilterMapper/TermDropdownStrategy/SelectBuilder.php +++ /dev/null @@ -1,102 +0,0 @@ -resourceConnection = $resourceConnection; - $this->scopeConfig = $scopeConfig; - $this->storeManager = $storeManager; - $this->applyStockConditionToSelect = $applyStockConditionToSelect; - } - - /** - * @param int $attributeId - * @param string $alias - * @param Select $select - */ - public function execute( - int $attributeId, - string $alias, - Select $select - ) { - $joinCondition = sprintf( - 'search_index.entity_id = %1$s.entity_id AND %1$s.attribute_id = %2$d AND %1$s.store_id = %3$d', - $alias, - $attributeId, - $this->storeManager->getStore()->getId() - ); - $select->joinLeft( - [$alias => $this->resourceConnection->getTableName('catalog_product_index_eav')], - $joinCondition, - [] - ); - if ($this->isAddStockFilter()) { - $stockAlias = $alias . AliasResolver::STOCK_FILTER_SUFFIX; - $this->applyStockConditionToSelect->execute($alias, $stockAlias, $select); - } - } - - /** - * @return bool - */ - private function isAddStockFilter() - { - $isShowOutOfStock = $this->scopeConfig->isSetFlag( - 'cataloginventory/options/show_out_of_stock', - ScopeInterface::SCOPE_STORE - ); - - return false === $isShowOutOfStock; - } -} diff --git a/app/code/Magento/CatalogSearch/Model/Search/FilterMapper/VisibilityFilter.php b/app/code/Magento/CatalogSearch/Model/Search/FilterMapper/VisibilityFilter.php deleted file mode 100644 index 690ef9115edfe..0000000000000 --- a/app/code/Magento/CatalogSearch/Model/Search/FilterMapper/VisibilityFilter.php +++ /dev/null @@ -1,219 +0,0 @@ -resourceConnection = $resourceConnection; - $this->conditionManager = $conditionManager; - $this->storeManager = $storeManager; - $this->eavConfig = $eavConfig; - } - - /** - * Applies visibility filter through join or where condition - * - * @param Select $select - * @param FilterInterface $filter - * @param string $type - * @return Select - * @throws \InvalidArgumentException - * @throws \Magento\Framework\Exception\LocalizedException - */ - public function apply(Select $select, FilterInterface $filter, $type) - { - if ($type !== self::FILTER_BY_JOIN && $type !== self::FILTER_BY_WHERE) { - throw new \InvalidArgumentException(sprintf('Invalid filter type: %s', $type)); - } - - $select = clone $select; - - $type === self::FILTER_BY_JOIN - ? $this->applyFilterByJoin($filter, $select) - : $this->applyFilterByWhere($filter, $select); - - return $select; - } - - /** - * Applies filter by visibility as inner join - * - * @param Select $select - * @param FilterInterface $filter - * @return void - * @throws \InvalidArgumentException - * @throws \Magento\Framework\Exception\LocalizedException - */ - private function applyFilterByJoin(FilterInterface $filter, Select $select) - { - $mainTableAlias = $this->extractTableAliasFromSelect($select); - - $select->joinInner( - ['visibility_filter' => $this->resourceConnection->getTableName('catalog_product_index_eav')], - $this->conditionManager->combineQueries( - [ - sprintf('%s.entity_id = visibility_filter.entity_id', $mainTableAlias), - $this->conditionManager->generateCondition( - 'visibility_filter.attribute_id', - '=', - $this->getVisibilityAttributeId() - ), - $this->conditionManager->generateCondition( - 'visibility_filter.value', - is_array($filter->getValue()) ? 'in' : '=', - $filter->getValue() - ), - $this->conditionManager->generateCondition( - 'visibility_filter.store_id', - '=', - $this->storeManager->getStore()->getId() - ), - ], - Select::SQL_AND - ), - [] - ); - } - - /** - * Applies filter by visibility as where condition - * - * @param Select $select - * @param FilterInterface $filter - * @return void - * @throws \InvalidArgumentException - * @throws \Magento\Framework\Exception\LocalizedException - */ - private function applyFilterByWhere(FilterInterface $filter, Select $select) - { - $mainTableAlias = $this->extractTableAliasFromSelect($select); - - $select->where( - $this->conditionManager->combineQueries( - [ - $this->conditionManager->generateCondition( - sprintf('%s.attribute_id', $mainTableAlias), - '=', - $this->getVisibilityAttributeId() - ), - $this->conditionManager->generateCondition( - sprintf('%s.value', $mainTableAlias), - is_array($filter->getValue()) ? 'in' : '=', - $filter->getValue() - ), - $this->conditionManager->generateCondition( - sprintf('%s.store_id', $mainTableAlias), - '=', - $this->storeManager->getStore()->getId() - ), - ], - Select::SQL_AND - ) - ); - } - - /** - * Returns visibility attribute id - * - * @return int - * @throws \Magento\Framework\Exception\LocalizedException - */ - private function getVisibilityAttributeId() - { - $attr = $this->eavConfig->getAttribute( - \Magento\Catalog\Model\Product::ENTITY, - self::VISIBILITY_FILTER_FIELD - ); - - return (int) $attr->getId(); - } - - /** - * Extracts alias for table that is used in FROM clause in Select - * - * @param Select $select - * @return string|null - */ - private function extractTableAliasFromSelect(Select $select) - { - $fromArr = array_filter( - $select->getPart(Select::FROM), - function ($fromPart) { - return $fromPart['joinType'] === Select::FROM; - } - ); - - return $fromArr ? array_keys($fromArr)[0] : null; - } -} diff --git a/app/code/Magento/CatalogSearch/Model/Search/FiltersExtractor.php b/app/code/Magento/CatalogSearch/Model/Search/FiltersExtractor.php deleted file mode 100644 index 63d7ee0e6e4c0..0000000000000 --- a/app/code/Magento/CatalogSearch/Model/Search/FiltersExtractor.php +++ /dev/null @@ -1,95 +0,0 @@ -getType()) { - case QueryInterface::TYPE_BOOL: - /** @var \Magento\Framework\Search\Request\Query\BoolExpression $query */ - foreach ($query->getMust() as $subQuery) { - $filters[] = $this->extractFiltersFromQuery($subQuery); - } - foreach ($query->getShould() as $subQuery) { - $filters[] = $this->extractFiltersFromQuery($subQuery); - } - foreach ($query->getMustNot() as $subQuery) { - $filters[] = $this->extractFiltersFromQuery($subQuery); - } - break; - - case QueryInterface::TYPE_FILTER: - /** @var Filter $query */ - $filter = $query->getReference(); - if (FilterInterface::TYPE_BOOL === $filter->getType()) { - $filters[] = $this->getFiltersFromBoolFilter($filter); - } else { - $filters[] = [$filter]; - } - break; - - default: - break; - } - - return array_merge(...$filters); - } - - /** - * Returns list of filters from Bool filter - * - * @param BoolExpression $boolExpression - * @return FilterInterface[] - */ - private function getFiltersFromBoolFilter(BoolExpression $boolExpression) - { - $filters = [[]]; - - /** @var BoolExpression $filter */ - foreach ($boolExpression->getMust() as $filter) { - if ($filter->getType() === FilterInterface::TYPE_BOOL) { - $filters[] = $this->getFiltersFromBoolFilter($filter); - } else { - $filters[] = [$filter]; - } - } - foreach ($boolExpression->getShould() as $filter) { - if ($filter->getType() === FilterInterface::TYPE_BOOL) { - $filters[] = $this->getFiltersFromBoolFilter($filter); - } else { - $filters[] = [$filter]; - } - } - foreach ($boolExpression->getMustNot() as $filter) { - if ($filter->getType() === FilterInterface::TYPE_BOOL) { - $filters[] = $this->getFiltersFromBoolFilter($filter); - } else { - $filters[] = [$filter]; - } - } - return array_merge(...$filters); - } -} diff --git a/app/code/Magento/CatalogSearch/Model/Search/IndexBuilder.php b/app/code/Magento/CatalogSearch/Model/Search/IndexBuilder.php deleted file mode 100644 index 906220db28dc1..0000000000000 --- a/app/code/Magento/CatalogSearch/Model/Search/IndexBuilder.php +++ /dev/null @@ -1,118 +0,0 @@ -dimensionsProcessor = $dimensionsProcessor ?: ObjectManager::getInstance() - ->get(DimensionsProcessor::class); - - $this->selectContainerBuilder = $selectContainerBuilder ?: ObjectManager::getInstance() - ->get(SelectContainerBuilder::class); - - $this->baseSelectStrategyMapper = $baseSelectStrategyMapper ?: ObjectManager::getInstance() - ->get(BaseSelectStrategyMapper::class); - - $this->filterMapper = $filterMapper ?: ObjectManager::getInstance() - ->get(FilterMapper::class); - } - - /** - * Build index query - * - * @param RequestInterface $request - * @return Select - * @throws \DomainException - * @throws \InvalidArgumentException - * @throws \Magento\Framework\Exception\LocalizedException - */ - public function build(RequestInterface $request) - { - /** @var SelectContainer $selectContainer */ - $selectContainer = $this->selectContainerBuilder->buildByRequest($request); - - /** @var BaseSelectStrategyInterface $baseSelectStrategy */ - $baseSelectStrategy = $this->baseSelectStrategyMapper->mapSelectContainerToStrategy($selectContainer); - - $selectContainer = $baseSelectStrategy->createBaseSelect($selectContainer); - $selectContainer = $this->filterMapper->applyFilters($selectContainer); - $selectContainer = $this->dimensionsProcessor->processDimensions($selectContainer); - - return $selectContainer->getSelect(); - } -} diff --git a/app/code/Magento/CatalogSearch/Model/Search/QueryChecker/FullTextSearchCheck.php b/app/code/Magento/CatalogSearch/Model/Search/QueryChecker/FullTextSearchCheck.php deleted file mode 100644 index a47ea54375205..0000000000000 --- a/app/code/Magento/CatalogSearch/Model/Search/QueryChecker/FullTextSearchCheck.php +++ /dev/null @@ -1,123 +0,0 @@ -processQuery($query); - } - - /** - * Process query - * - * @param QueryInterface $query - * @return bool - * @throws \InvalidArgumentException - */ - private function processQuery(QueryInterface $query) - { - switch ($query->getType()) { - case QueryInterface::TYPE_MATCH: - return true; - break; - - case QueryInterface::TYPE_BOOL: - return $this->processBoolQuery($query); - break; - - case QueryInterface::TYPE_FILTER: - return $this->processFilterQuery($query); - break; - - default: - throw new \InvalidArgumentException(sprintf('Unknown query type \'%s\'', $query->getType())); - } - } - - /** - * Process boolean query - * - * @param BoolExpression $query - * @return bool - * @throws \InvalidArgumentException - */ - private function processBoolQuery(BoolExpression $query) - { - foreach ($query->getShould() as $shouldQuery) { - if ($this->processQuery($shouldQuery)) { - return true; - } - } - - foreach ($query->getMust() as $mustQuery) { - if ($this->processQuery($mustQuery)) { - return true; - } - } - - foreach ($query->getMustNot() as $mustNotQuery) { - if ($this->processQuery($mustNotQuery)) { - return true; - } - } - - return false; - } - - /** - * Process filter query - * - * @param Filter $query - * @return bool - * @throws \InvalidArgumentException - */ - private function processFilterQuery(Filter $query) - { - switch ($query->getReferenceType()) { - case Filter::REFERENCE_QUERY: - return $this->processQuery($query->getReference()); - break; - - case Filter::REFERENCE_FILTER: - return false; - break; - - default: - throw new \InvalidArgumentException( - sprintf( - 'Unknown reference type \'%s\'', - $query->getReferenceType() - ) - ); - } - } -} diff --git a/app/code/Magento/CatalogSearch/Model/Search/SelectContainer/SelectContainer.php b/app/code/Magento/CatalogSearch/Model/Search/SelectContainer/SelectContainer.php deleted file mode 100644 index f0eade4bfbcf5..0000000000000 --- a/app/code/Magento/CatalogSearch/Model/Search/SelectContainer/SelectContainer.php +++ /dev/null @@ -1,202 +0,0 @@ -nonCustomAttributesFilters = $nonCustomAttributesFilters; - $this->customAttributesFilters = $customAttributesFilters; - $this->visibilityFilter = $visibilityFilter; - $this->isFullTextSearchRequired = $isFullTextSearchRequired; - $this->isShowOutOfStockEnabled = $isShowOutOfStockEnabled; - $this->select = $select; - $this->usedIndex = $usedIndex; - $this->dimensions = $dimensions; - } - - /** - * @return array - */ - public function getNonCustomAttributesFilters() - { - return $this->nonCustomAttributesFilters; - } - - /** - * @return array - */ - public function getCustomAttributesFilters() - { - return $this->customAttributesFilters; - } - - /** - * @return bool - */ - public function hasCustomAttributesFilters() - { - return count($this->customAttributesFilters) > 0; - } - - /** - * @return bool - */ - public function hasVisibilityFilter() - { - return $this->visibilityFilter !== null; - } - - /** - * Returns a null or copy of FilterInterface - * This is done to ensure that SelectContainer is immutable - * - * @return FilterInterface - */ - public function getVisibilityFilter() - { - return $this->visibilityFilter === null ? null : clone $this->visibilityFilter; - } - - /** - * @return bool - */ - public function isFullTextSearchRequired() - { - return $this->isFullTextSearchRequired; - } - - /** - * @return bool - */ - public function isShowOutOfStockEnabled() - { - return $this->isShowOutOfStockEnabled; - } - - /** - * @return string - */ - public function getUsedIndex() - { - return $this->usedIndex; - } - - /** - * @return array - */ - public function getDimensions() - { - return $this->dimensions; - } - - /** - * Returns a copy of Select - * This is done to ensure that SelectContainer is immutable - * - * @return Select - */ - public function getSelect() - { - return clone $this->select; - } - - /** - * Returns new instance of SelectContainer on update - * This is done to ensure that SelectContainer is immutable - * - * @param Select $select - * @return SelectContainer - */ - public function updateSelect(Select $select) - { - $data = [ - clone $select, - $this->nonCustomAttributesFilters, - $this->customAttributesFilters, - $this->dimensions, - $this->isFullTextSearchRequired, - $this->isShowOutOfStockEnabled, - $this->usedIndex - - ]; - - if ($this->visibilityFilter !== null) { - $data[] = clone $this->visibilityFilter; - } - - return new self(...$data); - } -} diff --git a/app/code/Magento/CatalogSearch/Model/Search/SelectContainer/SelectContainerBuilder.php b/app/code/Magento/CatalogSearch/Model/Search/SelectContainer/SelectContainerBuilder.php deleted file mode 100644 index d5b7be8bf0106..0000000000000 --- a/app/code/Magento/CatalogSearch/Model/Search/SelectContainer/SelectContainerBuilder.php +++ /dev/null @@ -1,136 +0,0 @@ -selectContainerFactory = $selectContainerFactory; - $this->fullTextSearchCheck = $fullTextSearchCheck; - $this->customAttributeFilterCheck = $customAttributeFilterCheck; - $this->filtersExtractor = $filtersExtractor; - $this->scopeConfig = $scopeConfig; - $this->resource = $resource; - } - - /** - * Builds SelectContainer with all required data - * - * @param RequestInterface $request - * @return SelectContainer - * @throws \DomainException - * @throws \InvalidArgumentException - * @throws \Magento\Framework\Exception\LocalizedException - */ - public function buildByRequest(RequestInterface $request) - { - $nonCustomAttributesFilters = []; - $customAttributesFilters = []; - $visibilityFilter = null; - - foreach ($this->filtersExtractor->extractFiltersFromQuery($request->getQuery()) as $filter) { - if ($this->customAttributeFilterCheck->isCustom($filter)) { - if ($filter->getField() === VisibilityFilter::VISIBILITY_FILTER_FIELD) { - $visibilityFilter = clone $filter; - } else { - $customAttributesFilters[] = clone $filter; - } - } else { - $nonCustomAttributesFilters[] = clone $filter; - } - } - - $data = [ - 'select' => $this->resource->getConnection()->select(), - 'nonCustomAttributesFilters' => $nonCustomAttributesFilters, - 'customAttributesFilters' => $customAttributesFilters, - 'dimensions' => $request->getDimensions(), - 'isFullTextSearchRequired' => $this->fullTextSearchCheck->isRequiredForQuery($request->getQuery()), - 'isShowOutOfStockEnabled' => $this->isSetShowOutOfStockFlag(), - 'usedIndex' => $request->getIndex() - ]; - - if ($visibilityFilter !== null) { - $data['visibilityFilter'] = $visibilityFilter; - } - - return $this->selectContainerFactory->create($data); - } - - /** - * Checks if show_out_of_stock flag is enabled in current configuration - * - * @return bool - */ - private function isSetShowOutOfStockFlag() - { - return $this->scopeConfig->isSetFlag( - 'cataloginventory/options/show_out_of_stock', - ScopeInterface::SCOPE_STORE - ); - } -} diff --git a/app/code/Magento/CatalogSearch/Model/Search/TableMapper.php b/app/code/Magento/CatalogSearch/Model/Search/TableMapper.php deleted file mode 100644 index 6b18c4307f515..0000000000000 --- a/app/code/Magento/CatalogSearch/Model/Search/TableMapper.php +++ /dev/null @@ -1,121 +0,0 @@ -get(FilterStrategyInterface::class); - } - if (null === $aliasResolver) { - $aliasResolver = ObjectManager::getInstance()->get(AliasResolver::class); - } - if (null === $filtersExtractor) { - $filtersExtractor = ObjectManager::getInstance()->get(FiltersExtractor::class); - } - - $this->filterStrategy = $filterStrategy; - $this->aliasResolver = $aliasResolver; - $this->filtersExtractor = $filtersExtractor; - } - - /** - * @param Select $select - * @param RequestInterface $request - * @return Select - * @throws \LogicException - */ - public function addTables(Select $select, RequestInterface $request) - { - $appliedFilters = []; - $filters = $this->filtersExtractor->extractFiltersFromQuery($request->getQuery()); - foreach ($filters as $filter) { - $alias = $this->aliasResolver->getAlias($filter); - if (!array_key_exists($alias, $appliedFilters)) { - $isApplied = $this->filterStrategy->apply($filter, $select); - if ($isApplied) { - $appliedFilters[$alias] = true; - } - } - } - return $select; - } - - /** - * This method is deprecated. - * Please use \Magento\CatalogSearch\Model\Adapter\Mysql\Filter\AliasResolver::getAlias() instead. - * - * @deprecated 100.1.6 - * @see AliasResolver::getAlias() - * - * @param FilterInterface $filter - * @return string - */ - public function getMappingAlias(FilterInterface $filter) - { - return $this->aliasResolver->getAlias($filter); - } -} diff --git a/app/code/Magento/CatalogSearch/Plugin/EnableEavIndexer.php b/app/code/Magento/CatalogSearch/Plugin/EnableEavIndexer.php deleted file mode 100644 index 956a1b2360f89..0000000000000 --- a/app/code/Magento/CatalogSearch/Plugin/EnableEavIndexer.php +++ /dev/null @@ -1,36 +0,0 @@ -getData(self::SEARCH_ENGINE_VALUE_PATH); - if ($searchEngine === 'mysql') { - $data = $subject->getData(); - $data['groups']['search']['fields']['enable_eav_indexer']['value'] = 1; - - $subject->setData($data); - } - } -} diff --git a/app/code/Magento/CatalogSearch/Setup/Patch/Data/SetInitialSearchWeightForAttributes.php b/app/code/Magento/CatalogSearch/Setup/Patch/Data/SetInitialSearchWeightForAttributes.php index 21d5e82d494b5..410c468744ae9 100644 --- a/app/code/Magento/CatalogSearch/Setup/Patch/Data/SetInitialSearchWeightForAttributes.php +++ b/app/code/Magento/CatalogSearch/Setup/Patch/Data/SetInitialSearchWeightForAttributes.php @@ -14,13 +14,9 @@ /** * This patch sets up search weight for the product's system attributes, reindex required after patch applying. - * - * @deprecated - * @see \Magento\ElasticSearch */ class SetInitialSearchWeightForAttributes implements DataPatchInterface, PatchVersionInterface { - /** * @var IndexerInterfaceFactory */ @@ -68,6 +64,7 @@ function () use ($indexer) { ->save(); } ); + return $this; } /** diff --git a/app/code/Magento/CatalogSearch/Test/Mftf/Test/MinimalQueryLengthForCatalogSearchTest.xml b/app/code/Magento/CatalogSearch/Test/Mftf/Test/MinimalQueryLengthForCatalogSearchTest.xml index fd8615dd257ca..44bfc66a466a8 100644 --- a/app/code/Magento/CatalogSearch/Test/Mftf/Test/MinimalQueryLengthForCatalogSearchTest.xml +++ b/app/code/Magento/CatalogSearch/Test/Mftf/Test/MinimalQueryLengthForCatalogSearchTest.xml @@ -19,13 +19,11 @@ - - - + - + @@ -39,7 +37,8 @@ - + + diff --git a/app/code/Magento/CatalogSearch/Test/Mftf/Test/SearchEntityResultsTest/QuickSearchProductByNameWithThreeLettersTest.xml b/app/code/Magento/CatalogSearch/Test/Mftf/Test/SearchEntityResultsTest/QuickSearchProductByNameWithThreeLettersTest.xml index f01997b1f33d9..36977f476756e 100644 --- a/app/code/Magento/CatalogSearch/Test/Mftf/Test/SearchEntityResultsTest/QuickSearchProductByNameWithThreeLettersTest.xml +++ b/app/code/Magento/CatalogSearch/Test/Mftf/Test/SearchEntityResultsTest/QuickSearchProductByNameWithThreeLettersTest.xml @@ -17,9 +17,6 @@ - - - diff --git a/app/code/Magento/CatalogSearch/Test/Mftf/Test/SearchEntityResultsTest/QuickSearchTwoProductsWithSameWeightTest.xml b/app/code/Magento/CatalogSearch/Test/Mftf/Test/SearchEntityResultsTest/QuickSearchTwoProductsWithSameWeightTest.xml index d6d59240dcec8..e1488f4d000eb 100644 --- a/app/code/Magento/CatalogSearch/Test/Mftf/Test/SearchEntityResultsTest/QuickSearchTwoProductsWithSameWeightTest.xml +++ b/app/code/Magento/CatalogSearch/Test/Mftf/Test/SearchEntityResultsTest/QuickSearchTwoProductsWithSameWeightTest.xml @@ -17,9 +17,6 @@ - - - @@ -31,7 +28,6 @@ - @@ -79,6 +75,7 @@ + @@ -86,11 +83,11 @@ - + - + diff --git a/app/code/Magento/CatalogSearch/Test/Mftf/Test/StorefrontAdvancedSearchByPartialNameTest.xml b/app/code/Magento/CatalogSearch/Test/Mftf/Test/StorefrontAdvancedSearchByPartialNameTest.xml index 1430f32c81162..d8f8924c4db0b 100644 --- a/app/code/Magento/CatalogSearch/Test/Mftf/Test/StorefrontAdvancedSearchByPartialNameTest.xml +++ b/app/code/Magento/CatalogSearch/Test/Mftf/Test/StorefrontAdvancedSearchByPartialNameTest.xml @@ -19,7 +19,7 @@ - + diff --git a/app/code/Magento/CatalogSearch/Test/Mftf/Test/StorefrontPartialWordQuickSearchUsingElasticSearchTest.xml b/app/code/Magento/CatalogSearch/Test/Mftf/Test/StorefrontPartialWordQuickSearchUsingElasticSearchTest.xml new file mode 100644 index 0000000000000..6b0146d579cbc --- /dev/null +++ b/app/code/Magento/CatalogSearch/Test/Mftf/Test/StorefrontPartialWordQuickSearchUsingElasticSearchTest.xml @@ -0,0 +1,60 @@ + + + + + + + + + + <description value="Support quick search with Partial word search using ES"/> + <severity value="CRITICAL"/> + <testCaseId value="MC-34205"/> + <group value="SearchEngineElasticsearch"/> + </annotations> + <before> + <!-- Create subcategory --> + <createData entity="SimpleSubCategory" stepKey="newCategory"/> + <createData entity="ProductForPartialSearch" stepKey="product1"> + <requiredEntity createDataKey="newCategory"/> + </createData> + <createData entity="ApiSimpleProduct" stepKey="product2"> + <requiredEntity createDataKey="newCategory"/> + </createData> + <createData entity="ApiSimpleProductWithNoSpace" stepKey="product3"> + <requiredEntity createDataKey="newCategory"/> + </createData> + </before> + <after> + <deleteData createDataKey="product1" stepKey="deleteProduct1"/> + <deleteData createDataKey="product2" stepKey="deleteProduct2"/> + <deleteData createDataKey="product3" stepKey="deleteProduct3"/> + <deleteData createDataKey="newCategory" stepKey="deleteCategory"/> + </after> + + <actionGroup ref="StorefrontOpenHomePageActionGroup" stepKey="goToHomePage"/> + + <!--Perform a quick seach using a partial word from product SKU--> + <actionGroup ref="StorefrontCheckQuickSearchStringActionGroup" stepKey="quickSearchPartialSku"> + <argument name="phrase" value="partial"/> + </actionGroup> + + <!--Perform a case insensitive quick search of partial word using case product name --> + <actionGroup ref="StorefrontCheckQuickSearchStringActionGroup" stepKey="quickSearchPartialCaseInSensitive"> + <argument name="phrase" value="simple"/> + </actionGroup> + <!--Perform a quick search using parts of the words from name/sku with additional characters--> + <actionGroup ref="StorefrontCheckQuickSearchStringActionGroup" stepKey="quickSearchPartialWordsWithExtraChars"> + <argument name="phrase" value="barstool"/> + </actionGroup> + <actionGroup ref="StorefrontCheckSearchIsEmptyActionGroup" stepKey="checkEmptySearchResult"/> + + </test> +</tests> + diff --git a/app/code/Magento/CatalogSearch/Test/Unit/Model/Adapter/Mysql/Aggregation/DataProvider/QueryBuilderTest.php b/app/code/Magento/CatalogSearch/Test/Unit/Model/Adapter/Mysql/Aggregation/DataProvider/QueryBuilderTest.php deleted file mode 100644 index a702f69f73152..0000000000000 --- a/app/code/Magento/CatalogSearch/Test/Unit/Model/Adapter/Mysql/Aggregation/DataProvider/QueryBuilderTest.php +++ /dev/null @@ -1,181 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -declare(strict_types=1); - -namespace Magento\CatalogSearch\Test\Unit\Model\Adapter\Mysql\Aggregation\DataProvider; - -use Magento\CatalogInventory\Model\Configuration as CatalogInventoryConfiguration; -use Magento\CatalogInventory\Model\Stock; -use Magento\CatalogSearch\Model\Adapter\Mysql\Aggregation\DataProvider\QueryBuilder; -use Magento\Eav\Model\Entity\Attribute\AbstractAttribute; -use Magento\Framework\App\ResourceConnection; -use Magento\Framework\App\ScopeResolverInterface; -use Magento\Framework\DB\Adapter\AdapterInterface; -use Magento\Framework\DB\Select; -use Magento\Framework\Indexer\Dimension; -use Magento\Framework\Indexer\DimensionFactory; -use Magento\Framework\Search\Request\IndexScopeResolverInterface; -use Magento\Store\Api\Data\StoreInterface; -use Magento\Store\Model\Store; -use Magento\Store\Model\StoreManagerInterface; -use PHPUnit\Framework\MockObject\MockObject; -use PHPUnit\Framework\TestCase; - -/** - * Test for Magento\CatalogSearch\Model\Adapter\Mysql\Aggregation\DataProvider\QueryBuilder. - * - * @SuppressWarnings(PHPMD.CouplingBetweenObjects) - * @deprecated Implementation class was replaced - * @see \Magento\ElasticSearch - */ -class QueryBuilderTest extends TestCase -{ - /** @var QueryBuilder */ - private $model; - - /** @var MockObject */ - private $resourceConnectionMock; - - /** @var MockObject */ - private $scopeResolverMock; - - /** @var MockObject */ - private $adapterMock; - - /** @var MockObject */ - private $inventoryConfigMock; - - /** @var IndexScopeResolverInterface|MockObject */ - private $indexScopeResolverMock; - - /** @var Dimension|MockObject */ - private $dimensionMock; - - /** @var DimensionFactory|MockObject */ - private $dimensionFactoryMock; - - /** @var StoreManagerInterface|MockObject */ - private $storeManagerMock; - - protected function setUp(): void - { - $this->resourceConnectionMock = $this->createMock(ResourceConnection::class); - $this->scopeResolverMock = $this->getMockForAbstractClass(ScopeResolverInterface::class); - $this->adapterMock = $this->getMockForAbstractClass(AdapterInterface::class); - $this->inventoryConfigMock = $this->createMock(CatalogInventoryConfiguration::class); - - $this->resourceConnectionMock->expects($this->atLeastOnce()) - ->method('getConnection') - ->willReturn($this->adapterMock); - - $this->indexScopeResolverMock = $this->createMock( - IndexScopeResolverInterface::class - ); - $this->dimensionMock = $this->createMock(Dimension::class); - $this->dimensionFactoryMock = $this->createMock(DimensionFactory::class); - $this->dimensionFactoryMock->method('create')->willReturn($this->dimensionMock); - $storeMock = $this->getMockForAbstractClass(StoreInterface::class); - $storeMock->method('getId')->willReturn(1); - $storeMock->method('getWebsiteId')->willReturn(1); - $this->storeManagerMock = $this->getMockForAbstractClass(StoreManagerInterface::class); - $this->storeManagerMock->method('getStore')->willReturn($storeMock); - $this->indexScopeResolverMock->method('resolve')->willReturn('catalog_product_index_price'); - - $this->model = new QueryBuilder( - $this->resourceConnectionMock, - $this->scopeResolverMock, - $this->inventoryConfigMock, - $this->indexScopeResolverMock, - $this->dimensionFactoryMock - ); - } - - public function testBuildWithPriceAttributeCode() - { - $tableName = 'test_table'; - $scope = 1; - $selectMock = $this->createMock(Select::class); - $attributeMock = $this->createMock(AbstractAttribute::class); - $storeMock = $this->createMock(Store::class); - - $this->adapterMock->expects($this->atLeastOnce())->method('select') - ->willReturn($selectMock); - $selectMock->expects($this->once())->method('joinInner') - ->with(['entities' => $tableName], 'main_table.entity_id = entities.entity_id', []); - $attributeMock->expects($this->once())->method('getAttributeCode') - ->willReturn('price'); - $this->scopeResolverMock->expects($this->once())->method('getScope') - ->with($scope)->willReturn($storeMock); - $storeMock->expects($this->once())->method('getWebsiteId')->willReturn(1); - $selectMock->expects($this->once())->method('from') - ->with(['main_table' => 'catalog_product_index_price'], null) - ->willReturn($selectMock); - $selectMock->expects($this->once())->method('columns') - ->with(['value' => 'main_table.min_price']) - ->willReturn($selectMock); - $selectMock->expects($this->exactly(2))->method('where') - ->withConsecutive( - ['main_table.customer_group_id = ?', 1], - ['main_table.website_id = ?', 1] - )->willReturn($selectMock); - - $this->model->build($attributeMock, $tableName, $scope, 1); - } - - public function testBuildWithNotPriceAttributeCode() - { - $tableName = 'test_table'; - $scope = 1; - $selectMock = $this->createMock(Select::class); - $attributeMock = $this->createMock(AbstractAttribute::class); - $storeMock = $this->createMock(Store::class); - - $this->adapterMock->expects($this->atLeastOnce())->method('select') - ->willReturn($selectMock); - $selectMock->expects($this->once())->method('joinInner') - ->with(['entities' => $tableName], 'main_table.entity_id = entities.entity_id', []); - $attributeMock->expects($this->once())->method('getBackendType') - ->willReturn('decimal'); - $this->scopeResolverMock->expects($this->once())->method('getScope') - ->with($scope)->willReturn($storeMock); - $storeMock->expects($this->once())->method('getId')->willReturn(1); - $this->resourceConnectionMock->expects($this->exactly(2))->method('getTableName') - ->withConsecutive( - ['catalog_product_index_eav_decimal'], - ['cataloginventory_stock_status'] - )->willReturnOnConsecutiveCalls( - 'catalog_product_index_eav_decimal', - 'cataloginventory_stock_status' - ); - - $selectMock->expects($this->exactly(2))->method('from') - ->withConsecutive( - [ - ['main_table' => 'catalog_product_index_eav_decimal'], - ['main_table.entity_id', 'main_table.value'] - ], - [['main_table' => $selectMock], ['main_table.value']] - ) - ->willReturn($selectMock); - $selectMock->expects($this->once())->method('distinct')->willReturn($selectMock); - $selectMock->expects($this->once())->method('joinLeft') - ->with( - ['stock_index' => 'cataloginventory_stock_status'], - 'main_table.source_id = stock_index.product_id', - [] - )->willReturn($selectMock); - $attributeMock->expects($this->once())->method('getAttributeId')->willReturn(3); - $selectMock->expects($this->exactly(3))->method('where') - ->withConsecutive( - ['main_table.attribute_id = ?', 3], - ['main_table.store_id = ? ', 1], - ['stock_index.stock_status = ?', Stock::STOCK_IN_STOCK] - )->willReturn($selectMock); - $this->inventoryConfigMock->expects($this->once())->method('isShowOutOfStock')->with(1)->willReturn(false); - - $this->model->build($attributeMock, $tableName, $scope, 1); - } -} diff --git a/app/code/Magento/CatalogSearch/Test/Unit/Model/Adapter/Mysql/Aggregation/DataProviderTest.php b/app/code/Magento/CatalogSearch/Test/Unit/Model/Adapter/Mysql/Aggregation/DataProviderTest.php deleted file mode 100644 index bc039f7d85678..0000000000000 --- a/app/code/Magento/CatalogSearch/Test/Unit/Model/Adapter/Mysql/Aggregation/DataProviderTest.php +++ /dev/null @@ -1,148 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -declare(strict_types=1); - -namespace Magento\CatalogSearch\Test\Unit\Model\Adapter\Mysql\Aggregation; - -use Magento\Catalog\Model\Product; -use Magento\CatalogSearch\Model\Adapter\Mysql\Aggregation\DataProvider; -use Magento\CatalogSearch\Model\Adapter\Mysql\Aggregation\DataProvider\SelectBuilderForAttribute; -use Magento\Customer\Model\Session; -use Magento\Eav\Model\Config; -use Magento\Eav\Model\Entity\Attribute; -use Magento\Framework\App\ResourceConnection; -use Magento\Framework\App\ScopeResolverInterface; -use Magento\Framework\DB\Adapter\AdapterInterface; -use Magento\Framework\DB\Ddl\Table; -use Magento\Framework\DB\Select; -use Magento\Framework\Event\Manager; -use Magento\Framework\Search\Request\BucketInterface; -use Magento\Framework\Search\Request\Dimension; -use Magento\Store\Model\Store; -use PHPUnit\Framework\MockObject\MockObject; -use PHPUnit\Framework\TestCase; - -/** - * @SuppressWarnings(PHPMD.CouplingBetweenObjects) - * - * @deprecated Implementation class was replaced - * @see \Magento\ElasticSearch - */ -class DataProviderTest extends TestCase -{ - /** - * @var DataProvider - */ - private $model; - - /** - * @var MockObject - */ - private $eavConfigMock; - - /** - * @var MockObject - */ - private $sessionMock; - - /** - * @var MockObject - */ - private $resourceConnectionMock; - - /** - * @var MockObject - */ - private $scopeResolverMock; - - /** - * @var MockObject - */ - private $adapterMock; - - /** - * @var MockObject|SelectBuilderForAttribute - */ - private $selectBuilderForAttribute; - - /** - * @var Manager|MockObject - */ - private $eventManager; - - protected function setUp(): void - { - $this->eavConfigMock = $this->createMock(Config::class); - $this->resourceConnectionMock = $this->createMock(ResourceConnection::class); - $this->scopeResolverMock = $this->getMockForAbstractClass(ScopeResolverInterface::class); - $this->sessionMock = $this->createMock(Session::class); - $this->adapterMock = $this->getMockForAbstractClass(AdapterInterface::class); - $this->resourceConnectionMock->expects($this->once())->method('getConnection')->willReturn($this->adapterMock); - $this->selectBuilderForAttribute = $this->createMock(SelectBuilderForAttribute::class); - $this->eventManager = $this->createMock(Manager::class); - $this->model = new DataProvider( - $this->eavConfigMock, - $this->resourceConnectionMock, - $this->scopeResolverMock, - $this->sessionMock, - $this->selectBuilderForAttribute, - $this->eventManager - ); - } - - public function testGetDataSetUsesFrontendPriceIndexerTableIfAttributeIsPrice() - { - $storeId = 1; - $attributeCode = 'price'; - - $scopeMock = $this->createMock(Store::class); - $scopeMock->expects($this->atLeastOnce())->method('getId')->willReturn($storeId); - $dimensionMock = $this->createMock(Dimension::class); - $dimensionMock->expects($this->atLeastOnce())->method('getValue')->willReturn($storeId); - $this->scopeResolverMock->expects($this->any())->method('getScope')->with($storeId)->willReturn($scopeMock); - - $bucketMock = $this->getMockForAbstractClass(BucketInterface::class); - $bucketMock->expects($this->once())->method('getField')->willReturn($attributeCode); - $attributeMock = $this->createMock(Attribute::class); - $this->eavConfigMock->expects($this->once()) - ->method('getAttribute')->with(Product::ENTITY, $attributeCode) - ->willReturn($attributeMock); - - $selectMock = $this->createMock(Select::class); - $this->adapterMock->expects($this->atLeastOnce())->method('select')->willReturn($selectMock); - $this->eventManager->expects($this->once())->method('dispatch')->willReturn($selectMock); - $tableMock = $this->createMock(Table::class); - - $this->model->getDataSet($bucketMock, ['scope' => $dimensionMock], $tableMock); - } - - public function testGetDataSetUsesFrontendPriceIndexerTableForDecimalAttributes() - { - $storeId = 1; - $attributeCode = 'my_decimal'; - - $scopeMock = $this->createMock(Store::class); - $scopeMock->expects($this->atLeastOnce())->method('getId')->willReturn($storeId); - $dimensionMock = $this->createMock(Dimension::class); - $dimensionMock->expects($this->atLeastOnce())->method('getValue')->willReturn($storeId); - $this->scopeResolverMock->expects($this->atLeastOnce())->method('getScope')->with($storeId) - ->willReturn($scopeMock); - - $bucketMock = $this->getMockForAbstractClass(BucketInterface::class); - $bucketMock->expects($this->once())->method('getField')->willReturn($attributeCode); - $attributeMock = $this->createMock(Attribute::class); - $this->eavConfigMock->expects($this->once()) - ->method('getAttribute')->with(Product::ENTITY, $attributeCode) - ->willReturn($attributeMock); - - $selectMock = $this->createMock(Select::class); - $this->selectBuilderForAttribute->expects($this->once())->method('build')->willReturn($selectMock); - $this->adapterMock->expects($this->atLeastOnce())->method('select')->willReturn($selectMock); - $this->eventManager->expects($this->once())->method('dispatch')->willReturn($selectMock); - $tableMock = $this->createMock(Table::class); - $this->model->getDataSet($bucketMock, ['scope' => $dimensionMock], $tableMock); - } -} diff --git a/app/code/Magento/CatalogSearch/Test/Unit/Model/Adapter/Mysql/Dynamic/DataProviderTest.php b/app/code/Magento/CatalogSearch/Test/Unit/Model/Adapter/Mysql/Dynamic/DataProviderTest.php deleted file mode 100644 index 29e4eb2ec4dfd..0000000000000 --- a/app/code/Magento/CatalogSearch/Test/Unit/Model/Adapter/Mysql/Dynamic/DataProviderTest.php +++ /dev/null @@ -1,117 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -declare(strict_types=1); - -namespace Magento\CatalogSearch\Test\Unit\Model\Adapter\Mysql\Dynamic; - -use Magento\Catalog\Model\Layer\Filter\Price\Range; -use Magento\CatalogSearch\Model\Adapter\Mysql\Dynamic\DataProvider; -use Magento\Customer\Model\Session; -use Magento\Framework\App\ResourceConnection; -use Magento\Framework\DB\Adapter\AdapterInterface; -use Magento\Framework\DB\Ddl\Table; -use Magento\Framework\DB\Select; -use Magento\Framework\Indexer\Dimension; -use Magento\Framework\Indexer\DimensionFactory; -use Magento\Framework\Search\Adapter\Mysql\Aggregation\DataProviderInterface; -use Magento\Framework\Search\Dynamic\EntityStorage; -use Magento\Framework\Search\Dynamic\IntervalFactory; -use Magento\Framework\Search\Request\IndexScopeResolverInterface; -use Magento\Store\Api\Data\StoreInterface; -use Magento\Store\Model\StoreManager; -use PHPUnit\Framework\MockObject\MockObject; -use PHPUnit\Framework\TestCase; - -/** - * @SuppressWarnings(PHPMD.CouplingBetweenObjects) - * @deprecated Implementation class was replaced - * @see \Magento\ElasticSearch - */ -class DataProviderTest extends TestCase -{ - /**@var DataProvider */ - private $model; - - /**@var Session|MockObject */ - private $sessionMock; - - /**@var ResourceConnection|MockObject */ - private $resourceConnectionMock; - - /**@var Range|MockObject */ - private $rangeMock; - - /**@var MockObject */ - private $adapterMock; - - /**@var DataProviderInterface|MockObject */ - private $mysqlDataProviderMock; - - /**@var IntervalFactory|MockObject */ - private $intervalFactoryMock; - - /**@var StoreManager|MockObject */ - private $storeManagerMock; - - /**@var IndexScopeResolverInterface|MockObject */ - private $indexScopeResolverMock; - - /**@var Dimension|MockObject */ - private $dimensionMock; - - /**@var DimensionFactory|MockObject */ - private $dimensionFactoryMock; - - protected function setUp(): void - { - $this->resourceConnectionMock = $this->createMock(ResourceConnection::class); - $this->sessionMock = $this->createMock(Session::class); - $this->adapterMock = $this->getMockForAbstractClass(AdapterInterface::class); - $this->resourceConnectionMock->expects($this->once())->method('getConnection')->willReturn($this->adapterMock); - $this->rangeMock = $this->createMock(Range::class); - $this->mysqlDataProviderMock = $this->getMockForAbstractClass(DataProviderInterface::class); - $this->intervalFactoryMock = $this->createMock(IntervalFactory::class); - $this->storeManagerMock = $this->createMock(StoreManager::class); - $this->indexScopeResolverMock = $this->createMock( - IndexScopeResolverInterface::class - ); - $this->dimensionMock = $this->createMock(Dimension::class); - $this->dimensionFactoryMock = $this->createMock(DimensionFactory::class); - $this->dimensionFactoryMock->method('create')->willReturn($this->dimensionMock); - $storeMock = $this->getMockForAbstractClass(StoreInterface::class); - $storeMock->method('getId')->willReturn(1); - $storeMock->method('getWebsiteId')->willReturn(1); - $this->storeManagerMock->method('getStore')->willReturn($storeMock); - $this->indexScopeResolverMock->method('resolve')->willReturn('catalog_product_index_price'); - $this->sessionMock->method('getCustomerGroupId')->willReturn(1); - - $this->model = new DataProvider( - $this->resourceConnectionMock, - $this->rangeMock, - $this->sessionMock, - $this->mysqlDataProviderMock, - $this->intervalFactoryMock, - $this->storeManagerMock, - $this->indexScopeResolverMock, - $this->dimensionFactoryMock - ); - } - - public function testGetAggregationsUsesFrontendPriceIndexerTable() - { - $selectMock = $this->createMock(Select::class); - $selectMock->expects($this->any())->method('from')->willReturnSelf(); - $selectMock->expects($this->any())->method('where')->willReturnSelf(); - $selectMock->expects($this->any())->method('columns')->willReturnSelf(); - $this->adapterMock->expects($this->once())->method('select')->willReturn($selectMock); - $tableMock = $this->createMock(Table::class); - - $entityStorageMock = $this->createMock(EntityStorage::class); - $entityStorageMock->expects($this->any())->method('getSource')->willReturn($tableMock); - - $this->model->getAggregations($entityStorageMock); - } -} diff --git a/app/code/Magento/CatalogSearch/Test/Unit/Model/Adapter/Mysql/Field/ResolverTest.php b/app/code/Magento/CatalogSearch/Test/Unit/Model/Adapter/Mysql/Field/ResolverTest.php deleted file mode 100644 index 67f425cadf34b..0000000000000 --- a/app/code/Magento/CatalogSearch/Test/Unit/Model/Adapter/Mysql/Field/ResolverTest.php +++ /dev/null @@ -1,122 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -declare(strict_types=1); - -namespace Magento\CatalogSearch\Test\Unit\Model\Adapter\Mysql\Field; - -use Magento\Catalog\Model\ResourceModel\Product\Attribute\Collection; -use Magento\CatalogSearch\Model\Adapter\Mysql\Field\Resolver; -use Magento\Framework\DataObject; -use Magento\Framework\Search\Adapter\Mysql\Field\Field; -use Magento\Framework\Search\Adapter\Mysql\Field\FieldFactory; -use Magento\Framework\Search\Adapter\Mysql\Field\FieldInterface; -use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; -use PHPUnit\Framework\MockObject\MockObject; -use PHPUnit\Framework\TestCase; - -/** - * Unit tests for Magento\CatalogSearch\Model\Adapter\Mysql\Field\Resolver class. - * - * @deprecated Implementation class was replaced - * @see \Magento\ElasticSearch - */ -class ResolverTest extends TestCase -{ - /** - * @var Collection|MockObject - */ - private $attributeCollection; - - /** - * @var FieldFactory|MockObject - */ - private $fieldFactory; - - /** - * @var Resolver - */ - private $model; - - /** - * @inheritdoc - */ - protected function setUp(): void - { - $this->attributeCollection = $this->getMockBuilder( - Collection::class - ) - ->disableOriginalConstructor() - ->getMock(); - $this->fieldFactory = $this->getMockBuilder(FieldFactory::class) - ->disableOriginalConstructor() - ->setMethods(['create']) - ->getMock(); - - $objectManagerHelper = new ObjectManager($this); - $this->model = $objectManagerHelper->getObject( - Resolver::class, - [ - 'attributeCollection' => $this->attributeCollection, - 'fieldFactory' => $this->fieldFactory, - ] - ); - } - - /** - * Test resolve method. - * - * @param array $fields - * @param int|null $attributeId - * @param MockObject $field - * @param array $expectedResult - * @return void - * @dataProvider resolveDataProvider - */ - public function testResolve( - array $fields, - $attributeId, - MockObject $field, - array $expectedResult - ) { - $item = $this->getMockBuilder(DataObject::class) - ->disableOriginalConstructor() - ->setMethods(['getId']) - ->getMock(); - $this->attributeCollection->expects($this->once()) - ->method('addFieldToFilter') - ->with('attribute_code', ['in' => $fields]) - ->willReturnSelf(); - $this->fieldFactory->expects($this->once()) - ->method('create') - ->with(['attributeId' => $attributeId, 'column' => 'data_index', 'type' => FieldInterface::TYPE_FULLTEXT]) - ->willReturn($field); - if ($attributeId) { - $this->attributeCollection->expects($this->once()) - ->method('getItemByColumnValue') - ->with('attribute_code', $fields[0]) - ->willReturn($item); - $item->expects($this->once())->method('getId')->willReturn($attributeId); - } - - $this->assertSame($expectedResult, $this->model->resolve($fields)); - } - - /** - * Data provider for resolve method. - * - * @return array - */ - public function resolveDataProvider() - { - $field = $this->getMockBuilder(Field::class) - ->disableOriginalConstructor() - ->getMock(); - return [ - [['code_1'], 1, $field, ['code_1' => $field]], - [['*'], null, $field, [$field]], - ]; - } -} diff --git a/app/code/Magento/CatalogSearch/Test/Unit/Model/Adapter/Mysql/Filter/AliasResolverTest.php b/app/code/Magento/CatalogSearch/Test/Unit/Model/Adapter/Mysql/Filter/AliasResolverTest.php deleted file mode 100644 index b677cb34dcd94..0000000000000 --- a/app/code/Magento/CatalogSearch/Test/Unit/Model/Adapter/Mysql/Filter/AliasResolverTest.php +++ /dev/null @@ -1,76 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -declare(strict_types=1); - -namespace Magento\CatalogSearch\Test\Unit\Model\Adapter\Mysql\Filter; - -use Magento\CatalogSearch\Model\Adapter\Mysql\Filter\AliasResolver; -use Magento\CatalogSearch\Model\Search\RequestGenerator; -use Magento\Framework\Search\Request\Filter\Term; -use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; -use PHPUnit\Framework\TestCase; - -/** - * @deprecated Implementation class was replaced - * @see \Magento\ElasticSearch - */ -class AliasResolverTest extends TestCase -{ - /** - * @var AliasResolver - */ - private $aliasResolver; - - /** - * @inheritDoc - */ - protected function setUp(): void - { - $objectManagerHelper = new ObjectManagerHelper($this); - $this->aliasResolver = $objectManagerHelper->getObject( - AliasResolver::class, - [] - ); - } - - /** - * @param string $field - * @param string $expectedAlias - * @dataProvider aliasDataProvider - */ - public function testGetFilterAlias($field, $expectedAlias) - { - $filter = $this->getMockBuilder(Term::class) - ->setMethods(['getField']) - ->disableOriginalConstructor() - ->getMock(); - $filter->expects($this->once()) - ->method('getField') - ->willReturn($field); - $this->assertSame($expectedAlias, $this->aliasResolver->getAlias($filter)); - } - - /** - * @return array - */ - public function aliasDataProvider() - { - return [ - 'general' => [ - 'field' => 'general', - 'alias' => 'general' . RequestGenerator::FILTER_SUFFIX, - ], - 'price' => [ - 'field' => 'price', - 'alias' => 'price_index', - ], - 'category_ids' => [ - 'field' => 'category_ids', - 'alias' => 'category_ids_index', - ], - ]; - } -} diff --git a/app/code/Magento/CatalogSearch/Test/Unit/Model/Adapter/Mysql/Filter/PreprocessorTest.php b/app/code/Magento/CatalogSearch/Test/Unit/Model/Adapter/Mysql/Filter/PreprocessorTest.php deleted file mode 100644 index a517e23452b01..0000000000000 --- a/app/code/Magento/CatalogSearch/Test/Unit/Model/Adapter/Mysql/Filter/PreprocessorTest.php +++ /dev/null @@ -1,488 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -declare(strict_types=1); - -namespace Magento\CatalogSearch\Test\Unit\Model\Adapter\Mysql\Filter; - -use Magento\Catalog\Model\Product; -use Magento\CatalogSearch\Model\Adapter\Mysql\Filter\AliasResolver; -use Magento\CatalogSearch\Model\Adapter\Mysql\Filter\Preprocessor; -use Magento\Customer\Model\Session; -use Magento\Eav\Model\Config; -use Magento\Eav\Model\Entity\Attribute\AbstractAttribute; -use Magento\Framework\App\ResourceConnection; -use Magento\Framework\App\ScopeInterface; -use Magento\Framework\App\ScopeResolverInterface; -use Magento\Framework\DB\Adapter\AdapterInterface; -use Magento\Framework\DB\Select; -use Magento\Framework\EntityManager\EntityMetadata; -use Magento\Framework\EntityManager\MetadataPool; -use Magento\Framework\Search\Adapter\Mysql\ConditionManager; -use Magento\Framework\Search\Request\FilterInterface; -use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; -use PHPUnit\Framework\MockObject\MockObject; -use PHPUnit\Framework\TestCase; - -/** - * @SuppressWarnings(PHPMD.CouplingBetweenObjects) - * @deprecated Implementation class was replaced - * @see \Magento\ElasticSearch - */ -class PreprocessorTest extends TestCase -{ - /** - * @var AliasResolver|MockObject - */ - private $aliasResolver; - - /** - * @var AdapterInterface|MockObject - */ - private $connection; - - /** - * @var Preprocessor - */ - protected $target; - - /** - * @var Resource|MockObject - */ - private $resource; - - /** - * @var AbstractAttribute|MockObject - */ - private $attribute; - - /** - * @var Select|MockObject - */ - private $select; - - /** - * @var FilterInterface|MockObject - */ - private $filter; - - /** - * @var ScopeInterface|MockObject - */ - private $scope; - - /** - * @var Config|MockObject - */ - private $config; - - /** - * @var ScopeResolverInterface|MockObject - */ - private $scopeResolver; - - /** - * @var ConditionManager|MockObject - */ - private $conditionManager; - - /** - * @var MockObject - */ - private $metadataPoolMock; - - /** - * @var Session|MockObject - */ - protected $customerSessionMock; - - /** - * @var int - */ - private $customerGroupId = 42; - - /** - * @SuppressWarnings(PHPMD.ExcessiveMethodLength) - */ - protected function setUp(): void - { - $objectManagerHelper = new ObjectManagerHelper($this); - - $this->conditionManager = $this->getMockBuilder(ConditionManager::class) - ->disableOriginalConstructor() - ->setMethods(['wrapBrackets']) - ->getMock(); - $this->scopeResolver = $this->getMockBuilder(ScopeResolverInterface::class) - ->disableOriginalConstructor() - ->setMethods(['getScope']) - ->getMockForAbstractClass(); - $this->scope = $this->getMockBuilder(ScopeInterface::class) - ->disableOriginalConstructor() - ->setMethods(['getId']) - ->getMockForAbstractClass(); - $this->scopeResolver->expects($this->any()) - ->method('getScope') - ->willReturn($this->scope); - $this->config = $this->getMockBuilder(Config::class) - ->disableOriginalConstructor() - ->setMethods(['getAttribute']) - ->getMock(); - $methods = ['getBackendTable', 'isStatic', 'getAttributeId', - 'getAttributeCode', 'getFrontendInput', 'getBackendType' - ]; - $this->attribute = $this->getMockBuilder(AbstractAttribute::class) - ->disableOriginalConstructor() - ->setMethods($methods) - ->getMockForAbstractClass(); - $this->resource = $resource = $this->getMockBuilder(ResourceConnection::class) - ->disableOriginalConstructor() - ->setMethods(['getConnection', 'getTableName']) - ->getMock(); - $this->connection = $this->getMockBuilder(AdapterInterface::class) - ->disableOriginalConstructor() - ->setMethods(['select', 'getIfNullSql', 'quote', 'quoteInto']) - ->getMockForAbstractClass(); - $this->select = $this->getMockBuilder(Select::class) - ->disableOriginalConstructor() - ->setMethods(['from', 'join', 'where', '__toString', 'joinLeft', 'columns', 'having']) - ->getMock(); - $this->connection->expects($this->any()) - ->method('select') - ->willReturn($this->select); - $this->connection->expects($this->any()) - ->method('quoteIdentifier') - ->willReturnArgument(0); - $resource->expects($this->atLeastOnce()) - ->method('getConnection') - ->willReturn($this->connection); - $this->filter = $this->getMockBuilder(FilterInterface::class) - ->disableOriginalConstructor() - ->setMethods(['getField', 'getValue', 'getType']) - ->getMockForAbstractClass(); - - $this->conditionManager->expects($this->any()) - ->method('wrapBrackets') - ->with($this->select) - ->willReturnCallback( - function ($select) { - return '(' . $select . ')'; - } - ); - - $this->aliasResolver = $this->getMockBuilder(AliasResolver::class) - ->disableOriginalConstructor() - ->getMock(); - $this->metadataPoolMock = $this->getMockBuilder(MetadataPool::class) - ->disableOriginalConstructor() - ->getMock(); - - $metadata = $this->getMockBuilder(EntityMetadata::class) - ->disableOriginalConstructor() - ->getMock(); - - $this->metadataPoolMock->expects($this->any())->method('getMetadata')->willReturn($metadata); - $metadata->expects($this->any())->method('getLinkField')->willReturn('entity_id'); - - $this->customerSessionMock = $this->getMockBuilder(Session::class) - ->disableOriginalConstructor() - ->setMethods(['getCustomerGroupId']) - ->getMock(); - - $this->customerSessionMock->expects($this->any()) - ->method('getCustomerGroupId') - ->willReturn($this->customerGroupId); - - $this->target = $objectManagerHelper->getObject( - Preprocessor::class, - [ - 'conditionManager' => $this->conditionManager, - 'scopeResolver' => $this->scopeResolver, - 'config' => $this->config, - 'resource' => $resource, - 'attributePrefix' => 'attr_', - 'metadataPool' => $this->metadataPoolMock, - 'aliasResolver' => $this->aliasResolver, - 'customerSession' => $this->customerSessionMock - ] - ); - } - - public function testProcessPrice() - { - $expectedResult = 'price_index.min_price = 23 AND price_index.customer_group_id = ' . $this->customerGroupId; - $isNegation = false; - $query = 'price = 23'; - - $this->filter->expects($this->exactly(2)) - ->method('getField') - ->willReturn('price'); - $this->config->expects($this->exactly(1)) - ->method('getAttribute') - ->with(Product::ENTITY, 'price') - ->willReturn($this->attribute); - - $actualResult = $this->target->process($this->filter, $isNegation, $query); - $this->assertSame($expectedResult, $this->removeWhitespaces($actualResult)); - } - - /** - * @return array - */ - public function processCategoryIdsDataProvider() - { - return [ - ['5', "category_ids_index.category_id in ('5')"], - [3, "category_ids_index.category_id in (3)"], - ["' and 1 = 0", "category_ids_index.category_id in ('\' and 1 = 0')"], - [['5', '10'], "category_ids_index.category_id in ('5', '10')"] - ]; - } - - /** - * @param string|int $categoryId - * @param string $expectedResult - * @dataProvider processCategoryIdsDataProvider - */ - public function testProcessCategoryIds($categoryId, $expectedResult) - { - $isNegation = false; - $query = 'SELECT category_ids FROM catalog_product_entity'; - - $this->filter->expects($this->exactly(3)) - ->method('getField') - ->willReturn('category_ids'); - - $this->filter->expects($this->once()) - ->method('getValue') - ->willReturn($categoryId); - - $this->config->expects($this->exactly(1)) - ->method('getAttribute') - ->with(Product::ENTITY, 'category_ids') - ->willReturn($this->attribute); - - $this->connection - ->expects($this->once()) - ->method('quoteInto') - ->with('category_ids_index.category_id in (?)', $categoryId) - ->willReturn($expectedResult); - - $actualResult = $this->target->process($this->filter, $isNegation, $query); - $this->assertSame($expectedResult, $this->removeWhitespaces($actualResult)); - } - - public function testProcessStaticAttribute() - { - $expectedResult = 'attr_table_alias.static_attribute LIKE %name%'; - $isNegation = false; - $query = 'static_attribute LIKE %name%'; - - $this->attribute->method('getAttributeCode') - ->willReturn('static_attribute'); - $this->aliasResolver->expects($this->once())->method('getAlias') - ->willReturn('attr_table_alias'); - $this->filter->expects($this->exactly(3)) - ->method('getField') - ->willReturn('static_attribute'); - $this->config->expects($this->exactly(1)) - ->method('getAttribute') - ->with(Product::ENTITY, 'static_attribute') - ->willReturn($this->attribute); - $this->attribute->expects($this->once()) - ->method('isStatic') - ->willReturn(true); - - $actualResult = $this->target->process($this->filter, $isNegation, $query); - $this->assertSame($expectedResult, $this->removeWhitespaces($actualResult)); - } - - /** - * @dataProvider testTermFilterDataProvider - */ - public function testProcessTermFilter($frontendInput, $fieldValue, $isNegation, $expected) - { - $this->config->expects($this->exactly(1)) - ->method('getAttribute') - ->with(Product::ENTITY, 'termField') - ->willReturn($this->attribute); - - $this->attribute->expects($this->once()) - ->method('isStatic') - ->willReturn(false); - - $this->filter->expects($this->once()) - ->method('getType') - ->willReturn(FilterInterface::TYPE_TERM); - $this->attribute->expects($this->once()) - ->method('getFrontendInput') - ->willReturn($frontendInput); - - $this->aliasResolver->expects($this->once())->method('getAlias') - ->willReturn('termAttrAlias'); - - $this->filter->expects($this->exactly(4)) - ->method('getField') - ->willReturn('termField'); - $this->filter->expects($this->exactly(2)) - ->method('getValue') - ->willReturn($fieldValue); - - $this->connection->expects($this->atLeastOnce())->method('quote')->willReturnArgument(0); - $actualResult = $this->target->process($this->filter, $isNegation, 'This filter is not depends on used query'); - $this->assertSame($expected, $this->removeWhitespaces($actualResult)); - } - - /** - * @return array - */ - public function testTermFilterDataProvider() - { - return [ - 'selectPositiveEqual' => [ - 'frontendInput' => 'select', - 'fieldValue' => 'positiveValue', - 'isNegation' => false, - 'expected' => 'termAttrAlias.value = positiveValue', - ], - 'selectPositiveArray' => [ - 'frontendInput' => 'select', - 'fieldValue' => [2, 3, 15], - 'isNegation' => false, - 'expected' => 'termAttrAlias.value IN (2,3,15)', - ], - 'selectNegativeEqual' => [ - 'frontendInput' => 'select', - 'fieldValue' => 'positiveValue', - 'isNegation' => true, - 'expected' => 'termAttrAlias.value != positiveValue', - ], - 'selectNegativeArray' => [ - 'frontendInput' => 'select', - 'fieldValue' => [4, 3, 42], - 'isNegation' => true, - 'expected' => 'termAttrAlias.value NOT IN (4,3,42)', - ], - 'multiSelectPositiveEqual' => [ - 'frontendInput' => 'multiselect', - 'fieldValue' => 'positiveValue', - 'isNegation' => false, - 'expected' => 'termAttrAlias.value = positiveValue', - ], - 'multiSelectPositiveArray' => [ - 'frontendInput' => 'multiselect', - 'fieldValue' => [2, 3, 15], - 'isNegation' => false, - 'expected' => 'termAttrAlias.value IN (2,3,15)', - ], - 'multiSelectNegativeEqual' => [ - 'frontendInput' => 'multiselect', - 'fieldValue' => 'negativeValue', - 'isNegation' => true, - 'expected' => 'termAttrAlias.value != negativeValue', - ], - 'multiSelectNegativeArray' => [ - 'frontendInput' => 'multiselect', - 'fieldValue' => [4, 3, 42], - 'isNegation' => true, - 'expected' => 'termAttrAlias.value NOT IN (4,3,42)', - ], - ]; - } - - public function testProcessNotStaticAttribute() - { - $expectedResult = 'search_index.entity_id IN (select entity_id from (TEST QUERY PART) as filter)'; - $scopeId = 0; - $isNegation = false; - $query = 'SELECT field FROM table'; - $attributeId = 1234567; - - $this->scope->expects($this->once())->method('getId')->willReturn($scopeId); - $this->filter->expects($this->exactly(5)) - ->method('getField') - ->willReturn('not_static_attribute'); - $this->config->expects($this->exactly(1)) - ->method('getAttribute') - ->with(Product::ENTITY, 'not_static_attribute') - ->willReturn($this->attribute); - $this->attribute->expects($this->once()) - ->method('isStatic') - ->willReturn(false); - $this->attribute->expects($this->once()) - ->method('getBackendTable') - ->willReturn('backend_table'); - $this->attribute->expects($this->once()) - ->method('getAttributeId') - ->willReturn($attributeId); - $this->connection->expects($this->once()) - ->method('getIfNullSql') - ->with('current_store.value', 'main_table.value') - ->willReturn('IF NULL SQL'); - $this->resource->expects($this->once())->method('getTableName')->willReturn('catalog_product_entity'); - $this->select->expects($this->once()) - ->method('from') - ->with(['e' => 'catalog_product_entity'], ['entity_id'])->willReturnSelf(); - $this->select->expects($this->once()) - ->method('join') - ->with(['main_table' => 'backend_table'], "main_table.entity_id = e.entity_id")->willReturnSelf(); - $this->select->expects($this->once()) - ->method('joinLeft') - ->with(['current_store' => 'backend_table'])->willReturnSelf(); - $this->select->expects($this->once()) - ->method('columns') - ->with(['not_static_attribute' => 'IF NULL SQL'])->willReturnSelf(); - $this->select->expects($this->exactly(2)) - ->method('where')->willReturnSelf(); - $this->select->expects($this->once()) - ->method('__toString') - ->willReturn('TEST QUERY PART'); - - $actualResult = $this->target->process($this->filter, $isNegation, $query); - $this->assertSame($expectedResult, $this->removeWhitespaces($actualResult)); - } - - /** - * @param $actualResult - * @return mixed - */ - private function removeWhitespaces($actualResult) - { - return preg_replace(['/(\s)+/', '/(\() /', '/ (\))/'], '${1}', $actualResult); - } - - public function testProcessRangeFilter() - { - $query = 'static_attribute LIKE %name%'; - $expected = 'search_index.entity_id IN (select entity_id from () as filter)'; - - $this->filter->expects($this->any()) - ->method('getField') - ->willReturn('termField'); - $this->config->expects($this->exactly(1)) - ->method('getAttribute') - ->with(Product::ENTITY, 'termField') - ->willReturn($this->attribute); - - $this->attribute->expects($this->once()) - ->method('isStatic') - ->willReturn(false); - - $this->filter->expects($this->any()) - ->method('getType') - ->willReturn(FilterInterface::TYPE_RANGE); - $this->attribute->expects($this->any()) - ->method('getBackendType') - ->willReturn('decimal'); - - $this->select->expects($this->any())->method('from')->willReturnSelf(); - $this->select->expects($this->any())->method('join')->willReturnSelf(); - $this->select->expects($this->any())->method('columns')->willReturnSelf(); - $this->select->expects($this->any())->method('joinLeft')->willReturnSelf(); - $this->select->expects($this->any())->method('having')->willReturnSelf(); - $this->select->expects($this->any())->method('where')->willReturnSelf(); - $actualResult = $this->target->process($this->filter, false, $query); - $this->assertSame($expected, $this->removeWhitespaces($actualResult)); - } -} diff --git a/app/code/Magento/CatalogSearch/Test/Unit/Model/Indexer/FulltextTest.php b/app/code/Magento/CatalogSearch/Test/Unit/Model/Indexer/FulltextTest.php index 446c131209c20..d07b15dbfd5d9 100644 --- a/app/code/Magento/CatalogSearch/Test/Unit/Model/Indexer/FulltextTest.php +++ b/app/code/Magento/CatalogSearch/Test/Unit/Model/Indexer/FulltextTest.php @@ -10,9 +10,8 @@ use Magento\CatalogSearch\Model\Indexer\Fulltext; use Magento\CatalogSearch\Model\Indexer\Fulltext\Action\Full; use Magento\CatalogSearch\Model\Indexer\Fulltext\Action\FullFactory; -use Magento\CatalogSearch\Model\Indexer\IndexerHandler; +use Magento\Framework\Indexer\SaveHandler\IndexerInterface; use Magento\CatalogSearch\Model\Indexer\IndexerHandlerFactory; -use Magento\CatalogSearch\Model\Indexer\Scope\IndexSwitcher; use Magento\CatalogSearch\Model\Indexer\Scope\State; use Magento\Framework\App\ResourceConnection; use Magento\Framework\Indexer\Dimension; @@ -38,7 +37,7 @@ class FulltextTest extends TestCase protected $fullAction; /** - * @var IndexerHandler|MockObject + * @var IndexerInterface|MockObject */ protected $saveHandler; @@ -47,11 +46,6 @@ class FulltextTest extends TestCase */ protected $fulltextResource; - /** - * @var IndexSwitcher|MockObject - */ - private $indexSwitcher; - /** * @var DimensionProviderInterface|MockObject */ @@ -70,7 +64,7 @@ protected function setUp(): void ['create'] ); $fullActionFactory->expects($this->any())->method('create')->willReturn($this->fullAction); - $this->saveHandler = $this->getClassMock(IndexerHandler::class); + $this->saveHandler = $this->getClassMock(IndexerInterface::class); $indexerHandlerFactory = $this->createPartialMock( IndexerHandlerFactory::class, ['create'] @@ -79,11 +73,6 @@ protected function setUp(): void $this->fulltextResource = $this->getClassMock(\Magento\CatalogSearch\Model\ResourceModel\Fulltext::class); - $this->indexSwitcher = $this->getMockBuilder(IndexSwitcher::class) - ->disableOriginalConstructor() - ->setMethods(['switchIndex']) - ->getMock(); - $this->dimensionProviderMock = $this->getMockBuilder(DimensionProviderInterface::class) ->getMock(); $stateMock = $this->getMockBuilder(State::class) @@ -101,7 +90,6 @@ protected function setUp(): void 'indexerHandlerFactory' => $indexerHandlerFactory, 'fulltextResource' => $this->fulltextResource, 'data' => [], - 'indexSwitcher' => $this->indexSwitcher, 'dimensionProvider' => $this->dimensionProviderMock, 'indexScopeState' => $stateMock, 'processManager' => $this->processManager, @@ -172,8 +160,6 @@ public function testExecuteFull() $indexData = new \ArrayObject([new \ArrayObject([]), new \ArrayObject([])]); $this->setupDataProvider($stores); - $this->indexSwitcher->expects($this->exactly(2))->method('switchIndex'); - $this->saveHandler->expects($this->exactly(count($stores)))->method('cleanIndex'); $this->saveHandler->expects($this->exactly(2))->method('saveIndex'); $consecutiveStoreRebuildArguments = array_map( diff --git a/app/code/Magento/CatalogSearch/Test/Unit/Model/Indexer/IndexSwitcherProxyTest.php b/app/code/Magento/CatalogSearch/Test/Unit/Model/Indexer/IndexSwitcherProxyTest.php deleted file mode 100644 index eb73079db7b62..0000000000000 --- a/app/code/Magento/CatalogSearch/Test/Unit/Model/Indexer/IndexSwitcherProxyTest.php +++ /dev/null @@ -1,123 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -declare(strict_types=1); - -namespace Magento\CatalogSearch\Test\Unit\Model\Indexer; - -use Magento\CatalogSearch\Model\Indexer\IndexSwitcherInterface; -use Magento\CatalogSearch\Model\Indexer\IndexSwitcherProxy; -use Magento\Framework\ObjectManagerInterface; -use Magento\Framework\Search\EngineResolverInterface; -use PHPUnit\Framework\MockObject\MockObject; -use PHPUnit\Framework\TestCase; - -class IndexSwitcherProxyTest extends TestCase -{ - /** @var IndexSwitcherProxy */ - private $model; - - /** @var ObjectManagerInterface|MockObject */ - private $objectManagerMock; - - /** @var EngineResolverInterface|MockObject */ - private $engineResolverMock; - - protected function setUp(): void - { - $this->objectManagerMock = $this->getMockBuilder(ObjectManagerInterface::class) - ->getMockForAbstractClass(); - $this->engineResolverMock = $this->getMockBuilder(EngineResolverInterface::class) - ->getMockForAbstractClass(); - } - - public function testSwitchIndex() - { - $currentHandler = 'current_handler'; - $currentHandlerClass = IndexSwitcherInterface::class; - $handles = [ - $currentHandler => $currentHandlerClass, - ]; - $dimensions = ['dimension']; - - $this->engineResolverMock->expects($this->once()) - ->method('getCurrentSearchEngine') - ->willReturn($currentHandler); - - $indexSwitcherMock = $this->getMockBuilder($currentHandlerClass) - ->getMockForAbstractClass(); - - $this->objectManagerMock->expects($this->once()) - ->method('create') - ->with($currentHandlerClass) - ->willReturn($indexSwitcherMock); - - $indexSwitcherMock->expects($this->once()) - ->method('switchIndex') - ->with($dimensions); - - $this->model = new IndexSwitcherProxy( - $this->objectManagerMock, - $this->engineResolverMock, - $handles - ); - - $this->model->switchIndex($dimensions); - } - - public function testSwitchIndexWithoutHandlers() - { - $currentHandler = 'current_handler'; - $handles = []; - $dimensions = ['dimension']; - - $this->engineResolverMock->expects($this->once()) - ->method('getCurrentSearchEngine') - ->willReturn($currentHandler); - - $this->objectManagerMock->expects($this->never()) - ->method('create'); - - $this->model = new IndexSwitcherProxy( - $this->objectManagerMock, - $this->engineResolverMock, - $handles - ); - - $this->model->switchIndex($dimensions); - } - - public function testSwitchIndexWithWrongHandler() - { - $this->expectException('InvalidArgumentException'); - $this->expectExceptionMessage('current_handler index switcher doesn\'t implement'); - $currentHandler = 'current_handler'; - $currentHandlerClass = \stdClass::class; - $handles = [ - $currentHandler => $currentHandlerClass, - ]; - $dimensions = ['dimension']; - - $this->engineResolverMock->expects($this->once()) - ->method('getCurrentSearchEngine') - ->willReturn($currentHandler); - - $indexSwitcherMock = $this->getMockBuilder($currentHandlerClass) - ->getMockForAbstractClass(); - - $this->objectManagerMock->expects($this->once()) - ->method('create') - ->with($currentHandlerClass) - ->willReturn($indexSwitcherMock); - - $this->model = new IndexSwitcherProxy( - $this->objectManagerMock, - $this->engineResolverMock, - $handles - ); - - $this->model->switchIndex($dimensions); - } -} diff --git a/app/code/Magento/CatalogSearch/Test/Unit/Model/Indexer/Scope/IndexSwitcherTest.php b/app/code/Magento/CatalogSearch/Test/Unit/Model/Indexer/Scope/IndexSwitcherTest.php deleted file mode 100644 index 4ab34f415bec1..0000000000000 --- a/app/code/Magento/CatalogSearch/Test/Unit/Model/Indexer/Scope/IndexSwitcherTest.php +++ /dev/null @@ -1,219 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -declare(strict_types=1); - -namespace Magento\CatalogSearch\Test\Unit\Model\Indexer\Scope; - -use Magento\CatalogSearch\Model\Indexer\Fulltext as FulltextIndexer; -use Magento\CatalogSearch\Model\Indexer\Scope\IndexSwitcher; -use Magento\CatalogSearch\Model\Indexer\Scope\State; -use Magento\Framework\App\ResourceConnection; -use Magento\Framework\DB\Adapter\AdapterInterface; -use Magento\Framework\Search\Request\Dimension; -use Magento\Framework\Search\Request\IndexScopeResolverInterface; -use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; -use PHPUnit\Framework\MockObject\MockObject; -use PHPUnit\Framework\TestCase; - -class IndexSwitcherTest extends TestCase -{ - /** - * @var AdapterInterface|MockObject - */ - private $connection; - - /** - * @var IndexScopeResolverInterface|MockObject - */ - private $indexScopeResolver; - - /** - * @var State|MockObject - */ - private $scopeState; - - /** - * @var IndexSwitcher - */ - private $indexSwitcher; - - /** - * @var ResourceConnection|MockObject - */ - private $resource; - - protected function setUp(): void - { - $this->resource = $this->getMockBuilder(ResourceConnection::class) - ->setMethods(['getConnection']) - ->disableOriginalConstructor() - ->getMock(); - $this->connection = $this->getMockBuilder(AdapterInterface::class) - ->setMethods(['isTableExists', 'dropTable', 'renameTable']) - ->getMockForAbstractClass(); - $this->resource->expects($this->any()) - ->method('getConnection') - ->willReturn($this->connection); - $this->indexScopeResolver = $this->getMockBuilder( - IndexScopeResolverInterface::class - ) - ->setMethods(['resolve']) - ->getMockForAbstractClass(); - $this->scopeState = $this->getMockBuilder(State::class) - ->setMethods(['getState', 'useRegularIndex', 'useTemporaryIndex']) - ->disableOriginalConstructor() - ->getMock(); - - $objectManagerHelper = new ObjectManagerHelper($this); - $this->indexSwitcher = $objectManagerHelper->getObject( - IndexSwitcher::class, - [ - 'resource' => $this->resource, - 'indexScopeResolver' => $this->indexScopeResolver, - 'state' => $this->scopeState, - ] - ); - } - - public function testSwitchRegularIndex() - { - $dimensions = [$this->getMockBuilder(Dimension::class) - ->setConstructorArgs(['scope', '1'])]; - - $this->scopeState->expects($this->once()) - ->method('getState') - ->willReturn(State::USE_REGULAR_INDEX); - - $this->indexScopeResolver->expects($this->never())->method('resolve'); - $this->connection->expects($this->never())->method('renameTable'); - - $this->indexSwitcher->switchIndex($dimensions); - } - - public function testSwitchIndexWithUnknownState() - { - $dimensions = [$this->getMockBuilder(Dimension::class) - ->setConstructorArgs(['scope', '1'])]; - - $this->scopeState->expects($this->once()) - ->method('getState') - ->willReturn('unknown_state'); - - $this->indexScopeResolver->expects($this->never())->method('resolve'); - $this->connection->expects($this->never())->method('renameTable'); - - $this->indexSwitcher->switchIndex($dimensions); - } - - public function testSwitchTemporaryIndexWhenRegularIndexExist() - { - $dimensions = [$this->getMockBuilder(Dimension::class) - ->setConstructorArgs(['scope', '1'])]; - - $this->scopeState->expects($this->once()) - ->method('getState') - ->willReturn(State::USE_TEMPORARY_INDEX); - - $this->scopeState->expects($this->at(1))->method('useRegularIndex'); - $this->scopeState->expects($this->at(2))->method('useTemporaryIndex'); - - $this->indexScopeResolver->expects($this->exactly(2))->method('resolve') - ->withConsecutive( - [$this->equalTo(FulltextIndexer::INDEXER_ID), $this->equalTo($dimensions)], - [$this->equalTo(FulltextIndexer::INDEXER_ID), $this->equalTo($dimensions)] - ) - ->willReturnOnConsecutiveCalls( - 'catalogsearch_fulltext_scope1_tmp1', - 'catalogsearch_fulltext_scope1' - ); - - $this->connection->expects($this->exactly(2))->method('isTableExists') - ->withConsecutive( - [$this->equalTo('catalogsearch_fulltext_scope1_tmp1'), $this->equalTo(null)], - [$this->equalTo('catalogsearch_fulltext_scope1'), $this->equalTo(null)] - ) - ->willReturnOnConsecutiveCalls( - true, - true - ); - - $this->connection->expects($this->once())->method('dropTable')->with('catalogsearch_fulltext_scope1', null); - $this->connection->expects($this->once()) - ->method('renameTable') - ->with('catalogsearch_fulltext_scope1_tmp1', 'catalogsearch_fulltext_scope1'); - - $this->indexSwitcher->switchIndex($dimensions); - } - - public function testSwitchTemporaryIndexWhenRegularIndexNotExist() - { - $dimensions = [$this->getMockBuilder(Dimension::class) - ->setConstructorArgs(['scope', '1'])]; - - $this->scopeState->expects($this->once()) - ->method('getState') - ->willReturn(State::USE_TEMPORARY_INDEX); - - $this->scopeState->expects($this->at(1))->method('useRegularIndex'); - $this->scopeState->expects($this->at(2))->method('useTemporaryIndex'); - - $this->indexScopeResolver->expects($this->exactly(2))->method('resolve') - ->withConsecutive( - [$this->equalTo(FulltextIndexer::INDEXER_ID), $this->equalTo($dimensions)], - [$this->equalTo(FulltextIndexer::INDEXER_ID), $this->equalTo($dimensions)] - ) - ->willReturnOnConsecutiveCalls( - 'catalogsearch_fulltext_scope1_tmp1', - 'catalogsearch_fulltext_scope1' - ); - - $this->connection->expects($this->exactly(2))->method('isTableExists') - ->withConsecutive( - [$this->equalTo('catalogsearch_fulltext_scope1_tmp1'), $this->equalTo(null)], - [$this->equalTo('catalogsearch_fulltext_scope1'), $this->equalTo(null)] - ) - ->willReturnOnConsecutiveCalls( - true, - false - ); - - $this->connection->expects($this->never())->method('dropTable')->with('catalogsearch_fulltext_scope1', null); - $this->connection->expects($this->once()) - ->method('renameTable') - ->with('catalogsearch_fulltext_scope1_tmp1', 'catalogsearch_fulltext_scope1'); - - $this->indexSwitcher->switchIndex($dimensions); - } - - public function testSwitchWhenTemporaryIndexNotExist() - { - $this->expectException('Magento\CatalogSearch\Model\Indexer\Scope\IndexTableNotExistException'); - $this->expectExceptionMessage('Temporary table for index catalogsearch_fulltext doesn\'t exist'); - $dimensions = [$this->getMockBuilder(Dimension::class) - ->setConstructorArgs(['scope', '1'])]; - - $this->scopeState->expects($this->once()) - ->method('getState') - ->willReturn(State::USE_TEMPORARY_INDEX); - - $this->scopeState->expects($this->never())->method('useRegularIndex'); - $this->scopeState->expects($this->never())->method('useTemporaryIndex'); - - $this->indexScopeResolver->expects($this->once())->method('resolve') - ->with(FulltextIndexer::INDEXER_ID, $dimensions) - ->willReturn('catalogsearch_fulltext_scope1_tmp1'); - - $this->connection->expects($this->once()) - ->method('isTableExists') - ->with('catalogsearch_fulltext_scope1_tmp1', null) - ->willReturn(false); - - $this->connection->expects($this->never())->method('dropTable')->with('catalogsearch_fulltext_scope1', null); - $this->connection->expects($this->never())->method('renameTable'); - - $this->indexSwitcher->switchIndex($dimensions); - } -} diff --git a/app/code/Magento/CatalogSearch/Test/Unit/Model/ResourceModel/Advanced/CollectionTest.php b/app/code/Magento/CatalogSearch/Test/Unit/Model/ResourceModel/Advanced/CollectionTest.php index 15cbd7cfb0f7e..93b409d5f9566 100644 --- a/app/code/Magento/CatalogSearch/Test/Unit/Model/ResourceModel/Advanced/CollectionTest.php +++ b/app/code/Magento/CatalogSearch/Test/Unit/Model/ResourceModel/Advanced/CollectionTest.php @@ -18,16 +18,21 @@ use Magento\CatalogSearch\Model\ResourceModel\Fulltext\Collection\SearchResultApplierInterface; use Magento\CatalogSearch\Model\ResourceModel\Fulltext\Collection\TotalRecordsResolverFactory; use Magento\CatalogSearch\Model\ResourceModel\Fulltext\Collection\TotalRecordsResolverInterface; -use Magento\CatalogSearch\Test\Unit\Model\ResourceModel\BaseCollection; use Magento\Eav\Model\Config; +use Magento\Eav\Model\Entity\AbstractEntity; use Magento\Framework\Api\Filter; use Magento\Framework\Api\FilterBuilder; use Magento\Framework\Api\Search\SearchCriteriaBuilder; use Magento\Framework\Api\Search\SearchResultInterface; -use Magento\Framework\Search\Adapter\Mysql\TemporaryStorageFactory; +use Magento\Framework\DB\Adapter\Pdo\Mysql; +use Magento\Framework\DB\Select; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; +use Magento\Framework\Validator\UniversalFactory; use Magento\Search\Api\SearchInterface; +use Magento\Store\Model\Store; +use Magento\Store\Model\StoreManagerInterface; use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\TestCase; /** * Tests Magento\CatalogSearch\Model\ResourceModel\Advanced\Collection @@ -36,7 +41,7 @@ * @deprecated Implementation class was replaced * @see \Magento\ElasticSearch */ -class CollectionTest extends BaseCollection +class CollectionTest extends TestCase { /** * @var ObjectManager @@ -58,11 +63,6 @@ class CollectionTest extends BaseCollection */ private $criteriaBuilder; - /** - * @var TemporaryStorageFactory|MockObject - */ - private $temporaryStorageFactory; - /** * @var SearchInterface|MockObject */ @@ -89,9 +89,6 @@ protected function setUp(): void $universalFactory = $this->getUniversalFactory(); $this->criteriaBuilder = $this->getCriteriaBuilder(); $this->filterBuilder = $this->createMock(FilterBuilder::class); - $this->temporaryStorageFactory = $this->createMock( - TemporaryStorageFactory::class - ); $this->search = $this->getMockForAbstractClass(SearchInterface::class); $productLimitationMock = $this->createMock( @@ -141,7 +138,6 @@ protected function setUp(): void 'universalFactory' => $universalFactory, 'searchCriteriaBuilder' => $this->criteriaBuilder, 'filterBuilder' => $this->filterBuilder, - 'temporaryStorageFactory' => $this->temporaryStorageFactory, 'search' => $this->search, 'productLimitationFactory' => $productLimitationFactoryMock, 'collectionProvider' => null, @@ -221,4 +217,74 @@ protected function getCriteriaBuilder() return $criteriaBuilder; } + + /** + * Get Mocks for StoreManager so Collection can be used. + * + * @return MockObject + */ + protected function getStoreManager() + { + $store = $this->getMockBuilder(Store::class) + ->setMethods(['getId']) + ->disableOriginalConstructor() + ->getMock(); + $store->expects($this->once()) + ->method('getId') + ->willReturn(1); + + $storeManager = $this->getMockBuilder(StoreManagerInterface::class) + ->setMethods(['getStore']) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $storeManager->expects($this->once()) + ->method('getStore') + ->willReturn($store); + + return $storeManager; + } + + /** + * Get mock for UniversalFactory so Collection can be used. + * + * @return MockObject + */ + protected function getUniversalFactory() + { + $connection = $this->getMockBuilder(Mysql::class) + ->disableOriginalConstructor() + ->setMethods(['select']) + ->getMockForAbstractClass(); + $select = $this->getMockBuilder(Select::class) + ->disableOriginalConstructor() + ->getMock(); + $connection->expects($this->any())->method('select')->willReturn($select); + + $entity = $this->getMockBuilder(AbstractEntity::class) + ->setMethods(['getConnection', 'getTable', 'getDefaultAttributes', 'getEntityTable']) + ->disableOriginalConstructor() + ->getMock(); + $entity->expects($this->once()) + ->method('getConnection') + ->willReturn($connection); + $entity->expects($this->exactly(2)) + ->method('getTable') + ->willReturnArgument(0); + $entity->expects($this->once()) + ->method('getDefaultAttributes') + ->willReturn(['attr1', 'attr2']); + $entity->expects($this->once()) + ->method('getEntityTable') + ->willReturn('table'); + + $universalFactory = $this->getMockBuilder(UniversalFactory::class) + ->setMethods(['create']) + ->disableOriginalConstructor() + ->getMock(); + $universalFactory->expects($this->once()) + ->method('create') + ->willReturn($entity); + + return $universalFactory; + } } diff --git a/app/code/Magento/CatalogSearch/Test/Unit/Model/ResourceModel/BaseCollection.php b/app/code/Magento/CatalogSearch/Test/Unit/Model/ResourceModel/BaseCollection.php deleted file mode 100644 index 1b1de88d28a47..0000000000000 --- a/app/code/Magento/CatalogSearch/Test/Unit/Model/ResourceModel/BaseCollection.php +++ /dev/null @@ -1,98 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -declare(strict_types=1); - -namespace Magento\CatalogSearch\Test\Unit\Model\ResourceModel; - -use Magento\Eav\Model\Entity\AbstractEntity; -use Magento\Framework\DB\Adapter\Pdo\Mysql; -use Magento\Framework\DB\Select; -use Magento\Framework\Validator\UniversalFactory; -use Magento\Store\Model\Store; -use Magento\Store\Model\StoreManagerInterface; -use PHPUnit\Framework\MockObject\MockObject; -use PHPUnit\Framework\TestCase; - -/** - * Base class for Collection tests. - * - * Contains helper methods to get commonly used mocks used for collection tests. - * - * @deprecated Implementation class was replaced - * @see \Magento\ElasticSearch - **/ -class BaseCollection extends TestCase -{ - /** - * Get Mocks for StoreManager so Collection can be used. - * - * @return MockObject - */ - protected function getStoreManager() - { - $store = $this->getMockBuilder(Store::class) - ->setMethods(['getId']) - ->disableOriginalConstructor() - ->getMock(); - $store->expects($this->once()) - ->method('getId') - ->willReturn(1); - - $storeManager = $this->getMockBuilder(StoreManagerInterface::class) - ->setMethods(['getStore']) - ->disableOriginalConstructor() - ->getMockForAbstractClass(); - $storeManager->expects($this->once()) - ->method('getStore') - ->willReturn($store); - - return $storeManager; - } - - /** - * Get mock for UniversalFactory so Collection can be used. - * - * @return MockObject - */ - protected function getUniversalFactory() - { - $connection = $this->getMockBuilder(Mysql::class) - ->disableOriginalConstructor() - ->setMethods(['select']) - ->getMockForAbstractClass(); - $select = $this->getMockBuilder(Select::class) - ->disableOriginalConstructor() - ->getMock(); - $connection->expects($this->any())->method('select')->willReturn($select); - - $entity = $this->getMockBuilder(AbstractEntity::class) - ->setMethods(['getConnection', 'getTable', 'getDefaultAttributes', 'getEntityTable']) - ->disableOriginalConstructor() - ->getMock(); - $entity->expects($this->once()) - ->method('getConnection') - ->willReturn($connection); - $entity->expects($this->exactly(2)) - ->method('getTable') - ->willReturnArgument(0); - $entity->expects($this->once()) - ->method('getDefaultAttributes') - ->willReturn(['attr1', 'attr2']); - $entity->expects($this->once()) - ->method('getEntityTable') - ->willReturn('table'); - - $universalFactory = $this->getMockBuilder(UniversalFactory::class) - ->setMethods(['create']) - ->disableOriginalConstructor() - ->getMock(); - $universalFactory->expects($this->once()) - ->method('create') - ->willReturn($entity); - - return $universalFactory; - } -} diff --git a/app/code/Magento/CatalogSearch/Test/Unit/Model/ResourceModel/EngineTest.php b/app/code/Magento/CatalogSearch/Test/Unit/Model/ResourceModel/EngineTest.php deleted file mode 100644 index 73ef83b063f16..0000000000000 --- a/app/code/Magento/CatalogSearch/Test/Unit/Model/ResourceModel/EngineTest.php +++ /dev/null @@ -1,95 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -declare(strict_types=1); - -namespace Magento\CatalogSearch\Test\Unit\Model\ResourceModel; - -use Magento\CatalogSearch\Model\ResourceModel\Engine; -use Magento\Framework\App\ResourceConnection; -use Magento\Framework\DB\Adapter\AdapterInterface; -use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; -use PHPUnit\Framework\MockObject\MockObject; -use PHPUnit\Framework\TestCase; - -class EngineTest extends TestCase -{ - /** - * @var Engine - */ - private $target; - - /** - * @var AdapterInterface|MockObject - */ - private $connection; - - protected function setUp(): void - { - $this->connection = $this->getMockBuilder(AdapterInterface::class) - ->disableOriginalConstructor() - ->setMethods(['getIfNullSql']) - ->getMockForAbstractClass(); - $resource = $this->getMockBuilder(ResourceConnection::class) - ->disableOriginalConstructor() - ->setMethods(['getConnection', 'getTableName']) - ->getMock(); - $resource->expects($this->any()) - ->method('getConnection') - ->willReturn($this->connection); - - $resource->expects($this->any()) - ->method('getTableName') - ->willReturnArgument(0); - - $objectManager = new ObjectManager($this); - $this->target = $objectManager->getObject( - Engine::class, - [ - 'resource' => $resource, - ] - ); - } - - /** - * @param null|string $expected - * @param array $data - * @dataProvider prepareEntityIndexDataProvider - */ - public function testPrepareEntityIndex($expected, array $data) - { - $this->assertEquals($expected, $this->target->prepareEntityIndex($data['index'], $data['separator'])); - } - - /** - * @return array - */ - public function prepareEntityIndexDataProvider() - { - return [ - [ - [], - [ - 'index' => [], - 'separator' => '--' - ], - ], - [ - ['element1','element2','element3--element4'], - [ - 'index' => [ - 'element1', - 'element2', - [ - 'element3', - 'element4', - ], - ], - 'separator' => '--' - ] - ] - ]; - } -} diff --git a/app/code/Magento/CatalogSearch/Test/Unit/Model/ResourceModel/Fulltext/CollectionTest.php b/app/code/Magento/CatalogSearch/Test/Unit/Model/ResourceModel/Fulltext/CollectionTest.php index 2827517628c3c..32e765a9be599 100644 --- a/app/code/Magento/CatalogSearch/Test/Unit/Model/ResourceModel/Fulltext/CollectionTest.php +++ b/app/code/Magento/CatalogSearch/Test/Unit/Model/ResourceModel/Fulltext/CollectionTest.php @@ -3,50 +3,32 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ -declare(strict_types=1); - namespace Magento\CatalogSearch\Test\Unit\Model\ResourceModel\Fulltext; -use Magento\Catalog\Model\ResourceModel\Product\Collection\ProductLimitation; use Magento\Catalog\Model\ResourceModel\Product\Collection\ProductLimitationFactory; -use Magento\CatalogSearch\Model\ResourceModel\Fulltext\Collection; use Magento\CatalogSearch\Model\ResourceModel\Fulltext\Collection\SearchCriteriaResolverFactory; use Magento\CatalogSearch\Model\ResourceModel\Fulltext\Collection\SearchCriteriaResolverInterface; use Magento\CatalogSearch\Model\ResourceModel\Fulltext\Collection\SearchResultApplierFactory; -use Magento\CatalogSearch\Model\ResourceModel\Fulltext\Collection\SearchResultApplierInterface; use Magento\CatalogSearch\Model\ResourceModel\Fulltext\Collection\TotalRecordsResolverFactory; +use Magento\CatalogSearch\Model\ResourceModel\Fulltext\Collection\SearchResultApplierInterface; use Magento\CatalogSearch\Model\ResourceModel\Fulltext\Collection\TotalRecordsResolverInterface; -use Magento\CatalogSearch\Test\Unit\Model\ResourceModel\BaseCollection; -use Magento\Framework\Api\Filter; -use Magento\Framework\Api\FilterBuilder; -use Magento\Framework\Api\Search\SearchCriteriaBuilder; -use Magento\Framework\Api\Search\SearchResultInterface; -use Magento\Framework\App\Config\ScopeConfigInterface; -use Magento\Framework\Search\Adapter\Mysql\TemporaryStorage; -use Magento\Framework\Search\Adapter\Mysql\TemporaryStorageFactory; -use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; -use Magento\Search\Api\SearchInterface; use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\TestCase; /** * Test class for Fulltext Collection * * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ -class CollectionTest extends BaseCollection +class CollectionTest extends TestCase { /** - * @var ObjectManager + * @var \Magento\Framework\TestFramework\Unit\Helper\ObjectManager */ private $objectManager; /** - * @var TemporaryStorage|MockObject - */ - private $temporaryStorage; - - /** - * @var SearchInterface|MockObject + * @var \Magento\Search\Api\SearchInterface|MockObject */ private $search; @@ -81,12 +63,12 @@ class CollectionTest extends BaseCollection private $searchResultApplierFactory; /** - * @var Collection + * @var \Magento\CatalogSearch\Model\ResourceModel\Fulltext\Collection */ private $model; /** - * @var Filter + * @var \Magento\Framework\Api\Filter */ private $filter; @@ -95,8 +77,7 @@ class CollectionTest extends BaseCollection */ protected function setUp(): void { - $this->markTestSkipped("MC-18332: Mysql Search Engine is deprecated and will be removed"); - $this->objectManager = new ObjectManager($this); + $this->objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); $this->storeManager = $this->getStoreManager(); $this->universalFactory = $this->getUniversalFactory(); $this->scopeConfig = $this->getScopeConfig(); @@ -104,7 +85,7 @@ protected function setUp(): void $this->filterBuilder = $this->getFilterBuilder(); $productLimitationMock = $this->createMock( - ProductLimitation::class + \Magento\Catalog\Model\ResourceModel\Product\Collection\ProductLimitation::class ); $productLimitationFactoryMock = $this->getMockBuilder(ProductLimitationFactory::class) ->disableOriginalConstructor() @@ -113,16 +94,6 @@ protected function setUp(): void $productLimitationFactoryMock->method('create') ->willReturn($productLimitationMock); - $this->temporaryStorage = $this->getMockBuilder(TemporaryStorage::class) - ->disableOriginalConstructor() - ->getMock(); - $temporaryStorageFactory = $this->getMockBuilder(TemporaryStorageFactory::class) - ->setMethods(['create']) - ->disableOriginalConstructor() - ->getMock(); - $temporaryStorageFactory->expects($this->any()) - ->method('create') - ->willReturn($this->temporaryStorage); $searchCriteriaResolver = $this->getMockBuilder(SearchCriteriaResolverInterface::class) ->disableOriginalConstructor() ->setMethods(['resolve']) @@ -153,12 +124,11 @@ protected function setUp(): void ->willReturn($totalRecordsResolver); $this->model = $this->objectManager->getObject( - Collection::class, + \Magento\CatalogSearch\Model\ResourceModel\Fulltext\Collection::class, [ 'storeManager' => $this->storeManager, 'universalFactory' => $this->universalFactory, 'scopeConfig' => $this->scopeConfig, - 'temporaryStorageFactory' => $temporaryStorageFactory, 'productLimitationFactory' => $productLimitationFactoryMock, 'searchCriteriaResolverFactory' => $searchCriteriaResolverFactory, 'searchResultApplierFactory' => $this->searchResultApplierFactory, @@ -166,7 +136,7 @@ protected function setUp(): void ] ); - $this->search = $this->getMockBuilder(SearchInterface::class) + $this->search = $this->getMockBuilder(\Magento\Search\Api\SearchInterface::class) ->setMethods(['search']) ->getMockForAbstractClass(); $this->model->setSearchCriteriaBuilder($this->criteriaBuilder); @@ -191,7 +161,7 @@ public function testGetFacetedDataWithEmptyAggregations() { $pageSize = 10; - $searchResult = $this->getMockBuilder(SearchResultInterface::class) + $searchResult = $this->getMockBuilder(\Magento\Framework\Api\Search\SearchResultInterface::class) ->getMockForAbstractClass(); $this->search->expects($this->once()) ->method('search') @@ -242,7 +212,7 @@ public function testAddFieldToFilter() */ protected function getScopeConfig() { - $scopeConfig = $this->getMockBuilder(ScopeConfigInterface::class) + $scopeConfig = $this->getMockBuilder(\Magento\Framework\App\Config\ScopeConfigInterface::class) ->setMethods(['getValue']) ->disableOriginalConstructor() ->getMockForAbstractClass(); @@ -255,7 +225,7 @@ protected function getScopeConfig() */ protected function getCriteriaBuilder() { - $criteriaBuilder = $this->getMockBuilder(SearchCriteriaBuilder::class) + $criteriaBuilder = $this->getMockBuilder(\Magento\Framework\Api\Search\SearchCriteriaBuilder::class) ->setMethods(['addFilter', 'create', 'setRequestName']) ->disableOriginalConstructor() ->getMock(); @@ -268,7 +238,7 @@ protected function getCriteriaBuilder() */ protected function getFilterBuilder() { - $filterBuilder = $this->createMock(FilterBuilder::class); + $filterBuilder = $this->createMock(\Magento\Framework\Api\FilterBuilder::class); return $filterBuilder; } @@ -300,10 +270,80 @@ protected function addFiltersToFilterBuilder(MockObject $filterBuilder, array $f */ protected function createFilter() { - $filter = $this->getMockBuilder(Filter::class) + $filter = $this->getMockBuilder(\Magento\Framework\Api\Filter::class) ->disableOriginalConstructor() ->getMock(); return $filter; } + + /** + * Get Mocks for StoreManager so Collection can be used. + * + * @return \PHPUnit\Framework\MockObject\MockObject + */ + private function getStoreManager() + { + $store = $this->getMockBuilder(\Magento\Store\Model\Store::class) + ->setMethods(['getId']) + ->disableOriginalConstructor() + ->getMock(); + $store->expects($this->once()) + ->method('getId') + ->willReturn(1); + + $storeManager = $this->getMockBuilder(\Magento\Store\Model\StoreManagerInterface::class) + ->setMethods(['getStore']) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $storeManager->expects($this->once()) + ->method('getStore') + ->willReturn($store); + + return $storeManager; + } + + /** + * Get mock for UniversalFactory so Collection can be used. + * + * @return \PHPUnit\Framework\MockObject\MockObject + */ + private function getUniversalFactory() + { + $connection = $this->getMockBuilder(\Magento\Framework\DB\Adapter\Pdo\Mysql::class) + ->disableOriginalConstructor() + ->setMethods(['select']) + ->getMockForAbstractClass(); + $select = $this->getMockBuilder(\Magento\Framework\DB\Select::class) + ->disableOriginalConstructor() + ->getMock(); + $connection->expects($this->any())->method('select')->willReturn($select); + + $entity = $this->getMockBuilder(\Magento\Eav\Model\Entity\AbstractEntity::class) + ->setMethods(['getConnection', 'getTable', 'getDefaultAttributes', 'getEntityTable']) + ->disableOriginalConstructor() + ->getMock(); + $entity->expects($this->once()) + ->method('getConnection') + ->willReturn($connection); + $entity->expects($this->exactly(2)) + ->method('getTable') + ->willReturnArgument(0); + $entity->expects($this->once()) + ->method('getDefaultAttributes') + ->willReturn(['attr1', 'attr2']); + $entity->expects($this->once()) + ->method('getEntityTable') + ->willReturn('table'); + + $universalFactory = $this->getMockBuilder(\Magento\Framework\Validator\UniversalFactory::class) + ->setMethods(['create']) + ->disableOriginalConstructor() + ->getMock(); + $universalFactory->expects($this->once()) + ->method('create') + ->willReturn($entity); + + return $universalFactory; + } } diff --git a/app/code/Magento/CatalogSearch/Test/Unit/Model/Search/BaseSelectStrategy/StrategyMapperTest.php b/app/code/Magento/CatalogSearch/Test/Unit/Model/Search/BaseSelectStrategy/StrategyMapperTest.php deleted file mode 100644 index ff47e882c67f8..0000000000000 --- a/app/code/Magento/CatalogSearch/Test/Unit/Model/Search/BaseSelectStrategy/StrategyMapperTest.php +++ /dev/null @@ -1,154 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -declare(strict_types=1); - -namespace Magento\CatalogSearch\Test\Unit\Model\Search\BaseSelectStrategy; - -use Magento\CatalogSearch\Model\Adapter\Mysql\BaseSelectStrategy\BaseSelectAttributesSearchStrategy; -use Magento\CatalogSearch\Model\Adapter\Mysql\BaseSelectStrategy\BaseSelectFullTextSearchStrategy; -use Magento\CatalogSearch\Model\Search\BaseSelectStrategy\StrategyMapper; -use Magento\CatalogSearch\Model\Search\SelectContainer\SelectContainer; -use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; -use PHPUnit\Framework\MockObject\MockObject; -use PHPUnit\Framework\TestCase; - -/** - * @deprecated Implementation class was replaced - * @see \Magento\ElasticSearch - */ -class StrategyMapperTest extends TestCase -{ - /** @var BaseSelectAttributesSearchStrategy|MockObject */ - private $baseSelectAttributeSearchStrategyMock; - - /** @var BaseSelectFullTextSearchStrategy|MockObject */ - private $baseSelectFullTextSearchStrategyMock; - - /** @var SelectContainer|MockObject */ - private $selectContainerMock; - - /** @var StrategyMapper|MockObject */ - private $strategyMapper; - - protected function setUp(): void - { - $this->baseSelectAttributeSearchStrategyMock = $this->getMockBuilder( - BaseSelectAttributesSearchStrategy::class - )->disableOriginalConstructor() - ->getMock(); - - $this->baseSelectFullTextSearchStrategyMock = $this->getMockBuilder( - BaseSelectFullTextSearchStrategy::class - )->disableOriginalConstructor() - ->getMock(); - - $this->selectContainerMock = $this->getMockBuilder(SelectContainer::class) - ->disableOriginalConstructor() - ->setMethods(['isFullTextSearchRequired', 'hasCustomAttributesFilters', 'hasVisibilityFilter']) - ->getMock(); - - $objectManagerHelper = new ObjectManager($this); - - $this->strategyMapper = $objectManagerHelper->getObject( - StrategyMapper::class, - [ - 'baseSelectFullTextSearchStrategy' => $this->baseSelectFullTextSearchStrategyMock, - 'baseSelectAttributesSearchStrategy' => $this->baseSelectAttributeSearchStrategyMock, - ] - ); - } - - /** - * @param $validStrategy - * @param $isFullTextSearchRequired - * @param $hasCustomAttributesFilters - * @param $hasVisibilityFilter - * @param $errorMsg - * @dataProvider dataProvider - */ - public function testBaseSelectFullTextSearchStrategy( - $validStrategy, - $isFullTextSearchRequired, - $hasCustomAttributesFilters, - $hasVisibilityFilter, - $errorMsg - ) { - $this->selectContainerMock - ->method('isFullTextSearchRequired') - ->willReturn($isFullTextSearchRequired); - - $this->selectContainerMock - ->method('hasCustomAttributesFilters') - ->willReturn($hasCustomAttributesFilters); - - $this->selectContainerMock - ->method('hasVisibilityFilter') - ->willReturn($hasVisibilityFilter); - - $expected = $validStrategy === 'BaseSelectFullTextSearchStrategy' - ? $this->baseSelectFullTextSearchStrategyMock - : $this->baseSelectAttributeSearchStrategyMock; - - $this->assertSame( - $expected, - $this->strategyMapper->mapSelectContainerToStrategy($this->selectContainerMock), - $errorMsg - ); - } - - /** - * @return array - */ - public function dataProvider() - { - return [ - [ - 'validStrategy' => 'BaseSelectFullTextSearchStrategy', - 'isFullTextSearchRequired' => true, - 'hasCustomAttributesFilters' => false, - 'hasVisibilityFilter' => false, - 'errorMsg' => 'BaseSelectFullTextSearchStrategy should be returned for selectContainer ' - . 'that requires fulltext search and has no custom attributes and no visibility filters.' - ], [ - 'validStrategy' => 'BaseSelectAttributeSearchStrategy', - 'isFullTextSearchRequired' => false, - 'hasCustomAttributesFilters' => false, - 'hasVisibilityFilter' => false, - 'errorMsg' => 'BaseSelectAttributeSearchStrategy should be returned for selectContainer ' - . 'that does not require fulltext search.' - ], [ - 'validStrategy' => 'BaseSelectAttributeSearchStrategy', - 'isFullTextSearchRequired' => false, - 'hasCustomAttributesFilters' => true, - 'hasVisibilityFilter' => true, - 'errorMsg' => 'BaseSelectAttributeSearchStrategy should be returned for selectContainer ' - . 'that does not require fulltext search but has both custom and visibility filters.' - ], [ - 'validStrategy' => 'BaseSelectAttributeSearchStrategy', - 'isFullTextSearchRequired' => true, - 'hasCustomAttributesFilters' => true, - 'hasVisibilityFilter' => false, - 'errorMsg' => 'BaseSelectAttributeSearchStrategy should be returned for selectContainer ' - . 'that requires fulltext search and has custom attributes.' - ], [ - 'validStrategy' => 'BaseSelectAttributeSearchStrategy', - 'isFullTextSearchRequired' => true, - 'hasCustomAttributesFilters' => false, - 'hasVisibilityFilter' => true, - 'errorMsg' => 'BaseSelectAttributeSearchStrategy should be returned for selectContainer ' - . 'that requires fulltext search and has visibility filters.' - ], [ - 'validStrategy' => 'BaseSelectAttributeSearchStrategy', - 'isFullTextSearchRequired' => true, - 'hasCustomAttributesFilters' => true, - 'hasVisibilityFilter' => true, - 'errorMsg' => 'BaseSelectAttributeSearchStrategy should be returned for selectContainer ' - . 'that requires fulltext search and has both custom and visibility filters.' - ], - - ]; - } -} diff --git a/app/code/Magento/CatalogSearch/Test/Unit/Model/Search/CustomAttributeFilterCheckTest.php b/app/code/Magento/CatalogSearch/Test/Unit/Model/Search/CustomAttributeFilterCheckTest.php deleted file mode 100644 index 6a4b39ac97e14..0000000000000 --- a/app/code/Magento/CatalogSearch/Test/Unit/Model/Search/CustomAttributeFilterCheckTest.php +++ /dev/null @@ -1,197 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -declare(strict_types=1); - -namespace Magento\CatalogSearch\Test\Unit\Model\Search; - -use Magento\Catalog\Model\Product; -use Magento\CatalogSearch\Model\Search\CustomAttributeFilterCheck; -use Magento\Eav\Model\Config; -use Magento\Eav\Model\Entity\Attribute\AbstractAttribute; -use Magento\Framework\Search\Request\Filter\Term; -use Magento\Framework\Search\Request\FilterInterface; -use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; -use PHPUnit\Framework\MockObject\MockObject; -use PHPUnit\Framework\TestCase; - -class CustomAttributeFilterCheckTest extends TestCase -{ - /** @var Config|MockObject */ - private $eavConfig; - - /** @var CustomAttributeFilterCheck */ - private $customAttributeFilterCheck; - - protected function setUp(): void - { - $this->eavConfig = $this->getMockBuilder(Config::class) - ->disableOriginalConstructor() - ->setMethods(['getAttribute']) - ->getMock(); - - $objectManagerHelper = new ObjectManager($this); - $this->customAttributeFilterCheck = $objectManagerHelper->getObject( - CustomAttributeFilterCheck::class, - [ - 'eavConfig' => $this->eavConfig - ] - ); - } - - /** - * @param $attributeFrontEndType - * @dataProvider dataProviderForIsCustomPositive - */ - public function testIsCustomPositive($attributeFrontEndType) - { - $filterField = 'someField'; - - $filter = $this->getMockBuilder(Term::class) - ->disableOriginalConstructor() - ->setMethods(['getType', 'getField']) - ->getMock(); - - $filter - ->method('getField') - ->willReturn($filterField); - - $filter - ->method('getType') - ->willReturn(FilterInterface::TYPE_TERM); - - $attribute = $this->getMockBuilder(AbstractAttribute::class) - ->disableOriginalConstructor() - ->setMethods(['getFrontendInput']) - ->getMockForAbstractClass(); - - $attribute - ->method('getFrontendInput') - ->willReturn($attributeFrontEndType); - - $this->eavConfig - ->method('getAttribute') - ->with(Product::ENTITY, $filterField) - ->willReturn($attribute); - - $this->assertTrue( - $this->customAttributeFilterCheck->isCustom($filter), - 'Filter must be custom!' - ); - } - - /** - * @return array - */ - public function dataProviderForIsCustomPositive() - { - return [ - ['select'], - ['multiselect'] - ]; - } - - public function testIsCustomNegative1() - { - $filterField = 'someField'; - - $filter = $this->getMockBuilder(Term::class) - ->disableOriginalConstructor() - ->setMethods(['getType', 'getField']) - ->getMock(); - - $filter - ->method('getField') - ->willReturn($filterField); - - $filter - ->method('getType') - ->willReturn(FilterInterface::TYPE_TERM); - - $this->eavConfig - ->method('getAttribute') - ->with(Product::ENTITY, $filterField) - ->willReturn(null); - - $this->assertFalse( - $this->customAttributeFilterCheck->isCustom($filter), - 'Filter must not be custom because attribute is null!' - ); - } - - public function testIsCustomNegative2() - { - $filterField = 'someField'; - - $filter = $this->getMockBuilder(Term::class) - ->disableOriginalConstructor() - ->setMethods(['getType', 'getField']) - ->getMock(); - - $filter - ->method('getField') - ->willReturn($filterField); - - $filter - ->method('getType') - ->willReturn(FilterInterface::TYPE_BOOL); - - $attribute = $this->getMockBuilder(AbstractAttribute::class) - ->disableOriginalConstructor() - ->setMethods(['getFrontendInput']) - ->getMockForAbstractClass(); - - $attribute - ->method('getFrontendInput') - ->willReturn('select'); - - $this->eavConfig - ->method('getAttribute') - ->with(Product::ENTITY, $filterField) - ->willReturn($attribute); - - $this->assertFalse( - $this->customAttributeFilterCheck->isCustom($filter), - 'Filter must not be custom because filter type is not termFilter!' - ); - } - - public function testIsCustomNegative3() - { - $filterField = 'someField'; - - $filter = $this->getMockBuilder(Term::class) - ->disableOriginalConstructor() - ->setMethods(['getType', 'getField']) - ->getMock(); - - $filter - ->method('getField') - ->willReturn($filterField); - - $filter - ->method('getType') - ->willReturn(FilterInterface::TYPE_TERM); - - $attribute = $this->getMockBuilder(AbstractAttribute::class) - ->disableOriginalConstructor() - ->setMethods(['getFrontendInput']) - ->getMockForAbstractClass(); - - $attribute - ->method('getFrontendInput') - ->willReturn('any-random-type'); - - $this->eavConfig - ->method('getAttribute') - ->with(Product::ENTITY, $filterField) - ->willReturn($attribute); - - $this->assertFalse( - $this->customAttributeFilterCheck->isCustom($filter), - 'Filter must not be custom because attribute frontend type is not select or multiselect!' - ); - } -} diff --git a/app/code/Magento/CatalogSearch/Test/Unit/Model/Search/FilterMapper/ExclusionStrategyTest.php b/app/code/Magento/CatalogSearch/Test/Unit/Model/Search/FilterMapper/ExclusionStrategyTest.php deleted file mode 100644 index 538cdb190c809..0000000000000 --- a/app/code/Magento/CatalogSearch/Test/Unit/Model/Search/FilterMapper/ExclusionStrategyTest.php +++ /dev/null @@ -1,97 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -declare(strict_types=1); - -namespace Magento\CatalogSearch\Test\Unit\Model\Search\FilterMapper; - -use Magento\CatalogSearch\Model\Adapter\Mysql\Filter\AliasResolver; -use Magento\CatalogSearch\Model\Search\FilterMapper\ExclusionStrategy; -use Magento\Framework\App\Http\Context; -use Magento\Framework\App\ResourceConnection; -use Magento\Framework\DB\Adapter\AdapterInterface; -use Magento\Framework\DB\Select; -use Magento\Framework\Indexer\Dimension; -use Magento\Framework\Indexer\DimensionFactory; -use Magento\Framework\Indexer\ScopeResolver\IndexScopeResolver; -use Magento\Framework\Search\Request\Filter\Term; -use Magento\Framework\Search\Request\IndexScopeResolverInterface; -use Magento\Store\Api\Data\StoreInterface; -use Magento\Store\Api\Data\WebsiteInterface; -use Magento\Store\Model\StoreManagerInterface; -use PHPUnit\Framework\MockObject\MockObject; -use PHPUnit\Framework\TestCase; - -/** - * @SuppressWarnings(PHPMD.CouplingBetweenObjects) - * @deprecated Implementation class was replaced - * @see \Magento\ElasticSearch - */ -class ExclusionStrategyTest extends TestCase -{ - /** - * @var ExclusionStrategy - */ - private $model; - - /** - * @var MockObject - */ - private $storeManagerMock; - - protected function setUp(): void - { - $resourceConnectionMock = $this->createMock(ResourceConnection::class); - $adapterMock = $this->getMockForAbstractClass(AdapterInterface::class); - $resourceConnectionMock->expects($this->any())->method('getConnection')->willReturn($adapterMock); - $this->storeManagerMock = $this->getMockForAbstractClass(StoreManagerInterface::class); - $aliasResolverMock = $this->createMock(AliasResolver::class); - - $indexScopeResolverMock = $this->createMock( - IndexScopeResolverInterface::class - ); - $tableResolverMock = $this->createMock( - IndexScopeResolver::class - ); - $dimensionMock = $this->createMock(Dimension::class); - $dimensionFactoryMock = $this->createMock(DimensionFactory::class); - $dimensionFactoryMock->method('create')->willReturn($dimensionMock); - $storeMock = $this->getMockForAbstractClass(StoreInterface::class); - $storeMock->method('getId')->willReturn(1); - $storeMock->method('getWebsiteId')->willReturn(1); - $this->storeManagerMock->method('getStore')->willReturn($storeMock); - $indexScopeResolverMock->method('resolve')->willReturn('catalog_product_index_price'); - $httpContextMock = $this->createMock(Context::class); - $httpContextMock->method('getValue')->willReturn(1); - - $this->model = new ExclusionStrategy( - $resourceConnectionMock, - $this->storeManagerMock, - $aliasResolverMock, - $tableResolverMock, - $dimensionFactoryMock, - $indexScopeResolverMock, - $httpContextMock - ); - } - - public function testApplyUsesFrontendPriceIndexerTableIfAttributeCodeIsPrice() - { - $attributeCode = 'price'; - $websiteId = 1; - $selectMock = $this->createMock(Select::class); - $selectMock->expects($this->any())->method('joinInner')->willReturnSelf(); - $selectMock->expects($this->any())->method('getPart')->willReturn([]); - - $searchFilterMock = $this->createMock(Term::class); - $searchFilterMock->expects($this->any())->method('getField')->willReturn($attributeCode); - - $websiteMock = $this->getMockForAbstractClass(WebsiteInterface::class); - $websiteMock->expects($this->any())->method('getId')->willReturn($websiteId); - $this->storeManagerMock->expects($this->any())->method('getWebsite')->willReturn($websiteMock); - - $this->assertTrue($this->model->apply($searchFilterMock, $selectMock)); - } -} diff --git a/app/code/Magento/CatalogSearch/Test/Unit/Model/Search/FilterMapper/FilterContextTest.php b/app/code/Magento/CatalogSearch/Test/Unit/Model/Search/FilterMapper/FilterContextTest.php deleted file mode 100644 index ef3c8ebd9cd49..0000000000000 --- a/app/code/Magento/CatalogSearch/Test/Unit/Model/Search/FilterMapper/FilterContextTest.php +++ /dev/null @@ -1,247 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -declare(strict_types=1); - -namespace Magento\CatalogSearch\Test\Unit\Model\Search\FilterMapper; - -use Magento\Catalog\Model\Product; -use Magento\Catalog\Model\ResourceModel\Eav\Attribute; -use Magento\CatalogSearch\Model\Adapter\Mysql\Filter\AliasResolver; -use Magento\CatalogSearch\Model\Search\FilterMapper\ExclusionStrategy; -use Magento\CatalogSearch\Model\Search\FilterMapper\FilterContext; -use Magento\CatalogSearch\Model\Search\FilterMapper\StaticAttributeStrategy; -use Magento\CatalogSearch\Model\Search\FilterMapper\TermDropdownStrategy; -use Magento\Eav\Model\Config; -use Magento\Eav\Model\Entity\Attribute\AbstractAttribute; -use Magento\Framework\DB\Select; -use Magento\Framework\Search\Request\FilterInterface; -use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; -use PHPUnit\Framework\MockObject\MockObject; -use PHPUnit\Framework\TestCase; - -/** - * @deprecated Implementation class was replaced - * @see \Magento\ElasticSearch - * @SuppressWarnings(PHPMD.CouplingBetweenObjects) - */ -class FilterContextTest extends TestCase -{ - /** - * @var FilterContext|MockObject - */ - private $filterContext; - - /** - * @var AliasResolver|MockObject - */ - private $aliasResolver; - - /** - * @var Config|MockObject - */ - private $eavConfig; - - /** - * @var ExclusionStrategy|MockObject - */ - private $exclusionStrategy; - - /** - * @var TermDropdownStrategy|MockObject - */ - private $termDropdownStrategy; - - /** - * @var StaticAttributeStrategy|MockObject - */ - private $staticAttributeStrategy; - - /** - * @var Select - */ - private $select; - - /** - * @inheritDoc - */ - protected function setUp(): void - { - $this->eavConfig = $this->getMockBuilder(Config::class) - ->disableOriginalConstructor() - ->setMethods(['getAttribute']) - ->getMock(); - $this->aliasResolver = $this->getMockBuilder( - AliasResolver::class - ) - ->disableOriginalConstructor() - ->setMethods(['getAlias']) - ->getMock(); - $this->exclusionStrategy = $this->getMockBuilder(ExclusionStrategy::class) - ->disableOriginalConstructor() - ->setMethods(['apply']) - ->getMock(); - $this->termDropdownStrategy = $this->getMockBuilder(TermDropdownStrategy::class) - ->disableOriginalConstructor() - ->setMethods(['apply']) - ->getMock(); - $this->staticAttributeStrategy = $this->getMockBuilder(StaticAttributeStrategy::class) - ->disableOriginalConstructor() - ->setMethods(['apply']) - ->getMock(); - $this->select = $this->getMockBuilder(Select::class) - ->disableOriginalConstructor() - ->setMethods([]) - ->getMock(); - $objectManager = new ObjectManager($this); - $this->filterContext = $objectManager->getObject( - FilterContext::class, - [ - 'eavConfig' => $this->eavConfig, - 'aliasResolver' => $this->aliasResolver, - 'exclusionStrategy' => $this->exclusionStrategy, - 'termDropdownStrategy' => $this->termDropdownStrategy, - 'staticAttributeStrategy' => $this->staticAttributeStrategy, - ] - ); - } - - public function testApplyOnExclusionFilter() - { - $filter = $this->createFilterMock(); - $this->exclusionStrategy->expects($this->once()) - ->method('apply') - ->with($filter, $this->select) - ->willReturn(true); - $this->eavConfig->expects($this->never())->method('getAttribute'); - $this->assertTrue($this->filterContext->apply($filter, $this->select)); - } - - public function testApplyFilterWithoutAttribute() - { - $filter = $this->createFilterMock('some_field'); - $this->exclusionStrategy->expects($this->once()) - ->method('apply') - ->with($filter, $this->select) - ->willReturn(false); - $this->eavConfig->expects($this->once()) - ->method('getAttribute') - ->with(Product::ENTITY, 'some_field') - ->willReturn(null); - $this->assertFalse($this->filterContext->apply($filter, $this->select)); - } - - public function testApplyOnTermFilterBySelect() - { - $filter = $this->createFilterMock('select_field', FilterInterface::TYPE_TERM); - $attribute = $this->createAttributeMock('select'); - $this->eavConfig->expects($this->once()) - ->method('getAttribute') - ->with(Product::ENTITY, 'select_field') - ->willReturn($attribute); - $this->exclusionStrategy->expects($this->once()) - ->method('apply') - ->with($filter, $this->select) - ->willReturn(false); - $this->termDropdownStrategy->expects($this->never()) - ->method('apply') - ->with($filter, $this->select) - ->willReturn(true); - $this->assertFalse($this->filterContext->apply($filter, $this->select)); - } - - public function testApplyOnTermFilterByMultiSelect() - { - $filter = $this->createFilterMock('multiselect_field', FilterInterface::TYPE_TERM); - $attribute = $this->createAttributeMock('multiselect'); - $this->eavConfig->expects($this->once()) - ->method('getAttribute') - ->with(Product::ENTITY, 'multiselect_field') - ->willReturn($attribute); - $this->exclusionStrategy->expects($this->once()) - ->method('apply') - ->with($filter, $this->select) - ->willReturn(false); - $this->termDropdownStrategy->expects($this->never()) - ->method('apply') - ->with($filter, $this->select) - ->willReturn(true); - $this->assertFalse($this->filterContext->apply($filter, $this->select)); - } - - public function testApplyOnTermFilterByStaticAttribute() - { - $filter = $this->createFilterMock('multiselect_field', FilterInterface::TYPE_TERM); - $attribute = $this->createAttributeMock('text', AbstractAttribute::TYPE_STATIC); - $this->eavConfig->expects($this->once()) - ->method('getAttribute') - ->with(Product::ENTITY, 'multiselect_field') - ->willReturn($attribute); - $this->exclusionStrategy->expects($this->once()) - ->method('apply') - ->with($filter, $this->select) - ->willReturn(false); - $this->staticAttributeStrategy->expects($this->once()) - ->method('apply') - ->with($filter, $this->select) - ->willReturn(true); - $this->assertTrue($this->filterContext->apply($filter, $this->select)); - } - - public function testApplyOnTermFilterByUnknownAttributeType() - { - $filter = $this->createFilterMock('multiselect_field', FilterInterface::TYPE_TERM); - $attribute = $this->createAttributeMock('text', 'text'); - $this->eavConfig->expects($this->once()) - ->method('getAttribute') - ->with(Product::ENTITY, 'multiselect_field') - ->willReturn($attribute); - $this->exclusionStrategy->expects($this->once()) - ->method('apply') - ->with($filter, $this->select) - ->willReturn(false); - $this->assertFalse($this->filterContext->apply($filter, $this->select)); - } - - /** - * @param string $field - * @param string $type - * @return FilterInterface|MockObject - */ - private function createFilterMock($field = null, $type = null) - { - $filter = $this->getMockBuilder(FilterInterface::class) - ->setMethods(['getField', 'getType']) - ->getMockForAbstractClass(); - $filter->expects($this->any()) - ->method('getField') - ->willReturn($field); - $filter->expects($this->any()) - ->method('getType') - ->willReturn($type); - - return $filter; - } - - /** - * @param string|null $frontendInput - * @param string|null $backendType - * @return Attribute|MockObject - */ - private function createAttributeMock($frontendInput = null, $backendType = null) - { - $attribute = $this->getMockBuilder(Attribute::class) - ->disableOriginalConstructor() - ->setMethods(['getFrontendInput', 'getBackendType']) - ->getMock(); - $attribute->expects($this->any()) - ->method('getFrontendInput') - ->willReturn($frontendInput); - $attribute->expects($this->any()) - ->method('getBackendType') - ->willReturn($backendType); - return $attribute; - } -} diff --git a/app/code/Magento/CatalogSearch/Test/Unit/Model/Search/FilterMapper/TermDropdownStrategyTest.php b/app/code/Magento/CatalogSearch/Test/Unit/Model/Search/FilterMapper/TermDropdownStrategyTest.php deleted file mode 100644 index a61c7c7b62018..0000000000000 --- a/app/code/Magento/CatalogSearch/Test/Unit/Model/Search/FilterMapper/TermDropdownStrategyTest.php +++ /dev/null @@ -1,85 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -declare(strict_types=1); - -namespace Magento\CatalogSearch\Test\Unit\Model\Search\FilterMapper; - -use Magento\Catalog\Model\ResourceModel\Eav\Attribute; -use Magento\CatalogSearch\Model\Adapter\Mysql\Filter\AliasResolver; -use Magento\CatalogSearch\Model\Search\FilterMapper\TermDropdownStrategy; -use Magento\CatalogSearch\Model\Search\FilterMapper\TermDropdownStrategy\SelectBuilder; -use Magento\Eav\Model\Config as EavConfig; -use Magento\Framework\DB\Select; -use Magento\Framework\Search\Request\FilterInterface; -use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; -use PHPUnit\Framework\MockObject\MockObject; -use PHPUnit\Framework\TestCase; - -/** - * Unit test for \Magento\CatalogSearch\Model\Search\FilterMapper\TermDropdownStrategy. - * - * @deprecated Implementation class was replaced - * @see \Magento\ElasticSearch - */ -class TermDropdownStrategyTest extends TestCase -{ - /** - * @var MockObject - */ - private $eavConfig; - - /** - * @var TermDropdownStrategy - */ - private $termDropdownStrategy; - - /** - * @var AliasResolver|MockObject - */ - private $aliasResolver; - - /** - * @var SelectBuilder|MockObject - */ - private $selectBuilder; - - protected function setUp(): void - { - $objectManager = new ObjectManager($this); - $this->eavConfig = $this->createMock(EavConfig::class); - $this->aliasResolver = $this->createMock(AliasResolver::class); - $this->selectBuilder = $this->createMock(SelectBuilder::class); - $this->termDropdownStrategy = $objectManager->getObject( - TermDropdownStrategy::class, - [ - 'eavConfig' => $this->eavConfig, - 'aliasResolver' => $this->aliasResolver, - 'selectBuilder' => $this->selectBuilder - ] - ); - } - - public function testApply() - { - $attributeId = 5; - $alias = 'some_alias'; - $this->aliasResolver->expects($this->once())->method('getAlias')->willReturn($alias); - $searchFilter = $this->getMockBuilder(FilterInterface::class) - ->addMethods(['getField']) - ->onlyMethods(['getType', 'getName']) - ->getMockForAbstractClass(); - - $select = $this->createMock(Select::class); - $attribute = $this->createMock(Attribute::class); - - $this->eavConfig->expects($this->once())->method('getAttribute')->willReturn($attribute); - $attribute->expects($this->once())->method('getId')->willReturn($attributeId); - $searchFilter->expects($this->once())->method('getField'); - $this->selectBuilder->expects($this->once())->method('execute')->with($attributeId, $alias, $select); - - $this->assertTrue($this->termDropdownStrategy->apply($searchFilter, $select)); - } -} diff --git a/app/code/Magento/CatalogSearch/Test/Unit/Model/Search/IndexBuilderTest.php b/app/code/Magento/CatalogSearch/Test/Unit/Model/Search/IndexBuilderTest.php deleted file mode 100644 index c31693ec3e071..0000000000000 --- a/app/code/Magento/CatalogSearch/Test/Unit/Model/Search/IndexBuilderTest.php +++ /dev/null @@ -1,186 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -declare(strict_types=1); - -namespace Magento\CatalogSearch\Test\Unit\Model\Search; - -use Magento\CatalogSearch\Model\Search\BaseSelectStrategy\BaseSelectStrategyInterface; -use Magento\CatalogSearch\Model\Search\BaseSelectStrategy\StrategyMapper as BaseSelectStrategyMapper; -use Magento\CatalogSearch\Model\Search\FilterMapper\DimensionsProcessor; -use Magento\CatalogSearch\Model\Search\FilterMapper\FilterMapper; -use Magento\CatalogSearch\Model\Search\IndexBuilder; -use Magento\CatalogSearch\Model\Search\SelectContainer\SelectContainer; -use Magento\CatalogSearch\Model\Search\SelectContainer\SelectContainerBuilder; -use Magento\CatalogSearch\Model\Search\TableMapper; -use Magento\Framework\App\Config\ScopeConfigInterface; -use Magento\Framework\App\ResourceConnection; -use Magento\Framework\App\ScopeResolverInterface; -use Magento\Framework\DB\Select; -use Magento\Framework\Indexer\ScopeResolver\IndexScopeResolver; -use Magento\Framework\Search\Adapter\Mysql\ConditionManager; -use Magento\Framework\Search\RequestInterface; -use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; -use Magento\Store\Model\StoreManagerInterface; -use PHPUnit\Framework\MockObject\MockObject; -use PHPUnit\Framework\TestCase; - -/** - * Test for \Magento\CatalogSearch\Model\Search\IndexBuilder - * - * @SuppressWarnings(PHPMD.CouplingBetweenObjects) - * @deprecated Implementation class was replaced - * @see \Magento\ElasticSearch - */ -class IndexBuilderTest extends TestCase -{ - /** - * @var DimensionsProcessor|MockObject - */ - private $dimensionsProcessor; - - /** - * @var SelectContainerBuilder|MockObject - */ - private $selectContainerBuilder; - - /** - * @var BaseSelectStrategyMapper|MockObject - */ - private $baseSelectStrategyMapper; - - /** - * @var FilterMapper|MockObject - */ - private $filterMapper; - - /** - * @var IndexBuilder - */ - private $indexBuilder; - - /** - * @SuppressWarnings(PHPMD.ExcessiveMethodLength) - * @return void - */ - protected function setUp(): void - { - $resource = $this->getMockBuilder(ResourceConnection::class) - ->disableOriginalConstructor() - ->getMock(); - - $config = $this->getMockBuilder(ScopeConfigInterface::class) - ->disableOriginalConstructor() - ->getMockForAbstractClass(); - - $storeManager = $this->getMockBuilder(StoreManagerInterface::class) - ->getMock(); - - $conditionManager = $this->getMockBuilder(ConditionManager::class) - ->disableOriginalConstructor() - ->getMock(); - - $scopeResolver = $this->getMockBuilder(IndexScopeResolver::class) - ->disableOriginalConstructor() - ->getMock(); - - $tableMapper = $this->getMockBuilder(TableMapper::class) - ->disableOriginalConstructor() - ->getMock(); - - $dimensionScopeResolver = $this->getMockBuilder(ScopeResolverInterface::class) - ->disableOriginalConstructor() - ->getMockForAbstractClass(); - - $this->dimensionsProcessor = $this->getMockBuilder(DimensionsProcessor::class) - ->disableOriginalConstructor() - ->getMock(); - - $this->selectContainerBuilder = $this->getMockBuilder(SelectContainerBuilder::class) - ->disableOriginalConstructor() - ->getMock(); - - $this->baseSelectStrategyMapper = $this->getMockBuilder(BaseSelectStrategyMapper::class) - ->disableOriginalConstructor() - ->getMock(); - - $this->filterMapper = $this->getMockBuilder(FilterMapper::class) - ->disableOriginalConstructor() - ->getMock(); - - $objectManagerHelper = new ObjectManager($this); - $this->indexBuilder = $objectManagerHelper->getObject( - IndexBuilder::class, - [ - 'resource' => $resource, - 'config' => $config, - 'storeManager' => $storeManager, - 'conditionManager' => $conditionManager, - 'scopeResolver' => $scopeResolver, - 'tableMapper' => $tableMapper, - 'dimensionScopeResolver' => $dimensionScopeResolver, - 'dimensionsProcessor' => $this->dimensionsProcessor, - 'selectContainerBuilder' => $this->selectContainerBuilder, - 'baseSelectStrategyMapper' => $this->baseSelectStrategyMapper, - 'filterMapper' => $this->filterMapper, - ] - ); - } - - public function testBuilder() - { - $request = $this->getMockBuilder(RequestInterface::class) - ->disableOriginalConstructor() - ->getMockForAbstractClass(); - - $select = $this->getMockBuilder(Select::class) - ->disableOriginalConstructor() - ->getMock(); - - $selectContainer = $this->getMockBuilder(SelectContainer::class) - ->disableOriginalConstructor() - ->setMethods(['getSelect']) - ->getMock(); - - $selectContainer - ->method('getSelect') - ->willReturn($select); - - $baseSelectStrategyInterface = $this->getMockBuilder(BaseSelectStrategyInterface::class) - ->disableOriginalConstructor() - ->getMockForAbstractClass(); - - $this->selectContainerBuilder - ->method('buildByRequest') - ->with($request) - ->willReturn($selectContainer); - - $this->baseSelectStrategyMapper - ->method('mapSelectContainerToStrategy') - ->with($selectContainer) - ->willReturn($baseSelectStrategyInterface); - - $baseSelectStrategyInterface - ->method('createBaseSelect') - ->with($selectContainer) - ->willReturn($selectContainer); - - $this->filterMapper - ->method('applyFilters') - ->with($selectContainer) - ->willReturn($selectContainer); - - $this->dimensionsProcessor - ->method('processDimensions') - ->with($selectContainer) - ->willReturn($selectContainer); - - $this->assertSame( - $select, - $this->indexBuilder->build($request), - 'Build must return Select instance' - ); - } -} diff --git a/app/code/Magento/CatalogSearch/Test/Unit/Model/Search/Indexer/IndexStructureTest.php b/app/code/Magento/CatalogSearch/Test/Unit/Model/Search/Indexer/IndexStructureTest.php deleted file mode 100644 index c5943988a1113..0000000000000 --- a/app/code/Magento/CatalogSearch/Test/Unit/Model/Search/Indexer/IndexStructureTest.php +++ /dev/null @@ -1,217 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -declare(strict_types=1); - -namespace Magento\CatalogSearch\Test\Unit\Model\Search\Indexer; - -use Magento\CatalogSearch\Model\Indexer\IndexStructure; -use Magento\Framework\App\ResourceConnection; -use Magento\Framework\DB\Adapter\AdapterInterface; -use Magento\Framework\DB\Ddl\Table; -use Magento\Framework\Indexer\ScopeResolver\IndexScopeResolver; -use Magento\Framework\Search\Request\Dimension; -use Magento\Framework\Search\Request\IndexScopeResolverInterface; -use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; -use PHPUnit\Framework\MockObject\MockObject; -use PHPUnit\Framework\TestCase; - -/** - * Test for \Magento\Framework\Indexer\IndexStructure - */ -class IndexStructureTest extends TestCase -{ - /** - * @var IndexScopeResolver|MockObject - */ - private $indexScopeResolver; - - /** - * @var ResourceConnection|MockObject - */ - private $resource; - - /** - * @var AdapterInterface|MockObject - */ - private $connection; - - /** - * @var IndexStructure - */ - private $target; - - protected function setUp(): void - { - $this->connection = $this->getMockBuilder(AdapterInterface::class) - ->disableOriginalConstructor() - ->getMockForAbstractClass(); - $this->resource = $this->getMockBuilder(ResourceConnection::class) - ->setMethods(['getConnection']) - ->disableOriginalConstructor() - ->getMock(); - $this->resource->expects($this->atLeastOnce()) - ->method('getConnection') - ->willReturn($this->connection); - $this->indexScopeResolver = $this->getMockBuilder( - IndexScopeResolverInterface::class - )->setMethods(['resolve']) - ->getMock(); - - $objectManager = new ObjectManager($this); - - $this->target = $objectManager->getObject( - IndexStructure::class, - [ - 'resource' => $this->resource, - 'indexScopeResolver' => $this->indexScopeResolver, - ] - ); - } - - public function testDelete() - { - $index = 'index_name'; - $dimensions = [ - 'index_name_scope_3' => $this->createDimensionMock('scope', 3), - 'index_name_scope_5' => $this->createDimensionMock('scope', 5), - 'index_name_scope_1' => $this->createDimensionMock('scope', 1), - ]; - $expectedTable = 'index_name_scope3_scope5_scope1'; - $this->indexScopeResolver->expects($this->once()) - ->method('resolve') - ->with($index, $dimensions) - ->willReturn($expectedTable); - $position = 0; - $position = $this->mockDropTable($position, $expectedTable, true); - - $this->target->delete($index, $dimensions); - } - - public function testCreateWithEmptyFields() - { - $index = 'index_name'; - $expectedTable = 'index_name_scope3_scope5_scope1'; - $dimensions = [ - 'index_name_scope_3' => $this->createDimensionMock('scope', 3), - 'index_name_scope_5' => $this->createDimensionMock('scope', 5), - 'index_name_scope_1' => $this->createDimensionMock('scope', 1), - ]; - $position = 0; - $this->indexScopeResolver->expects($this->once()) - ->method('resolve') - ->with($index, $dimensions) - ->willReturn($expectedTable); - $this->mockFulltextTable($position, $expectedTable, true); - - $this->target->create($index, [], $dimensions); - } - - /** - * @param string $name - * @param string $value - */ - private function createDimensionMock($name, $value) - { - $dimension = $this->getMockBuilder(Dimension::class) - ->setMethods(['getName', 'getValue']) - ->disableOriginalConstructor() - ->getMock(); - $dimension->expects($this->any()) - ->method('getName') - ->willReturn($name); - $dimension->expects($this->any()) - ->method('getValue') - ->willReturn($value); - return $dimension; - } - - /** - * @param $callNumber - * @param $tableName - * @param $isTableExist - * @return mixed - */ - private function mockDropTable($callNumber, $tableName, $isTableExist) - { - $this->connection->expects($this->at($callNumber++)) - ->method('isTableExists') - ->with($tableName) - ->willReturn($isTableExist); - if ($isTableExist) { - $this->connection->expects($this->at($callNumber++)) - ->method('dropTable') - ->with($tableName) - ->willReturn(true); - } - return $callNumber; - } - - /** - * @param $callNumber - * @param $tableName - * @return mixed - */ - private function mockFulltextTable($callNumber, $tableName) - { - $table = $this->getMockBuilder(Table::class) - ->setMethods(['addColumn', 'addIndex']) - ->disableOriginalConstructor() - ->getMock(); - $table->expects($this->at(0)) - ->method('addColumn') - ->with( - 'entity_id', - Table::TYPE_INTEGER, - 10, - ['unsigned' => true, 'nullable' => false], - 'Entity ID' - )->willReturnSelf(); - $table->expects($this->at(1)) - ->method('addColumn') - ->with( - 'attribute_id', - Table::TYPE_INTEGER, - 10, - ['unsigned' => true, 'nullable' => false] - )->willReturnSelf(); - - $table->expects($this->at(2)) - ->method('addColumn') - ->with( - 'data_index', - Table::TYPE_TEXT, - '4g', - ['nullable' => true], - 'Data index' - )->willReturnSelf(); - - $table->expects($this->at(3)) - ->method('addIndex') - ->with( - 'idx_primary', - ['entity_id', 'attribute_id'], - ['type' => AdapterInterface::INDEX_TYPE_PRIMARY] - )->willReturnSelf(); - $table->expects($this->at(4)) - ->method('addIndex') - ->with( - 'FTI_FULLTEXT_DATA_INDEX', - ['data_index'], - ['type' => AdapterInterface::INDEX_TYPE_FULLTEXT] - )->willReturnSelf(); - - $this->connection->expects($this->at($callNumber++)) - ->method('newTable') - ->with($tableName) - ->willReturn($table); - $this->connection->expects($this->at($callNumber++)) - ->method('createTable') - ->with($table) - ->willReturnSelf(); - - return $callNumber; - } -} diff --git a/app/code/Magento/CatalogSearch/Test/Unit/Model/Search/QueryChecker/FullTextSearchCheckTest.php b/app/code/Magento/CatalogSearch/Test/Unit/Model/Search/QueryChecker/FullTextSearchCheckTest.php deleted file mode 100644 index dee23f5a44e6c..0000000000000 --- a/app/code/Magento/CatalogSearch/Test/Unit/Model/Search/QueryChecker/FullTextSearchCheckTest.php +++ /dev/null @@ -1,211 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -declare(strict_types=1); - -namespace Magento\CatalogSearch\Test\Unit\Model\Search\QueryChecker; - -use Magento\CatalogSearch\Model\Search\QueryChecker\FullTextSearchCheck; -use Magento\Framework\Search\Request\Query\BoolExpression; -use Magento\Framework\Search\Request\Query\Filter; -use Magento\Framework\Search\Request\QueryInterface; -use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; -use PHPUnit\Framework\MockObject\MockObject; -use PHPUnit\Framework\TestCase; - -class FullTextSearchCheckTest extends TestCase -{ - /** - * @var FullTextSearchCheck - */ - private $fullTextSearchCheck; - - protected function setUp(): void - { - $this->fullTextSearchCheck = (new ObjectManager($this)) - ->getObject(FullTextSearchCheck::class); - } - - /** - * @param $query - * @param $errorMsg - * - * @dataProvider positiveDataProvider - */ - public function testPositiveCheck($query, $errorMsg) - { - $this->assertTrue( - $this->fullTextSearchCheck->isRequiredForQuery($query), - $errorMsg - ); - } - - /** - * @param $query - * @param $errorMsg - * - * @dataProvider negativeDataProvider - */ - public function testNegativeCheck($query, $errorMsg) - { - $this->assertFalse( - $this->fullTextSearchCheck->isRequiredForQuery($query), - $errorMsg - ); - } - - public function testInvalidArgumentException1() - { - $this->expectException('InvalidArgumentException'); - $matchQueryMock = $this->getMockBuilder(QueryInterface::class) - ->disableOriginalConstructor() - ->setMethods(['getType']) - ->getMockForAbstractClass(); - - $matchQueryMock->expects($this->any()) - ->method('getType') - ->willReturn('42'); - - $this->fullTextSearchCheck->isRequiredForQuery($matchQueryMock); - } - - public function testInvalidArgumentException2() - { - $this->expectException('InvalidArgumentException'); - $filterMock = $this->getFilterQueryMock(); - - $filterMock->expects($this->any()) - ->method('getReferenceType') - ->willReturn('42'); - - $this->fullTextSearchCheck->isRequiredForQuery($filterMock); - } - - /** - * @return array - */ - public function positiveDataProvider() - { - $boolQueryMock = $this->getBoolQueryMock(); - - $boolQueryMock->expects($this->any()) - ->method('getShould') - ->willReturn([]); - - $boolQueryMock->expects($this->any()) - ->method('getMust') - ->willReturn([$this->getMatchQueryMock()]); - - $filterMock = $this->getFilterQueryMock(); - - $filterMock->expects($this->any()) - ->method('getReferenceType') - ->willReturn(Filter::REFERENCE_QUERY); - - $filterMock->expects($this->any()) - ->method('getReference') - ->willReturn($this->getMatchQueryMock()); - - return [ - [ - $this->getMatchQueryMock(), - 'Testing match query' - ], [ - $boolQueryMock, - 'Testing bool query' - ], [ - $filterMock, - 'Testing filter query' - ] - ]; - } - - /** - * @return array - */ - public function negativeDataProvider() - { - $emptyBoolQueryMock = $this->getBoolQueryMock(); - - $emptyBoolQueryMock->expects($this->any()) - ->method('getShould') - ->willReturn([]); - - $emptyBoolQueryMock->expects($this->any()) - ->method('getMust') - ->willReturn([]); - - $emptyBoolQueryMock->expects($this->any()) - ->method('getMustNot') - ->willReturn([]); - - $filterMock = $this->getFilterQueryMock(); - - $filterMock->expects($this->any()) - ->method('getReferenceType') - ->willReturn(Filter::REFERENCE_FILTER); - - return [ - [ - $emptyBoolQueryMock, - 'Testing bool query' - ], [ - $filterMock, - 'Testing filter query' - ] - ]; - } - - /** - * @return MockObject - */ - private function getMatchQueryMock() - { - $matchQueryMock = $this->getMockBuilder(QueryInterface::class) - ->disableOriginalConstructor() - ->setMethods(['getType']) - ->getMockForAbstractClass(); - - $matchQueryMock->expects($this->any()) - ->method('getType') - ->willReturn(QueryInterface::TYPE_MATCH); - - return $matchQueryMock; - } - - /** - * @return MockObject - */ - private function getBoolQueryMock() - { - $boolQueryMock = $this->getMockBuilder(BoolExpression::class) - ->disableOriginalConstructor() - ->setMethods(['getType', 'getShould', 'getMust', 'getMustNot']) - ->getMock(); - - $boolQueryMock->expects($this->any()) - ->method('getType') - ->willReturn(QueryInterface::TYPE_BOOL); - - return $boolQueryMock; - } - - /** - * @return MockObject - */ - private function getFilterQueryMock() - { - $filterQueryMock = $this->getMockBuilder(Filter::class) - ->disableOriginalConstructor() - ->setMethods(['getType', 'getReferenceType', 'getReference']) - ->getMock(); - - $filterQueryMock->expects($this->any()) - ->method('getType') - ->willReturn(QueryInterface::TYPE_FILTER); - - return $filterQueryMock; - } -} diff --git a/app/code/Magento/CatalogSearch/Test/Unit/Model/Search/SelectContainer/SelectContainerBuilderTest.php b/app/code/Magento/CatalogSearch/Test/Unit/Model/Search/SelectContainer/SelectContainerBuilderTest.php deleted file mode 100644 index f7a0548efb59d..0000000000000 --- a/app/code/Magento/CatalogSearch/Test/Unit/Model/Search/SelectContainer/SelectContainerBuilderTest.php +++ /dev/null @@ -1,229 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -declare(strict_types=1); - -namespace Magento\CatalogSearch\Test\Unit\Model\Search\SelectContainer; - -use Magento\CatalogSearch\Model\Search\CustomAttributeFilterCheck; -use Magento\CatalogSearch\Model\Search\FiltersExtractor; -use Magento\CatalogSearch\Model\Search\QueryChecker\FullTextSearchCheck; -use Magento\CatalogSearch\Model\Search\SelectContainer\SelectContainer; -use Magento\CatalogSearch\Model\Search\SelectContainer\SelectContainerBuilder; -use Magento\CatalogSearch\Model\Search\SelectContainer\SelectContainerFactory; -use Magento\Framework\App\Config\ScopeConfigInterface; -use Magento\Framework\App\ResourceConnection; -use Magento\Framework\DB\Adapter\AdapterInterface; -use Magento\Framework\DB\Select; -use Magento\Framework\Search\Request\Filter\Term; -use Magento\Framework\Search\Request\QueryInterface; -use Magento\Framework\Search\RequestInterface; -use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; -use Magento\Store\Model\ScopeInterface; -use PHPUnit\Framework\MockObject\MockObject; -use PHPUnit\Framework\TestCase; - -/** - * @SuppressWarnings(PHPMD.CouplingBetweenObjects) - */ -class SelectContainerBuilderTest extends TestCase -{ - /** - * @var SelectContainerFactory|MockObject - */ - private $selectContainerFactoryMock; - - /** - * @var FullTextSearchCheck|MockObject - */ - private $fullTextSearchCheckMock; - - /** - * @var CustomAttributeFilterCheck|MockObject - */ - private $customAttributeFilterCheckMock; - - /** - * @var FiltersExtractor|MockObject - */ - private $filtersExtractorMock; - - /** - * @var ScopeConfigInterface|MockObject - */ - private $scopeConfigInterfaceMock; - - /** - * @var ResourceConnection|MockObject - */ - private $resourceConnectionMock; - - /** - * @var RequestInterface|MockObject - */ - private $requestMock; - - /** - * @var SelectContainerBuilder - */ - private $selectContainerBuilder; - - protected function setUp(): void - { - $this->selectContainerFactoryMock = $this->getMockBuilder(SelectContainerFactory::class) - ->disableOriginalConstructor() - ->setMethods(['create']) - ->getMock(); - - $this->fullTextSearchCheckMock = $this->getMockBuilder(FullTextSearchCheck::class) - ->disableOriginalConstructor() - ->getMock(); - - $this->customAttributeFilterCheckMock = $this->getMockBuilder(CustomAttributeFilterCheck::class) - ->disableOriginalConstructor() - ->getMock(); - - $this->filtersExtractorMock = $this->getMockBuilder(FiltersExtractor::class) - ->disableOriginalConstructor() - ->getMock(); - - $this->scopeConfigInterfaceMock = $this->getMockBuilder(ScopeConfigInterface::class) - ->disableOriginalConstructor() - ->getMockForAbstractClass(); - - $this->resourceConnectionMock = $this->getMockBuilder(ResourceConnection::class) - ->disableOriginalConstructor() - ->getMock(); - - $this->requestMock = $this->getMockBuilder(RequestInterface::class) - ->disableOriginalConstructor() - ->getMockForAbstractClass(); - - $objectManagerHelper = new ObjectManager($this); - $this->selectContainerBuilder = $objectManagerHelper->getObject( - SelectContainerBuilder::class, - [ - 'selectContainerFactory' => $this->selectContainerFactoryMock, - 'fullTextSearchCheck' => $this->fullTextSearchCheckMock, - 'customAttributeFilterCheck' => $this->customAttributeFilterCheckMock, - 'filtersExtractor' => $this->filtersExtractorMock, - 'scopeConfig' => $this->scopeConfigInterfaceMock, - 'resource' => $this->resourceConnectionMock - ] - ); - } - - public function testBuildByRequest() - { - list($visibilityFilter, $customFilter, $nonCustomFilter) = $this->mockFilters(); - $requestGetQueryResult = $this->mockQuery(); - $requestGetIndexResult = 'space-banana'; - $requestGetDimensionsResult = [1, 2, 3]; - $fullTextSearchCheckResult = true; - $isShowOutOfStockEnabled = true; - $selectContainerMock = $this->getMockBuilder(SelectContainer::class) - ->disableOriginalConstructor() - ->getMock(); - - $this->requestMock - ->method('getQuery') - ->willReturn($requestGetQueryResult); - - $this->requestMock - ->method('getIndex') - ->willReturn($requestGetIndexResult); - - $this->requestMock - ->method('getDimensions') - ->willReturn($requestGetDimensionsResult); - - $this->filtersExtractorMock - ->method('extractFiltersFromQuery') - ->with($requestGetQueryResult) - ->willReturn([$visibilityFilter, $customFilter, $nonCustomFilter]); - - $this->customAttributeFilterCheckMock - ->method('isCustom') - ->withConsecutive([$visibilityFilter], [$customFilter], [$nonCustomFilter]) - ->will($this->onConsecutiveCalls(true, true, false)); - - $this->fullTextSearchCheckMock - ->method('isRequiredForQuery') - ->with($requestGetQueryResult) - ->willReturn($fullTextSearchCheckResult); - - $selectMock = $this->getMockBuilder(Select::class) - ->disableOriginalConstructor() - ->getMock(); - - $connectionMock = $this->getMockBuilder(AdapterInterface::class) - ->disableOriginalConstructor() - ->getMockForAbstractClass(); - - $connectionMock - ->method('select') - ->willReturn($selectMock); - - $this->resourceConnectionMock - ->method('getConnection') - ->willReturn($connectionMock); - - $this->scopeConfigInterfaceMock - ->method('isSetFlag') - ->with('cataloginventory/options/show_out_of_stock', ScopeInterface::SCOPE_STORE) - ->willReturn($isShowOutOfStockEnabled); - - $this->selectContainerFactoryMock - ->method('create') - ->with([ - 'nonCustomAttributesFilters' => [$nonCustomFilter], - 'customAttributesFilters' => [$customFilter], - 'visibilityFilter' => $visibilityFilter, - 'isFullTextSearchRequired' => $fullTextSearchCheckResult, - 'isShowOutOfStockEnabled' => $isShowOutOfStockEnabled, - 'usedIndex' => $requestGetIndexResult, - 'dimensions' => $requestGetDimensionsResult, - 'select' => $selectMock - ])->willReturn($selectContainerMock); - - $this->assertSame( - $selectContainerMock, - $this->selectContainerBuilder->buildByRequest($this->requestMock) - ); - } - - /** - * @return MockObject - */ - private function mockQuery() - { - return $this->getMockBuilder(QueryInterface::class) - ->disableOriginalConstructor() - ->getMockForAbstractClass(); - } - - /** - * @return array - */ - private function mockFilters() - { - $visibilityFilter = $this->getMockBuilder(Term::class) - ->setConstructorArgs(['name1', 'value1', 'visibility']) - ->setMethods(null) - ->getMock(); - - $customFilter = $this->getMockBuilder(Term::class) - ->setConstructorArgs(['name2', 'value2', 'field1']) - ->setMethods(null) - ->getMock(); - - $nonCustomFilter = $this->getMockBuilder(Term::class) - ->setConstructorArgs(['name3', 'value3', 'field2']) - ->setMethods(null) - ->getMock(); - - return [$visibilityFilter, $customFilter, $nonCustomFilter]; - } -} diff --git a/app/code/Magento/CatalogSearch/Test/Unit/Model/Search/TableMapperTest.php b/app/code/Magento/CatalogSearch/Test/Unit/Model/Search/TableMapperTest.php deleted file mode 100644 index d37a5082d450e..0000000000000 --- a/app/code/Magento/CatalogSearch/Test/Unit/Model/Search/TableMapperTest.php +++ /dev/null @@ -1,370 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -declare(strict_types=1); - -namespace Magento\CatalogSearch\Test\Unit\Model\Search; - -use Magento\Catalog\Model\ResourceModel\Product\Attribute\CollectionFactory; -use Magento\CatalogSearch\Model\Adapter\Mysql\Filter\AliasResolver; -use Magento\CatalogSearch\Model\Search\FilterMapper\FilterStrategyInterface; -use Magento\CatalogSearch\Model\Search\FiltersExtractor; -use Magento\CatalogSearch\Model\Search\TableMapper; -use Magento\Eav\Model\Config; -use Magento\Framework\App\Config\ScopeConfigInterface; -use Magento\Framework\App\ResourceConnection; -use Magento\Framework\DB\Select; -use Magento\Framework\Search\Request\Filter\Term; -use Magento\Framework\Search\Request\FilterInterface; -use Magento\Framework\Search\Request\QueryInterface; -use Magento\Framework\Search\RequestInterface; -use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; -use Magento\Store\Model\StoreManagerInterface; -use PHPUnit\Framework\MockObject\MockObject; -use PHPUnit\Framework\TestCase; - -/** - * Test for \Magento\CatalogSearch\Model\Search\TableMapper - * - * @SuppressWarnings(PHPMD.CouplingBetweenObjects) - * @deprecated Implementation class was replaced - * @see \Magento\ElasticSearch - */ -class TableMapperTest extends TestCase -{ - /** - * @var AliasResolver|MockObject - */ - private $aliasResolver; - - /** - * @var TableMapper - */ - private $tableMapper; - - /** - * @var FiltersExtractor|MockObject - */ - private $filterExtractorMock; - - /** - * @var FilterStrategyInterface|MockObject - */ - private $filterStrategy; - - protected function setUp(): void - { - $objectManager = new ObjectManager($this); - - $resource = $this->getMockBuilder(ResourceConnection::class) - ->disableOriginalConstructor() - ->getMock(); - - $storeManager = $this->getMockBuilder(StoreManagerInterface::class) - ->disableOriginalConstructor() - ->getMockForAbstractClass(); - - $attributeCollectionFactory = $this->getMockBuilder(CollectionFactory::class) - ->setMethods(['create']) - ->disableOriginalConstructor() - ->getMock(); - - $eavConfig = $this->getMockBuilder(Config::class) - ->setMethods(['getAttribute']) - ->disableOriginalConstructor() - ->getMock(); - - $scopeConfig = $this->getMockBuilder(ScopeConfigInterface::class) - ->disableOriginalConstructor() - ->getMockForAbstractClass(); - - $this->aliasResolver = $this->getMockBuilder(AliasResolver::class) - ->disableOriginalConstructor() - ->getMock(); - - $this->filterExtractorMock = $this->getMockBuilder(FiltersExtractor::class) - ->disableOriginalConstructor() - ->getMock(); - - $this->filterStrategy = $this->getMockBuilder(FilterStrategyInterface::class) - ->disableOriginalConstructor() - ->getMockForAbstractClass(); - - $this->tableMapper = $objectManager->getObject( - TableMapper::class, - [ - 'resource' => $resource, - 'storeManager' => $storeManager, - 'attributeCollectionFactory' => $attributeCollectionFactory, - 'eavConfig' => $eavConfig, - 'scopeConfig' => $scopeConfig, - 'filterStrategy' => $this->filterStrategy, - 'aliasResolver' => $this->aliasResolver, - 'filtersExtractor' => $this->filterExtractorMock - ] - ); - } - - public function testRequestHasNoFilters() - { - $select = $this->getSelectMock(); - $request = $this->getRequestMock(); - $query = $this->getQueryMock(); - - $request - ->method('getQuery') - ->willReturn($query); - - $this->filterExtractorMock - ->method('extractFiltersFromQuery') - ->with($query) - ->willReturn([]); - - $this->aliasResolver - ->expects($this->never()) - ->method('getAlias'); - - $this->filterStrategy - ->expects($this->never()) - ->method('apply'); - - $this->tableMapper->addTables($select, $request); - } - - public function testRequestHasDifferentFilters() - { - $select = $this->getSelectMock(); - $request = $this->getRequestMock(); - $query = $this->getQueryMock(); - $filters = $this->getDifferentFiltersMock(); - - $request - ->method('getQuery') - ->willReturn($query); - - $this->filterExtractorMock - ->method('extractFiltersFromQuery') - ->with($query) - ->willReturn($filters); - - $consecutiveFilters = array_map( - function ($filter) { - return [$filter]; - }, - $filters - ); - - $this->aliasResolver - ->expects($this->exactly(count($filters))) - ->method('getAlias') - ->withConsecutive(...$consecutiveFilters) - ->willReturnCallback( - function (FilterInterface $filter) { - return $filter->getField() . '_alias'; - } - ); - - $consecutiveFilters = array_map( - function ($filter) use ($select) { - return [$filter, $select]; - }, - $filters - ); - - $this->filterStrategy - ->expects($this->exactly(count($filters))) - ->method('apply') - ->withConsecutive(...$consecutiveFilters) - ->willReturn(true); - - $this->tableMapper->addTables($select, $request); - } - - public function testRequestHasSameFilters() - { - $select = $this->getSelectMock(); - $request = $this->getRequestMock(); - $query = $this->getQueryMock(); - $filters = $this->getSameFiltersMock(); - $uniqueFilters = [$filters[0], $filters[2]]; - - $request - ->method('getQuery') - ->willReturn($query); - - $this->filterExtractorMock - ->method('extractFiltersFromQuery') - ->with($query) - ->willReturn($filters); - - $consecutiveFilters = array_map( - function ($filter) { - return [$filter]; - }, - $filters - ); - - $this->aliasResolver - ->expects($this->exactly(count($filters))) - ->method('getAlias') - ->withConsecutive(...$consecutiveFilters) - ->willReturnCallback( - function (FilterInterface $filter) { - return $filter->getField() . '_alias'; - } - ); - - $consecutiveUniqueFilters = array_map( - function ($filter) use ($select) { - return [$filter, $select]; - }, - $uniqueFilters - ); - - $this->filterStrategy - ->expects($this->exactly(count($uniqueFilters))) - ->method('apply') - ->withConsecutive(...$consecutiveUniqueFilters) - ->willReturn(true); - - $this->tableMapper->addTables($select, $request); - } - - public function testRequestHasUnAppliedFilters() - { - $select = $this->getSelectMock(); - $request = $this->getRequestMock(); - $query = $this->getQueryMock(); - $filters = $this->getSameFiltersMock(); - - $request - ->method('getQuery') - ->willReturn($query); - - $this->filterExtractorMock - ->method('extractFiltersFromQuery') - ->with($query) - ->willReturn($filters); - - $consecutiveFilters = array_map( - function ($filter) { - return [$filter]; - }, - $filters - ); - - $this->aliasResolver - ->expects($this->exactly(count($filters))) - ->method('getAlias') - ->withConsecutive(...$consecutiveFilters) - ->willReturnCallback( - function (FilterInterface $filter) { - return $filter->getField() . '_alias'; - } - ); - - $consecutiveFilters = array_map( - function ($filter) use ($select) { - return [$filter, $select]; - }, - $filters - ); - - $this->filterStrategy - ->expects($this->exactly(count($filters))) - ->method('apply') - ->withConsecutive(...$consecutiveFilters) - ->willReturnCallback( - function (FilterInterface $filter) { - return !($filter->getName() === 'name1' || $filter->getName() === 'name3') - ? true - : false; - } - ); - - $this->tableMapper->addTables($select, $request); - } - - /** - * @return MockObject - */ - private function getSelectMock() - { - return $this->getMockBuilder(Select::class) - ->disableOriginalConstructor() - ->getMock(); - } - - /** - * @return MockObject - */ - private function getRequestMock() - { - return $this->getMockBuilder(RequestInterface::class) - ->disableOriginalConstructor() - ->getMockForAbstractClass(); - } - - /** - * @return MockObject - */ - private function getQueryMock() - { - return $this->getMockBuilder(QueryInterface::class) - ->disableOriginalConstructor() - ->getMockForAbstractClass(); - } - - /** - * @return array - */ - private function getDifferentFiltersMock() - { - $visibilityFilter = $this->getMockBuilder(Term::class) - ->setConstructorArgs(['name1', 'value1', 'visibility']) - ->setMethods(null) - ->getMock(); - - $customFilter = $this->getMockBuilder(Term::class) - ->setConstructorArgs(['name2', 'value2', 'field1']) - ->setMethods(null) - ->getMock(); - - $nonCustomFilter = $this->getMockBuilder(Term::class) - ->setConstructorArgs(['name3', 'value3', 'field2']) - ->setMethods(null) - ->getMock(); - - return [$visibilityFilter, $customFilter, $nonCustomFilter]; - } - - /** - * @return array - */ - private function getSameFiltersMock() - { - $visibilityFilter1 = $this->getMockBuilder(Term::class) - ->setConstructorArgs(['name1', 'value1', 'visibility']) - ->setMethods(null) - ->getMock(); - - $visibilityFilter2 = $this->getMockBuilder(Term::class) - ->setConstructorArgs(['name2', 'value2', 'visibility']) - ->setMethods(null) - ->getMock(); - - $customFilter1 = $this->getMockBuilder(Term::class) - ->setConstructorArgs(['name3', 'value3', 'field1']) - ->setMethods(null) - ->getMock(); - - $customFilter2 = $this->getMockBuilder(Term::class) - ->setConstructorArgs(['name4', 'value4', 'field1']) - ->setMethods(null) - ->getMock(); - - return [$visibilityFilter1, $visibilityFilter2, $customFilter1, $customFilter2]; - } -} diff --git a/app/code/Magento/CatalogSearch/Test/Unit/Plugin/EnableEavIndexerTest.php b/app/code/Magento/CatalogSearch/Test/Unit/Plugin/EnableEavIndexerTest.php deleted file mode 100644 index d93694d1c65f1..0000000000000 --- a/app/code/Magento/CatalogSearch/Test/Unit/Plugin/EnableEavIndexerTest.php +++ /dev/null @@ -1,76 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -declare(strict_types=1); - -namespace Magento\CatalogSearch\Test\Unit\Plugin; - -use Magento\CatalogSearch\Plugin\EnableEavIndexer; -use Magento\Config\Model\Config; -use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; -use PHPUnit\Framework\MockObject\MockObject; -use PHPUnit\Framework\TestCase; - -/** - * @deprecated Implementation class was replaced - * @see \Magento\ElasticSearch - */ -class EnableEavIndexerTest extends TestCase -{ - /** - * @var EnableEavIndexer - */ - private $model; - - /** - * @var Config|MockObject - */ - private $config; - - /** - * Set up - * - * @return void - */ - protected function setUp(): void - { - $this->config = $this->getMockBuilder(Config::class) - ->disableOriginalConstructor() - ->setMethods(['getData', 'setData']) - ->getMock(); - - $objectManagerHelper = new ObjectManagerHelper($this); - $this->model = $objectManagerHelper->getObject( - EnableEavIndexer::class - ); - } - - /** - * Test with other search engine (not MySQL) selected in config - * - * @return void - */ - public function testBeforeSave() - { - $this->config->expects($this->once())->method('getData')->willReturn('elasticsearch'); - $this->config->expects($this->never())->method('setData')->willReturnSelf(); - - $this->model->beforeSave($this->config); - } - - /** - * Test with MySQL search engine selected in config - * - * @return void - */ - public function testBeforeSaveMysqlSearchEngine() - { - $this->config->expects($this->at(0))->method('getData')->willReturn('mysql'); - $this->config->expects($this->at(1))->method('getData')->willReturn([]); - $this->config->expects($this->once())->method('setData')->willReturnSelf(); - - $this->model->beforeSave($this->config); - } -} diff --git a/app/code/Magento/CatalogSearch/etc/di.xml b/app/code/Magento/CatalogSearch/etc/di.xml index 286a6a512a661..6ff9119e78c2a 100644 --- a/app/code/Magento/CatalogSearch/etc/di.xml +++ b/app/code/Magento/CatalogSearch/etc/di.xml @@ -6,40 +6,14 @@ */ --> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd"> - <preference for="Magento\Framework\Search\Adapter\Mysql\Field\ResolverInterface" type="Magento\CatalogSearch\Model\Adapter\Mysql\Field\Resolver" /> - <preference for="Magento\Framework\Search\Adapter\Mysql\Aggregation\DataProviderInterface" type="Magento\CatalogSearch\Model\Adapter\Mysql\Aggregation\DataProvider"/> - <preference for="Magento\Framework\Search\Adapter\Mysql\Filter\PreprocessorInterface" type="Magento\CatalogSearch\Model\Adapter\Mysql\Filter\Preprocessor" /> - <preference for="Magento\Framework\Search\Dynamic\DataProviderInterface" type="Magento\CatalogSearch\Model\Adapter\Mysql\Dynamic\DataProvider" /> <preference for="Magento\Framework\Search\Adapter\OptionsInterface" type="Magento\CatalogSearch\Model\Adapter\Options" /> - <preference for="Magento\CatalogSearch\Model\Search\FilterMapper\FilterStrategyInterface" type="Magento\CatalogSearch\Model\Search\FilterMapper\FilterContext"/> <preference for="Magento\CatalogSearch\Model\Indexer\IndexSwitcherInterface" type="Magento\CatalogSearch\Model\Indexer\IndexSwitcherProxy"/> <preference for="Magento\CatalogSearch\Model\Adapter\Aggregation\RequestCheckerInterface" type="Magento\CatalogSearch\Model\Adapter\Aggregation\RequestCheckerComposite"/> <preference for="Magento\CatalogSearch\Model\ResourceModel\Fulltext\Collection\SearchCriteriaResolverInterface" type="Magento\CatalogSearch\Model\ResourceModel\Fulltext\Collection\SearchCriteriaResolver"/> <preference for="Magento\CatalogSearch\Model\ResourceModel\Fulltext\Collection\SearchResultApplierInterface" type="Magento\CatalogSearch\Model\ResourceModel\Fulltext\Collection\SearchResultApplier"/> <preference for="Magento\CatalogSearch\Model\ResourceModel\Fulltext\Collection\TotalRecordsResolverInterface" type="Magento\CatalogSearch\Model\ResourceModel\Fulltext\Collection\TotalRecordsResolver"/> <preference for="Magento\CatalogSearch\Model\Search\ItemCollectionProviderInterface" type="Magento\CatalogSearch\Model\Search\ItemCollectionProvider"/> - <type name="Magento\CatalogSearch\Model\Indexer\IndexerHandlerFactory"> - <arguments> - <argument name="handlers" xsi:type="array"> - <item name="mysql" xsi:type="string">Magento\CatalogSearch\Model\Indexer\IndexerHandler</item> - </argument> - </arguments> - </type> - <type name="Magento\CatalogSearch\Model\Indexer\IndexSwitcherProxy"> - <arguments> - <argument name="handlers" xsi:type="array"> - <item name="mysql" xsi:type="string">\Magento\CatalogSearch\Model\Indexer\Scope\IndexSwitcher</item> - </argument> - </arguments> - </type> - <type name="Magento\CatalogSearch\Model\Indexer\IndexStructureFactory"> - <arguments> - <argument name="structures" xsi:type="array"> - <item name="mysql" xsi:type="string">Magento\CatalogSearch\Model\Indexer\IndexStructure</item> - </argument> - </arguments> - </type> - <preference for="Magento\Framework\Indexer\IndexStructureInterface" type="Magento\CatalogSearch\Model\Indexer\IndexStructureProxy" /> + <preference for="Magento\Framework\Indexer\IndexStructureInterface" type="Magento\CatalogSearch\Model\Indexer\IndexStructure" /> <type name="Magento\Catalog\Model\Indexer\Product\Full"> <arguments> <argument name="indexerList" xsi:type="array"> @@ -47,13 +21,6 @@ </argument> </arguments> </type> - <type name="Magento\Framework\Search\Adapter\Mysql\Aggregation\DataProviderContainer"> - <arguments> - <argument name="dataProviders" xsi:type="array"> - <item name="catalogsearch_fulltext" xsi:type="object">Magento\CatalogSearch\Model\Adapter\Mysql\Aggregation\DataProvider</item> - </argument> - </arguments> - </type> <type name="Magento\Framework\Module\Setup\Migration"> <arguments> <argument name="compositeModules" xsi:type="array"> @@ -61,11 +28,6 @@ </argument> </arguments> </type> - <type name="Magento\CatalogSearch\Model\Adapter\Mysql\Field\Resolver"> - <arguments> - <argument name="attributeCollection" xsi:type="object" shared="false">Magento\Catalog\Model\ResourceModel\Product\Attribute\Collection</argument> - </arguments> - </type> <type name="Magento\Catalog\Model\ResourceModel\Product"> <plugin name="catalogsearchFulltextProduct" type="Magento\CatalogSearch\Model\Indexer\Fulltext\Plugin\Product"/> </type> @@ -94,33 +56,9 @@ <argument name="entityId" xsi:type="string">entity_id</argument> </arguments> </virtualType> - <type name="Magento\Framework\Search\Adapter\Mysql\DocumentFactory"> - <arguments> - <argument name="entityMetadata" xsi:type="object">Magento\Framework\Search\ProductEntityMetadata</argument> - </arguments> - </type> - <type name="Magento\Framework\Search\Adapter\Mysql\Aggregation\Builder"> - <arguments> - <argument name="entityMetadata" xsi:type="object">Magento\Framework\Search\ProductEntityMetadata</argument> - </arguments> - </type> <type name="Magento\Framework\Search\Request\Config\FilesystemReader"> <plugin name="catalogSearchDynamicFields" type="Magento\CatalogSearch\Model\Search\ReaderPlugin" /> </type> - <type name="Magento\Framework\Search\Dynamic\IntervalFactory"> - <arguments> - <argument name="intervals" xsi:type="array"> - <item name="mysql" xsi:type="string">Magento\Framework\Search\Adapter\Mysql\Aggregation\Interval</item> - </argument> - </arguments> - </type> - <type name="Magento\Framework\Search\Dynamic\DataProviderFactory"> - <arguments> - <argument name="dataProviders" xsi:type="array"> - <item name="mysql" xsi:type="string">Magento\CatalogSearch\Model\Adapter\Mysql\Dynamic\DataProvider</item> - </argument> - </arguments> - </type> <type name="Magento\Backend\Controller\Adminhtml\Index\GlobalSearch"> <arguments> <argument name="searchModules" xsi:type="array"> @@ -200,14 +138,6 @@ <argument name="collectionProvider" xsi:type="object">Magento\CatalogSearch\Model\Search\ItemCollectionProviderInterface</argument> </arguments> </type> - <type name="Magento\CatalogSearch\Model\Search\ItemCollectionProvider"> - <arguments> - <argument name="factories" xsi:type="array"> - <item name="default" xsi:type="object">Magento\CatalogSearch\Model\ResourceModel\Advanced\CollectionFactory</item> - <item name="mysql" xsi:type="object">Magento\CatalogSearch\Model\ResourceModel\Advanced\CollectionFactory</item> - </argument> - </arguments> - </type> <virtualType name="Magento\CatalogSearch\Model\Layer\Category\Context" type="Magento\Catalog\Model\Layer\Category\Context"> <arguments> <argument name="collectionProvider" xsi:type="object">Magento\CatalogSearch\Model\Layer\Category\ItemCollectionProvider</argument> @@ -229,27 +159,6 @@ <argument name="context" xsi:type="object">Magento\CatalogSearch\Model\Layer\Search\Context</argument> </arguments> </type> - <type name="Magento\CatalogSearch\Model\Adapter\Mysql\Aggregation\DataProvider"> - <arguments> - <argument name="range" xsi:type="object">Magento\Catalog\Model\Layer\Filter\Price\Range\Proxy</argument> - <!-- @deprecated parameter customerSession has been deprecated and not in used now --> - <argument name="customerSession" xsi:type="null"/> - </arguments> - <plugin name="categoryIdAggregation" type="Magento\CatalogSearch\Model\Adapter\Mysql\Plugin\Aggregation\Category\DataProvider" /> - </type> - <type name="Magento\Framework\Search\Adapter\Mysql\Mapper"> - <arguments> - <argument name="indexProviders" xsi:type="array"> - <item name="catalogsearch_fulltext" xsi:type="object">Magento\CatalogSearch\Model\Search\IndexBuilder</item> - </argument> - <argument name="entityMetadata" xsi:type="object">Magento\Framework\Search\ProductEntityMetadata</argument> - </arguments> - </type> - <type name="Magento\CatalogSearch\Model\Adapter\Mysql\Filter\Preprocessor"> - <arguments> - <argument name="attributePrefix" xsi:type="const">Magento\CatalogSearch\Model\ResourceModel\Engine::ATTRIBUTE_PREFIX</argument> - </arguments> - </type> <type name="Magento\Search\Model\Autocomplete"> <arguments> <argument name="dataProviders" xsi:type="array"> @@ -272,29 +181,6 @@ </argument> </arguments> </type> - <type name="Magento\CatalogSearch\Model\Indexer\IndexerHandler"> - <arguments> - <argument name="indexScopeResolver" xsi:type="object">\Magento\CatalogSearch\Model\Indexer\Scope\ScopeProxy</argument> - </arguments> - </type> - <type name="Magento\CatalogSearch\Model\Indexer\IndexStructure"> - <arguments> - <argument name="indexScopeResolver" xsi:type="object">\Magento\CatalogSearch\Model\Indexer\Scope\ScopeProxy</argument> - </arguments> - </type> - <type name="Magento\CatalogSearch\Model\Indexer\Scope\IndexSwitcher"> - <arguments> - <argument name="indexScopeResolver" xsi:type="object">\Magento\CatalogSearch\Model\Indexer\Scope\ScopeProxy</argument> - </arguments> - </type> - <type name="Magento\CatalogSearch\Model\Indexer\Scope\ScopeProxy"> - <arguments> - <argument name="states" xsi:type="array"> - <item name="use_temporary_table" xsi:type="string">\Magento\CatalogSearch\Model\Indexer\Scope\TemporaryResolver</item> - <item name="use_main_table" xsi:type="string">\Magento\Framework\Indexer\ScopeResolver\IndexScopeResolver</item> - </argument> - </arguments> - </type> <type name="Magento\CatalogSearch\Model\Adapter\Aggregation\RequestCheckerComposite"> <arguments> <argument name="queryCheckers" xsi:type="array"> @@ -313,16 +199,6 @@ <argument name="name" xsi:type="string">catalog_view_container</argument> </arguments> </type> - <type name="Magento\CatalogSearch\Model\Search\FilterMapper\TermDropdownStrategy"> - <arguments> - <!-- @deprecated parameter storeManager has been deprecated and not in used now --> - <argument name="storeManager" xsi:type="null"/> - <!-- @deprecated parameter resourceConnection has been deprecated and not in used now --> - <argument name="resourceConnection" xsi:type="null"/> - <!-- @deprecated parameter scopeConfig has been deprecated and not in used now --> - <argument name="scopeConfig" xsi:type="null"/> - </arguments> - </type> <type name="Magento\CatalogSearch\Model\Indexer\Fulltext"> <arguments> <argument name="dimensionProvider" xsi:type="object" shared="false"> @@ -330,38 +206,42 @@ </argument> </arguments> </type> - <type name="Magento\CatalogSearch\Model\Search\FilterMapper\ExclusionStrategy"> + <type name="Magento\Eav\Model\Entity\Setup\PropertyMapper\Composite"> <arguments> - <argument name="priceTableResolver" xsi:type="object"> - Magento\Catalog\Model\Indexer\Product\Price\PriceTableResolver + <argument name="propertyMappers" xsi:type="array"> + <item name="catalog_search" xsi:type="string">Magento\CatalogSearch\Model\ResourceModel\Setup\PropertyMapper</item> </argument> </arguments> </type> - <type name="Magento\CatalogSearch\Model\Adapter\Mysql\Dynamic\DataProvider"> + <type name="Magento\CatalogSearch\Model\Indexer\Fulltext\Action\DataProvider"> + <plugin name="stockedProductsFilterPlugin" type="Magento\CatalogSearch\Model\Indexer\Plugin\StockedProductsFilterPlugin"/> + </type> + <type name="Magento\CatalogSearch\Model\Indexer\Fulltext\Action\Full"> <arguments> - <argument name="priceTableResolver" xsi:type="object"> - Magento\Catalog\Model\Indexer\Product\Price\PriceTableResolver - </argument> + <!-- @deprecated parameter indexIteratorFactory has been deprecated and not in use now --> + <argument name="indexIteratorFactory" xsi:type="null" /> </arguments> </type> - <type name="Magento\CatalogSearch\Model\Adapter\Mysql\Aggregation\DataProvider\QueryBuilder"> + <type name="Magento\CatalogSearch\Model\ResourceModel\Advanced\Collection"> <arguments> - <argument name="priceTableResolver" xsi:type="object"> - Magento\Catalog\Model\Indexer\Product\Price\PriceTableResolver - </argument> + <!-- @deprecated parameter requestBuilder has been deprecated and not in use now --> + <argument name="requestBuilder" xsi:type="null" /> + <!-- @deprecated parameter searchEngine has been deprecated and not in use now --> + <argument name="searchEngine" xsi:type="null" /> + <!-- @deprecated parameter temporaryStorageFactory has been deprecated and not in use now --> + <argument name="temporaryStorageFactory" xsi:type="null" /> </arguments> </type> - <type name="Magento\Config\Model\Config"> - <plugin name="config_enable_eav_indexer" type="Magento\CatalogSearch\Plugin\EnableEavIndexer" /> - </type> - <type name="Magento\Eav\Model\Entity\Setup\PropertyMapper\Composite"> + <type name="Magento\CatalogSearch\Model\ResourceModel\Fulltext\Collection"> <arguments> - <argument name="propertyMappers" xsi:type="array"> - <item name="catalog_search" xsi:type="string">Magento\CatalogSearch\Model\ResourceModel\Setup\PropertyMapper</item> - </argument> + <!-- @deprecated parameter catalogSearchData has been deprecated and not in use now --> + <argument name="catalogSearchData" xsi:type="null" /> + <!-- @deprecated parameter requestBuilder has been deprecated and not in use now --> + <argument name="requestBuilder" xsi:type="null" /> + <!-- @deprecated parameter searchEngine has been deprecated and not in use now --> + <argument name="searchEngine" xsi:type="null" /> + <!-- @deprecated parameter temporaryStorageFactory has been deprecated and not in use now --> + <argument name="temporaryStorageFactory" xsi:type="null" /> </arguments> </type> - <type name="Magento\CatalogSearch\Model\Indexer\Fulltext\Action\DataProvider"> - <plugin name="stockedProductsFilterPlugin" type="Magento\CatalogSearch\Model\Indexer\Plugin\StockedProductsFilterPlugin"/> - </type> </config> diff --git a/app/code/Magento/CatalogSearch/etc/search_request.xml b/app/code/Magento/CatalogSearch/etc/search_request.xml index 6f9eb6e20666e..2111c469986ec 100644 --- a/app/code/Magento/CatalogSearch/etc/search_request.xml +++ b/app/code/Magento/CatalogSearch/etc/search_request.xml @@ -14,6 +14,7 @@ <queries> <query xsi:type="boolQuery" name="quick_search_container" boost="1"> <queryReference clause="should" ref="search" /> + <queryReference clause="should" ref="partial_search" /> <queryReference clause="must" ref="category"/> <queryReference clause="must" ref="price"/> <queryReference clause="must" ref="visibility"/> @@ -21,6 +22,11 @@ <query xsi:type="matchQuery" value="$search_term$" name="search"> <match field="*"/> </query> + <query xsi:type="matchQuery" value="$search_term$" name="partial_search"> + <match field="*"/> + <match field="name" matchCondition="match_phrase_prefix"/> + <match field="sku" matchCondition="match_phrase_prefix"/> + </query> <query xsi:type="filteredQuery" name="category"> <filterReference clause="must" ref="category_filter"/> </query> diff --git a/app/code/Magento/Checkout/Controller/Sidebar/RemoveItem.php b/app/code/Magento/Checkout/Controller/Sidebar/RemoveItem.php index 3a17f4f718019..f50d8843a5f9d 100644 --- a/app/code/Magento/Checkout/Controller/Sidebar/RemoveItem.php +++ b/app/code/Magento/Checkout/Controller/Sidebar/RemoveItem.php @@ -9,6 +9,8 @@ use Exception; use Magento\Checkout\Model\Sidebar; +use Magento\Framework\App\Action\Action; +use Magento\Framework\App\Action\Context; use Magento\Framework\App\Action\HttpPostActionInterface; use Magento\Framework\App\RequestInterface; use Magento\Framework\Controller\Result\JsonFactory as ResultJsonFactory; @@ -17,7 +19,7 @@ use Magento\Framework\Exception\LocalizedException; use Psr\Log\LoggerInterface; -class RemoveItem implements HttpPostActionInterface +class RemoveItem extends Action implements HttpPostActionInterface { /** * @var RequestInterface @@ -32,7 +34,7 @@ class RemoveItem implements HttpPostActionInterface /** * @var ResultRedirectFactory */ - private $resultRedirectFactory; + protected $resultRedirectFactory; /** * @var Sidebar @@ -50,6 +52,7 @@ class RemoveItem implements HttpPostActionInterface protected $logger; /** + * @param Context $context * @param RequestInterface $request * @param ResultJsonFactory $resultJsonFactory * @param ResultRedirectFactory $resultRedirectFactory @@ -58,6 +61,7 @@ class RemoveItem implements HttpPostActionInterface * @param LoggerInterface $logger */ public function __construct( + Context $context, RequestInterface $request, ResultJsonFactory $resultJsonFactory, ResultRedirectFactory $resultRedirectFactory, @@ -65,6 +69,7 @@ public function __construct( Validator $formKeyValidator, LoggerInterface $logger ) { + parent::__construct($context); $this->request = $request; $this->resultJsonFactory = $resultJsonFactory; $this->resultRedirectFactory = $resultRedirectFactory; diff --git a/app/code/Magento/Cms/Controller/Page/View.php b/app/code/Magento/Cms/Controller/Page/View.php index da35e7a9ea9e4..1bfe735fd01ca 100644 --- a/app/code/Magento/Cms/Controller/Page/View.php +++ b/app/code/Magento/Cms/Controller/Page/View.php @@ -8,6 +8,8 @@ namespace Magento\Cms\Controller\Page; use Magento\Cms\Helper\Page as PageHelper; +use Magento\Framework\App\Action\Action; +use Magento\Framework\App\Action\Context; use Magento\Framework\App\Action\HttpGetActionInterface; use Magento\Framework\App\Action\HttpPostActionInterface; use Magento\Framework\App\RequestInterface; @@ -17,7 +19,7 @@ /** * Custom page for storefront. Needs to be accessible by POST because of the store switching. */ -class View implements HttpGetActionInterface, HttpPostActionInterface +class View extends Action implements HttpGetActionInterface, HttpPostActionInterface { /** * @var ForwardFactory @@ -35,15 +37,18 @@ class View implements HttpGetActionInterface, HttpPostActionInterface private $pageHelper; /** + * @param Context $context * @param RequestInterface $request * @param PageHelper $pageHelper * @param ForwardFactory $resultForwardFactory */ public function __construct( + Context $context, RequestInterface $request, PageHelper $pageHelper, ForwardFactory $resultForwardFactory ) { + parent::__construct($context); $this->request = $request; $this->pageHelper = $pageHelper; $this->resultForwardFactory = $resultForwardFactory; diff --git a/app/code/Magento/CmsGraphQl/Model/Resolver/Blocks.php b/app/code/Magento/CmsGraphQl/Model/Resolver/Blocks.php index e55db2a3fa42a..b450ff2dc3500 100644 --- a/app/code/Magento/CmsGraphQl/Model/Resolver/Blocks.php +++ b/app/code/Magento/CmsGraphQl/Model/Resolver/Blocks.php @@ -14,6 +14,7 @@ use Magento\Framework\GraphQl\Exception\GraphQlNoSuchEntityException; use Magento\Framework\GraphQl\Query\ResolverInterface; use Magento\Framework\GraphQl\Schema\Type\ResolveInfo; +use function is_numeric; /** * CMS blocks field resolver, used for GraphQL request processing @@ -44,14 +45,13 @@ public function resolve( array $value = null, array $args = null ) { - + $storeId = (int)$context->getExtensionAttributes()->getStore()->getId(); $blockIdentifiers = $this->getBlockIdentifiers($args); - $blocksData = $this->getBlocksData($blockIdentifiers); + $blocksData = $this->getBlocksData($blockIdentifiers, $storeId); - $resultData = [ + return [ 'items' => $blocksData, ]; - return $resultData; } /** @@ -74,15 +74,22 @@ private function getBlockIdentifiers(array $args): array * Get blocks data * * @param array $blockIdentifiers + * @param int $storeId * @return array * @throws GraphQlNoSuchEntityException */ - private function getBlocksData(array $blockIdentifiers): array + private function getBlocksData(array $blockIdentifiers, int $storeId): array { $blocksData = []; foreach ($blockIdentifiers as $blockIdentifier) { try { - $blocksData[$blockIdentifier] = $this->blockDataProvider->getData($blockIdentifier); + if (!is_numeric($blockIdentifier)) { + $blocksData[$blockIdentifier] = $this->blockDataProvider + ->getBlockByIdentifier($blockIdentifier, $storeId); + } else { + $blocksData[$blockIdentifier] = $this->blockDataProvider + ->getBlockById((int)$blockIdentifier, $storeId); + } } catch (NoSuchEntityException $e) { $blocksData[$blockIdentifier] = new GraphQlNoSuchEntityException(__($e->getMessage()), $e); } diff --git a/app/code/Magento/CmsGraphQl/Model/Resolver/DataProvider/Block.php b/app/code/Magento/CmsGraphQl/Model/Resolver/DataProvider/Block.php index 21bdca732b606..c1457b2c45e6e 100644 --- a/app/code/Magento/CmsGraphQl/Model/Resolver/DataProvider/Block.php +++ b/app/code/Magento/CmsGraphQl/Model/Resolver/DataProvider/Block.php @@ -9,7 +9,9 @@ use Magento\Cms\Api\BlockRepositoryInterface; use Magento\Cms\Api\Data\BlockInterface; +use Magento\Framework\Api\SearchCriteriaBuilder; use Magento\Framework\Exception\NoSuchEntityException; +use Magento\Store\Model\Store; use Magento\Widget\Model\Template\FilterEmulate; /** @@ -27,43 +29,87 @@ class Block */ private $widgetFilter; + /** + * @var SearchCriteriaBuilder + */ + private $searchCriteriaBuilder; + /** * @param BlockRepositoryInterface $blockRepository * @param FilterEmulate $widgetFilter + * @param SearchCriteriaBuilder $searchCriteriaBuilder */ public function __construct( BlockRepositoryInterface $blockRepository, - FilterEmulate $widgetFilter + FilterEmulate $widgetFilter, + SearchCriteriaBuilder $searchCriteriaBuilder ) { $this->blockRepository = $blockRepository; $this->widgetFilter = $widgetFilter; + $this->searchCriteriaBuilder = $searchCriteriaBuilder; } /** - * Get block data + * Get block data by identifier * * @param string $blockIdentifier + * @param int $storeId + * @return array + * @throws NoSuchEntityException + */ + public function getBlockByIdentifier(string $blockIdentifier, int $storeId): array + { + $blockData = $this->fetchBlockData($blockIdentifier, BlockInterface::IDENTIFIER, $storeId); + + return $blockData; + } + + /** + * Get block data by block_id + * + * @param int $blockId + * @param int $storeId * @return array * @throws NoSuchEntityException */ - public function getData(string $blockIdentifier): array + public function getBlockById(int $blockId, int $storeId): array { - $block = $this->blockRepository->getById($blockIdentifier); + $blockData = $this->fetchBlockData($blockId, BlockInterface::BLOCK_ID, $storeId); - if (false === $block->isActive()) { + return $blockData; + } + + /** + * Fetch black data by either id or identifier field + * + * @param mixed $identifier + * @param string $field + * @param int $storeId + * @return array + * @throws NoSuchEntityException + */ + private function fetchBlockData($identifier, string $field, int $storeId): array + { + $searchCriteria = $this->searchCriteriaBuilder + ->addFilter($field, $identifier) + ->addFilter(Store::STORE_ID, [$storeId, Store::DEFAULT_STORE_ID], 'in') + ->addFilter(BlockInterface::IS_ACTIVE, true)->create(); + + $blockResults = $this->blockRepository->getList($searchCriteria)->getItems(); + + if (empty($blockResults)) { throw new NoSuchEntityException( - __('The CMS block with the "%1" ID doesn\'t exist.', $blockIdentifier) + __('The CMS block with the "%1" ID doesn\'t exist.', $identifier) ); } + $block = current($blockResults); $renderedContent = $this->widgetFilter->filterDirective($block->getContent()); - - $blockData = [ + return [ BlockInterface::BLOCK_ID => $block->getId(), BlockInterface::IDENTIFIER => $block->getIdentifier(), BlockInterface::TITLE => $block->getTitle(), BlockInterface::CONTENT => $renderedContent, ]; - return $blockData; } } diff --git a/app/code/Magento/CmsGraphQl/composer.json b/app/code/Magento/CmsGraphQl/composer.json index c0c07dddd4dc2..0e4c849fe8344 100644 --- a/app/code/Magento/CmsGraphQl/composer.json +++ b/app/code/Magento/CmsGraphQl/composer.json @@ -6,7 +6,8 @@ "php": "~7.3.0||~7.4.0", "magento/framework": "*", "magento/module-cms": "*", - "magento/module-widget": "*" + "magento/module-widget": "*", + "magento/module-store": "*" }, "suggest": { "magento/module-graph-ql": "*", diff --git a/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/StorefrontAdvanceCatalogSearchConfigurableBySkuWithHyphenTest.xml b/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/StorefrontAdvanceCatalogSearchConfigurableBySkuWithHyphenTest.xml index b0731da92d652..f26a8d611c56f 100644 --- a/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/StorefrontAdvanceCatalogSearchConfigurableBySkuWithHyphenTest.xml +++ b/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/StorefrontAdvanceCatalogSearchConfigurableBySkuWithHyphenTest.xml @@ -19,7 +19,7 @@ <group value="ConfigurableProduct"/> <group value="SearchEngineElasticsearch"/> <skip> - <issueId value="MC-21228"/> + <issueId value="MC-34217"/> </skip> </annotations> <before> diff --git a/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/StorefrontConfigurableProductChildSearchTest.xml b/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/StorefrontConfigurableProductChildSearchTest.xml index 32136370e08e3..fbf23597a3927 100644 --- a/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/StorefrontConfigurableProductChildSearchTest.xml +++ b/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/StorefrontConfigurableProductChildSearchTest.xml @@ -18,9 +18,6 @@ <testCaseId value="MC-249"/> <group value="ConfigurableProduct"/> <group value="SearchEngineElasticsearch"/> - <skip> - <issueId value="MC-21228"/> - </skip> </annotations> <before> <!-- TODO: This should be converted to an actionGroup once MQE-993 is fixed. --> @@ -148,6 +145,9 @@ <magentoCron groups="index" stepKey="reindexInvalidatedIndices"/> </after> + <magentoCLI command="indexer:reindex" stepKey="reindexAll"/> + <magentoCLI command="cache:flush" stepKey="flushCache"/> + <!-- Quick search the storefront for the first attribute option --> <amOnPage stepKey="goToStoreFront" url="{{StorefrontHomePage.url}}"/> <waitForPageLoad stepKey="waitForStorefront"/> diff --git a/app/code/Magento/ConfigurableProductGraphQl/Model/Options/Collection.php b/app/code/Magento/ConfigurableProductGraphQl/Model/Options/Collection.php index 36ee00d55339b..5e3666407a383 100644 --- a/app/code/Magento/ConfigurableProductGraphQl/Model/Options/Collection.php +++ b/app/code/Magento/ConfigurableProductGraphQl/Model/Options/Collection.php @@ -9,11 +9,11 @@ use Magento\Catalog\Api\Data\ProductInterface; use Magento\Catalog\Model\Product; -use Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\Configurable\Attribute\CollectionFactory; +use Magento\Catalog\Model\ProductFactory; +use Magento\ConfigurableProduct\Model\Product\Type\Configurable\Attribute; use Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\Configurable\Attribute\Collection as AttributeCollection; -use Magento\ConfigurableProduct\Model\Product\Type\Configurable\Attribute; -use Magento\Catalog\Model\ProductFactory; +use Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\Configurable\Attribute\CollectionFactory; use Magento\Framework\EntityManager\MetadataPool; /** @@ -121,6 +121,8 @@ private function fetch() : array $attributeData = $attribute->getData(); $this->attributeMap[$productId][$attribute->getId()] = $attribute->getData(); $this->attributeMap[$productId][$attribute->getId()]['id'] = $attribute->getId(); + $this->attributeMap[$productId][$attribute->getId()]['attribute_id_v2'] + = $attribute->getProductAttribute()->getAttributeId(); $this->attributeMap[$productId][$attribute->getId()]['attribute_code'] = $attribute->getProductAttribute()->getAttributeCode(); $this->attributeMap[$productId][$attribute->getId()]['values'] = $attributeData['options']; diff --git a/app/code/Magento/ConfigurableProductGraphQl/etc/schema.graphqls b/app/code/Magento/ConfigurableProductGraphQl/etc/schema.graphqls index 5053ed848b4e5..2e9576b35e6e8 100644 --- a/app/code/Magento/ConfigurableProductGraphQl/etc/schema.graphqls +++ b/app/code/Magento/ConfigurableProductGraphQl/etc/schema.graphqls @@ -22,7 +22,8 @@ type ConfigurableAttributeOption @doc(description: "ConfigurableAttributeOption type ConfigurableProductOptions @doc(description: "ConfigurableProductOptions defines configurable attributes for the specified product") { id: Int @doc(description: "The configurable option ID number assigned by the system") - attribute_id: String @doc(description: "The ID assigned to the attribute") + attribute_id: String @deprecated(reason: "Use attribute_id_v2 instead") @doc(description: "The ID assigned to the attribute") + attribute_id_v2: Int @doc(description: "The ID assigned to the attribute") attribute_code: String @doc(description: "A string that identifies the attribute") label: String @doc(description: "A string that describes the configurable product option, which is displayed on the UI") position: Int @doc(description: "A number that indicates the order in which the attribute is displayed") diff --git a/app/code/Magento/CustomerGraphQl/Model/Customer/Address/CreateCustomerAddress.php b/app/code/Magento/CustomerGraphQl/Model/Customer/Address/CreateCustomerAddress.php index 37230df202a6f..26b327362650a 100644 --- a/app/code/Magento/CustomerGraphQl/Model/Customer/Address/CreateCustomerAddress.php +++ b/app/code/Magento/CustomerGraphQl/Model/Customer/Address/CreateCustomerAddress.php @@ -11,12 +11,12 @@ use Magento\Customer\Api\Data\AddressInterface; use Magento\Customer\Api\Data\AddressInterfaceFactory; use Magento\Directory\Helper\Data as DirectoryData; -use Magento\Framework\Api\DataObjectHelper; +use Magento\Directory\Model\ResourceModel\Region\CollectionFactory as RegionCollectionFactory; use Magento\Framework\Exception\LocalizedException; use Magento\Framework\GraphQl\Exception\GraphQlInputException; /** - * Create customer address + * Create customer and validate address */ class CreateCustomerAddress { @@ -35,34 +35,51 @@ class CreateCustomerAddress */ private $addressRepository; - /** - * @var DataObjectHelper - */ - private $dataObjectHelper; /** * @var DirectoryData */ private $directoryData; + /** + * @var RegionCollectionFactory + */ + private $regionCollectionFactory; + + /** + * @var ValidateAddress + */ + private $addressValidator; + + /** + * @var PopulateCustomerAddressFromInput + */ + private $populateCustomerAddressFromInput; + /** * @param GetAllowedAddressAttributes $getAllowedAddressAttributes * @param AddressInterfaceFactory $addressFactory * @param AddressRepositoryInterface $addressRepository - * @param DataObjectHelper $dataObjectHelper * @param DirectoryData $directoryData + * @param RegionCollectionFactory $regionCollectionFactory + * @param ValidateAddress $addressValidator + * @param PopulateCustomerAddressFromInput $populateCustomerAddressFromInput */ public function __construct( GetAllowedAddressAttributes $getAllowedAddressAttributes, AddressInterfaceFactory $addressFactory, AddressRepositoryInterface $addressRepository, - DataObjectHelper $dataObjectHelper, - DirectoryData $directoryData + DirectoryData $directoryData, + RegionCollectionFactory $regionCollectionFactory, + ValidateAddress $addressValidator, + PopulateCustomerAddressFromInput $populateCustomerAddressFromInput ) { $this->getAllowedAddressAttributes = $getAllowedAddressAttributes; $this->addressFactory = $addressFactory; $this->addressRepository = $addressRepository; - $this->dataObjectHelper = $dataObjectHelper; $this->directoryData = $directoryData; + $this->regionCollectionFactory = $regionCollectionFactory; + $this->addressValidator = $addressValidator; + $this->populateCustomerAddressFromInput =$populateCustomerAddressFromInput; } /** @@ -79,15 +96,13 @@ public function execute(int $customerId, array $data): AddressInterface if (isset($data['country_code'])) { $data['country_id'] = $data['country_code']; } + $this->validateData($data); /** @var AddressInterface $address */ $address = $this->addressFactory->create(); - $this->dataObjectHelper->populateWithArray($address, $data, AddressInterface::class); - - if (isset($data['region']['region_id'])) { - $address->setRegionId($address->getRegion()->getRegionId()); - } + $this->populateCustomerAddressFromInput->execute($address, $data); + $this->addressValidator->execute($address); $address->setCustomerId($customerId); try { diff --git a/app/code/Magento/CustomerGraphQl/Model/Customer/Address/PopulateCustomerAddressFromInput.php b/app/code/Magento/CustomerGraphQl/Model/Customer/Address/PopulateCustomerAddressFromInput.php new file mode 100644 index 0000000000000..39a7de3b77429 --- /dev/null +++ b/app/code/Magento/CustomerGraphQl/Model/Customer/Address/PopulateCustomerAddressFromInput.php @@ -0,0 +1,121 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\CustomerGraphQl\Model\Customer\Address; + +use Magento\Customer\Api\Data\AddressInterface; +use Magento\Customer\Api\Data\AddressInterfaceFactory; +use Magento\Customer\Api\Data\RegionInterface; +use Magento\Customer\Api\Data\RegionInterfaceFactory; +use Magento\Directory\Helper\Data as DirectoryData; +use Magento\Directory\Model\ResourceModel\Region\CollectionFactory as RegionCollectionFactory; +use Magento\Framework\Api\DataObjectHelper; +use Magento\Framework\GraphQl\Exception\GraphQlInputException; + +/** + * Populate customer address from the input + */ +class PopulateCustomerAddressFromInput +{ + /** + * @var AddressInterfaceFactory + */ + private $addressFactory; + + /** + * @var RegionInterfaceFactory + */ + private $regionFactory; + + /** + * @var DirectoryData + */ + private $directoryData; + + /** + * @var RegionCollectionFactory + */ + private $regionCollectionFactory; + + /** + * @var DataObjectHelper + */ + private $dataObjectHelper; + + /** + * @param AddressInterfaceFactory $addressFactory + * @param RegionInterfaceFactory $regionFactory + * @param DirectoryData $directoryData + * @param RegionCollectionFactory $regionCollectionFactory + * @param DataObjectHelper $dataObjectHelper + */ + public function __construct( + AddressInterfaceFactory $addressFactory, + RegionInterfaceFactory $regionFactory, + DirectoryData $directoryData, + RegionCollectionFactory $regionCollectionFactory, + DataObjectHelper $dataObjectHelper + ) { + $this->addressFactory = $addressFactory; + $this->regionFactory = $regionFactory; + $this->directoryData = $directoryData; + $this->regionCollectionFactory = $regionCollectionFactory; + $this->dataObjectHelper = $dataObjectHelper; + } + + /** + * Populate the customer address and region data from input + * + * @param AddressInterface $address + * @param array $addressData + * @return AddressInterface + * @throws GraphQlInputException + */ + public function execute(AddressInterface $address, array $addressData): AddressInterface + { + $this->dataObjectHelper->populateWithArray($address, $addressData, AddressInterface::class); + + return $this->setRegionData($address, $addressData); + } + + /** + * Set the address region data + * + * @param AddressInterface $address + * @param array $addressData + * @return AddressInterface + * @throws GraphQlInputException + */ + private function setRegionData(AddressInterface $address, array $addressData):AddressInterface + { + if (!empty($addressData['region']['region_id'])) { + if (array_key_exists('country_code', $addressData)) { + $regionCollection = $this->regionCollectionFactory + ->create() + ->addCountryFilter($addressData['country_code']); + if (!empty($addressData['region']['region_code'])) { + $regionCollection->addRegionCodeFilter($addressData['region']['region_code']); + } + + $regionResult = $regionCollection->getItemById($addressData['region']['region_id']); + /** @var RegionInterface $region */ + $region = $this->regionFactory->create(); + if ($regionResult != null) { + $region->setRegionId($regionResult->getRegionId()); + $region->setRegionCode($regionResult->getCode()); + $region->setRegion($regionResult->getDefaultName()); + $address->setRegion($region); + } else { + throw new GraphQlInputException( + __('The region_id does not match the selected country or region') + ); + } + } + } + return $address; + } +} diff --git a/app/code/Magento/CustomerGraphQl/Model/Customer/Address/UpdateCustomerAddress.php b/app/code/Magento/CustomerGraphQl/Model/Customer/Address/UpdateCustomerAddress.php index 26e53c7c3a0a8..afc4fd6eed1ca 100644 --- a/app/code/Magento/CustomerGraphQl/Model/Customer/Address/UpdateCustomerAddress.php +++ b/app/code/Magento/CustomerGraphQl/Model/Customer/Address/UpdateCustomerAddress.php @@ -9,12 +9,14 @@ use Magento\Customer\Api\AddressRepositoryInterface; use Magento\Customer\Api\Data\AddressInterface; +use Magento\Directory\Helper\Data as DirectoryData; +use Magento\Directory\Model\ResourceModel\Region\CollectionFactory as RegionCollectionFactory; +use Magento\Framework\Api\DataObjectHelper; use Magento\Framework\Exception\LocalizedException; use Magento\Framework\GraphQl\Exception\GraphQlInputException; -use Magento\Framework\Api\DataObjectHelper; /** - * Update customer address + * Update customer address on the existing customer address */ class UpdateCustomerAddress { @@ -38,21 +40,53 @@ class UpdateCustomerAddress */ private $restrictedKeys; + /** + * @var DirectoryData + */ + private $directoryData; + + /** + * @var RegionCollectionFactory + */ + private $regionCollectionFactory; + + /** + * @var ValidateAddress + */ + private $addressValidator; + + /** + * @var PopulateCustomerAddressFromInput + */ + private $populateCustomerAddressFromInput; + /** * @param GetAllowedAddressAttributes $getAllowedAddressAttributes * @param AddressRepositoryInterface $addressRepository * @param DataObjectHelper $dataObjectHelper + * @param DirectoryData $directoryData + * @param RegionCollectionFactory $regionCollectionFactory + * @param ValidateAddress $addressValidator + * @param PopulateCustomerAddressFromInput $populateCustomerAddressFromInput * @param array $restrictedKeys */ public function __construct( GetAllowedAddressAttributes $getAllowedAddressAttributes, AddressRepositoryInterface $addressRepository, DataObjectHelper $dataObjectHelper, + DirectoryData $directoryData, + RegionCollectionFactory $regionCollectionFactory, + ValidateAddress $addressValidator, + PopulateCustomerAddressFromInput $populateCustomerAddressFromInput, array $restrictedKeys = [] ) { $this->getAllowedAddressAttributes = $getAllowedAddressAttributes; $this->addressRepository = $addressRepository; $this->dataObjectHelper = $dataObjectHelper; + $this->directoryData = $directoryData; + $this->regionCollectionFactory = $regionCollectionFactory; + $this->addressValidator = $addressValidator; + $this->populateCustomerAddressFromInput = $populateCustomerAddressFromInput; $this->restrictedKeys = $restrictedKeys; } @@ -74,10 +108,15 @@ public function execute(AddressInterface $address, array $data): void $filteredData = array_diff_key($data, array_flip($this->restrictedKeys)); $this->dataObjectHelper->populateWithArray($address, $filteredData, AddressInterface::class); - if (isset($data['region']['region_id'])) { + if (!empty($data['region']['region_id'])) { $address->setRegionId($address->getRegion()->getRegionId()); + } else { + $data['region']['region_id'] = null; } + $this->populateCustomerAddressFromInput->execute($address, $filteredData); + $this->addressValidator->execute($address); + try { $this->addressRepository->save($address); } catch (LocalizedException $e) { diff --git a/app/code/Magento/CustomerGraphQl/Model/Customer/Address/ValidateAddress.php b/app/code/Magento/CustomerGraphQl/Model/Customer/Address/ValidateAddress.php new file mode 100644 index 0000000000000..c1bb26ae2eed1 --- /dev/null +++ b/app/code/Magento/CustomerGraphQl/Model/Customer/Address/ValidateAddress.php @@ -0,0 +1,110 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\CustomerGraphQl\Model\Customer\Address; + +use Magento\Customer\Api\Data\AddressInterface; +use Magento\Customer\Api\Data\AddressInterfaceFactory; +use Magento\Customer\Api\Data\RegionInterfaceFactory; +use Magento\Directory\Helper\Data as DirectoryData; +use Magento\Directory\Model\ResourceModel\Region\CollectionFactory as RegionCollectionFactory; +use Magento\Framework\GraphQl\Exception\GraphQlInputException; + +/** + * Customer address validation used during customer account creation and updating + */ +class ValidateAddress +{ + /** + * @var AddressInterfaceFactory + */ + private $addressFactory; + + /** + * @var RegionInterfaceFactory + */ + private $regionFactory; + + /** + * @var DirectoryData + */ + private $directoryData; + + /** + * @var RegionCollectionFactory + */ + private $regionCollectionFactory; + + /** + * @var ExtractCustomerAddressData + */ + private $extractCustomerAddressData; + + /** + * ValidateCustomerData constructor. + * + * @param AddressInterfaceFactory $addressFactory + * @param RegionInterfaceFactory $regionFactory + * @param DirectoryData $directoryData + * @param RegionCollectionFactory $regionCollectionFactory + * @param ExtractCustomerAddressData $extractCustomerAddressData + */ + public function __construct( + AddressInterfaceFactory $addressFactory, + RegionInterfaceFactory $regionFactory, + DirectoryData $directoryData, + RegionCollectionFactory $regionCollectionFactory, + ExtractCustomerAddressData $extractCustomerAddressData + ) { + $this->addressFactory = $addressFactory; + $this->regionFactory = $regionFactory; + $this->directoryData = $directoryData; + $this->regionCollectionFactory = $regionCollectionFactory; + $this->extractCustomerAddressData = $extractCustomerAddressData; + } + + /** + * Validate customer address data + * + * @param AddressInterface $address + * @throws GraphQlInputException + */ + public function execute(AddressInterface $address): void + { + $addressData = $this->extractCustomerAddressData->execute($address); + + if (isset($addressData['country_code'])) { + $isRegionRequired = $this->directoryData->isRegionRequired($addressData['country_code']); + + if ($isRegionRequired && empty($addressData['region']['region_id'])) { + throw new GraphQlInputException(__('A region_id is required for the specified country code')); + } + $regionCollection = $this->regionCollectionFactory + ->create() + ->addCountryFilter($addressData['country_code']); + + if ($isRegionRequired) { + if (!empty($addressData['region']['region_code'])) { + $regionCollection->addRegionCodeFilter($addressData['region']['region_code']); + } + + if (empty($regionCollection->getItemById($addressData['region']['region_id']))) { + throw new GraphQlInputException( + __('The specified region is not a part of the selected country or region') + ); + } + } else { + if (!empty($addressData['region']['region_id']) && + empty($regionCollection->getItemById($addressData['region']['region_id']))) { + throw new GraphQlInputException( + __('The region_id does not match the selected country or region') + ); + } + } + } + } +} diff --git a/app/code/Magento/CustomerGraphQl/etc/schema.graphqls b/app/code/Magento/CustomerGraphQl/etc/schema.graphqls index 3bf36d11e71fe..42a52bd5a99a7 100644 --- a/app/code/Magento/CustomerGraphQl/etc/schema.graphqls +++ b/app/code/Magento/CustomerGraphQl/etc/schema.graphqls @@ -51,7 +51,7 @@ input CustomerAddressInput { input CustomerAddressRegionInput @doc(description: "CustomerAddressRegionInput defines the customer's state or province") { region_code: String @doc(description: "The address region code") region: String @doc(description: "The state or province name") - region_id: Int @doc(description: "region_id is deprecated. Region ID is excessive on storefront and region code should suffice for all scenarios") + region_id: Int @doc(description: "The unique ID for a pre-defined region") } input CustomerAddressAttributeInput { @@ -110,7 +110,7 @@ type CustomerAddress @doc(description: "CustomerAddress contains detailed inform id: Int @doc(description: "The ID assigned to the address object") customer_id: Int @doc(description: "The customer ID") @deprecated(reason: "customer_id is not needed as part of CustomerAddress, address ID (id) is unique identifier for the addresses.") region: CustomerAddressRegion @doc(description: "An object containing the region name, region code, and region ID") - region_id: Int @deprecated(reason: "Region ID is excessive on storefront and region code should suffice for all scenarios") + region_id: Int @doc(description: "The unique ID for a pre-defined region") country_id: String @doc(description: "The customer's country") @deprecated(reason: "Use `country_code` instead.") country_code: CountryCodeEnum @doc(description: "The customer's country") street: [String] @doc(description: "An array of strings that define the street number and name") @@ -134,7 +134,7 @@ type CustomerAddress @doc(description: "CustomerAddress contains detailed inform type CustomerAddressRegion @doc(description: "CustomerAddressRegion defines the customer's state or province") { region_code: String @doc(description: "The address region code") region: String @doc(description: "The state or province name") - region_id: Int @deprecated(reason: "Region ID is excessive on storefront and region code should suffice for all scenarios") + region_id: Int @doc(description: "The unique ID for a pre-defined region") } type CustomerAddressAttribute { diff --git a/app/code/Magento/Downloadable/Test/Mftf/Test/StorefrontAdvanceCatalogSearchDownloadableBySkuWithHyphenTest.xml b/app/code/Magento/Downloadable/Test/Mftf/Test/StorefrontAdvanceCatalogSearchDownloadableBySkuWithHyphenTest.xml index 21a6a1e3aec14..5f7e9970c27e3 100644 --- a/app/code/Magento/Downloadable/Test/Mftf/Test/StorefrontAdvanceCatalogSearchDownloadableBySkuWithHyphenTest.xml +++ b/app/code/Magento/Downloadable/Test/Mftf/Test/StorefrontAdvanceCatalogSearchDownloadableBySkuWithHyphenTest.xml @@ -19,7 +19,7 @@ <group value="Downloadable"/> <group value="SearchEngineElasticsearch"/> <skip> - <issueId value="MC-21228"/> + <issueId value="MC-34217"/> </skip> </annotations> <before> diff --git a/app/code/Magento/Eav/etc/db_schema.xml b/app/code/Magento/Eav/etc/db_schema.xml index f1f5d19dd2c74..5decc27ea8f26 100644 --- a/app/code/Magento/Eav/etc/db_schema.xml +++ b/app/code/Magento/Eav/etc/db_schema.xml @@ -486,10 +486,6 @@ referenceColumn="attribute_id" onDelete="CASCADE"/> <constraint xsi:type="foreign" referenceId="EAV_ATTRIBUTE_LABEL_STORE_ID_STORE_STORE_ID" table="eav_attribute_label" column="store_id" referenceTable="store" referenceColumn="store_id" onDelete="CASCADE"/> - <constraint xsi:type="unique" referenceId="EAV_ATTRIBUTE_LABEL_ATTRIBUTE_ID_STORE_ID_UNIQUE"> - <column name="store_id"/> - <column name="attribute_id"/> - </constraint> <index referenceId="EAV_ATTRIBUTE_LABEL_STORE_ID" indexType="btree"> <column name="store_id"/> </index> diff --git a/app/code/Magento/Eav/etc/db_schema_whitelist.json b/app/code/Magento/Eav/etc/db_schema_whitelist.json index 756c584d0e4d7..6ed241bbe9edf 100644 --- a/app/code/Magento/Eav/etc/db_schema_whitelist.json +++ b/app/code/Magento/Eav/etc/db_schema_whitelist.json @@ -307,8 +307,7 @@ "constraint": { "PRIMARY": true, "EAV_ATTRIBUTE_LABEL_ATTRIBUTE_ID_EAV_ATTRIBUTE_ATTRIBUTE_ID": true, - "EAV_ATTRIBUTE_LABEL_STORE_ID_STORE_STORE_ID": true, - "EAV_ATTRIBUTE_LABEL_STORE_ID_ATTRIBUTE_ID": true + "EAV_ATTRIBUTE_LABEL_STORE_ID_STORE_STORE_ID": true } }, "eav_form_type": { diff --git a/app/code/Magento/Elasticsearch/Model/ResourceModel/Engine.php b/app/code/Magento/Elasticsearch/Model/ResourceModel/Engine.php index 0f6c674bcda73..8edc8bb4bc618 100644 --- a/app/code/Magento/Elasticsearch/Model/ResourceModel/Engine.php +++ b/app/code/Magento/Elasticsearch/Model/ResourceModel/Engine.php @@ -61,7 +61,7 @@ public function allowAdvancedIndex() } /** - * {@inheritdoc} + * @inheritdoc */ public function processAttributeValue($attribute, $value) { @@ -70,11 +70,12 @@ public function processAttributeValue($attribute, $value) /** * Prepare index array as a string glued by separator + * * Support 2 level array gluing * * @param array $index * @param string $separator - * @return string + * @return array * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ public function prepareEntityIndex($index, $separator = ' ') @@ -83,7 +84,7 @@ public function prepareEntityIndex($index, $separator = ' ') } /** - * {@inheritdoc} + * @inheritdoc */ public function isAvailable() { diff --git a/app/code/Magento/Elasticsearch/SearchAdapter/Query/Builder/Match.php b/app/code/Magento/Elasticsearch/SearchAdapter/Query/Builder/Match.php index 1012918b15a8b..ac40e4ee3c089 100644 --- a/app/code/Magento/Elasticsearch/SearchAdapter/Query/Builder/Match.php +++ b/app/code/Magento/Elasticsearch/SearchAdapter/Query/Builder/Match.php @@ -80,10 +80,10 @@ public function build(array $selectQuery, RequestQueryInterface $requestQuery, $ $minimumShouldMatch = $this->config->getElasticsearchConfigData('minimum_should_match'); foreach ($queries as $query) { $queryBody = $query['body']; - $matchKey = isset($queryBody['match_phrase']) ? 'match_phrase' : 'match'; + $matchKey = array_keys($queryBody)[0]; foreach ($queryBody[$matchKey] as $field => $matchQuery) { $matchQuery['boost'] = $requestQueryBoost + $matchQuery['boost']; - if ($minimumShouldMatch) { + if ($minimumShouldMatch && $matchKey != 'match_phrase_prefix') { $matchQuery['minimum_should_match'] = $minimumShouldMatch; } $queryBody[$matchKey][$field] = $matchQuery; @@ -153,11 +153,11 @@ protected function buildQueries(array $matches, array $queryValue) //Value is incompatible with this field type. continue; } - + $matchCondition = $match['matchCondition'] ?? $condition; $conditions[] = [ 'condition' => $queryValue['condition'], 'body' => [ - $condition => [ + $matchCondition => [ $resolvedField => [ 'query' => $transformedValue, 'boost' => $match['boost'] ?? 1, diff --git a/app/code/Magento/Elasticsearch/Test/Unit/SearchAdapter/Query/Builder/MatchTest.php b/app/code/Magento/Elasticsearch/Test/Unit/SearchAdapter/Query/Builder/MatchTest.php index a6e549379aac3..204c1ac7e5e5b 100644 --- a/app/code/Magento/Elasticsearch/Test/Unit/SearchAdapter/Query/Builder/MatchTest.php +++ b/app/code/Magento/Elasticsearch/Test/Unit/SearchAdapter/Query/Builder/MatchTest.php @@ -86,6 +86,7 @@ protected function setUp(): void * @param array $expected * @param string|null $minimumShouldMatch * @dataProvider buildDataProvider + * @dataProvider buildDataProviderForMatchPhrasePrefix */ public function testBuild( string $searchQuery, @@ -201,10 +202,60 @@ public function buildDataProvider(): array ], ], '2<75%' - ] + ], + ]; } + /** + * @return array + */ + public function buildDataProviderForMatchPhrasePrefix() + { + return [ + 'match_phrase_prefix query with minimum_should_match' => [ + '"fitness bottle"', + [ + [ + 'field' => 'name', + 'boost' => 5, + 'matchCondition' => 'match_phrase_prefix' + ] + ], + [ + [ + 'match_phrase_prefix' => [ + 'name' => [ + 'query' => 'fitness bottle', + 'boost' => 6 + ], + ], + ], + ], + '2<75%' + ], + 'match_phrase_prefix query with no minimum_should_match' => [ + '"fitness bottle"', + [ + [ + 'field' => 'name', + 'boost' => 5, + 'matchCondition' => 'match_phrase_prefix' + ] + ], + [ + [ + 'match_phrase_prefix' => [ + 'name' => [ + 'query' => 'fitness bottle', + 'boost' => 6 + ], + ], + ], + ] + ]]; + } + /** * Mock attribute * diff --git a/app/code/Magento/Elasticsearch/etc/di.xml b/app/code/Magento/Elasticsearch/etc/di.xml index 96410a9d85e26..633889e70591b 100644 --- a/app/code/Magento/Elasticsearch/etc/di.xml +++ b/app/code/Magento/Elasticsearch/etc/di.xml @@ -13,6 +13,7 @@ <preference for="Magento\Elasticsearch\Model\Adapter\FieldMapper\Product\FieldProvider\FieldIndex\ConverterInterface" type="Magento\Elasticsearch\Model\Adapter\FieldMapper\Product\FieldProvider\FieldIndex\Converter" /> <preference for="Magento\Elasticsearch\Model\Adapter\FieldMapper\Product\FieldProvider\FieldType\ConverterInterface" type="Magento\Elasticsearch\Model\Adapter\FieldMapper\Product\FieldProvider\FieldType\Converter" /> <preference for="Magento\Elasticsearch\Model\Adapter\FieldMapper\Product\FieldProviderInterface" type="Magento\Elasticsearch\Model\Adapter\FieldMapper\Product\CompositeFieldProvider" /> + <preference for="Magento\Framework\Search\Dynamic\DataProviderInterface" type="Magento\Elasticsearch\SearchAdapter\Dynamic\DataProvider" /> <preference for="Magento\CatalogSearch\Model\ResourceModel\Fulltext\Collection\SearchResultApplierInterface" type="Magento\Elasticsearch\Model\ResourceModel\Fulltext\Collection\SearchResultApplier"/> <type name="Magento\Catalog\Model\Indexer\Category\Product\Action\Rows"> <plugin name="catalogsearchFulltextProductAssignment" type="Magento\Elasticsearch\Model\Indexer\Fulltext\Plugin\Category\Product\Action\Rows"/> diff --git a/app/code/Magento/Elasticsearch7/etc/di.xml b/app/code/Magento/Elasticsearch7/etc/di.xml index 6ba5b2599f626..b5d013a294e26 100644 --- a/app/code/Magento/Elasticsearch7/etc/di.xml +++ b/app/code/Magento/Elasticsearch7/etc/di.xml @@ -176,6 +176,7 @@ <arguments> <argument name="factories" xsi:type="array"> <item name="elasticsearch7" xsi:type="object">elasticsearchAdvancedCollectionFactory</item> + <item name="default" xsi:type="object">elasticsearchAdvancedCollectionFactory</item> </argument> </arguments> </type> diff --git a/app/code/Magento/GroupedProduct/Test/Mftf/Test/StorefrontAdvanceCatalogSearchGroupedProductBySkuWithHyphenTest.xml b/app/code/Magento/GroupedProduct/Test/Mftf/Test/StorefrontAdvanceCatalogSearchGroupedProductBySkuWithHyphenTest.xml index fc22f7254a7ee..aaa9cf5b2f925 100644 --- a/app/code/Magento/GroupedProduct/Test/Mftf/Test/StorefrontAdvanceCatalogSearchGroupedProductBySkuWithHyphenTest.xml +++ b/app/code/Magento/GroupedProduct/Test/Mftf/Test/StorefrontAdvanceCatalogSearchGroupedProductBySkuWithHyphenTest.xml @@ -19,7 +19,7 @@ <group value="GroupedProduct"/> <group value="SearchEngineElasticsearch"/> <skip> - <issueId value="MC-21228"/> + <issueId value="MC-34217"/> </skip> </annotations> diff --git a/app/code/Magento/LayeredNavigation/Test/Mftf/Test/ShopByButtonInMobileTest.xml b/app/code/Magento/LayeredNavigation/Test/Mftf/Test/ShopByButtonInMobileTest.xml index 3f4e7e6270ca6..cdd692763d399 100644 --- a/app/code/Magento/LayeredNavigation/Test/Mftf/Test/ShopByButtonInMobileTest.xml +++ b/app/code/Magento/LayeredNavigation/Test/Mftf/Test/ShopByButtonInMobileTest.xml @@ -18,9 +18,6 @@ <testCaseId value="MC-6092"/> <group value="LayeredNavigation"/> <group value="SearchEngineElasticsearch"/> - <skip> - <issueId value="MC-21228"/> - </skip> </annotations> <before> <createData entity="productDropDownAttribute" stepKey="attribute"/> @@ -58,7 +55,7 @@ <!-- Check storefront mobile view for shop by button is functioning as expected --> <comment userInput="Check storefront mobile view for shop by button is functioning as expected" stepKey="commentCheckShopByButton" /> <actionGroup ref="StorefrontOpenHomePageActionGroup" stepKey="goToHomePage"/> - <submitForm selector="#search_mini_form" parameterArray="['q' => 'Test Simple Product']" stepKey="fillSearchBar" /> + <submitForm selector="#search_mini_form" parameterArray="['q' => 'Simple']" stepKey="fillSearchBar" /> <resizeWindow width="600" height="800" stepKey="resizeWindow"/> <waitForPageLoad stepKey="waitForHomePageToLoad2"/> <seeElement selector="{{StorefrontCategorySidebarMobileSection.shopByButton}}" stepKey="seeShopByButton"/> diff --git a/app/code/Magento/MediaGallery/Model/Keyword/Command/GetAssetKeywords.php b/app/code/Magento/MediaGallery/Model/Keyword/Command/GetAssetKeywords.php index 27d32e5444f4b..4118fd1495dbb 100644 --- a/app/code/Magento/MediaGallery/Model/Keyword/Command/GetAssetKeywords.php +++ b/app/code/Magento/MediaGallery/Model/Keyword/Command/GetAssetKeywords.php @@ -67,10 +67,11 @@ public function execute(int $assetId): array { try { $connection = $this->resourceConnection->getConnection(); + $tableAssetKeyword = $this->resourceConnection->getTableName(self::TABLE_ASSET_KEYWORD); $select = $connection->select() ->from(['k' => $this->resourceConnection->getTableName(self::TABLE_KEYWORD)]) - ->join(['ak' => self::TABLE_ASSET_KEYWORD], 'k.id = ak.keyword_id') + ->join(['ak' => $tableAssetKeyword], 'k.id = ak.keyword_id') ->where('ak.asset_id = ?', $assetId); $data = $connection->query($select)->fetchAll(); diff --git a/app/code/Magento/MediaGallery/Model/ResourceModel/Keyword/GetAssetsKeywords.php b/app/code/Magento/MediaGallery/Model/ResourceModel/Keyword/GetAssetsKeywords.php index 11b0a0fa3a359..63aaf2b23f05d 100644 --- a/app/code/Magento/MediaGallery/Model/ResourceModel/Keyword/GetAssetsKeywords.php +++ b/app/code/Magento/MediaGallery/Model/ResourceModel/Keyword/GetAssetsKeywords.php @@ -87,7 +87,7 @@ private function getKeywordsData(array $assetIds): array $connection = $this->resourceConnection->getConnection(); $select = $connection->select() ->from(['k' => $this->resourceConnection->getTableName(self::TABLE_KEYWORD)]) - ->join(['ak' => self::TABLE_ASSET_KEYWORD], 'k.id = ak.keyword_id') + ->join(['ak' => $this->resourceConnection->getTableName(self::TABLE_ASSET_KEYWORD)], 'k.id = ak.keyword_id') ->where('ak.asset_id IN (?)', $assetIds); return $connection->query($select)->fetchAll(); } diff --git a/app/code/Magento/PageCache/etc/di.xml b/app/code/Magento/PageCache/etc/di.xml index adf9526fc1108..9bc86b6f1e3f9 100644 --- a/app/code/Magento/PageCache/etc/di.xml +++ b/app/code/Magento/PageCache/etc/di.xml @@ -40,6 +40,13 @@ <type name="Magento\Framework\App\FrontControllerInterface"> <plugin name="page_cache_from_key_from_cookie" type="Magento\PageCache\Plugin\RegisterFormKeyFromCookie" /> </type> + <type name="Magento\Framework\App\Cache\RuntimeStaleCacheStateModifier"> + <arguments> + <argument name="cacheTypes" xsi:type="array"> + <item name="full_page_cache" xsi:type="const">Magento\PageCache\Model\Cache\Type::TYPE_IDENTIFIER</item> + </argument> + </arguments> + </type> <preference for="Magento\PageCache\Model\VclGeneratorInterface" type="Magento\PageCache\Model\Varnish\VclGenerator"/> <preference for="Magento\PageCache\Model\VclTemplateLocatorInterface" type="Magento\PageCache\Model\Varnish\VclTemplateLocator"/> </config> diff --git a/app/code/Magento/QuoteGraphQl/Model/Cart/ExtractQuoteAddressData.php b/app/code/Magento/QuoteGraphQl/Model/Cart/ExtractQuoteAddressData.php index 468ef4b8f879c..ed08d60f3f3b4 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Cart/ExtractQuoteAddressData.php +++ b/app/code/Magento/QuoteGraphQl/Model/Cart/ExtractQuoteAddressData.php @@ -49,7 +49,8 @@ public function execute(QuoteAddress $address): array ], 'region' => [ 'code' => $address->getRegionCode(), - 'label' => $address->getRegion() + 'label' => $address->getRegion(), + 'region_id'=> $address->getRegionId() ], 'street' => $address->getStreet(), 'items_weight' => $address->getWeight(), diff --git a/app/code/Magento/QuoteGraphQl/Model/Cart/GetCartProducts.php b/app/code/Magento/QuoteGraphQl/Model/Cart/GetCartProducts.php new file mode 100644 index 0000000000000..82cbd8cbfde2d --- /dev/null +++ b/app/code/Magento/QuoteGraphQl/Model/Cart/GetCartProducts.php @@ -0,0 +1,65 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\QuoteGraphQl\Model\Cart; + +use Magento\Catalog\Api\ProductRepositoryInterface; +use Magento\Framework\Api\SearchCriteriaBuilder; +use Magento\Quote\Model\Quote; + +/** + * Fetch Product models corresponding to a cart's items + */ +class GetCartProducts +{ + /** + * @var ProductRepositoryInterface + */ + private $productRepository; + + /** + * @var SearchCriteriaBuilder + */ + private $searchCriteriaBuilder; + + /** + * @param ProductRepositoryInterface $productRepository + * @param SearchCriteriaBuilder $searchCriteriaBuilder + */ + public function __construct( + ProductRepositoryInterface $productRepository, + SearchCriteriaBuilder $searchCriteriaBuilder + ) { + $this->productRepository = $productRepository; + $this->searchCriteriaBuilder = $searchCriteriaBuilder; + } + + /** + * Get product models based on items in cart + * + * @param Quote $cart + * @return ProductInterface[] + */ + public function execute(Quote $cart): array + { + $cartItems = $cart->getAllVisibleItems(); + if (empty($cartItems)) { + return []; + } + $cartItemIds = \array_map( + function ($item) { + return $item->getProduct()->getId(); + }, + $cartItems + ); + + $searchCriteria = $this->searchCriteriaBuilder->addFilter('entity_id', $cartItemIds, 'in')->create(); + $products = $this->productRepository->getList($searchCriteria)->getItems(); + + return $products; + } +} diff --git a/app/code/Magento/QuoteGraphQl/Model/Cart/QuoteAddressFactory.php b/app/code/Magento/QuoteGraphQl/Model/Cart/QuoteAddressFactory.php index 9cb3d9173ac59..7f88e9e52f116 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Cart/QuoteAddressFactory.php +++ b/app/code/Magento/QuoteGraphQl/Model/Cart/QuoteAddressFactory.php @@ -9,15 +9,15 @@ use Magento\Customer\Helper\Address as AddressHelper; use Magento\CustomerGraphQl\Model\Customer\Address\GetCustomerAddress; +use Magento\Directory\Helper\Data as CountryHelper; +use Magento\Directory\Model\AllowedCountries; +use Magento\Directory\Model\ResourceModel\Region\CollectionFactory as RegionCollectionFactory; use Magento\Framework\Exception\LocalizedException; use Magento\Framework\GraphQl\Exception\GraphQlAuthorizationException; use Magento\Framework\GraphQl\Exception\GraphQlInputException; use Magento\Framework\GraphQl\Exception\GraphQlNoSuchEntityException; use Magento\Quote\Model\Quote\Address as QuoteAddress; use Magento\Quote\Model\Quote\AddressFactory as BaseQuoteAddressFactory; -use Magento\Directory\Model\ResourceModel\Region\CollectionFactory as RegionCollectionFactory; -use Magento\Directory\Helper\Data as CountryHelper; -use Magento\Directory\Model\AllowedCountries; /** * Create QuoteAddress @@ -98,18 +98,9 @@ public function createBasedOnInputData(array $addressInput): QuoteAddress if (!in_array($addressInput['country_code'], $allowedCountries, true)) { throw new GraphQlInputException(__('Country is not available')); } - $isRegionRequired = $this->countryHelper->isRegionRequired($addressInput['country_code']); - if ($isRegionRequired && !empty($addressInput['region'])) { - $regionCollection = $this->regionCollectionFactory - ->create() - ->addRegionCodeFilter($addressInput['region']) - ->addCountryFilter($addressInput['country_code']); - if ($regionCollection->getSize() === 0) { - throw new GraphQlInputException( - __('Region is not available for the selected country') - ); - } - } + + $this->validateRegion($addressInput); + $maxAllowedLineCount = $this->addressHelper->getStreetLines(); if (is_array($addressInput['street']) && count($addressInput['street']) > $maxAllowedLineCount) { throw new GraphQlInputException( @@ -122,6 +113,65 @@ public function createBasedOnInputData(array $addressInput): QuoteAddress return $quoteAddress; } + /** + * Validate the address region + * + * @param array $addressInput + * @throws GraphQlInputException + */ + private function validateRegion(array $addressInput): void + { + $isRegionRequired = $this->countryHelper->isRegionRequired($addressInput['country_code']); + + if ($isRegionRequired && (empty($addressInput['region']) && empty($addressInput['region_id']))) { + throw new GraphQlInputException(__('Region is required.')); + } + + if ($isRegionRequired) { + $this->validateRegionRequiredAddressInput($addressInput); + } else { + $regionCollection = $this->regionCollectionFactory + ->create() + ->addCountryFilter($addressInput['country_code']); + + if (!empty($addressInput['region_id']) && + empty($regionCollection->getItemById($addressInput['region_id']))) { + throw new GraphQlInputException( + __('The specified region is not a part of the selected country or region') + ); + } + } + } + + /** + * Validate the address region when region is required for the country + * + * @param array $addressInput + * @throws GraphQlInputException + */ + private function validateRegionRequiredAddressInput(array $addressInput): void + { + $regionCollection = $this->regionCollectionFactory + ->create() + ->addCountryFilter($addressInput['country_code']); + + if (!empty($addressInput['region'])) { + $regionCollection->addRegionCodeFilter($addressInput['region']); + } + + if (!empty($addressInput['region_id'])) { + if (empty($regionCollection->getItemById($addressInput['region_id']))) { + throw new GraphQlInputException( + __('The region_id does not match the selected country or region') + ); + } + } else { + if ($regionCollection->getSize() > 1) { + throw new GraphQlInputException(__('Region input is ambiguous. Specify region_id.')); + } + } + } + /** * Create Quote Address based on Customer Address * diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/CartItems.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/CartItems.php index 8017a91b5cfd2..39cf287a518b4 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Resolver/CartItems.php +++ b/app/code/Magento/QuoteGraphQl/Model/Resolver/CartItems.php @@ -10,15 +10,31 @@ use Magento\Framework\Exception\LocalizedException; use Magento\Framework\GraphQl\Config\Element\Field; use Magento\Framework\GraphQl\Exception\GraphQlInputException; +use Magento\Framework\GraphQl\Exception\GraphQlNoSuchEntityException; use Magento\Framework\GraphQl\Query\ResolverInterface; use Magento\Framework\GraphQl\Schema\Type\ResolveInfo; +use Magento\Quote\Model\Quote; use Magento\Quote\Model\Quote\Item as QuoteItem; +use Magento\QuoteGraphQl\Model\Cart\GetCartProducts; /** * @inheritdoc */ class CartItems implements ResolverInterface { + /** + * @var GetCartProducts + */ + private $getCartProducts; + + /** + * @param GetCartProducts $getCartProducts + */ + public function __construct(GetCartProducts $getCartProducts) + { + $this->getCartProducts = $getCartProducts; + } + /** * @inheritdoc */ @@ -36,12 +52,19 @@ public function resolve(Field $field, $context, ResolveInfo $info, array $value $itemsData[] = new GraphQlInputException(__($error->getText())); } } - foreach ($cart->getAllVisibleItems() as $cartItem) { - /** - * @var QuoteItem $cartItem - */ - $productData = $cartItem->getProduct()->getData(); - $productData['model'] = $cartItem->getProduct(); + + $cartProductsData = $this->getCartProductsData($cart); + $cartItems = $cart->getAllVisibleItems(); + /** @var QuoteItem $cartItem */ + foreach ($cartItems as $cartItem) { + $productId = $cartItem->getProduct()->getId(); + if (!isset($cartProductsData[$productId])) { + $itemsData[] = new GraphQlNoSuchEntityException( + __("The product that was requested doesn't exist. Verify the product and try again.") + ); + continue; + } + $productData = $cartProductsData[$productId]; $itemsData[] = [ 'id' => $cartItem->getItemId(), @@ -52,4 +75,22 @@ public function resolve(Field $field, $context, ResolveInfo $info, array $value } return $itemsData; } + + /** + * Get product data for cart items + * + * @param Quote $cart + * @return array + */ + private function getCartProductsData(Quote $cart): array + { + $products = $this->getCartProducts->execute($cart); + $productsData = []; + foreach ($products as $product) { + $productsData[$product->getId()] = $product->getData(); + $productsData[$product->getId()]['model'] = $product; + } + + return $productsData; + } } diff --git a/app/code/Magento/QuoteGraphQl/etc/schema.graphqls b/app/code/Magento/QuoteGraphQl/etc/schema.graphqls index 1ca00d5ef7bdc..955ee1cc2429a 100644 --- a/app/code/Magento/QuoteGraphQl/etc/schema.graphqls +++ b/app/code/Magento/QuoteGraphQl/etc/schema.graphqls @@ -109,6 +109,7 @@ input CartAddressInput { street: [String!]! city: String! region: String + region_id: Int postcode: String country_code: String! telephone: String! @@ -239,8 +240,9 @@ type CartItemQuantity @doc(description:"Deprecated: `cart_items` field of `Shipp } type CartAddressRegion { - code: String! - label: String! + code: String + label: String + region_id: Int } type CartAddressCountry { diff --git a/app/code/Magento/Robots/Controller/Index/Index.php b/app/code/Magento/Robots/Controller/Index/Index.php index 3a7eb152afdd2..640b9baf28224 100644 --- a/app/code/Magento/Robots/Controller/Index/Index.php +++ b/app/code/Magento/Robots/Controller/Index/Index.php @@ -7,6 +7,8 @@ namespace Magento\Robots\Controller\Index; +use Magento\Framework\App\Action\Action; +use Magento\Framework\App\Action\Context; use Magento\Framework\App\Action\HttpGetActionInterface; use Magento\Framework\View\Result\Page; use Magento\Framework\View\Result\PageFactory; @@ -14,7 +16,7 @@ /** * Processes request to robots.txt file and returns robots.txt content as result */ -class Index implements HttpGetActionInterface +class Index extends Action implements HttpGetActionInterface { /** * @var PageFactory @@ -22,11 +24,14 @@ class Index implements HttpGetActionInterface private $resultPageFactory; /** + * @param Context $context * @param PageFactory $resultPageFactory */ public function __construct( + Context $context, PageFactory $resultPageFactory ) { + parent::__construct($context); $this->resultPageFactory = $resultPageFactory; } diff --git a/app/code/Magento/Search/Controller/Term/Popular.php b/app/code/Magento/Search/Controller/Term/Popular.php index 2b3ac5c73c9dd..734554539bcc9 100644 --- a/app/code/Magento/Search/Controller/Term/Popular.php +++ b/app/code/Magento/Search/Controller/Term/Popular.php @@ -7,6 +7,8 @@ namespace Magento\Search\Controller\Term; +use Magento\Framework\App\Action\Action; +use Magento\Framework\App\Action\Context; use Magento\Framework\App\Action\HttpGetActionInterface; use Magento\Framework\App\Config\ScopeConfigInterface; use Magento\Framework\Controller\Result\ForwardFactory as ResultForwardFactory; @@ -16,7 +18,7 @@ /** * Popular search terms page */ -class Popular implements HttpGetActionInterface +class Popular extends Action implements HttpGetActionInterface { private const XML_PATH_SEO_SEARCH_TERMS = 'catalog/seo/search_terms'; @@ -36,15 +38,18 @@ class Popular implements HttpGetActionInterface private $scopeConfig; /** + * @param Context $context * @param ResultForwardFactory $resultForwardFactory * @param ResultPageFactory $resultPageFactory * @param ScopeConfigInterface $scopeConfig */ public function __construct( + Context $context, ResultForwardFactory $resultForwardFactory, ResultPageFactory $resultPageFactory, ScopeConfigInterface $scopeConfig ) { + parent::__construct($context); $this->resultForwardFactory = $resultForwardFactory; $this->resultPageFactory = $resultPageFactory; $this->scopeConfig = $scopeConfig; diff --git a/app/code/Magento/Search/etc/di.xml b/app/code/Magento/Search/etc/di.xml index 9c471aa2ff14d..7db64bf78d6ce 100644 --- a/app/code/Magento/Search/etc/di.xml +++ b/app/code/Magento/Search/etc/di.xml @@ -16,13 +16,6 @@ </argument> </arguments> </type> - <type name="Magento\Search\Model\AdapterFactory"> - <arguments> - <argument name="adapters" xsi:type="array"> - <item name="mysql" xsi:type="string">Magento\Framework\Search\Adapter\Mysql\Adapter</item> - </argument> - </arguments> - </type> <preference for="Magento\Search\Model\QueryFactoryInterface" type="Magento\Search\Model\QueryFactory" /> <preference for="Magento\Search\Model\QueryInterface" type="Magento\Search\Model\Query" /> <preference for="Magento\Search\Api\SynonymAnalyzerInterface" type="Magento\Search\Model\SynonymAnalyzer" /> @@ -55,13 +48,6 @@ <preference for="Magento\Search\Api\Data\SynonymGroupInterface" type="Magento\Search\Model\SynonymGroup" /> <preference for="Magento\Search\Api\SynonymGroupRepositoryInterface" type="Magento\Search\Model\SynonymGroupRepository" /> <preference for="Magento\Framework\Search\Adapter\Preprocessor\PreprocessorInterface" type="Magento\Search\Adapter\Query\Preprocessor\Synonyms" /> - <type name="Magento\Framework\Search\Adapter\Mysql\Query\Builder\Match"> - <arguments> - <argument name="preprocessors" xsi:type="array"> - <item name="synonymsPreprocessor" xsi:type="object">Magento\Search\Adapter\Query\Preprocessor\Synonyms</item> - </argument> - </arguments> - </type> <preference for="Magento\Framework\Search\SearchEngine\ConfigInterface" type="Magento\Search\Model\SearchEngine\Config" /> <type name="Magento\Search\Model\SearchEngine\Config"> <arguments> diff --git a/app/code/Magento/Swagger/Controller/Index/Index.php b/app/code/Magento/Swagger/Controller/Index/Index.php index c486989c0b1bc..8c1958b6627d5 100644 --- a/app/code/Magento/Swagger/Controller/Index/Index.php +++ b/app/code/Magento/Swagger/Controller/Index/Index.php @@ -7,11 +7,13 @@ namespace Magento\Swagger\Controller\Index; +use Magento\Framework\App\Action\Action; +use Magento\Framework\App\Action\Context; use Magento\Framework\App\Action\HttpGetActionInterface; use Magento\Framework\View\Page\Config as PageConfig; use Magento\Framework\View\Result\PageFactory as PageFactory; -class Index implements HttpGetActionInterface +class Index extends Action implements HttpGetActionInterface { /** * @var PageConfig @@ -24,11 +26,13 @@ class Index implements HttpGetActionInterface private $pageFactory; /** + * @param Context $context * @param PageConfig $pageConfig * @param PageFactory $pageFactory */ - public function __construct(PageConfig $pageConfig, PageFactory $pageFactory) + public function __construct(Context $context, PageConfig $pageConfig, PageFactory $pageFactory) { + parent::__construct($context); $this->pageConfig = $pageConfig; $this->pageFactory = $pageFactory; } diff --git a/app/code/Magento/Swagger/Test/Unit/Controller/Index/IndexTest.php b/app/code/Magento/Swagger/Test/Unit/Controller/Index/IndexTest.php index abfc40d7e5437..be2932de2e1df 100644 --- a/app/code/Magento/Swagger/Test/Unit/Controller/Index/IndexTest.php +++ b/app/code/Magento/Swagger/Test/Unit/Controller/Index/IndexTest.php @@ -8,6 +8,7 @@ namespace Magento\Swagger\Test\Unit\Controller\Index; +use Magento\Framework\App\Action\Context; use Magento\Framework\View\Page\Config as PageConfig; use Magento\Framework\View\Result\PageFactory; use Magento\Swagger\Controller\Index\Index; @@ -18,6 +19,9 @@ class IndexTest extends TestCase { public function testExecute() { + /** @var MockObject|Context $pageConfigMock */ + $contextMock = $this->createMock(Context::class); + /** @var MockObject|PageConfig $pageConfigMock */ $pageConfigMock = $this->getMockBuilder(PageConfig::class) ->disableOriginalConstructor() @@ -30,7 +34,7 @@ public function testExecute() $pageConfigMock->expects($this->once())->method('addBodyClass')->with('swagger-section'); $resultPageFactory->expects($this->once())->method('create'); - $indexAction = new Index($pageConfigMock, $resultPageFactory); + $indexAction = new Index($contextMock, $pageConfigMock, $resultPageFactory); $indexAction->execute(); } } diff --git a/app/code/Magento/Ui/view/base/web/js/form/element/image-uploader.js b/app/code/Magento/Ui/view/base/web/js/form/element/image-uploader.js index 99329839bd913..1031f7ed6e365 100644 --- a/app/code/Magento/Ui/view/base/web/js/form/element/image-uploader.js +++ b/app/code/Magento/Ui/view/base/web/js/form/element/image-uploader.js @@ -78,7 +78,7 @@ define([ '/type/image/?isAjax=true'; if (this.mediaGallery.initialOpenSubpath) { - openDialogUrl += '¤t_tree_path=' + Base64.mageEncode(this.mediaGallery.initialOpenSubpath); + openDialogUrl += '¤t_tree_path=' + Base64.idEncode(this.mediaGallery.initialOpenSubpath); } browser.openDialog( diff --git a/app/code/Magento/Ui/view/base/web/js/grid/columns/image-preview.js b/app/code/Magento/Ui/view/base/web/js/grid/columns/image-preview.js index 0464788d155e2..d675bd7a60ab5 100644 --- a/app/code/Magento/Ui/view/base/web/js/grid/columns/image-preview.js +++ b/app/code/Magento/Ui/view/base/web/js/grid/columns/image-preview.js @@ -16,7 +16,7 @@ define([ visibleRecord: null, height: 0, displayedRecord: {}, - lastOpenedImage: null, + lastOpenedImage: false, fields: { previewUrl: 'preview_url', title: 'title' @@ -167,7 +167,7 @@ define([ * Close image preview */ hide: function () { - this.lastOpenedImage(null); + this.lastOpenedImage(false); this.visibleRecord(null); this.height(0); this._selectRow(null); diff --git a/app/code/Magento/Version/Controller/Index/Index.php b/app/code/Magento/Version/Controller/Index/Index.php index 2c874c601ea08..16004f18bd0c4 100644 --- a/app/code/Magento/Version/Controller/Index/Index.php +++ b/app/code/Magento/Version/Controller/Index/Index.php @@ -7,6 +7,8 @@ namespace Magento\Version\Controller\Index; +use Magento\Framework\App\Action\Action; +use Magento\Framework\App\Action\Context; use Magento\Framework\App\Action\HttpGetActionInterface; use Magento\Framework\App\ProductMetadataInterface; use Magento\Framework\Controller\Result\RawFactory as RawResponseFactory; @@ -14,7 +16,7 @@ /** * Magento Version controller: Sets the response body to ProductName/Major.MinorVersion (Edition). */ -class Index implements HttpGetActionInterface +class Index extends Action implements HttpGetActionInterface { const DEV_PREFIX = 'dev-'; @@ -29,11 +31,16 @@ class Index implements HttpGetActionInterface private $rawFactory; /** + * @param Context $context * @param RawResponseFactory $rawFactory * @param ProductMetadataInterface $productMetadata */ - public function __construct(RawResponseFactory $rawFactory, ProductMetadataInterface $productMetadata) - { + public function __construct( + Context $context, + RawResponseFactory $rawFactory, + ProductMetadataInterface $productMetadata + ) { + parent::__construct($context); $this->rawFactory = $rawFactory; $this->productMetadata = $productMetadata; } diff --git a/app/code/Magento/Version/Test/Unit/Controller/Index/IndexTest.php b/app/code/Magento/Version/Test/Unit/Controller/Index/IndexTest.php index d0d146c65f0fe..2667a5b993ef4 100644 --- a/app/code/Magento/Version/Test/Unit/Controller/Index/IndexTest.php +++ b/app/code/Magento/Version/Test/Unit/Controller/Index/IndexTest.php @@ -7,6 +7,7 @@ namespace Magento\Version\Test\Unit\Controller\Index; +use Magento\Framework\App\Action\Context; use Magento\Framework\App\ProductMetadataInterface; use Magento\Framework\Controller\Result\Raw; use Magento\Framework\Controller\Result\RawFactory; @@ -28,11 +29,16 @@ class IndexTest extends TestCase /** @var MockObject|Raw */ private $rawResponseMock; + /** @var MockObject|Context */ + private $contextMock; + /** * Prepare test preconditions */ protected function setUp(): void { + $this->contextMock = $this->createMock(Context::class); + $this->productMetadataMock = $this->getMockBuilder(ProductMetadataInterface::class) ->disableOriginalConstructor() ->setMethods(['getName', 'getEdition', 'getVersion']) @@ -42,7 +48,11 @@ protected function setUp(): void $this->rawResponseMock = $this->createPartialMock(Raw::class, ['setContents']); $this->rawResponseFactoryMock->method('create')->willReturn($this->rawResponseMock); - $this->versionController = new VersionIndex($this->rawResponseFactoryMock, $this->productMetadataMock); + $this->versionController = new VersionIndex( + $this->contextMock, + $this->rawResponseFactoryMock, + $this->productMetadataMock + ); } /** diff --git a/app/etc/di.xml b/app/etc/di.xml index 93ec69dfe1586..7b91941fe05d6 100644 --- a/app/etc/di.xml +++ b/app/etc/di.xml @@ -13,10 +13,7 @@ <preference for="Magento\Framework\View\Template\Html\MinifierInterface" type="Magento\Framework\View\Template\Html\Minifier" /> <preference for="Magento\Framework\Model\Entity\ScopeInterface" type="Magento\Framework\Model\Entity\Scope" /> <preference for="Magento\Framework\ObjectManager\FactoryInterface" type="Magento\Framework\ObjectManager\Factory\Dynamic\Developer" /> - <preference for="Magento\Framework\Search\Adapter\Mysql\Filter\PreprocessorInterface" type="Magento\Framework\Search\Adapter\Mysql\Filter\Preprocessor" /> - <preference for="Magento\Framework\Search\Adapter\Mysql\Field\ResolverInterface" type="Magento\Framework\Search\Adapter\Mysql\Field\Resolver" /> <preference for="Magento\Framework\Search\Request\Aggregation\StatusInterface" type="Magento\Framework\Search\Request\Aggregation\Status" /> - <preference for="Magento\Framework\Search\Adapter\Mysql\Field\FieldInterface" type="Magento\Framework\Search\Adapter\Mysql\Field\Field"/> <preference for="Magento\Framework\Search\Adapter\Aggregation\AggregationResolverInterface" type="Magento\Framework\Search\Adapter\Aggregation\AggregationResolver"/> <preference for="Magento\Framework\App\RequestInterface" type="Magento\Framework\App\Request\Http" /> <preference for="Magento\Framework\App\PlainTextRequestInterface" type="Magento\Framework\App\Request\Http" /> @@ -800,15 +797,6 @@ </type> <type name="Magento\Framework\View\Layout\ScheduledStructure" shared="false" /> <type name="Magento\Framework\View\Page\Config\Structure" shared="false" /> - <type name="Magento\Framework\Search\Adapter\Mysql\Aggregation\Builder\Container"> - <arguments> - <argument name="buckets" xsi:type="array"> - <item name="termBucket" xsi:type="object">Magento\Framework\Search\Adapter\Mysql\Aggregation\Builder\Term</item> - <item name="rangeBucket" xsi:type="object">Magento\Framework\Search\Adapter\Mysql\Aggregation\Builder\Range</item> - <item name="dynamicBucket" xsi:type="object">Magento\Framework\Search\Adapter\Mysql\Aggregation\Builder\Dynamic</item> - </argument> - </arguments> - </type> <type name="Magento\Framework\Search\Dynamic\Algorithm\Repository"> <arguments> <argument name="algorithms" xsi:type="array"> @@ -1789,6 +1777,13 @@ <argument name="locker" xsi:type="object">Magento\Framework\Lock\Backend\Database</argument> </arguments> </type> + <type name="Magento\Framework\Cache\CompositeStaleCacheNotifier"> + <arguments> + <argument name="notifiers" xsi:type="array"> + <item name="runtime_cache_modifier" xsi:type="object">Magento\Framework\App\Cache\RuntimeStaleCacheStateModifier</item> + </argument> + </arguments> + </type> <preference for="Magento\Framework\HTTP\AsyncClientInterface" type="Magento\Framework\HTTP\AsyncClient\GuzzleAsyncClient" /> <preference for="Magento\Framework\MessageQueue\PoisonPill\PoisonPillCompareInterface" type="Magento\Framework\MessageQueue\PoisonPill\PoisonPillCompare"/> <preference for="Magento\Framework\MessageQueue\PoisonPill\PoisonPillPutInterface" type="Magento\Framework\MessageQueue\PoisonPill\PoisonPillPut"/> diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/ProductSearchTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/ProductSearchTest.php index 7182c233f0f47..1a95a3d6f4925 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/ProductSearchTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/ProductSearchTest.php @@ -1800,6 +1800,279 @@ public function testProductBasicFullTextSearchQuery() } } + /** + * Partial search filtered for price and sorted by price and name + * + * @magentoApiDataFixture Magento/Catalog/_files/category.php + * @magentoApiDataFixture Magento/Catalog/_files/multiple_products.php + */ + public function testProductPartialNameFullTextSearchQuery() + { + $this->reIndexAndCleanCache(); + $textToSearch = 'Sim'; + $query + =<<<QUERY +{ + products( + search: "{$textToSearch}" + filter:{ + price:{to:"25"} + } + sort:{ + price:DESC + name:ASC + } + ) + { + total_count + items { + name + sku + price { + minimalPrice { + amount { + value + currency + } + } + } + } + page_info { + page_size + current_page + } + filters{ + filter_items { + items_count + label + value_string + } + } + aggregations{ + attribute_code + count + label + options{ + count + label + value + } + } + } +} +QUERY; + /** @var ProductRepositoryInterface $productRepository */ + $productRepository = ObjectManager::getInstance()->get(ProductRepositoryInterface::class); + + $prod1 = $productRepository->get('simple1'); + $prod2 = $productRepository->get('simple2'); + $response = $this->graphQlQuery($query); + $this->assertEquals(2, $response['products']['total_count']); + + $filteredProducts = [$prod1, $prod2]; + $productItemsInResponse = array_map(null, $response['products']['items'], $filteredProducts); + foreach ($productItemsInResponse as $itemIndex => $itemArray) { + $this->assertNotEmpty($itemArray); + $this->assertResponseFields( + $productItemsInResponse[$itemIndex][0], + [ + 'sku' => $filteredProducts[$itemIndex]->getSku(), + 'name' => $filteredProducts[$itemIndex]->getName(), + 'price' => [ + 'minimalPrice' => [ + 'amount' => [ + 'value' => $filteredProducts[$itemIndex]->getSpecialPrice(), + 'currency' => 'USD' + ] + ] + ] + ] + ); + } + } + + /** + * Partial search on sku filtered for price and sorted by price and sku + * + * @magentoApiDataFixture Magento/Catalog/_files/category.php + * @magentoApiDataFixture Magento/Catalog/_files/multiple_products_with_different_sku_and_name.php + */ + public function testProductPartialSkuFullTextSearchQuery() + { + $this->reIndexAndCleanCache(); + $textToSearch = 'prd'; + $query + =<<<QUERY +{ + products( + search: "{$textToSearch}" + filter:{ + price:{to:"25"} + } + sort:{ + price:DESC + name:ASC + } + ) + { + total_count + items { + name + sku + price { + minimalPrice { + amount { + value + currency + } + } + } + } + page_info { + page_size + current_page + } + filters{ + filter_items { + items_count + label + value_string + } + } + aggregations{ + attribute_code + count + label + options{ + count + label + value + } + } + } +} +QUERY; + /** @var ProductRepositoryInterface $productRepository */ + $productRepository = ObjectManager::getInstance()->get(ProductRepositoryInterface::class); + + $prod1 = $productRepository->get('prd1sku'); + $prod2 = $productRepository->get('prd2-sku2'); + $response = $this->graphQlQuery($query); + $this->assertEquals(2, $response['products']['total_count']); + + $filteredProducts = [$prod1, $prod2]; + $productItemsInResponse = array_map(null, $response['products']['items'], $filteredProducts); + foreach ($productItemsInResponse as $itemIndex => $itemArray) { + $this->assertNotEmpty($itemArray); + $this->assertResponseFields( + $productItemsInResponse[$itemIndex][0], + [ + 'sku' => $filteredProducts[$itemIndex]->getSku(), + 'name' => $filteredProducts[$itemIndex]->getName(), + 'price' => [ + 'minimalPrice' => [ + 'amount' => [ + 'value' => $filteredProducts[$itemIndex]->getSpecialPrice(), + 'currency' => 'USD' + ] + ] + ] + ] + ); + } + } + + /** + * Partial search on hyphenated sku filtered for price and sorted by price and sku + * + * @magentoApiDataFixture Magento/Catalog/_files/category.php + * @magentoApiDataFixture Magento/Catalog/_files/multiple_products_with_different_sku_and_name.php + */ + public function testProductPartialSkuHyphenatedFullTextSearchQuery() + { + $this->reIndexAndCleanCache(); + /** @var ProductRepositoryInterface $productRepository */ + $productRepository = ObjectManager::getInstance()->get(ProductRepositoryInterface::class); + + $prod2 = $productRepository->get('prd2-sku2'); + $textToSearch = 'sku2'; + $query + =<<<QUERY +{ + products( + search: "{$textToSearch}" + filter:{ + price:{to:"25"} + } + sort:{ + price:DESC + name:ASC + } + ) + { + total_count + items { + name + sku + price { + minimalPrice { + amount { + value + currency + } + } + } + } + page_info { + page_size + current_page + } + filters{ + filter_items { + items_count + label + value_string + } + } + aggregations{ + attribute_code + count + label + options{ + count + label + value + } + } + } +} +QUERY; + + $response = $this->graphQlQuery($query); + $this->assertEquals(1, $response['products']['total_count']); + + $filteredProducts = [$prod2]; + $productItemsInResponse = array_map(null, $response['products']['items'], $filteredProducts); + foreach ($productItemsInResponse as $itemIndex => $itemArray) { + $this->assertNotEmpty($itemArray); + $this->assertResponseFields( + $productItemsInResponse[$itemIndex][0], + [ + 'sku' => $filteredProducts[$itemIndex]->getSku(), + 'name' => $filteredProducts[$itemIndex]->getName(), + 'price' => [ + 'minimalPrice' => [ + 'amount' => [ + 'value' => $filteredProducts[$itemIndex]->getSpecialPrice(), + 'currency' => 'USD' + ] + ] + ] + ] + ); + } + } + /** * Filter products purely in a given price range * diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/CatalogCms/CategoryBlockTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/CatalogCms/CategoryBlockTest.php index 5788313c4704e..8e9a76a3a0cfd 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/CatalogCms/CategoryBlockTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/CatalogCms/CategoryBlockTest.php @@ -59,4 +59,29 @@ public function testCategoryCmsBlock() $this->assertEquals($block->getIdentifier(), $actualBlock['identifier']); $this->assertEquals($renderedContent, $actualBlock['content']); } + + /** + * @magentoApiDataFixture Magento/Catalog/_files/category_tree.php + */ + public function testCategoryWithNoCmsBlock() + { + $query = <<<QUERY +{ + category(id: 401){ + name + cms_block{ + identifier + title + content + } + } +} +QUERY; + + $response = $this->graphQlQuery($query); + $this->assertArrayNotHasKey('errors', $response); + $this->assertNotEmpty($response['category']); + $this->assertArrayHasKey('cms_block', $response['category']); + $this->assertEquals(null, $response['category']['cms_block']); + } } diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Cms/CmsBlockTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Cms/CmsBlockTest.php index 5c8bfa1e6b147..07de3e1641b60 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Cms/CmsBlockTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Cms/CmsBlockTest.php @@ -8,6 +8,7 @@ namespace Magento\GraphQl\Cms; use Magento\Cms\Api\BlockRepositoryInterface; +use Magento\Store\Model\Store; use Magento\TestFramework\Helper\Bootstrap; use Magento\TestFramework\TestCase\GraphQl\ResponseContainsErrorsException; use Magento\TestFramework\TestCase\GraphQlAbstract; @@ -206,4 +207,130 @@ public function testGetEnabledAndDisabledCmsBlockInOneRequest() $responseData['errors'][0]['message'] ); } + + /** + * Verify correct CMS block information per store + * + * @magentoApiDataFixture Magento/Store/_files/multiple_websites_with_store_groups_stores.php + * @magentoApiDataFixture Magento/Cms/_files/blocks_for_different_stores.php + */ + public function testGetCmsBlockPerSpecificStore(): void + { + $blockIdentifier1 = 'test-block'; + $blockIdentifier2 = 'test-block-2'; + $secondStoreCode = 'second_store_view'; + $thirdStoreCode = 'third_store_view'; + + //Verify the correct block information for second store is returned + $cmsBlockResponseSecondStore = $this->getCmsBlockQuery($blockIdentifier1, $secondStoreCode); + self::assertArrayHasKey('cmsBlocks', $cmsBlockResponseSecondStore); + self::assertArrayHasKey('items', $cmsBlockResponseSecondStore['cmsBlocks']); + self::assertEquals('test-block', $cmsBlockResponseSecondStore['cmsBlocks']['items'][0]['identifier']); + self::assertEquals('Second store block', $cmsBlockResponseSecondStore['cmsBlocks']['items'][0]['title']); + self::assertEquals('second_store_view', $cmsBlockResponseSecondStore['storeConfig']['code']); + + //Verify the correct block information for third store is returned + $cmsBlockResponseThirdStore = $this->getCmsBlockQuery($blockIdentifier1, $thirdStoreCode); + self::assertArrayHasKey('cmsBlocks', $cmsBlockResponseThirdStore); + self::assertArrayHasKey('items', $cmsBlockResponseThirdStore['cmsBlocks']); + self::assertEquals('test-block', $cmsBlockResponseThirdStore['cmsBlocks']['items'][0]['identifier']); + self::assertEquals('Third store block', $cmsBlockResponseThirdStore['cmsBlocks']['items'][0]['title']); + self::assertEquals('third_store_view', $cmsBlockResponseThirdStore['storeConfig']['code']); + + //Verify the correct block information for second block for second store is returned + $cmsBlockResponseSecondStore = $this->getCmsBlockQuery($blockIdentifier2, $secondStoreCode); + self::assertArrayHasKey('cmsBlocks', $cmsBlockResponseSecondStore); + self::assertArrayHasKey('items', $cmsBlockResponseSecondStore['cmsBlocks']); + self::assertEquals('test-block-2', $cmsBlockResponseSecondStore['cmsBlocks']['items'][0]['identifier']); + self::assertEquals('Second store block 2', $cmsBlockResponseSecondStore['cmsBlocks']['items'][0]['title']); + self::assertEquals('second_store_view', $cmsBlockResponseSecondStore['storeConfig']['code']); + + //Verify that exception is returned if block is not assigned to the store specified + $this->expectException(\Exception::class); + $this->expectExceptionMessage('The CMS block with the "test-block-2" ID doesn\'t exist'); + + $query = + <<<QUERY +{ + cmsBlocks(identifiers: "$blockIdentifier2") { + items { + identifier + title + content + } + } +} +QUERY; + $headerMap['Store'] = $thirdStoreCode; + $this->graphQlQuery($query, [], '', $headerMap); + } + + /** + * Verify CMS block for a disabled store + * + * @magentoApiDataFixture Magento/Store/_files/multiple_websites_with_store_groups_stores.php + * @magentoApiDataFixture Magento/Cms/_files/blocks_for_different_stores.php + */ + public function testGetCmsBlockForDisabledStore(): void + { + $blockIdentifier = 'test-block'; + $thirdStoreCode = 'third_store_view'; + $store = Bootstrap::getObjectManager()->get(Store::class); + $store->load('third_store_view', 'code')->setIsActive(0)->save(); + $this->expectException(\Exception::class); + $this->expectExceptionMessage('Requested store is not found'); + $this->getCmsBlockQuery($blockIdentifier, $thirdStoreCode); + } + + /** + * @magentoApiDataFixture Magento/Cms/_files/block_default_store.php + */ + public function testGetCmsBlockAssignedToDefaultStore(): void + { + $blockIdentifier = 'default_store_block'; + $query = <<<QUERY +{ + cmsBlocks(identifiers: "$blockIdentifier") { + items { + identifier + title + content + } + } +} +QUERY; + $response = $this->graphQlQuery($query); + $this->assertArrayNotHasKey('errors', $response); + $this->assertArrayHasKey('cmsBlocks', $response); + $this->assertCount(1, $response['cmsBlocks']['items']); + $this->assertEquals($blockIdentifier, $response['cmsBlocks']['items'][0]['identifier']); + } + + /** + * Get cmsBlockQuery per store + * + * @param string $blockIdentifier + * @param string $storeCode + * @return array + * @throws \Exception + */ + private function getCmsBlockQuery($blockIdentifier, $storeCode): array + { + $query = + <<<QUERY +{ + cmsBlocks(identifiers: "$blockIdentifier") { + items { + identifier + title + content + } + } + storeConfig{code} +} +QUERY; + $headerMap['Store'] = $storeCode; + $response = $this->graphQlQuery($query, [], '', $headerMap); + return $response; + } } diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/ConfigurableProduct/ConfigurableProductViewTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/ConfigurableProduct/ConfigurableProductViewTest.php index 757998daf816f..49bbabc212fc2 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/ConfigurableProduct/ConfigurableProductViewTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/ConfigurableProduct/ConfigurableProductViewTest.php @@ -96,6 +96,7 @@ public function testQueryConfigurableProductLinks() configurable_options { id attribute_id + attribute_id_v2 label position use_default @@ -335,12 +336,7 @@ private function assertConfigurableVariants($actualResponse) $mediaGalleryEntries, "Precondition failed since there are incorrect number of media gallery entries" ); - $this->assertIsArray($actualResponse['variants'] - [$variantKey] - ['product'] - ['media_gallery_entries'] - - ); + $this->assertIsArray($actualResponse['variants'][$variantKey]['product']['media_gallery_entries']); $this->assertCount( 1, $actualResponse['variants'][$variantKey]['product']['media_gallery_entries'], @@ -348,10 +344,7 @@ private function assertConfigurableVariants($actualResponse) ); $mediaGalleryEntry = $mediaGalleryEntries[0]; $this->assertResponseFields( - $actualResponse['variants'] - [$variantKey] - ['product'] - ['media_gallery_entries'][0], + $actualResponse['variants'][$variantKey]['product']['media_gallery_entries'][0], [ 'disabled' => (bool)$mediaGalleryEntry->isDisabled(), 'file' => $mediaGalleryEntry->getFile(), @@ -363,12 +356,7 @@ private function assertConfigurableVariants($actualResponse) ); $videoContent = $mediaGalleryEntry->getExtensionAttributes()->getVideoContent(); $this->assertResponseFields( - $actualResponse['variants'] - [$variantKey] - ['product'] - ['media_gallery_entries'] - [0] - ['video_content'], + $actualResponse['variants'][$variantKey]['product']['media_gallery_entries'][0]['video_content'], [ 'media_type' =>$videoContent->getMediaType(), 'video_description' => $videoContent->getVideoDescription(), @@ -454,6 +442,11 @@ private function assertConfigurableProductOptions($actualResponse) $actualResponse['configurable_options'][0]['attribute_id'], $configurableAttributeOption['attribute_id'] ); + $this->assertEquals( + $actualResponse['configurable_options'][0]['attribute_id_v2'], + $configurableAttributeOption['attribute_id'] + ); + $this->assertIsInt($actualResponse['configurable_options'][0]['attribute_id_v2']); $this->assertEquals( $actualResponse['configurable_options'][0]['label'], $configurableAttributeOption['label'] diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/CreateCustomerAddressTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/CreateCustomerAddressTest.php index 4576bb654f22a..6c8ded61ca368 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/CreateCustomerAddressTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/CreateCustomerAddressTest.php @@ -10,9 +10,9 @@ use Exception; use Magento\Customer\Api\AddressRepositoryInterface; use Magento\Customer\Api\Data\AddressInterface; +use Magento\Integration\Api\CustomerTokenServiceInterface; use Magento\TestFramework\Helper\Bootstrap; use Magento\TestFramework\TestCase\GraphQlAbstract; -use Magento\Integration\Api\CustomerTokenServiceInterface; /** * Create customer address tests @@ -133,6 +133,102 @@ public function testCreateCustomerAddress() $this->assertCustomerAddressesFields($address, $newAddress); } + /** + * @magentoApiDataFixture Magento/Customer/_files/customer_without_addresses.php + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + */ + public function testCreateCustomerAddressWithNoRegionId() + { + $newAddress = [ + 'region' => [ + 'region' => 'Arizona', + 'region_id' => 4, + 'region_code' => 'AZ' + ], + 'country_code' => 'US', + 'street' => ['Line 1 Street', 'Line 2'], + 'company' => 'Company name', + 'telephone' => '123456789', + 'fax' => '123123123', + 'postcode' => '7777', + 'city' => 'City Name', + 'firstname' => 'Adam', + 'lastname' => 'Phillis', + 'middlename' => 'A', + 'prefix' => 'Mr.', + 'suffix' => 'Jr.', + 'vat_id' => '1', + 'default_shipping' => true, + 'default_billing' => false + ]; + + $mutation + = <<<MUTATION +mutation { + createCustomerAddress(input: { + region: { + region: "{$newAddress['region']['region']}" + region_id: {$newAddress['region']['region_id']} + region_code: "{$newAddress['region']['region_code']}" + } + country_code: {$newAddress['country_code']} + street: ["{$newAddress['street'][0]}","{$newAddress['street'][1]}"] + company: "{$newAddress['company']}" + telephone: "{$newAddress['telephone']}" + fax: "{$newAddress['fax']}" + postcode: "{$newAddress['postcode']}" + city: "{$newAddress['city']}" + firstname: "{$newAddress['firstname']}" + lastname: "{$newAddress['lastname']}" + middlename: "{$newAddress['middlename']}" + prefix: "{$newAddress['prefix']}" + suffix: "{$newAddress['suffix']}" + vat_id: "{$newAddress['vat_id']}" + default_shipping: true + default_billing: false + }) { + id + customer_id + region { + region + region_id + region_code + } + country_code + street + company + telephone + fax + postcode + city + firstname + lastname + middlename + prefix + suffix + vat_id + default_shipping + default_billing + } +} +MUTATION; + + $userName = 'customer@example.com'; + $password = 'password'; + + $response = $this->graphQlMutation($mutation, [], '', $this->getCustomerAuthHeaders($userName, $password)); + $this->assertArrayHasKey('createCustomerAddress', $response); + $this->assertArrayHasKey('customer_id', $response['createCustomerAddress']); + $this->assertNull($response['createCustomerAddress']['customer_id']); + $this->assertArrayHasKey('id', $response['createCustomerAddress']); + + $address = $this->addressRepository->getById($response['createCustomerAddress']['id']); + $this->assertEquals($address->getId(), $response['createCustomerAddress']['id']); + $address->setCustomerId(null); + $this->assertCustomerAddressesFields($address, $response['createCustomerAddress']); + $this->assertCustomerAddressesFields($address, $newAddress); + } + /** * Test case for deprecated `country_id` field. * @@ -173,7 +269,7 @@ public function testCreateCustomerAddressWithCountryId() region_id: {$newAddress['region']['region_id']} region_code: "{$newAddress['region']['region_code']}" } - country_id: {$newAddress['country_id']} + country_code: {$newAddress['country_id']} street: ["{$newAddress['street'][0]}","{$newAddress['street'][1]}"] company: "{$newAddress['company']}" telephone: "{$newAddress['telephone']}" @@ -450,6 +546,262 @@ public function testCreateCustomerAddressWithInvalidInput($input, $exceptionMess $this->graphQlMutation($mutation, [], '', $this->getCustomerAuthHeaders($userName, $password)); } + /** + * @magentoApiDataFixture Magento/Customer/_files/customer_without_addresses.php + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + */ + public function testCreateCustomerAddressRegionCodeWithoutRegionId() + { + $newAddress = [ + 'region' => [ + 'region_code' => 'NY', + ], + 'country_code' => 'US', + 'street' => ['Line 1 Street', 'Line 2'], + 'company' => 'Company name', + 'telephone' => '123456789', + 'postcode' => '10019', + 'city' => 'Manhattan', + 'firstname' => 'Adam', + 'lastname' => 'Phillis' + ]; + + $mutation + = <<<MUTATION +mutation { + createCustomerAddress(input: { + region: { + region_code: "{$newAddress['region']['region_code']}" + } + country_code: {$newAddress['country_code']} + street: ["{$newAddress['street'][0]}","{$newAddress['street'][1]}"] + company: "{$newAddress['company']}" + telephone: "{$newAddress['telephone']}" + postcode: "{$newAddress['postcode']}" + city: "{$newAddress['city']}" + firstname: "{$newAddress['firstname']}" + lastname: "{$newAddress['lastname']}" + }) { + id + customer_id + region { + region + region_id + region_code + } + country_code + street + company + telephone + postcode + city + firstname + lastname + } +} +MUTATION; + $userName = 'customer@example.com'; + $password = 'password'; + $this->expectExceptionMessage('A region_id is required for the specified country code'); + $this->graphQlMutation($mutation, [], '', $this->getCustomerAuthHeaders($userName, $password)); + } + + /** + * @magentoApiDataFixture Magento/Customer/_files/customer_without_addresses.php + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + */ + public function testCreateCustomerAddressRegionCodeWithRegionIdForNoRegionRequiredCountry() + { + $newAddress = [ + 'region' => [ + 'region_code' => 'NY', + 'region_id' => 43, + ], + 'country_code' => 'GB', + 'street' => ['Line 1 Street', 'Line 2'], + 'company' => 'Company name', + 'telephone' => '123456789', + 'postcode' => '10019', + 'city' => 'London', + 'firstname' => 'Adams', + 'lastname' => 'Phillips' + ]; + + $mutation + = <<<MUTATION +mutation { + createCustomerAddress(input: { + region: { + region_code: "{$newAddress['region']['region_code']}" + region_id: {$newAddress['region']['region_id']} + } + country_code: {$newAddress['country_code']} + street: ["{$newAddress['street'][0]}","{$newAddress['street'][1]}"] + company: "{$newAddress['company']}" + telephone: "{$newAddress['telephone']}" + postcode: "{$newAddress['postcode']}" + city: "{$newAddress['city']}" + firstname: "{$newAddress['firstname']}" + lastname: "{$newAddress['lastname']}" + }) { + id + customer_id + region { + region + region_id + region_code + } + country_code + street + company + telephone + postcode + city + firstname + lastname + } +} +MUTATION; + $userName = 'customer@example.com'; + $password = 'password'; + $this->expectExceptionMessage('The region_id does not match the selected country or region'); + $this->graphQlMutation($mutation, [], '', $this->getCustomerAuthHeaders($userName, $password)); + } + + /** + * @magentoApiDataFixture Magento/Customer/_files/customer_without_addresses.php + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + */ + public function testCreateCustomerAddressRegionCodeWithWrongRegionIdForRegionRequiredCountry() + { + $newAddress = [ + 'region' => [ + 'region_code' => 'NY', + 'region_id' => 53, + ], + 'country_code' => 'US', + 'street' => ['Line 1 Street', 'Line 2'], + 'company' => 'Company name', + 'telephone' => '123456789', + 'postcode' => '10019', + 'city' => 'London', + 'firstname' => 'Adams', + 'lastname' => 'Phillips' + ]; + + $mutation + = <<<MUTATION +mutation { + createCustomerAddress(input: { + region: { + region_code: "{$newAddress['region']['region_code']}" + region_id: {$newAddress['region']['region_id']} + } + country_code: {$newAddress['country_code']} + street: ["{$newAddress['street'][0]}","{$newAddress['street'][1]}"] + company: "{$newAddress['company']}" + telephone: "{$newAddress['telephone']}" + postcode: "{$newAddress['postcode']}" + city: "{$newAddress['city']}" + firstname: "{$newAddress['firstname']}" + lastname: "{$newAddress['lastname']}" + }) { + id + customer_id + region { + region + region_id + region_code + } + country_code + street + company + telephone + postcode + city + firstname + lastname + } +} +MUTATION; + $userName = 'customer@example.com'; + $password = 'password'; + $this->expectExceptionMessage('The region_id does not match the selected country or region'); + $this->graphQlMutation($mutation, [], '', $this->getCustomerAuthHeaders($userName, $password)); + } + + /** + * @magentoApiDataFixture Magento/Customer/_files/customer_without_addresses.php + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + */ + public function testCreateCustomerAddressRegionCodeWithOutRegionIdForNoRegionRequiredCountry() + { + $newAddress = [ + 'region' => [ + 'region_code' => 'some', + 'region' => 'some region' + ], + 'country_code' => 'GB', + 'street' => ['Line 1 Street', 'Line 2'], + 'company' => 'Company name', + 'telephone' => '123456789', + 'postcode' => '10019', + 'city' => 'London', + 'firstname' => 'Adams', + 'lastname' => 'Phillips' + ]; + + $mutation + = <<<MUTATION +mutation { + createCustomerAddress(input: { + region: { + region_code: "{$newAddress['region']['region_code']}" + region: "{$newAddress['region']['region']}" + } + country_code: {$newAddress['country_code']} + street: ["{$newAddress['street'][0]}","{$newAddress['street'][1]}"] + company: "{$newAddress['company']}" + telephone: "{$newAddress['telephone']}" + postcode: "{$newAddress['postcode']}" + city: "{$newAddress['city']}" + firstname: "{$newAddress['firstname']}" + lastname: "{$newAddress['lastname']}" + }) { + id + customer_id + region { + region + region_id + region_code + } + country_code + street + company + telephone + postcode + city + firstname + lastname + } +} +MUTATION; + $userName = 'customer@example.com'; + $password = 'password'; + $response = $this->graphQlMutation( + $mutation, + [], + '', + $this->getCustomerAuthHeaders($userName, $password) + ); + $this->assertEquals("some region", $response["createCustomerAddress"]["region"]["region"]); + $this->assertEquals("some", $response["createCustomerAddress"]["region"]["region_code"]); + } + /** * @return array */ diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/UpdateCustomerAddressTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/UpdateCustomerAddressTest.php index d897407c1a9ab..7b32600e74aa7 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/UpdateCustomerAddressTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/UpdateCustomerAddressTest.php @@ -8,12 +8,12 @@ namespace Magento\GraphQl\Customer; use Exception; -use Magento\Customer\Api\CustomerRepositoryInterface; use Magento\Customer\Api\AddressRepositoryInterface; +use Magento\Customer\Api\CustomerRepositoryInterface; use Magento\Customer\Api\Data\AddressInterface; +use Magento\Integration\Api\CustomerTokenServiceInterface; use Magento\TestFramework\Helper\Bootstrap; use Magento\TestFramework\TestCase\GraphQlAbstract; -use Magento\Integration\Api\CustomerTokenServiceInterface; /** * Update customer address tests @@ -100,6 +100,7 @@ public function testUpdateCustomerAddressWithCountryId() region_id: {$updateAddress['region']['region_id']} region_code: "{$updateAddress['region']['region_code']}" } + country_code: {$updateAddress['country_code']} country_id: {$updateAddress['country_code']} street: ["{$updateAddress['street'][0]}","{$updateAddress['street'][1]}"] company: "{$updateAddress['company']}" @@ -178,6 +179,33 @@ public function testUpdateCustomerAddressWithMissingAttribute() $this->graphQlMutation($mutation, [], '', $this->getCustomerAuthHeaders($userName, $password)); } + /** + * Verify customers with credentials update address + * with missing required Firstname attribute + * + * @magentoApiDataFixture Magento/Customer/_files/customer.php + * @magentoApiDataFixture Magento/Customer/_files/customer_address.php + */ + public function testUpdateCustomerAddressWithoutMissingAttribute() + { + $userName = 'customer@example.com'; + $password = 'password'; + $addressId = 1; + + $mutation + = <<<MUTATION +mutation { + updateCustomerAddress(id: {$addressId}, input: { + firstname: "some" + lastname: "Phillis" + }) { + id + } +} +MUTATION; + $this->graphQlMutation($mutation, [], '', $this->getCustomerAuthHeaders($userName, $password)); + } + /** * Test custom attributes of the customer's address * @magentoApiDataFixture Magento/Customer/_files/customer.php @@ -322,9 +350,6 @@ public function testUpdateCustomerAddressWithMissingId() */ public function testUpdateCustomerAddressWithInvalidIdType() { - $this->markTestSkipped( - 'Type validation returns wrong message https://github.com/magento/graphql-ce/issues/735' - ); $userName = 'customer@example.com'; $password = 'password'; @@ -363,7 +388,7 @@ public function testUpdateCustomerAddressWithInvalidIdType() MUTATION; $this->expectException(Exception::class); - $this->expectExceptionMessage('Expected type Int!, found ""'); + $this->expectExceptionMessage('Field "updateCustomerAddress" argument "id" requires type Int!, found "".'); $this->graphQlMutation($mutation, [], '', $this->getCustomerAuthHeaders($userName, $password)); } @@ -403,7 +428,10 @@ public function invalidInputDataProvider() { return [ ['', '"input" value must be specified'], - ['input: ""', 'requires type CustomerAddressInput, found ""'], + [ + 'input: ""', + 'Field "updateCustomerAddress" argument "input" requires type CustomerAddressInput, found ""' + ], ['input: "foo"', 'requires type CustomerAddressInput, found "foo"'] ]; } diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/SetBillingAddressOnCartTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/SetBillingAddressOnCartTest.php index 8fd1ef6dfde8e..67ae07775c1d8 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/SetBillingAddressOnCartTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/SetBillingAddressOnCartTest.php @@ -670,9 +670,9 @@ public function dataProviderSetWithoutRequiredParameters(): array telephone: "88776655" } }', - '"regionId" is required. Enter and try again.' + 'Region is required' ], - 'missed_multiple_fields' => [ + 'missed_postal_code' => [ 'cart_id: "cart_id_value" billing_address: { address: { @@ -681,12 +681,12 @@ public function dataProviderSetWithoutRequiredParameters(): array company: "test company" street: ["test street 1", "test street 2"] city: "test city" + region: "TX" country_code: "US" telephone: "88776655" } }', - '"postcode" is required. Enter and try again. -"regionId" is required. Enter and try again.' + '"postcode" is required. Enter and try again.' ], 'wrong_required_region' => [ 'cart_id: "cart_id_value" @@ -699,10 +699,29 @@ public function dataProviderSetWithoutRequiredParameters(): array region: "wrong region" city: "test city" country_code: "US" + postcode: "887766" + telephone: "88776655" + } + }', + '"regionId" is required. Enter and try again' + ], + 'wrong_required_region_name' => [ + 'cart_id: "cart_id_value" + billing_address: { + address: { + firstname: "test firstname" + lastname: "test lastname" + company: "test company" + street: ["test street 1", "test street 2"] + region: "wrong region" + region_id: 45 + city: "test city" + country_code: "US" + postcode: "887766" telephone: "88776655" } }', - 'Region is not available for the selected country' + 'The region_id does not match the selected country or region' ], ]; } @@ -880,7 +899,7 @@ public function testSetNewBillingAddressWithSaveInAddressBook() * @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php */ - public function testSetBillingAddressAndPlaceOrder() + public function testSetNewBillingAddressWithNotSaveInAddressBook() { $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote'); $query = <<<QUERY @@ -889,7 +908,6 @@ public function testSetBillingAddressAndPlaceOrder() input: { cart_id: "$maskedQuoteId" billing_address: { - same_as_shipping: true address: { firstname: "test firstname" lastname: "test lastname" @@ -897,10 +915,10 @@ public function testSetBillingAddressAndPlaceOrder() street: ["test street 1", "test street 2"] city: "test city" region: "AZ" - postcode: "88776" + postcode: "887766" country_code: "US" telephone: "88776655" - save_in_address_book: true + save_in_address_book: false } } } @@ -925,33 +943,18 @@ public function testSetBillingAddressAndPlaceOrder() } QUERY; $response = $this->graphQlMutation($query, [], '', $this->getHeaderMap()); - $this->graphQlMutation( - $this->getSetShippingMethodsQuery($maskedQuoteId, 'flatrate', 'flatrate'), - [], - '', - $this->getHeaderMap() - ); - $this->graphQlMutation( - $this->getSetPaymentMethodQuery( - $maskedQuoteId, - 'checkmo' - ), - [], - '', - $this->getHeaderMap() - ); - $this->graphQlMutation( - $this->getPlaceOrderQuery($maskedQuoteId), - [], - '', - $this->getHeaderMap() - ); $customer = $this->customerRepository->get('customer@example.com'); $searchCriteria = $this->searchCriteriaBuilder->addFilter('parent_id', $customer->getId())->create(); $addresses = $this->customerAddressRepository->getList($searchCriteria)->getItems(); - self::assertCount(1, $addresses); + self::assertCount(0, $addresses); self::assertArrayHasKey('cart', $response['setBillingAddressOnCart']); + + $cartResponse = $response['setBillingAddressOnCart']['cart']; + self::assertArrayHasKey('billing_address', $cartResponse); + $billingAddressResponse = $cartResponse['billing_address']; + $this->assertNewAddressFields($billingAddressResponse); + foreach ($addresses as $address) { $this->customerAddressRepository->delete($address); } @@ -963,26 +966,27 @@ public function testSetBillingAddressAndPlaceOrder() * @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php */ - public function testSetBillingAddressWithDefaultValueOfSaveInAddressBookAndPlaceOrder() + public function testWithInvalidBillingAddressInput() { $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote'); + $query = <<<QUERY mutation { setBillingAddressOnCart( input: { cart_id: "$maskedQuoteId" billing_address: { - same_as_shipping: true address: { firstname: "test firstname" - lastname: "test lastname" - company: "test company" - street: ["test street 1", "test street 2"] - city: "test city" - region: "AZ" - postcode: "88776" - country_code: "US" - telephone: "88776655" + lastname: "test lastname" + company: "test company" + street: ["test street 1", "test street 2"] + city: "test city" + region: "AZ" + postcode: "887766" + country_code: "USS" + telephone: "88776655" + save_in_address_book: false } } } @@ -1000,43 +1004,62 @@ public function testSetBillingAddressWithDefaultValueOfSaveInAddressBookAndPlace code label } - __typename } } } } QUERY; - $response = $this->graphQlMutation($query, [], '', $this->getHeaderMap()); - $this->graphQlMutation( - $this->getSetShippingMethodsQuery($maskedQuoteId, 'flatrate', 'flatrate'), - [], - '', - $this->getHeaderMap() - ); - $this->graphQlMutation( - $this->getSetPaymentMethodQuery( - $maskedQuoteId, - 'checkmo' - ), - [], - '', - $this->getHeaderMap() - ); - $this->graphQlMutation( - $this->getPlaceOrderQuery($maskedQuoteId), - [], - '', - $this->getHeaderMap() - ); - $customer = $this->customerRepository->get('customer@example.com'); - $searchCriteria = $this->searchCriteriaBuilder->addFilter('parent_id', $customer->getId())->create(); - $addresses = $this->customerAddressRepository->getList($searchCriteria)->getItems(); + $this->expectExceptionMessage('Country is not available'); + $this->graphQlMutation($query, [], '', $this->getHeaderMap()); + } - $this->assertCount(1, $addresses); - $this->assertArrayHasKey('cart', $response['setBillingAddressOnCart']); - foreach ($addresses as $address) { - $this->customerAddressRepository->delete($address); + /** + * @magentoApiDataFixture Magento/Customer/_files/customer.php + * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php + */ + public function testSetBillingAddressesWithNotRequiredRegion() + { + $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote'); + + $query = <<<QUERY +mutation { + setBillingAddressOnCart( + input: { + cart_id: "$maskedQuoteId" + billing_address: { + address: { + firstname: "Vasyl" + lastname: "Doe" + street: ["1 Svobody"] + city: "Lviv" + region: "Lviv" + postcode: "00000" + country_code: "UA" + telephone: "555-555-55-55" + } + } + } + ) { + cart { + billing_address { + region { + label + } + country { + code } + } + } + } +} +QUERY; + $response = $this->graphQlMutation($query, [], '', $this->getHeaderMap()); + self::assertArrayHasKey('cart', $response['setBillingAddressOnCart']); + $cartResponse = $response['setBillingAddressOnCart']['cart']; + self::assertEquals('UA', $cartResponse['billing_address']['country']['code']); + self::assertEquals('Lviv', $cartResponse['billing_address']['region']['label']); } /** @@ -1045,9 +1068,10 @@ public function testSetBillingAddressWithDefaultValueOfSaveInAddressBookAndPlace * @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php */ - public function testSetNewBillingAddressWithNotSaveInAddressBook() + public function testSetBillingAddressOnCartWithBothRegionAndRegionId() { $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote'); + $query = <<<QUERY mutation { setBillingAddressOnCart( @@ -1055,16 +1079,16 @@ public function testSetNewBillingAddressWithNotSaveInAddressBook() cart_id: "$maskedQuoteId" billing_address: { address: { - firstname: "test firstname" - lastname: "test lastname" - company: "test company" - street: ["test street 1", "test street 2"] - city: "test city" - region: "AZ" - postcode: "887766" + firstname: "John" + lastname: "Smith" + company: "Magento" + street: ["Magento Pkwy", "Main Street"] + city: "APO" + region: "AE" + region_id: 10 + postcode: "09369" country_code: "US" - telephone: "88776655" - save_in_address_book: false + telephone: "8675309" } } } @@ -1082,6 +1106,11 @@ public function testSetNewBillingAddressWithNotSaveInAddressBook() code label } + region { + code + label + region_id + } __typename } } @@ -1089,21 +1118,15 @@ public function testSetNewBillingAddressWithNotSaveInAddressBook() } QUERY; $response = $this->graphQlMutation($query, [], '', $this->getHeaderMap()); - $customer = $this->customerRepository->get('customer@example.com'); - $searchCriteria = $this->searchCriteriaBuilder->addFilter('parent_id', $customer->getId())->create(); - $addresses = $this->customerAddressRepository->getList($searchCriteria)->getItems(); - - self::assertCount(0, $addresses); - self::assertArrayHasKey('cart', $response['setBillingAddressOnCart']); - + $this->assertArrayHasKey('cart', $response['setBillingAddressOnCart']); $cartResponse = $response['setBillingAddressOnCart']['cart']; - self::assertArrayHasKey('billing_address', $cartResponse); + $this->assertArrayHasKey('billing_address', $cartResponse); $billingAddressResponse = $cartResponse['billing_address']; - $this->assertNewAddressFields($billingAddressResponse); - - foreach ($addresses as $address) { - $this->customerAddressRepository->delete($address); - } + $expectedRegionCode = "AE"; + $expectedRegionLabel = "Armed Forces Middle East"; + $this->assertEquals($expectedRegionCode, $billingAddressResponse['region']['code']); + $this->assertEquals($expectedRegionLabel, $billingAddressResponse['region']['label']); + $this->assertEquals(10, $billingAddressResponse['region']['region_id']); } /** @@ -1112,7 +1135,7 @@ public function testSetNewBillingAddressWithNotSaveInAddressBook() * @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php */ - public function testWithInvalidBillingAddressInput() + public function testSetBillingAddressOnCartWithFreeFormRegionForNoRequiredCountry() { $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote'); @@ -1123,16 +1146,15 @@ public function testWithInvalidBillingAddressInput() cart_id: "$maskedQuoteId" billing_address: { address: { - firstname: "test firstname" - lastname: "test lastname" - company: "test company" - street: ["test street 1", "test street 2"] - city: "test city" - region: "AZ" - postcode: "887766" - country_code: "USS" - telephone: "88776655" - save_in_address_book: false + firstname: "John" + lastname: "Smith" + company: "Magento" + street: ["test street 1", "test street 2"] + city: "London" + region: "Some" + postcode: "887766" + country_code: "GB" + telephone: "88776655" } } } @@ -1150,13 +1172,27 @@ public function testWithInvalidBillingAddressInput() code label } + region { + code + label + region_id + } + __typename } } } } QUERY; - $this->expectExceptionMessage('Country is not available'); - $this->graphQlMutation($query, [], '', $this->getHeaderMap()); + $response = $this->graphQlMutation($query, [], '', $this->getHeaderMap()); + $this->assertArrayHasKey('cart', $response['setBillingAddressOnCart']); + $cartResponse = $response['setBillingAddressOnCart']['cart']; + $this->assertArrayHasKey('billing_address', $cartResponse); + $billingAddressResponse = $cartResponse['billing_address']; + $expectedRegionCode = "Some"; + $expectedRegionLabel = "Some"; + $this->assertEquals($expectedRegionCode, $billingAddressResponse['region']['code']); + $this->assertEquals($expectedRegionLabel, $billingAddressResponse['region']['label']); + $this->assertEquals(null, $billingAddressResponse['region']['region_id']); } /** @@ -1165,7 +1201,7 @@ public function testWithInvalidBillingAddressInput() * @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php */ - public function testSetShippingAddressesWithNotRequiredRegion() + public function testSetBillingAddressOnCartWithRegionOnExistingDuplicateRegionCode() { $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote'); @@ -1175,52 +1211,247 @@ public function testSetShippingAddressesWithNotRequiredRegion() input: { cart_id: "$maskedQuoteId" billing_address: { - address: { - firstname: "Vasyl" - lastname: "Doe" - street: ["1 Svobody"] - city: "Lviv" - region: "Lviv" - postcode: "00000" - country_code: "UA" - telephone: "555-555-55-55" - } - } + address: { + firstname: "John" + lastname: "Smith" + company: "Magento" + street: ["Magento Pkwy", "Main Street"] + city: "APO" + region: "AE" + postcode: "09369" + country_code: "US" + telephone: "8675309" + } + } } ) { cart { billing_address { - region { + firstname + lastname + company + street + city + postcode + telephone + country { + code label } - country { + region { code + label } + __typename } } } } QUERY; - $response = $this->graphQlMutation($query, [], '', $this->getHeaderMap()); - self::assertArrayHasKey('cart', $response['setBillingAddressOnCart']); - $cartResponse = $response['setBillingAddressOnCart']['cart']; - self::assertEquals('UA', $cartResponse['billing_address']['country']['code']); - self::assertEquals('Lviv', $cartResponse['billing_address']['region']['label']); + $this->expectExceptionMessage( + 'Region input is ambiguous. Specify region_id.' + ); + $this->graphQlMutation($query, [], '', $this->getHeaderMap()); } /** - * Verify the all the whitelisted fields for a New Address Object - * - * @param array $addressResponse - * @param string $addressType + * @magentoApiDataFixture Magento/Customer/_files/customer.php + * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php */ - private function assertNewAddressFields(array $addressResponse, string $addressType = 'BillingCartAddress'): void + public function testSetBillingAddressOnCartWithRegionOnExistingDuplicateRegionCodeWithWrongRegionId() { - $assertionMap = [ - ['response_field' => 'firstname', 'expected_value' => 'test firstname'], - ['response_field' => 'lastname', 'expected_value' => 'test lastname'], - ['response_field' => 'company', 'expected_value' => 'test company'], - ['response_field' => 'street', 'expected_value' => [0 => 'test street 1', 1 => 'test street 2']], + $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote'); + + $query = <<<QUERY +mutation { + setBillingAddressOnCart( + input: { + cart_id: "$maskedQuoteId" + billing_address: { + address: { + firstname: "John" + lastname: "Smith" + company: "Magento" + street: ["Magento Pkwy", "Main Street"] + city: "APO" + region: "AE" + region_id: 17 + postcode: "09369" + country_code: "US" + telephone: "8675309" + } + } + } + ) { + cart { + billing_address { + firstname + lastname + company + street + city + postcode + telephone + country { + code + label + } + region { + code + label + } + __typename + } + } + } +} +QUERY; + $this->expectExceptionMessage( + 'The region_id does not match the selected country or region' + ); + $this->graphQlMutation($query, [], '', $this->getHeaderMap()); + } + + /** + * @magentoApiDataFixture Magento/Customer/_files/customer.php + * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php + */ + public function testSetBillingAddressOnCartWithWrongRegionId() + { + $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote'); + + $query = <<<QUERY +mutation { + setBillingAddressOnCart( + input: { + cart_id: "$maskedQuoteId" + billing_address: { + address: { + firstname: "John" + lastname: "Smith" + company: "Magento" + street: ["Magento Pkwy", "Main Street"] + city: "Dallas" + region: "TX" + region_id: 10 + postcode: "09369" + country_code: "US" + telephone: "8675309" + } + } + } + ) { + cart { + billing_address { + firstname + lastname + company + street + city + postcode + telephone + country { + code + label + } + region { + code + label + } + __typename + } + } + } +} +QUERY; + $this->expectExceptionMessage( + 'The region_id does not match the selected country or region' + ); + $this->graphQlMutation($query, [], '', $this->getHeaderMap()); + } + + /** + * @magentoApiDataFixture Magento/Customer/_files/customer.php + * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php + */ + public function testSetBillingAddressOnCartWithCorrectRegionId() + { + $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote'); + + $query = <<<QUERY +mutation { + setBillingAddressOnCart( + input: { + cart_id: "$maskedQuoteId" + billing_address: { + address: { + firstname: "John" + lastname: "Smith" + company: "Magento" + street: ["Magento Pkwy", "Main Street"] + city: "Dallas" + region: "TX" + region_id: 57 + postcode: "09369" + country_code: "US" + telephone: "8675309" + } + } + } + ) { + cart { + billing_address { + firstname + lastname + company + street + city + postcode + telephone + country { + code + label + } + region { + code + label + } + __typename + } + } + } +} +QUERY; + $response = $this->graphQlMutation($query, [], '', $this->getHeaderMap()); + $this->assertArrayHasKey('cart', $response['setBillingAddressOnCart']); + $cartResponse = $response['setBillingAddressOnCart']['cart']; + $this->assertArrayHasKey('billing_address', $cartResponse); + $billingAddressResponse = $cartResponse['billing_address']; + $expectedRegionCode = "TX"; + $expectedRegionLabel = "Texas"; + $this->assertEquals($expectedRegionCode, $billingAddressResponse['region']['code']); + $this->assertEquals($expectedRegionLabel, $billingAddressResponse['region']['label']); + } + + /** + * Verify the all the whitelisted fields for a New Address Object + * + * @param array $addressResponse + * @param string $addressType + */ + private function assertNewAddressFields(array $addressResponse, string $addressType = 'BillingCartAddress'): void + { + $assertionMap = [ + ['response_field' => 'firstname', 'expected_value' => 'test firstname'], + ['response_field' => 'lastname', 'expected_value' => 'test lastname'], + ['response_field' => 'company', 'expected_value' => 'test company'], + ['response_field' => 'street', 'expected_value' => [0 => 'test street 1', 1 => 'test street 2']], ['response_field' => 'city', 'expected_value' => 'test city'], ['response_field' => 'postcode', 'expected_value' => '887766'], ['response_field' => 'telephone', 'expected_value' => '88776655'], @@ -1320,6 +1551,171 @@ private function getSetShippingMethodsQuery( QUERY; } + /** + * @magentoApiDataFixture Magento/Customer/_files/customer.php + * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php + */ + public function testSetBillingAddressAndPlaceOrder() + { + $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote'); + $query = <<<QUERY +mutation { + setBillingAddressOnCart( + input: { + cart_id: "$maskedQuoteId" + billing_address: { + same_as_shipping: true + address: { + firstname: "test firstname" + lastname: "test lastname" + company: "test company" + street: ["test street 1", "test street 2"] + city: "test city" + region: "AZ" + postcode: "88776" + country_code: "US" + telephone: "88776655" + save_in_address_book: true + } + } + } + ) { + cart { + billing_address { + firstname + lastname + company + street + city + postcode + telephone + country { + code + label + } + __typename + } + } + } +} +QUERY; + $response = $this->graphQlMutation($query, [], '', $this->getHeaderMap()); + $this->graphQlMutation( + $this->getSetShippingMethodsQuery($maskedQuoteId, 'flatrate', 'flatrate'), + [], + '', + $this->getHeaderMap() + ); + $this->graphQlMutation( + $this->getSetPaymentMethodQuery( + $maskedQuoteId, + 'checkmo' + ), + [], + '', + $this->getHeaderMap() + ); + $this->graphQlMutation( + $this->getPlaceOrderQuery($maskedQuoteId), + [], + '', + $this->getHeaderMap() + ); + $customer = $this->customerRepository->get('customer@example.com'); + $searchCriteria = $this->searchCriteriaBuilder->addFilter('parent_id', $customer->getId())->create(); + $addresses = $this->customerAddressRepository->getList($searchCriteria)->getItems(); + + self::assertCount(1, $addresses); + self::assertArrayHasKey('cart', $response['setBillingAddressOnCart']); + foreach ($addresses as $address) { + $this->customerAddressRepository->delete($address); + } + } + + /** + * @magentoApiDataFixture Magento/Customer/_files/customer.php + * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php + */ + public function testSetBillingAddressWithDefaultValueOfSaveInAddressBookAndPlaceOrder() + { + $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote'); + $query = <<<QUERY +mutation { + setBillingAddressOnCart( + input: { + cart_id: "$maskedQuoteId" + billing_address: { + same_as_shipping: true + address: { + firstname: "test firstname" + lastname: "test lastname" + company: "test company" + street: ["test street 1", "test street 2"] + city: "test city" + region: "AZ" + postcode: "88776" + country_code: "US" + telephone: "88776655" + } + } + } + ) { + cart { + billing_address { + firstname + lastname + company + street + city + postcode + telephone + country { + code + label + } + __typename + } + } + } +} +QUERY; + $response = $this->graphQlMutation($query, [], '', $this->getHeaderMap()); + $this->graphQlMutation( + $this->getSetShippingMethodsQuery($maskedQuoteId, 'flatrate', 'flatrate'), + [], + '', + $this->getHeaderMap() + ); + $this->graphQlMutation( + $this->getSetPaymentMethodQuery( + $maskedQuoteId, + 'checkmo' + ), + [], + '', + $this->getHeaderMap() + ); + $this->graphQlMutation( + $this->getPlaceOrderQuery($maskedQuoteId), + [], + '', + $this->getHeaderMap() + ); + $customer = $this->customerRepository->get('customer@example.com'); + $searchCriteria = $this->searchCriteriaBuilder->addFilter('parent_id', $customer->getId())->create(); + $addresses = $this->customerAddressRepository->getList($searchCriteria)->getItems(); + + $this->assertCount(1, $addresses); + $this->assertArrayHasKey('cart', $response['setBillingAddressOnCart']); + foreach ($addresses as $address) { + $this->customerAddressRepository->delete($address); + } + } + /** * @param string $maskedQuoteId * @param string $methodCode diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/SetShippingAddressOnCartTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/SetShippingAddressOnCartTest.php index bcc46fec9a659..3e06b89c77fb7 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/SetShippingAddressOnCartTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/SetShippingAddressOnCartTest.php @@ -100,6 +100,7 @@ public function testSetNewShippingAddressOnCartWithSimpleProduct() street: ["test street 1", "test street 2"] city: "test city" region: "AZ" + region_id: 4 postcode: "887766" country_code: "US" telephone: "88776655" @@ -166,6 +167,7 @@ public function testSetNewShippingAddressOnCartWithVirtualProduct() street: ["test street 1", "test street 2"] city: "test city" region: "AZ" + region_id: 4 postcode: "887766" country_code: "US" telephone: "88776655" @@ -530,9 +532,9 @@ public function dataProviderUpdateWithMissedRequiredParameters(): array telephone: "88776655" } }]', - '"regionId" is required. Enter and try again.' + 'Region is required.' ], - 'missed_multiple_fields' => [ + 'missed_postal_code' => [ 'cart_id: "cart_id_value" shipping_addresses: [{ address: { @@ -541,12 +543,13 @@ public function dataProviderUpdateWithMissedRequiredParameters(): array company: "test company" street: ["test street 1", "test street 2"] city: "test city" + region: "TX" + region_id: 57 country_code: "US" telephone: "88776655" } }]', - '"postcode" is required. Enter and try again. -"regionId" is required. Enter and try again.' + '"postcode" is required. Enter and try again.' ], 'wrong_required_region' => [ 'cart_id: "cart_id_value" @@ -557,12 +560,32 @@ public function dataProviderUpdateWithMissedRequiredParameters(): array company: "test company" street: ["test street 1", "test street 2"] region: "wrong region" + region_id: 17 city: "test city" country_code: "US" + postcode: "887766" telephone: "88776655" } }]', - 'Region is not available for the selected country' + 'The region_id does not match the selected country or region' + ], + 'wrong_required_region_name' => [ + 'cart_id: "cart_id_value" + shipping_addresses: [{ + address: { + firstname: "test firstname" + lastname: "test lastname" + company: "test company" + street: ["test street 1", "test street 2"] + region: "wrong region" + region_id: 45 + city: "test city" + country_code: "US" + postcode: "887766" + telephone: "88776655" + } + }]', + 'The region_id does not match the selected country or region' ], ]; } @@ -651,6 +674,7 @@ public function testSetNewShippingAddressOnCartWithRedundantStreetLine() street: ["test street 1", "test street 2", "test street 3"] city: "test city" region: "AZ" + region_id: 4 postcode: "887766" country_code: "US" telephone: "88776655" @@ -765,6 +789,7 @@ public function testSetShippingAddressWithLowerCaseCountry() street: ["6161 West Centinella Avenue"] city: "Culver City" region: "CA" + region_id: 12 postcode: "90230" country_code: "us" telephone: "555-555-55-55" @@ -912,6 +937,7 @@ public function testSetNewShippingAddressWithSaveInAddressBook() street: ["test street 1", "test street 2"] city: "test city" region: "AZ" + region_id: 4 postcode: "887766" country_code: "US" telephone: "88776655" @@ -935,6 +961,10 @@ public function testSetNewShippingAddressWithSaveInAddressBook() code label } + region { + code + label + } __typename customer_notes } @@ -965,9 +995,8 @@ public function testSetNewShippingAddressWithSaveInAddressBook() * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php * @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php - * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_billing_address.php */ - public function testSetNewShippingAddressAndPlaceOrder() + public function testSetNewShippingAddressWithNotSaveInAddressBook() { $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote'); $query = <<<QUERY @@ -984,10 +1013,11 @@ public function testSetNewShippingAddressAndPlaceOrder() street: ["test street 1", "test street 2"] city: "test city" region: "AZ" + region_id: 4 postcode: "887766" country_code: "US" telephone: "88776655" - save_in_address_book: true + save_in_address_book: false } customer_notes: "Test note" } @@ -1015,32 +1045,11 @@ public function testSetNewShippingAddressAndPlaceOrder() } QUERY; $response = $this->graphQlMutation($query, [], '', $this->getHeaderMap()); - $this->graphQlMutation( - $this->getSetShippingMethodsQuery($maskedQuoteId, 'flatrate', 'flatrate'), - [], - '', - $this->getHeaderMap() - ); - $this->graphQlMutation( - $this->getSetPaymentMethodQuery( - $maskedQuoteId, - 'checkmo' - ), - [], - '', - $this->getHeaderMap() - ); - $this->graphQlMutation( - $this->getPlaceOrderQuery($maskedQuoteId), - [], - '', - $this->getHeaderMap() - ); $customer = $this->customerRepository->get('customer@example.com'); $searchCriteria = $this->searchCriteriaBuilder->addFilter('parent_id', $customer->getId())->create(); $addresses = $this->customerAddressRepository->getList($searchCriteria)->getItems(); - self::assertCount(1, $addresses); + self::assertCount(0, $addresses); self::assertArrayHasKey('cart', $response['setShippingAddressesOnCart']); $cartResponse = $response['setShippingAddressesOnCart']['cart']; @@ -1053,6 +1062,504 @@ public function testSetNewShippingAddressAndPlaceOrder() } } + /** + * @magentoApiDataFixture Magento/Customer/_files/customer.php + * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php + */ + public function testSetShippingAddressOnCartWithBothRegionAndRegionId() + { + $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote'); + + $query = <<<QUERY +mutation { + setShippingAddressesOnCart( + input: { + cart_id: "$maskedQuoteId" + shipping_addresses: [ + { + address: { + firstname: "test firstname" + lastname: "test lastname" + company: "test company" + street: ["test street 1", "test street 2"] + city: "APO" + region: "AE" + region_id: 10 + postcode: "887766" + country_code: "US" + telephone: "88776655" + } + } + ] + } + ) { + cart { + shipping_addresses { + firstname + lastname + company + street + city + postcode + telephone + country { + label + code + } + region { + code + label + region_id + } + __typename + } + } + } +} +QUERY; + $response = $this->graphQlMutation($query, [], '', $this->getHeaderMap()); + $this->assertArrayHasKey('cart', $response['setShippingAddressesOnCart']); + $cartResponse = $response['setShippingAddressesOnCart']['cart']; + $this->assertArrayHasKey('shipping_addresses', $cartResponse); + $shippingAddressResponse = current($cartResponse['shipping_addresses']); + $expectedRegionCode = "AE"; + $expectedRegionLabel = "Armed Forces Middle East"; + $this->assertEquals($expectedRegionCode, $shippingAddressResponse['region']['code']); + $this->assertEquals($expectedRegionLabel, $shippingAddressResponse['region']['label']); + $this->assertEquals(10, $shippingAddressResponse['region']['region_id']); + } + + /** + * @magentoApiDataFixture Magento/Customer/_files/customer.php + * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php + */ + public function testSetShippingAddressOnCartWithFreeFormRegionForNoRequiredCountry() + { + $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote'); + + $query = <<<QUERY +mutation { + setShippingAddressesOnCart( + input: { + cart_id: "$maskedQuoteId" + shipping_addresses: [ + { + address: { + firstname: "test firstname" + lastname: "test lastname" + company: "test company" + street: ["test street 1", "test street 2"] + city: "London" + region: "Some" + postcode: "887766" + country_code: "GB" + telephone: "88776655" + } + } + ] + } + ) { + cart { + shipping_addresses { + firstname + lastname + company + street + city + postcode + telephone + country { + label + code + } + region { + code + label + region_id + } + __typename + } + } + } +} +QUERY; + $response = $this->graphQlMutation($query, [], '', $this->getHeaderMap()); + $this->assertArrayHasKey('cart', $response['setShippingAddressesOnCart']); + $cartResponse = $response['setShippingAddressesOnCart']['cart']; + $this->assertArrayHasKey('shipping_addresses', $cartResponse); + $shippingAddressResponse = current($cartResponse['shipping_addresses']); + $expectedRegionCode = "Some"; + $expectedRegionLabel = "Some"; + $this->assertEquals($expectedRegionCode, $shippingAddressResponse['region']['code']); + $this->assertEquals($expectedRegionLabel, $shippingAddressResponse['region']['label']); + $this->assertEquals(null, $shippingAddressResponse['region']['region_id']); + } + + /** + * @magentoApiDataFixture Magento/Customer/_files/customer.php + * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php + */ + public function testSetShippingAddressOnCartWithRegionOnExistingDuplicateRegionCode() + { + $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote'); + + $query = <<<QUERY +mutation { + setShippingAddressesOnCart( + input: { + cart_id: "$maskedQuoteId" + shipping_addresses: [ + { + address: { + firstname: "John" + lastname: "Smith" + company: "Magento" + street: ["Magento Pkwy", "Main Street"] + city: "APO" + region: "AE" + postcode: "09369" + country_code: "US" + telephone: "8675309" + } + } + ] + } + ) { + cart { + shipping_addresses { + firstname + lastname + company + street + city + postcode + telephone + country { + label + code + } + region { + code + label + } + __typename + } + } + } +} +QUERY; + $this->expectExceptionMessage( + 'Region input is ambiguous. Specify region_id.' + ); + $this->graphQlMutation($query, [], '', $this->getHeaderMap()); + } + + /** + * @magentoApiDataFixture Magento/Customer/_files/customer.php + * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php + */ + public function testSetShippingAddressOnCartWithRegionOnExistingDuplicateRegionCodeWithWrongRegionId() + { + $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote'); + + $query = <<<QUERY +mutation { + setShippingAddressesOnCart( + input: { + cart_id: "$maskedQuoteId" + shipping_addresses: [ + { + address: { + firstname: "John" + lastname: "Smith" + company: "Magento" + street: ["Magento Pkwy", "Main Street"] + city: "APO" + region: "AE" + region_id: 17 + postcode: "09369" + country_code: "US" + telephone: "8675309" + } + } + ] + } + ) { + cart { + shipping_addresses { + firstname + lastname + company + street + city + postcode + telephone + country { + label + code + } + region { + code + label + } + __typename + } + } + } +} +QUERY; + $this->expectExceptionMessage( + 'The region_id does not match the selected country or region' + ); + $this->graphQlMutation($query, [], '', $this->getHeaderMap()); + } + + /** + * @magentoApiDataFixture Magento/Customer/_files/customer.php + * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php + */ + public function testSetShippingAddressOnCartWithWrongRegionId() + { + $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote'); + + $query = <<<QUERY +mutation { + setShippingAddressesOnCart( + input: { + cart_id: "$maskedQuoteId" + shipping_addresses: [ + { + address: { + firstname: "test firstname" + lastname: "test lastname" + company: "test company" + street: ["test street 1", "test street 2"] + city: "Dallas" + region: "TX" + region_id: 45 + postcode: "887766" + country_code: "US" + telephone: "88776655" + } + } + ] + } + ) { + cart { + shipping_addresses { + firstname + lastname + company + street + city + postcode + telephone + country { + label + code + } + region { + code + label + } + __typename + } + } + } +} +QUERY; + $this->expectExceptionMessage( + 'The region_id does not match the selected country or region' + ); + $this->graphQlMutation($query, [], '', $this->getHeaderMap()); + } + + /** + * @magentoApiDataFixture Magento/Customer/_files/customer.php + * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php + */ + public function testSetShippingAddressOnCartWithCorrectRegionId() + { + $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote'); + + $query = <<<QUERY +mutation { + setShippingAddressesOnCart( + input: { + cart_id: "$maskedQuoteId" + shipping_addresses: [ + { + address: { + firstname: "test firstname" + lastname: "test lastname" + company: "test company" + street: ["test street 1", "test street 2"] + city: "Dallas" + region: "TX" + region_id: 57 + postcode: "887766" + country_code: "US" + telephone: "88776655" + } + } + ] + } + ) { + cart { + shipping_addresses { + firstname + lastname + company + street + city + postcode + telephone + country { + label + code + } + region { + code + label + } + __typename + } + } + } +} +QUERY; + $response = $this->graphQlMutation($query, [], '', $this->getHeaderMap()); + $this->assertArrayHasKey('cart', $response['setShippingAddressesOnCart']); + $cartResponse = $response['setShippingAddressesOnCart']['cart']; + $this->assertArrayHasKey('shipping_addresses', $cartResponse); + $shippingAddressResponse = current($cartResponse['shipping_addresses']); + $expectedRegionCode = "TX"; + $expectedRegionLabel = "Texas"; + $this->assertEquals($expectedRegionCode, $shippingAddressResponse['region']['code']); + $this->assertEquals($expectedRegionLabel, $shippingAddressResponse['region']['label']); + } + + /** + * @magentoApiDataFixture Magento/Customer/_files/customer_without_addresses.php + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + */ + public function testSetShippingAddressOnCartWithCreateCustomerAddressRegionCodeAndRegionId() + { + $newAddress = [ + 'region' => [ + 'region_code' => 'NY', + 'region_id' => 43 + ], + 'country_code' => 'US', + 'street' => ['Line 1 Street', 'Line 2'], + 'company' => 'Company name', + 'telephone' => '123456789', + 'postcode' => '10019', + 'city' => 'Manhattan', + 'firstname' => 'Adam', + 'lastname' => 'Phillis' + ]; + + $mutation + = <<<MUTATION +mutation { + createCustomerAddress(input: { + region: { + region_code: "{$newAddress['region']['region_code']}" + region_id: {$newAddress['region']['region_id']} + } + country_code: {$newAddress['country_code']} + street: ["{$newAddress['street'][0]}","{$newAddress['street'][1]}"] + company: "{$newAddress['company']}" + telephone: "{$newAddress['telephone']}" + postcode: "{$newAddress['postcode']}" + city: "{$newAddress['city']}" + firstname: "{$newAddress['firstname']}" + lastname: "{$newAddress['lastname']}" + }) { + id + customer_id + region { + region + region_id + region_code + } + country_code + street + company + telephone + postcode + city + firstname + lastname + } +} +MUTATION; + + $userName = 'customer@example.com'; + $password = 'password'; + $response = $this->graphQlMutation($mutation, [], '', $this->getHeaderMap($userName, $password)); + $this->assertArrayHasKey('createCustomerAddress', $response); + + $this->assertArrayHasKey('customer_id', $response['createCustomerAddress']); + $this->assertEquals(null, $response['createCustomerAddress']['customer_id']); + $this->assertArrayHasKey('id', $response['createCustomerAddress']); + $id = $response['createCustomerAddress']['id']; + $this->assertEquals(43, $response["createCustomerAddress"]["region"]["region_id"]); + + $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote'); + + $query = <<<QUERY +mutation { + setShippingAddressesOnCart( + input: { + cart_id: "$maskedQuoteId" + shipping_addresses: { + customer_address_id: $id + } + } + ) { + cart { + shipping_addresses { + city + region{ + code + label + region_id + } + } + } + } +} +QUERY; + $userName = 'customer@example.com'; + $password = 'password'; + $shippingAddressesResponse = $this->graphQlMutation( + $query, + [], + '', + $this->getHeaderMap($userName, $password) + ); + $cartResponse = $shippingAddressesResponse["setShippingAddressesOnCart"]["cart"]["shipping_addresses"][0]; + $this->assertEquals( + 43, + $cartResponse["region"]["region_id"] + ); + } + /** * @magentoApiDataFixture Magento/Customer/_files/customer.php * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php @@ -1060,7 +1567,7 @@ public function testSetNewShippingAddressAndPlaceOrder() * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_billing_address.php */ - public function testSetNewShippingAddressWithDefaultValueOfSaveInAddressBookAndPlaceOrder() + public function testSetNewShippingAddressAndPlaceOrder() { $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote'); $query = <<<QUERY @@ -1080,6 +1587,7 @@ public function testSetNewShippingAddressWithDefaultValueOfSaveInAddressBookAndP postcode: "887766" country_code: "US" telephone: "88776655" + save_in_address_book: true } customer_notes: "Test note" } @@ -1132,11 +1640,11 @@ public function testSetNewShippingAddressWithDefaultValueOfSaveInAddressBookAndP $searchCriteria = $this->searchCriteriaBuilder->addFilter('parent_id', $customer->getId())->create(); $addresses = $this->customerAddressRepository->getList($searchCriteria)->getItems(); - $this->assertCount(1, $addresses); - $this->assertArrayHasKey('cart', $response['setShippingAddressesOnCart']); + self::assertCount(1, $addresses); + self::assertArrayHasKey('cart', $response['setShippingAddressesOnCart']); $cartResponse = $response['setShippingAddressesOnCart']['cart']; - $this->assertArrayHasKey('shipping_addresses', $cartResponse); + self::assertArrayHasKey('shipping_addresses', $cartResponse); $shippingAddressResponse = current($cartResponse['shipping_addresses']); $this->assertNewShippingAddressFields($shippingAddressResponse); @@ -1150,8 +1658,9 @@ public function testSetNewShippingAddressWithDefaultValueOfSaveInAddressBookAndP * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php * @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_billing_address.php */ - public function testSetNewShippingAddressWithNotSaveInAddressBook() + public function testSetNewShippingAddressWithDefaultValueOfSaveInAddressBookAndPlaceOrder() { $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote'); $query = <<<QUERY @@ -1171,7 +1680,6 @@ public function testSetNewShippingAddressWithNotSaveInAddressBook() postcode: "887766" country_code: "US" telephone: "88776655" - save_in_address_book: false } customer_notes: "Test note" } @@ -1199,15 +1707,36 @@ public function testSetNewShippingAddressWithNotSaveInAddressBook() } QUERY; $response = $this->graphQlMutation($query, [], '', $this->getHeaderMap()); + $this->graphQlMutation( + $this->getSetShippingMethodsQuery($maskedQuoteId, 'flatrate', 'flatrate'), + [], + '', + $this->getHeaderMap() + ); + $this->graphQlMutation( + $this->getSetPaymentMethodQuery( + $maskedQuoteId, + 'checkmo' + ), + [], + '', + $this->getHeaderMap() + ); + $this->graphQlMutation( + $this->getPlaceOrderQuery($maskedQuoteId), + [], + '', + $this->getHeaderMap() + ); $customer = $this->customerRepository->get('customer@example.com'); $searchCriteria = $this->searchCriteriaBuilder->addFilter('parent_id', $customer->getId())->create(); $addresses = $this->customerAddressRepository->getList($searchCriteria)->getItems(); - self::assertCount(0, $addresses); - self::assertArrayHasKey('cart', $response['setShippingAddressesOnCart']); + $this->assertCount(1, $addresses); + $this->assertArrayHasKey('cart', $response['setShippingAddressesOnCart']); $cartResponse = $response['setShippingAddressesOnCart']['cart']; - self::assertArrayHasKey('shipping_addresses', $cartResponse); + $this->assertArrayHasKey('shipping_addresses', $cartResponse); $shippingAddressResponse = current($cartResponse['shipping_addresses']); $this->assertNewShippingAddressFields($shippingAddressResponse); diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/AddSimpleProductToCartTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/AddSimpleProductToCartTest.php index d67aa5430e436..1f6c8aca54ea5 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/AddSimpleProductToCartTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/AddSimpleProductToCartTest.php @@ -81,6 +81,54 @@ public function testAddSimpleProductToCart() self::assertEquals('USD', $rowTotalIncludingTax['currency']); } + /** + * @magentoApiDataFixture Magento/Catalog/_files/product_with_image_no_options.php + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php + */ + public function testAddProductToCartWithImage() + { + $sku = 'simple-2'; + $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote'); + + $query = <<<QUERY +mutation { + addSimpleProductsToCart(input: { + cart_id: "$maskedQuoteId", + cart_items: [{data: {sku: "$sku", quantity: 1}}] + }) { + cart { + items { + id + prices{ + price { + value + } + } + quantity + product { + sku + name + image { + label + url + } + } + } + } + } +} +QUERY; + + $response = $this->graphQlMutation($query); + $this->assertArrayHasKey('cart', $response['addSimpleProductsToCart']); + $this->assertCount(1, $response['addSimpleProductsToCart']['cart']['items']); + $cartItem = $response['addSimpleProductsToCart']['cart']['items'][0]; + $this->assertEquals('11', $cartItem['prices']['price']['value']); + $this->assertEquals($sku, $cartItem['product']['sku']); + $expectedImageRegex = '/^https?:\/\/.+magento_image(_[0-9]+)?.jpg$/'; + $this->assertMatchesRegularExpression($expectedImageRegex, $cartItem['product']['image']['url']); + } + /** * Add disabled product to cart * diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/Layer/Filter/Price/AlgorithmBaseTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/Layer/Filter/Price/AlgorithmBaseTest.php index 55fa56a5000c1..5d7b4cbb3f89a 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Model/Layer/Filter/Price/AlgorithmBaseTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/Layer/Filter/Price/AlgorithmBaseTest.php @@ -5,6 +5,7 @@ */ namespace Magento\Catalog\Model\Layer\Filter\Price; +use Magento\Framework\Search\Dynamic\IntervalInterface; use Magento\TestFramework\Helper\Bootstrap; /** @@ -42,32 +43,23 @@ class AlgorithmBaseTest extends \PHPUnit\Framework\TestCase * @param $categoryId * @param array $entityIds * @param array $intervalItems - * @covers \Magento\Framework\Search\Dynamic\Algorithm::calculateSeparators + * @covers \Magento\Framework\Search\Dynamic\Algorithm::calculateSeparators */ public function testPricesSegmentation($categoryId, array $entityIds, array $intervalItems) { + $this->markTestSkipped('MC-33826:' + . 'Stabilize skipped test cases for Integration AlgorithmBaseTest with elasticsearch'); $objectManager = Bootstrap::getObjectManager(); $layer = $objectManager->create(\Magento\Catalog\Model\Layer\Category::class); - /** @var \Magento\Framework\Search\Request\Aggregation\TermBucket $termBucket */ - $termBucket = $objectManager->create( - \Magento\Framework\Search\Request\Aggregation\TermBucket::class, - ['name' => 'name', 'field' => 'price', 'metrics' => []] - ); - - $dimensions = [ - 'scope' => $objectManager->create( - \Magento\Framework\Search\Request\Dimension::class, - ['name' => 'someName', 'value' => 'default'] - ), - ]; /** @var \Magento\Framework\Search\EntityMetadata $entityMetadata */ $entityMetadata = $objectManager->create(\Magento\Framework\Search\EntityMetadata::class, ['entityId' => 'id']); $idKey = $entityMetadata->getEntityId(); - /** @var \Magento\Framework\Search\Adapter\Mysql\DocumentFactory $documentFactory */ + // this class has been removed + /** @var \Magento\Elasticsearch\SearchAdapter\DocumentFactory $documentFactory */ $documentFactory = $objectManager->create( - \Magento\Framework\Search\Adapter\Mysql\DocumentFactory::class, + \Magento\Elasticsearch\SearchAdapter\DocumentFactory::class, ['entityMetadata' => $entityMetadata] ); @@ -80,22 +72,12 @@ public function testPricesSegmentation($categoryId, array $entityIds, array $int ]; $documents[] = $documentFactory->create($rawDocument); } - - /** @var \Magento\Framework\Search\Adapter\Mysql\TemporaryStorage $temporaryStorage */ - $temporaryStorage = $objectManager->create(\Magento\Framework\Search\Adapter\Mysql\TemporaryStorage::class); - $table = $temporaryStorage->storeDocuments($documents); - - /** @var \Magento\CatalogSearch\Model\Adapter\Mysql\Aggregation\DataProvider $dataProvider */ - $dataProvider = $objectManager->create( - \Magento\CatalogSearch\Model\Adapter\Mysql\Aggregation\DataProvider::class - ); - $select = $dataProvider->getDataSet($termBucket, $dimensions, $table); - - /** @var \Magento\Framework\Search\Adapter\Mysql\Aggregation\IntervalFactory $intervalFactory */ + /** @var \Magento\CatalogSearch\Model\Price\IntervalFactory $intervalFactory */ $intervalFactory = $objectManager->create( - \Magento\Framework\Search\Adapter\Mysql\Aggregation\IntervalFactory::class + \Magento\CatalogSearch\Model\Price\IntervalFactory::class ); - $interval = $intervalFactory->create(['select' => $select]); + /** @var \Magento\CatalogSearch\Model\Price\Interval $interval */ + $interval = $intervalFactory->create(); /** @var \Magento\Framework\Search\Dynamic\Algorithm $model */ $model = $objectManager->create(\Magento\Framework\Search\Dynamic\Algorithm::class); diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/multiple_products_with_different_sku_and_name.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/multiple_products_with_different_sku_and_name.php new file mode 100644 index 0000000000000..2921737faba1f --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/multiple_products_with_different_sku_and_name.php @@ -0,0 +1,56 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +/** @var $product \Magento\Catalog\Model\Product */ +$product = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(\Magento\Catalog\Model\Product::class); +$product->isObjectNew(true); +$product->setTypeId(\Magento\Catalog\Model\Product\Type::TYPE_SIMPLE) + ->setId(10) + ->setAttributeSetId(4) + ->setName('Simple Product1') + ->setSku('prd1sku') + ->setTaxClassId('none') + ->setDescription('description') + ->setShortDescription('short description') + ->setOptionsContainer('container1') + ->setMsrpDisplayActualPriceType(\Magento\Msrp\Model\Product\Attribute\Source\Type::TYPE_IN_CART) + ->setPrice(10) + ->setWeight(1) + ->setMetaTitle('meta title') + ->setMetaKeyword('meta keyword') + ->setMetaDescription('meta description') + ->setVisibility(\Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH) + ->setStatus(\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED) + ->setWebsiteIds([1]) + ->setCategoryIds([]) + ->setStockData(['use_config_manage_stock' => 1, 'qty' => 100, 'is_qty_decimal' => 0, 'is_in_stock' => 1]) + ->setSpecialPrice('5.99') + ->save(); + +$product = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(\Magento\Catalog\Model\Product::class); +$product->isObjectNew(true); +$product->setTypeId(\Magento\Catalog\Model\Product\Type::TYPE_SIMPLE) + ->setId(11) + ->setAttributeSetId(4) + ->setName('Simple Product2') + ->setSku('prd2-sku2') + ->setTaxClassId('none') + ->setDescription('description') + ->setShortDescription('short description') + ->setOptionsContainer('container1') + ->setMsrpDisplayActualPriceType(\Magento\Msrp\Model\Product\Attribute\Source\Type::TYPE_ON_GESTURE) + ->setPrice(20) + ->setWeight(1) + ->setMetaTitle('meta title') + ->setMetaKeyword('meta keyword') + ->setMetaDescription('meta description') + ->setVisibility(\Magento\Catalog\Model\Product\Visibility::VISIBILITY_IN_CATALOG) + ->setStatus(\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED) + ->setWebsiteIds([1]) + ->setCategoryIds([]) + ->setStockData(['use_config_manage_stock' => 1, 'qty' => 50, 'is_qty_decimal' => 0, 'is_in_stock' => 1]) + ->setSpecialPrice('15.99') + ->save(); diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/multiple_products_with_different_sku_and_name_rollback.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/multiple_products_with_different_sku_and_name_rollback.php new file mode 100644 index 0000000000000..aaeee1dc96102 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/multiple_products_with_different_sku_and_name_rollback.php @@ -0,0 +1,28 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +$objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + +/** @var \Magento\Framework\Registry $registry */ +$registry = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get(\Magento\Framework\Registry::class); + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', true); + +/** @var \Magento\Catalog\Api\ProductRepositoryInterface $productRepository */ +$productRepository = $objectManager->create(\Magento\Catalog\Api\ProductRepositoryInterface::class); + +foreach (['prd1sku', 'prd2-sku2'] as $sku) { + try { + $product = $productRepository->get($sku, false, null, true); + $productRepository->delete($product); + } catch (\Magento\Framework\Exception\NoSuchEntityException $exception) { + //Product already removed + } +} + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', false); diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/product_with_image_no_options.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_with_image_no_options.php new file mode 100644 index 0000000000000..d2565a0880239 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_with_image_no_options.php @@ -0,0 +1,29 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +use Magento\TestFramework\Workaround\Override\Fixture\Resolver; + +Resolver::getInstance()->requireDataFixture('Magento/Catalog/_files/product_image.php'); +Resolver::getInstance()->requireDataFixture('Magento/Catalog/_files/product_simple_without_custom_options.php'); + +$objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); +$productRepository = $objectManager->create(\Magento\Catalog\Api\ProductRepositoryInterface::class); +$product = $productRepository->get('simple-2'); + +/** @var $product \Magento\Catalog\Model\Product */ +$product->setStoreId(0) + ->setImage('/m/a/magento_image.jpg') + ->setSmallImage('/m/a/magento_image.jpg') + ->setThumbnail('/m/a/magento_image.jpg') + ->setData('media_gallery', ['images' => [ + [ + 'file' => '/m/a/magento_image.jpg', + 'position' => 1, + 'label' => 'Image Alt Text', + 'disabled' => 0, + 'media_type' => 'image' + ], + ]]) + ->save(); diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/product_with_image_no_options_rollback.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_with_image_no_options_rollback.php new file mode 100644 index 0000000000000..3a4853a98c81e --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_with_image_no_options_rollback.php @@ -0,0 +1,11 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +use Magento\TestFramework\Workaround\Override\Fixture\Resolver; + +Resolver::getInstance()->requireDataFixture('Magento/Catalog/_files/product_image_rollback.php'); +Resolver::getInstance()->requireDataFixture( + 'Magento/Catalog/_files/product_simple_without_custom_options_rollback.php' +); diff --git a/dev/tests/integration/testsuite/Magento/CatalogSearch/Model/Adapter/Mysql/BaseSelectStrategy/BaseSelectAttributesSearchStrategyTest.php b/dev/tests/integration/testsuite/Magento/CatalogSearch/Model/Adapter/Mysql/BaseSelectStrategy/BaseSelectAttributesSearchStrategyTest.php deleted file mode 100644 index 56d641a444c0f..0000000000000 --- a/dev/tests/integration/testsuite/Magento/CatalogSearch/Model/Adapter/Mysql/BaseSelectStrategy/BaseSelectAttributesSearchStrategyTest.php +++ /dev/null @@ -1,152 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -namespace Magento\CatalogSearch\Model\Adapter\Mysql\BaseSelectStrategy; - -use Magento\Framework\App\ResourceConnection; -use Magento\Store\Model\StoreManagerInterface; -use Magento\Framework\Indexer\ScopeResolver\IndexScopeResolver; -use Magento\CatalogSearch\Model\Search\SelectContainer\SelectContainerFactory; - -class BaseSelectAttributesSearchStrategyTest extends \PHPUnit\Framework\TestCase -{ - /** - * @var BaseSelectAttributesSearchStrategy - */ - private $baseSelectAttributesSearchStrategy; - - /** - * @var SelectContainerFactory - */ - private $selectContainerFactory; - - /** - * @var ResourceConnection - */ - private $resource; - - /** - * @var StoreManagerInterface - */ - private $storeManager; - - /** - * @var IndexScopeResolver - */ - private $scopeResolver; - - protected function setUp(): void - { - $this->baseSelectAttributesSearchStrategy = \Magento\TestFramework\Helper\Bootstrap::getObjectManager() - ->create(BaseSelectAttributesSearchStrategy::class); - - $this->selectContainerFactory = \Magento\TestFramework\Helper\Bootstrap::getObjectManager() - ->create(SelectContainerFactory::class); - - $this->resource = \Magento\TestFramework\Helper\Bootstrap::getObjectManager() - ->create(ResourceConnection::class); - - $this->storeManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager() - ->create(StoreManagerInterface::class); - - $this->scopeResolver = \Magento\TestFramework\Helper\Bootstrap::getObjectManager() - ->create(IndexScopeResolver::class); - } - - public function testCreateBaseSelectWithoutFullTextSearch() - { - $selectContainer = $this->getSelectContainerWithoutFullTextSearch(); - $selectContainer = $this->baseSelectAttributesSearchStrategy->createBaseSelect($selectContainer); - $select = $selectContainer->getSelect(); - $expectedSelect = $this->getMainSelect(); - - $this->assertEquals((string) $expectedSelect, (string) $select); - } - - public function testCreateBaseSelectWithFullTextSearch() - { - $selectContainer = $this->getSelectContainerWithFullTextSearch(); - $selectContainer = $this->baseSelectAttributesSearchStrategy->createBaseSelect($selectContainer); - $select = $selectContainer->getSelect(); - $expectedSelect = $this->getFulltextSelect(); - - $this->assertEquals((string) $expectedSelect, (string) $select); - } - - private function getMainSelect() - { - $select = $this->resource->getConnection()->select(); - $select->distinct() - ->from( - ['search_index' => $this->resource->getTableName('catalog_product_index_eav')], - ['entity_id' => 'entity_id'] - )->where( - $this->resource->getConnection()->quoteInto( - 'search_index.store_id = ?', - $this->storeManager->getStore()->getId() - ) - ); - - return $select; - } - - private function getFulltextSelect() - { - $select = $this->resource->getConnection()->select(); - $select->distinct() - ->from( - ['eav_index' => $this->resource->getTableName('catalog_product_index_eav')], - ['entity_id' => 'entity_id'] - )->where( - $this->resource->getConnection()->quoteInto( - 'eav_index.store_id = ?', - $this->storeManager->getStore()->getId() - ) - )->joinInner( - ['search_index' => $this->scopeResolver->resolve('', [])], - 'eav_index.entity_id = search_index.entity_id', - [] - )->joinInner( - ['cea' => $this->resource->getTableName('catalog_eav_attribute')], - 'search_index.attribute_id = cea.attribute_id', - [] - ); - - return $select; - } - - private function getSelectContainerWithFullTextSearch() - { - return $this->selectContainerFactory->create( - [ - 'nonCustomAttributesFilters' => [], - 'customAttributesFilters' => [], - 'visibilityFilter' => null, - 'isFullTextSearchRequired' => true, - 'isShowOutOfStockEnabled' => false, - 'usedIndex' => '', - 'dimensions' => [], - 'select' => $this->resource->getConnection()->select() - ] - ); - } - - private function getSelectContainerWithoutFullTextSearch() - { - return $this->selectContainerFactory->create( - [ - 'nonCustomAttributesFilters' => [], - 'customAttributesFilters' => [], - 'visibilityFilter' => null, - 'isFullTextSearchRequired' => false, - 'isShowOutOfStockEnabled' => false, - 'usedIndex' => '', - 'dimensions' => [], - 'select' => $this->resource->getConnection()->select() - ] - ); - } -} diff --git a/dev/tests/integration/testsuite/Magento/CatalogSearch/Model/Adapter/Mysql/BaseSelectStrategy/BaseSelectFullTextSearchStrategyTest.php b/dev/tests/integration/testsuite/Magento/CatalogSearch/Model/Adapter/Mysql/BaseSelectStrategy/BaseSelectFullTextSearchStrategyTest.php deleted file mode 100644 index 4d8623a4e9cac..0000000000000 --- a/dev/tests/integration/testsuite/Magento/CatalogSearch/Model/Adapter/Mysql/BaseSelectStrategy/BaseSelectFullTextSearchStrategyTest.php +++ /dev/null @@ -1,90 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -namespace Magento\CatalogSearch\Model\Adapter\Mysql\BaseSelectStrategy; - -use Magento\Framework\App\ResourceConnection; -use Magento\Framework\Indexer\ScopeResolver\IndexScopeResolver; -use Magento\CatalogSearch\Model\Search\SelectContainer\SelectContainerFactory; - -class BaseSelectFullTextSearchStrategyTest extends \PHPUnit\Framework\TestCase -{ - /** - * @var BaseSelectFullTextSearchStrategy - */ - private $baseSelectFullTextSearchStrategy; - - /** - * @var SelectContainerFactory - */ - private $selectContainerFactory; - - /** - * @var ResourceConnection - */ - private $resource; - - /** - * @var IndexScopeResolver - */ - private $scopeResolver; - - protected function setUp(): void - { - $this->baseSelectFullTextSearchStrategy = \Magento\TestFramework\Helper\Bootstrap::getObjectManager() - ->create(BaseSelectFullTextSearchStrategy::class); - - $this->selectContainerFactory = \Magento\TestFramework\Helper\Bootstrap::getObjectManager() - ->create(SelectContainerFactory::class); - - $this->resource = \Magento\TestFramework\Helper\Bootstrap::getObjectManager() - ->create(ResourceConnection::class); - - $this->scopeResolver = \Magento\TestFramework\Helper\Bootstrap::getObjectManager() - ->create(IndexScopeResolver::class); - } - - public function testCreateBaseSelect() - { - $selectContainer = $this->getSelectContainerWithFullTextSearch(); - $selectContainer = $this->baseSelectFullTextSearchStrategy->createBaseSelect($selectContainer); - $select = $selectContainer->getSelect(); - $expectedSelect = $this->getExpectedSelect(); - - $this->assertEquals((string) $expectedSelect, (string) $select); - } - - private function getExpectedSelect() - { - $select = $this->resource->getConnection()->select(); - $select->from( - ['search_index' => $this->scopeResolver->resolve('', [])], - ['entity_id' => 'entity_id'] - )->joinInner( - ['cea' => $this->resource->getTableName('catalog_eav_attribute')], - 'search_index.attribute_id = cea.attribute_id', - [] - ); - - return $select; - } - - private function getSelectContainerWithFullTextSearch() - { - return $this->selectContainerFactory->create( - [ - 'nonCustomAttributesFilters' => [], - 'customAttributesFilters' => [], - 'visibilityFilter' => null, - 'isFullTextSearchRequired' => true, - 'isShowOutOfStockEnabled' => false, - 'usedIndex' => '', - 'dimensions' => [], - 'select' => $this->resource->getConnection()->select() - ] - ); - } -} diff --git a/dev/tests/integration/testsuite/Magento/CatalogSearch/Model/Indexer/Fulltext/Action/FullTest.php b/dev/tests/integration/testsuite/Magento/CatalogSearch/Model/Indexer/Fulltext/Action/FullTest.php index 8033b73631f19..d0d59425ec6f9 100644 --- a/dev/tests/integration/testsuite/Magento/CatalogSearch/Model/Indexer/Fulltext/Action/FullTest.php +++ b/dev/tests/integration/testsuite/Magento/CatalogSearch/Model/Indexer/Fulltext/Action/FullTest.php @@ -7,7 +7,7 @@ use Magento\Catalog\Api\ProductRepositoryInterface; use Magento\Catalog\Model\Product\Attribute\Source\Status; -use Magento\CatalogSearch\Model\ResourceModel\Engine; +use Magento\CatalogSearch\Model\ResourceModel\EngineInterface as Engine; use Magento\Catalog\Api\ProductAttributeRepositoryInterface; use Magento\Catalog\Api\Data\ProductInterface; use Magento\Store\Model\Store; diff --git a/dev/tests/integration/testsuite/Magento/CatalogSearch/Model/Indexer/FulltextTest.php b/dev/tests/integration/testsuite/Magento/CatalogSearch/Model/Indexer/FulltextTest.php index 9da81d35ca9bd..79201d8605e7a 100644 --- a/dev/tests/integration/testsuite/Magento/CatalogSearch/Model/Indexer/FulltextTest.php +++ b/dev/tests/integration/testsuite/Magento/CatalogSearch/Model/Indexer/FulltextTest.php @@ -22,16 +22,6 @@ class FulltextTest extends \PHPUnit\Framework\TestCase */ protected $indexer; - /** - * @var \Magento\CatalogSearch\Model\ResourceModel\Engine - */ - protected $engine; - - /** - * @var \Magento\CatalogSearch\Model\Fulltext - */ - protected $fulltext; - /** * @var \Magento\Search\Model\QueryFactory */ diff --git a/dev/tests/integration/testsuite/Magento/CatalogSearch/Model/Indexer/IndexSwitcherMock.php b/dev/tests/integration/testsuite/Magento/CatalogSearch/Model/Indexer/IndexSwitcherMock.php deleted file mode 100644 index 47c60393c33ad..0000000000000 --- a/dev/tests/integration/testsuite/Magento/CatalogSearch/Model/Indexer/IndexSwitcherMock.php +++ /dev/null @@ -1,51 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -namespace Magento\CatalogSearch\Model\Indexer; - -/** - * The proxy class around index switcher which allows to ensure that the IndexSwitcher was actually used - */ -class IndexSwitcherMock extends \PHPUnit\Framework\Assert implements IndexSwitcherInterface -{ - private $isSwitched = false; - - /** - * @var \Magento\CatalogSearch\Model\Indexer\IndexSwitcherInterface - */ - private $indexSwitcher; - - /** - * @param \Magento\CatalogSearch\Model\Indexer\IndexSwitcherInterface $indexSwitcher - */ - public function __construct( - IndexSwitcherInterface $indexSwitcher - ) { - $this->indexSwitcher = $indexSwitcher; - } - - /** - * Switch current index with temporary index - * - * It will drop current index table and rename temporary index table to the current index table. - * - * @param array $dimensions - * @return void - */ - public function switchIndex(array $dimensions) - { - $this->isSwitched |= true; - $this->indexSwitcher->switchIndex($dimensions); - } - - /** - * @return bool - */ - public function isSwitched() - { - return (bool) $this->isSwitched; - } -} diff --git a/dev/tests/integration/testsuite/Magento/CatalogSearch/Model/Indexer/SwitcherUsedInFulltextTest.php b/dev/tests/integration/testsuite/Magento/CatalogSearch/Model/Indexer/SwitcherUsedInFulltextTest.php deleted file mode 100644 index 7f029ae537ddf..0000000000000 --- a/dev/tests/integration/testsuite/Magento/CatalogSearch/Model/Indexer/SwitcherUsedInFulltextTest.php +++ /dev/null @@ -1,202 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -namespace Magento\CatalogSearch\Model\Indexer; - -use Magento\Catalog\Model\Product; -use Magento\CatalogSearch\Model\ResourceModel\Fulltext\Collection; -use Magento\TestFramework\Helper\Bootstrap; - -/** - * @magentoDbIsolation disabled - * @magentoDataFixture Magento/CatalogSearch/_files/indexer_fulltext.php - * @SuppressWarnings(PHPMD.CouplingBetweenObjects) - */ -class SwitcherUsedInFulltextTest extends \PHPUnit\Framework\TestCase -{ - /** - * @var IndexSwitcherInterface - */ - private $indexSwitcher; - - /** - * @var \Magento\Framework\Indexer\IndexerInterface - */ - protected $indexer; - - /** - * @var \Magento\CatalogSearch\Model\ResourceModel\Engine - */ - protected $engine; - - /** - * @var \Magento\CatalogSearch\Model\Fulltext - */ - protected $fulltext; - - /** - * @var \Magento\Search\Model\QueryFactory - */ - protected $queryFactory; - - /** - * @var \Magento\Catalog\Model\Product - */ - protected $productApple; - - /** - * @var \Magento\Catalog\Model\Product - */ - protected $productBanana; - - /** - * @var \Magento\Catalog\Model\Product - */ - protected $productOrange; - - /** - * @var \Magento\Catalog\Model\Product - */ - protected $productPapaya; - - /** - * @var \Magento\Catalog\Model\Product - */ - protected $productCherry; - - /** - * @var \Magento\Framework\Search\Request\Dimension - */ - protected $dimension; - - protected function setUp(): void - { - $objectManager = Bootstrap::getObjectManager(); - - $objectManager->configure( - [ - ltrim(Fulltext::class, '\\') => [ - 'arguments' => [ - 'indexSwitcher' => [ - 'instance' => ltrim(IndexSwitcherMock::class, '\\'), - ], - ], - ], - ] - ); - - /** @var \Magento\Framework\Indexer\IndexerInterface indexer */ - $this->indexer = $objectManager->create( - \Magento\Indexer\Model\Indexer::class - ); - $this->indexer->load('catalogsearch_fulltext'); - - $this->engine = $objectManager->get( - \Magento\CatalogSearch\Model\ResourceModel\Engine::class - ); - - $this->queryFactory = $objectManager->get( - \Magento\Search\Model\QueryFactory::class - ); - - $this->dimension = $objectManager->create( - \Magento\Framework\Search\Request\Dimension::class, - ['name' => 'scope', 'value' => '1'] - ); - - $this->indexSwitcher = Bootstrap::getObjectManager()->get( - IndexSwitcherMock::class - ); - - $this->productApple = $this->getProductBySku('fulltext-1'); - $this->productBanana = $this->getProductBySku('fulltext-2'); - $this->productOrange = $this->getProductBySku('fulltext-3'); - $this->productPapaya = $this->getProductBySku('fulltext-4'); - $this->productCherry = $this->getProductBySku('fulltext-5'); - } - - /** - * @magentoAppIsolation enabled - */ - public function testReindexAll() - { - $this->indexer->reindexAll(); - - /** @var IndexSwitcherMock $indexSwitcher */ - $indexSwitcher = Bootstrap::getObjectManager()->get( - IndexSwitcherMock::class - ); - $this->assertTrue($indexSwitcher->isSwitched()); - } - - /** - * @magentoAppIsolation enabled - */ - public function testReindexList() - { - $this->indexer->reindexList([$this->productApple->getId(), $this->productBanana->getId()]); - - /** @var IndexSwitcherMock $indexSwitcher */ - $indexSwitcher = Bootstrap::getObjectManager()->get( - IndexSwitcherMock::class - ); - $this->assertFalse($indexSwitcher->isSwitched()); - } - - /** - * @magentoAppIsolation enabled - */ - public function testReindexRow() - { - $this->indexer->reindexRow($this->productPapaya->getId()); - - /** @var IndexSwitcherMock $indexSwitcher */ - $indexSwitcher = Bootstrap::getObjectManager()->get( - IndexSwitcherMock::class - ); - $this->assertFalse($indexSwitcher->isSwitched()); - } - - /** - * Search the text and return result collection - * - * @param string $text - * @return Product[] - */ - protected function search($text) - { - $query = $this->queryFactory->get(); - $query->unsetData(); - $query->setQueryText($text); - $query->saveIncrementalPopularity(); - $products = []; - $collection = Bootstrap::getObjectManager()->create( - Collection::class, - [ - 'searchRequestName' => 'quick_search_container' - ] - ); - $collection->addSearchFilter($text); - foreach ($collection as $product) { - $products[] = $product; - } - return $products; - } - - /** - * Return product by SKU - * - * @param string $sku - * @return Product - */ - protected function getProductBySku($sku) - { - /** @var Product $product */ - $product = Bootstrap::getObjectManager()->get( - \Magento\Catalog\Model\Product::class - ); - return $product->loadByAttribute('sku', $sku); - } -} diff --git a/dev/tests/integration/testsuite/Magento/CatalogSearch/Model/Search/FilterMapper/CustomAttributeFilterTest.php b/dev/tests/integration/testsuite/Magento/CatalogSearch/Model/Search/FilterMapper/CustomAttributeFilterTest.php deleted file mode 100644 index f6a7e2d2118ba..0000000000000 --- a/dev/tests/integration/testsuite/Magento/CatalogSearch/Model/Search/FilterMapper/CustomAttributeFilterTest.php +++ /dev/null @@ -1,251 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -namespace Magento\CatalogSearch\Model\Search\FilterMapper; - -use Magento\Framework\Search\Request\Filter\Term; -use Magento\Store\Model\StoreManagerInterface; -use Magento\Framework\App\ResourceConnection; -use Magento\Eav\Model\Config as EavConfig; -use Magento\Catalog\Model\Product; -use Magento\Eav\Model\Entity\Attribute\AbstractAttribute; -use Magento\Framework\Search\Adapter\Mysql\ConditionManager; -use Magento\Framework\DB\Select; - -class CustomAttributeFilterTest extends \PHPUnit\Framework\TestCase -{ - /** @var \Magento\Framework\ObjectManagerInterface */ - private $objectManager; - - /** @var ResourceConnection */ - private $resource; - - /** @var */ - private $customAttributeFilter; - - /** @var EavConfig|\PHPUnit\Framework\MockObject\MockObject */ - private $eavConfigMock; - - /** @var StoreManagerInterface */ - private $storeManager; - - /** @var ConditionManager */ - private $conditionManager; - - protected function setUp(): void - { - $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); - $this->resource = $this->objectManager->create(ResourceConnection::class); - $this->storeManager = $this->objectManager->create(StoreManagerInterface::class); - $this->conditionManager = $this->objectManager->create(ConditionManager::class); - - $this->eavConfigMock = $this->getMockBuilder(EavConfig::class) - ->disableOriginalConstructor() - ->getMock(); - - $this->customAttributeFilter = $this->objectManager->create( - CustomAttributeFilter::class, - [ - 'eavConfig' => $this->eavConfigMock - ] - ); - } - - public function testApplyWithoutFilters() - { - $select = $this->resource->getConnection()->select(); - $filters = []; - - $resultSelect = $this->customAttributeFilter->apply($select, ...$filters); - - $this->assertEquals( - (string) $select, - (string) $resultSelect, - 'Select queries must be the same in case when we have no filters to apply.' - ); - } - - /** - */ - public function testApplyWithWrongAttributeFilter() - { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('Invalid attribute id for field: field1'); - - $select = $this->resource->getConnection()->select(); - $filters = $this->mockFilters(); - $firstFilter = reset($filters); - - $this->eavConfigMock - ->method('getAttribute') - ->with(Product::ENTITY, $firstFilter->getField()) - ->willReturn(null); - - $this->customAttributeFilter->apply($select, ...$filters); - } - - public function testApplyByOneFilter() - { - $select = $this->resource->getConnection()->select(); - $select->from( - ['some_index' => 'some_table'], - ['entity_id' => 'entity_id'] - ); - - $filters = $this->mockFilters(); - $firstFilter = reset($filters); - - $attributes = $this->mockAttributes(); - $firstAttribute = reset($attributes); - - $this->eavConfigMock - ->method('getAttribute') - ->with(Product::ENTITY, $firstFilter->getField()) - ->willReturn($firstAttribute); - - $resultSelect = $this->customAttributeFilter->apply($select, ...[$firstFilter]); - - $expectedSelect = $this->getSqlForOneAttributeSearch(); - - $this->assertEquals( - (string) $expectedSelect, - (string) $resultSelect, - 'Select queries must be the same in case when we have one filter to apply.' - ); - } - - public function testApplyByTwoFilters() - { - $select = $this->resource->getConnection()->select(); - $select->from( - ['some_index' => 'some_table'], - ['entity_id' => 'entity_id'] - ); - - $filters = $this->mockFilters(); - $attributes = $this->mockAttributes(); - - $this->eavConfigMock - ->method('getAttribute') - ->withConsecutive( - [Product::ENTITY, $filters[0]->getField()], - [Product::ENTITY, $filters[1]->getField()] - )->will( - $this->onConsecutiveCalls(...$attributes) - ); - - $resultSelect = $this->customAttributeFilter->apply($select, ...$filters); - - $expectedSelect = $this->getSqlForTwoAttributeSearch(); - - $this->assertEquals( - (string) $expectedSelect, - (string) $resultSelect, - 'Select queries must be the same in case when we have two filters to apply.' - ); - } - - private function getSqlForOneAttributeSearch() - { - $filters = $this->mockFilters(); - $firstFilter = reset($filters); - $attributes = $this->mockAttributes(); - $firstAttribute = reset($attributes); - - $joinConditions = [ - '`some_index`.`entity_id` = `field1_filter`.`entity_id`', - sprintf('`field1_filter`.`attribute_id` = %s', $firstAttribute->getId()), - sprintf('`field1_filter`.`store_id` = %s', (int) $this->storeManager->getStore()->getId()) - ]; - - $select = $this->resource->getConnection()->select(); - $select->from( - ['some_index' => 'some_table'], - ['entity_id' => 'entity_id'] - )->joinInner( - ['field1_filter' => $this->resource->getTableName('catalog_product_index_eav')], - $this->conditionManager->combineQueries($joinConditions, Select::SQL_AND), - [] - )->where(sprintf('`some_index`.`attribute_id` = %s', $firstAttribute->getId())) - ->where(sprintf("`some_index`.`value` = '%s'", $firstFilter->getValue())); - - return $select; - } - - private function getSqlForTwoAttributeSearch() - { - $attributes = $this->mockAttributes(); - $firstAttribute = array_shift($attributes); - $secondAttribute = array_shift($attributes); - - $joinConditions1 = [ - '`some_index`.`entity_id` = `field1_filter`.`entity_id`', - sprintf('`field1_filter`.`attribute_id` = %s', $firstAttribute->getId()), - sprintf('`field1_filter`.`store_id` = %s', (int) $this->storeManager->getStore()->getId()) - ]; - - $joinConditions2 = [ - '`some_index`.`entity_id` = `field2_filter`.`entity_id`', - sprintf('`field2_filter`.`attribute_id` = %s', $secondAttribute->getId()), - sprintf('`field2_filter`.`store_id` = %s', (int) $this->storeManager->getStore()->getId()) - ]; - - $select = $this->resource->getConnection()->select(); - $select->from( - ['some_index' => 'some_table'], - ['entity_id' => 'entity_id'] - )->joinInner( - ['field1_filter' => $this->resource->getTableName('catalog_product_index_eav')], - $this->conditionManager->combineQueries($joinConditions1, Select::SQL_AND), - [] - )->joinInner( - ['field2_filter' => $this->resource->getTableName('catalog_product_index_eav')], - $this->conditionManager->combineQueries($joinConditions2, Select::SQL_AND), - [] - ); - - return $select; - } - - private function mockFilters() - { - $filters = []; - - $filters[] = $this->getMockBuilder(Term::class) - ->setConstructorArgs(['name2', 'value2', 'field1']) - ->setMethods(null) - ->getMock(); - - $filters[] = $this->getMockBuilder(Term::class) - ->setConstructorArgs(['name3', 'value3', 'field2']) - ->setMethods(null) - ->getMock(); - - return $filters; - } - - private function mockAttributes() - { - $attribute1 = $this->getMockBuilder(AbstractAttribute::class) - ->disableOriginalConstructor() - ->setMethods(['getId']) - ->getMockForAbstractClass(); - - $attribute1 - ->method('getId') - ->willReturn(42); - - $attribute2 = $this->getMockBuilder(AbstractAttribute::class) - ->disableOriginalConstructor() - ->setMethods(['getId']) - ->getMockForAbstractClass(); - - $attribute2 - ->method('getId') - ->willReturn(450); - - return [$attribute1, $attribute2]; - } -} diff --git a/dev/tests/integration/testsuite/Magento/CatalogSearch/Model/Search/FilterMapper/StockStatusFilterWithFullFilterTest.php b/dev/tests/integration/testsuite/Magento/CatalogSearch/Model/Search/FilterMapper/StockStatusFilterWithFullFilterTest.php deleted file mode 100644 index f323ac2fc2435..0000000000000 --- a/dev/tests/integration/testsuite/Magento/CatalogSearch/Model/Search/FilterMapper/StockStatusFilterWithFullFilterTest.php +++ /dev/null @@ -1,122 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -declare(strict_types=1); - -namespace Magento\CatalogSearch\Model\Search\FilterMapper; - -use Magento\Catalog\Model\Product; -use Magento\Catalog\Model\ProductRepository; -use Magento\CatalogInventory\Model\Stock; -use Magento\Eav\Model\Config as EavConfig; -use Magento\Framework\App\ResourceConnection; -use Magento\Framework\Search\Request\Filter\Term; -use Magento\Framework\Search\Request\FilterInterface; -use Magento\TestFramework\Helper\Bootstrap; -use PHPUnit\Framework\TestCase; - -/** - * @SuppressWarnings(PHPMD.CouplingBetweenObjects) - * - * @magentoDbIsolation disabled - * - * @magentoDataFixture Magento/Catalog/_files/multiple_products.php - * @magentoDataFixture Magento/Catalog/_files/product_simple_out_of_stock.php - * @magentoDataFixture Magento/Catalog/_files/products_with_multiselect_attribute.php - * @magentoDataFixture Magento/Catalog/_files/product_out_of_stock_with_multiselect_attribute.php - */ -class StockStatusFilterWithFullFilterTest extends TestCase -{ - /** - * @var \Magento\Framework\ObjectManagerInterface - */ - private $objectManager; - - /** - * @var ResourceConnection - */ - private $resource; - - /** - * @var StockStatusFilter - */ - private $stockStatusFilter; - - /** - * @var CustomAttributeFilter - */ - private $customAttributeFilter; - - /** - * @var FilterInterface - */ - private $filter; - - /** - * @inheritdoc - */ - protected function setUp(): void - { - parent::setUp(); - - $this->objectManager = Bootstrap::getObjectManager(); - $this->resource = $this->objectManager->get(ResourceConnection::class); - $this->stockStatusFilter = $this->objectManager->get(StockStatusFilter::class); - $this->customAttributeFilter = $this->objectManager->get(CustomAttributeFilter::class); - $eavConfig = $this->objectManager->get(EavConfig::class); - $attribute = $eavConfig->getAttribute(Product::ENTITY, 'multiselect_attribute'); - - $productRepository = $this->objectManager->get(ProductRepository::class); - $product = $productRepository->get('simple_ms_2'); - $multiSelectArray = explode(',', $product->getData('multiselect_attribute')); - - $this->filter = $this->objectManager->create( - Term::class, - [ - 'field' => $attribute->getAttributeCode(), - 'name' => $attribute->getAttributeCode() . '_filter', - 'value' => reset($multiSelectArray), - ] - ); - } - - /** - * @param bool $showOutOfStockFlag - * @param int $expectedResult - * @return void - * - * @dataProvider applyDataProvider - */ - public function testApply(bool $showOutOfStockFlag, int $expectedResult) - { - $select = $this->resource->getConnection()->select(); - $select->from( - [$this->resource->getTableName('catalog_product_index_eav')], - ['entity_id'] - )->distinct(true); - $select = $this->customAttributeFilter->apply($select, $this->filter); - $select = $this->stockStatusFilter->apply( - $select, - Stock::STOCK_IN_STOCK, - StockStatusFilter::FILTER_ENTITY_AND_SUB_PRODUCTS, - $showOutOfStockFlag - ); - - $data = $select->query()->fetchAll(); - - $this->assertEquals($expectedResult, count($data)); - } - - /** - * @return array - */ - public function applyDataProvider(): array - { - return [ - [true, 2], - [false, 1], - ]; - } -} diff --git a/dev/tests/integration/testsuite/Magento/CatalogSearch/Model/Search/FilterMapper/StockStatusFilterWithGeneralFilterTest.php b/dev/tests/integration/testsuite/Magento/CatalogSearch/Model/Search/FilterMapper/StockStatusFilterWithGeneralFilterTest.php deleted file mode 100644 index 617f878e041e3..0000000000000 --- a/dev/tests/integration/testsuite/Magento/CatalogSearch/Model/Search/FilterMapper/StockStatusFilterWithGeneralFilterTest.php +++ /dev/null @@ -1,106 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -declare(strict_types=1); - -namespace Magento\CatalogSearch\Model\Search\FilterMapper; - -use Magento\CatalogInventory\Model\Stock; -use Magento\Framework\App\ResourceConnection; -use Magento\TestFramework\Helper\Bootstrap; -use PHPUnit\Framework\TestCase; - -/** - * @magentoDbIsolation disabled - * - * @magentoDataFixture Magento/Catalog/_files/multiple_products.php - * @magentoDataFixture Magento/Catalog/_files/product_simple_out_of_stock.php - * @magentoDataFixture Magento/Catalog/_files/products_with_multiselect_attribute.php - * @magentoDataFixture Magento/Catalog/_files/product_out_of_stock_with_multiselect_attribute.php - */ -class StockStatusFilterWithGeneralFilterTest extends TestCase -{ - /** - * @var \Magento\Framework\ObjectManagerInterface - */ - private $objectManager; - - /** - * @var ResourceConnection - */ - private $resource; - - /** - * @var StockStatusFilter - */ - private $stockStatusFilter; - - /** - * @inheritdoc - */ - protected function setUp(): void - { - parent::setUp(); - - $this->objectManager = Bootstrap::getObjectManager(); - $this->resource = $this->objectManager->get(ResourceConnection::class); - $this->stockStatusFilter = $this->objectManager->get(StockStatusFilter::class); - } - - /** - * @return void - * - */ - public function testApplyWithWrongType() - { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('Invalid filter type: some_wrong_type'); - - $select = $this->resource->getConnection()->select(); - $this->stockStatusFilter->apply( - $select, - Stock::STOCK_IN_STOCK, - 'some_wrong_type', - true - ); - } - - /** - * @param bool $showOutOfStockFlag - * @param int $expectedResult - * @return void - * - * @dataProvider applyDataProvider - */ - public function testApply(bool $showOutOfStockFlag, int $expectedResult) - { - $select = $this->resource->getConnection()->select(); - $select->from( - [$this->resource->getTableName('catalog_product_index_eav')], - ['entity_id'] - )->distinct(true); - - $select = $this->stockStatusFilter->apply( - $select, - Stock::STOCK_IN_STOCK, - StockStatusFilter::FILTER_JUST_ENTITY, - $showOutOfStockFlag - ); - $data = $select->query()->fetchAll(); - - $this->assertEquals($expectedResult, count($data)); - } - - /** - * @return array - */ - public function applyDataProvider(): array - { - return [ - [true, 6], - [false, 4], - ]; - } -} diff --git a/dev/tests/integration/testsuite/Magento/CatalogSearch/Model/Search/FilterMapper/VisibilityFilterTest.php b/dev/tests/integration/testsuite/Magento/CatalogSearch/Model/Search/FilterMapper/VisibilityFilterTest.php deleted file mode 100644 index c8abd200d7f4b..0000000000000 --- a/dev/tests/integration/testsuite/Magento/CatalogSearch/Model/Search/FilterMapper/VisibilityFilterTest.php +++ /dev/null @@ -1,211 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -namespace Magento\CatalogSearch\Model\Search\FilterMapper; - -use Magento\Framework\Search\Request\Filter\Term; -use Magento\Store\Model\StoreManagerInterface; -use Magento\Framework\App\ResourceConnection; -use Magento\Eav\Model\Config as EavConfig; -use Magento\Eav\Model\Entity\Attribute\AbstractAttribute; -use Magento\Framework\Search\Adapter\Mysql\ConditionManager; -use Magento\Framework\DB\Select; - -class VisibilityFilterTest extends \PHPUnit\Framework\TestCase -{ - /** @var \Magento\Framework\ObjectManagerInterface */ - private $objectManager; - - /** @var ResourceConnection */ - private $resource; - - /** @var ConditionManager */ - private $conditionManager; - - /** @var StoreManagerInterface */ - private $storeManager; - - /** @var EavConfig|\PHPUnit\Framework\MockObject\MockObject */ - private $eavConfigMock; - - /** @var VisibilityFilter */ - private $visibilityFilter; - - /** @var int */ - private $answerToLifeTheUniverseAndEverything = 42; - - protected function setUp(): void - { - $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); - $this->resource = $this->objectManager->create(ResourceConnection::class); - $this->conditionManager = $this->objectManager->create(ConditionManager::class); - $this->storeManager = $this->objectManager->create(StoreManagerInterface::class); - - $this->eavConfigMock = $this->getMockBuilder(EavConfig::class) - ->disableOriginalConstructor() - ->getMock(); - - $this->visibilityFilter = $this->objectManager->create( - VisibilityFilter::class, - [ - 'eavConfig' => $this->eavConfigMock - ] - ); - } - - /** - */ - public function testApplyWithWrongType() - { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('Invalid filter type: Luke, I am your father!'); - - $select = $this->resource->getConnection()->select(); - $filter = $this->mockFilter(); - - $this->visibilityFilter->apply($select, $filter, 'Luke, I am your father!'); - } - - public function testApplyFilterAsWhere() - { - $select = $this->resource->getConnection()->select(); - $select->from( - ['some_index' => 'some_table'], - ['entity_id' => 'entity_id'] - ); - - $filter = $this->mockFilter(); - $attribute = $this->mockAttribute(); - - $this->eavConfigMock - ->method('getAttribute') - ->willReturn($attribute); - - $resultSelect = $this->visibilityFilter->apply($select, $filter, VisibilityFilter::FILTER_BY_WHERE); - $expectedSelect = $this->getExpectedSelectForWhereFilter(); - - $this->assertEquals( - (string) $expectedSelect, - (string) $resultSelect, - 'Select queries must be the same' - ); - } - - public function testApplyFilterAsJoin() - { - $select = $this->resource->getConnection()->select(); - $select->from( - ['some_index' => 'some_table'], - ['entity_id' => 'entity_id'] - ); - - $filter = $this->mockFilter(); - $attribute = $this->mockAttribute(); - - $this->eavConfigMock - ->method('getAttribute') - ->willReturn($attribute); - - $resultSelect = $this->visibilityFilter->apply($select, $filter, VisibilityFilter::FILTER_BY_JOIN); - $expectedSelect = $this->getExpectedSelectForJoinFilter(); - - $this->assertEquals( - (string) $expectedSelect, - (string) $resultSelect, - 'Select queries must be the same' - ); - } - - private function getExpectedSelectForWhereFilter() - { - $filter = $this->mockFilter(); - $select = $this->resource->getConnection()->select(); - $select->from( - ['some_index' => 'some_table'], - ['entity_id' => 'entity_id'] - )->where( - $this->conditionManager->combineQueries( - [ - $this->conditionManager->generateCondition( - 'some_index.attribute_id', - '=', - $this->answerToLifeTheUniverseAndEverything - ), - $this->conditionManager->generateCondition( - 'some_index.value', - is_array($filter->getValue()) ? 'in' : '=', - $filter->getValue() - ), - $this->conditionManager->generateCondition( - 'some_index.store_id', - '=', - $this->storeManager->getStore()->getId() - ), - ], - Select::SQL_AND - ) - ); - - return $select; - } - - private function getExpectedSelectForJoinFilter() - { - $filter = $this->mockFilter(); - $select = $this->resource->getConnection()->select(); - $select->from( - ['some_index' => 'some_table'], - ['entity_id' => 'entity_id'] - )->joinInner( - ['visibility_filter' => $this->resource->getTableName('catalog_product_index_eav')], - $this->conditionManager->combineQueries( - [ - 'some_index.entity_id = visibility_filter.entity_id', - $this->conditionManager->generateCondition( - 'visibility_filter.attribute_id', - '=', - $this->answerToLifeTheUniverseAndEverything - ), - $this->conditionManager->generateCondition( - 'visibility_filter.value', - is_array($filter->getValue()) ? 'in' : '=', - $filter->getValue() - ), - $this->conditionManager->generateCondition( - 'visibility_filter.store_id', - '=', - $this->storeManager->getStore()->getId() - ), - ], - Select::SQL_AND - ), - [] - ); - - return $select; - } - - private function mockFilter() - { - return $this->getMockBuilder(Term::class) - ->setConstructorArgs(['name2', [42, 450], 'visibility']) - ->setMethods(null) - ->getMock(); - } - - private function mockAttribute() - { - $attribute = $this->getMockBuilder(AbstractAttribute::class) - ->disableOriginalConstructor() - ->setMethods(['getId']) - ->getMockForAbstractClass(); - - $attribute - ->method('getId') - ->willReturn($this->answerToLifeTheUniverseAndEverything); - - return $attribute; - } -} diff --git a/dev/tests/integration/testsuite/Magento/Cms/_files/block_default_store.php b/dev/tests/integration/testsuite/Magento/Cms/_files/block_default_store.php new file mode 100644 index 0000000000000..de4e852f807bc --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Cms/_files/block_default_store.php @@ -0,0 +1,27 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +use Magento\Cms\Model\Block; +use Magento\Store\Model\Store; +use Magento\TestFramework\Helper\Bootstrap; + +/** @var $block Block */ +$block = Bootstrap::getObjectManager()->create(Block::class); +$block->setTitle( + 'CMS Block Title' +)->setIdentifier( + 'default_store_block' +)->setContent( + '<h1>Fixture Block Title</h1> +<a href="{{store url=""}}">store url</a> +<p>Config value: "{{config path="web/unsecure/base_url"}}".</p> +<p>Custom variable: "{{customvar code="variable_code"}}".</p>' +)->setIsActive( + 1 +)->setStores( + [Store::DEFAULT_STORE_ID] +)->save(); diff --git a/dev/tests/integration/testsuite/Magento/Cms/_files/block_default_store_rollback.php b/dev/tests/integration/testsuite/Magento/Cms/_files/block_default_store_rollback.php new file mode 100644 index 0000000000000..c504819a82259 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Cms/_files/block_default_store_rollback.php @@ -0,0 +1,30 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +use Magento\Cms\Api\BlockRepositoryInterface; +use Magento\Cms\Api\Data\BlockInterface; +use Magento\Framework\Api\SearchCriteriaBuilder; +use Magento\TestFramework\Helper\Bootstrap; + +$objectManager = Bootstrap::getObjectManager(); + +/** @var BlockRepositoryInterface $blockRepository */ +$blockRepository = $objectManager->get(BlockRepositoryInterface::class); + +/** @var SearchCriteriaBuilder $searchCriteriaBuilder */ +$searchCriteriaBuilder = $objectManager->get(SearchCriteriaBuilder::class); +$searchCriteria = $searchCriteriaBuilder->addFilter(BlockInterface::IDENTIFIER, 'default_store_block') + ->create(); +$result = $blockRepository->getList($searchCriteria); + +/** + * Tests which are wrapped with MySQL transaction clear all data by transaction rollback. + * In that case there is "if" which checks that "fixture_block" still exists in database. + */ +foreach ($result->getItems() as $item) { + $blockRepository->delete($item); +} diff --git a/dev/tests/integration/testsuite/Magento/Cms/_files/blocks_for_different_stores.php b/dev/tests/integration/testsuite/Magento/Cms/_files/blocks_for_different_stores.php new file mode 100644 index 0000000000000..b543b42ad22ad --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Cms/_files/blocks_for_different_stores.php @@ -0,0 +1,71 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +use Magento\Cms\Api\BlockRepositoryInterface; +use Magento\Cms\Api\Data\BlockInterface; +use Magento\Cms\Api\Data\BlockInterfaceFactory; +use Magento\Store\Model\StoreManagerInterface; +use Magento\TestFramework\Helper\Bootstrap; + +/** @var BlockRepositoryInterface $blockRepository */ +$blockRepository = Bootstrap::getObjectManager()->get(BlockRepositoryInterface::class); +/** @var BlockInterfaceFactory $blockFactory */ +$blockFactory = Bootstrap::getObjectManager()->get(BlockInterfaceFactory::class); +/** @var StoreManagerInterface $stores */ +$stores = Bootstrap::getObjectManager()->get(StoreManagerInterface::class)->getStores(); +array_shift($stores); + +/** @var BlockInterface $block */ +$block = $blockFactory->create([ + 'data' => [ + BlockInterface::IDENTIFIER => 'test-block', + BlockInterface::TITLE => 'Second store block', + BlockInterface::CONTENT => ' + <h1>Test Block 1 for Second Store</h1> + <a href="{{store url=""}}">store url</a> + <p>Config value: "{{config path="trans_email/ident_general/name"}}".</p> + <p>Custom path: "{{config path="trans_email/ident_general/email"}}".</p> + ', + BlockInterface::IS_ACTIVE => 1, + 'store_id' => [$stores[0]->getId()], + ] +]); +$blockRepository->save($block); + +/** @var BlockInterface $block */ +$block = $blockFactory->create([ + 'data' => [ + BlockInterface::IDENTIFIER => 'test-block-2', + BlockInterface::TITLE => 'Second store block 2', + BlockInterface::CONTENT => ' + <h1>Test Block 2 for Second Store</h1> + <a href="{{store url=""}}">store url</a> + <p>Config value: "{{config path="trans_email/ident_general/name"}}".</p> + <p>Custom path: "{{config path="trans_email/ident_general/email"}}".</p> + ', + BlockInterface::IS_ACTIVE => 1, + 'store_id' => [$stores[0]->getId()], + ] +]); +$blockRepository->save($block); + +/** @var BlockInterface $block */ +$block = $blockFactory->create([ + 'data' => [ + BlockInterface::IDENTIFIER => 'test-block', + BlockInterface::TITLE => 'Third store block', + BlockInterface::CONTENT => ' + <h1>Test Block for Third Store</h1> + <a href="{{store url=""}}">store url</a> + <p>Config value: "{{config path="trans_email/ident_general/name"}}".</p> + <p>Custom path: "{{config path="trans_email/ident_general/email"}}".</p> + ', + BlockInterface::IS_ACTIVE => 1, + 'store_id' => [$stores[1]->getId()], + ] +]); +$blockRepository->save($block); diff --git a/dev/tests/integration/testsuite/Magento/Cms/_files/blocks_for_different_stores_rollback.php b/dev/tests/integration/testsuite/Magento/Cms/_files/blocks_for_different_stores_rollback.php new file mode 100644 index 0000000000000..fbebb521ff2e2 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Cms/_files/blocks_for_different_stores_rollback.php @@ -0,0 +1,26 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +use Magento\Cms\Api\BlockRepositoryInterface; +use Magento\Cms\Api\Data\BlockInterface; +use Magento\Framework\Api\SearchCriteriaBuilder; +use Magento\TestFramework\Helper\Bootstrap; + +$objectManager = Bootstrap::getObjectManager(); + +/** @var BlockRepositoryInterface $blockRepository */ +$blockRepository = $objectManager->get(BlockRepositoryInterface::class); + +/** @var SearchCriteriaBuilder $searchCriteriaBuilder */ +$searchCriteriaBuilder = $objectManager->get(SearchCriteriaBuilder::class); +$searchCriteria = $searchCriteriaBuilder->addFilter(BlockInterface::IDENTIFIER, '%test-block%', 'like') + ->create(); +$result = $blockRepository->getList($searchCriteria); + +foreach ($result->getItems() as $item) { + $blockRepository->delete($item); +} diff --git a/dev/tests/integration/testsuite/Magento/Elasticsearch/SearchAdapter/AdapterTest.php b/dev/tests/integration/testsuite/Magento/Elasticsearch/SearchAdapter/AdapterTest.php index 4fe4a765b211f..73411d9ce4a17 100644 --- a/dev/tests/integration/testsuite/Magento/Elasticsearch/SearchAdapter/AdapterTest.php +++ b/dev/tests/integration/testsuite/Magento/Elasticsearch/SearchAdapter/AdapterTest.php @@ -5,6 +5,9 @@ */ namespace Magento\Elasticsearch\SearchAdapter; +use Magento\Catalog\Model\Product; +use Magento\Catalog\Model\ResourceModel\Eav\Attribute; +use Magento\Eav\Model\ResourceModel\Entity\Attribute\Option\Collection; use Magento\Framework\Search\EngineResolverInterface; use Magento\TestFramework\Helper\Bootstrap; use Magento\TestModuleCatalogSearch\Model\ElasticsearchVersionChecker; @@ -23,14 +26,33 @@ * testAdvancedSearchDateField(). * phpstan:ignore * + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ -class AdapterTest extends \Magento\Framework\Search\Adapter\Mysql\AdapterTest +class AdapterTest extends \PHPUnit\Framework\TestCase { + /** + * @var \Magento\Framework\Search\AdapterInterface + */ + private $adapter; + + /** + * @var \Magento\Framework\Search\Request\Builder + */ + private $requestBuilder; + + /** + * @var \Magento\Framework\ObjectManagerInterface + */ + private $objectManager; + /** * @var string */ - protected $searchEngine; + private $searchEngine; + /** + * @inheritdoc + */ protected function setUp(): void { $this->objectManager = Bootstrap::getObjectManager(); @@ -85,6 +107,19 @@ protected function assertPreConditions(): void $this->assertEquals($this->getInstalledSearchEngine(), $currentEngine); } + /** + * @return \Magento\Framework\Search\Response\QueryResponse + */ + private function executeQuery() + { + /** @var \Magento\Framework\Search\RequestInterface $queryRequest */ + $queryRequest = $this->requestBuilder->create(); + + $queryResponse = $this->adapter->query($queryRequest); + + return $queryResponse; + } + /** * @magentoAppIsolation enabled * @magentoConfigFixture current_store catalog/search/elasticsearch_index_prefix adaptertest @@ -92,7 +127,12 @@ protected function assertPreConditions(): void */ public function testMatchQuery() { - parent::testMatchQuery(); + $this->requestBuilder->bind('fulltext_search_query', 'socks'); + $this->requestBuilder->setRequestName('one_match'); + + $queryResponse = $this->executeQuery(); + + $this->assertEquals(1, $queryResponse->count()); } /** @@ -104,15 +144,30 @@ public function testMatchOrderedQuery() $this->markTestSkipped( 'Elasticsearch not expected to order results by default. Test is skipped intentionally.' ); + $expectedIds = [8, 7, 6, 5, 2]; + + //Verify that MySql randomized result of equal-weighted results + //consistently ordered by entity_id after multiple calls + $this->requestBuilder->bind('fulltext_search_query', 'shorts'); + $this->requestBuilder->setRequestName('one_match'); + $queryResponse = $this->executeQuery(); + + $this->assertEquals(5, $queryResponse->count()); + $this->assertOrderedProductIds($queryResponse, $expectedIds); } /** - * @magentoAppIsolation enabled - * @magentoConfigFixture current_store catalog/search/elasticsearch_index_prefix adaptertest + * @param \Magento\Framework\Search\Response\QueryResponse $queryResponse + * @param array $expectedIds */ - public function testAggregationsQuery() + private function assertOrderedProductIds($queryResponse, $expectedIds) { - $this->markTestSkipped('Range query is not supported. Test is skipped intentionally.'); + $actualIds = []; + foreach ($queryResponse as $document) { + /** @var \Magento\Framework\Api\Search\Document $document */ + $actualIds[] = $document->getId(); + } + $this->assertEquals($expectedIds, $actualIds); } /** @@ -122,7 +177,14 @@ public function testAggregationsQuery() */ public function testMatchQueryFilters() { - parent::testMatchQueryFilters(); + $this->requestBuilder->bind('fulltext_search_query', 'socks'); + $this->requestBuilder->bind('pidm_from', 11); + $this->requestBuilder->bind('pidm_to', 17); + $this->requestBuilder->bind('pidsh', 18); + $this->requestBuilder->setRequestName('one_match_filters'); + + $queryResponse = $this->executeQuery(); + $this->assertEquals(1, $queryResponse->count()); } /** @@ -134,7 +196,12 @@ public function testMatchQueryFilters() */ public function testRangeFilterWithAllFields() { - parent::testRangeFilterWithAllFields(); + $this->requestBuilder->bind('range_filter_from', 11); + $this->requestBuilder->bind('range_filter_to', 17); + $this->requestBuilder->setRequestName('range_filter'); + + $queryResponse = $this->executeQuery(); + $this->assertEquals(3, $queryResponse->count()); } /** @@ -146,7 +213,11 @@ public function testRangeFilterWithAllFields() */ public function testRangeFilterWithoutFromField() { - parent::testRangeFilterWithoutFromField(); + $this->requestBuilder->bind('range_filter_to', 18); + $this->requestBuilder->setRequestName('range_filter_without_from_field'); + + $queryResponse = $this->executeQuery(); + $this->assertEquals(4, $queryResponse->count()); } /** @@ -158,7 +229,11 @@ public function testRangeFilterWithoutFromField() */ public function testRangeFilterWithoutToField() { - parent::testRangeFilterWithoutToField(); + $this->requestBuilder->bind('range_filter_from', 14); + $this->requestBuilder->setRequestName('range_filter_without_to_field'); + + $queryResponse = $this->executeQuery(); + $this->assertEquals(4, $queryResponse->count()); } /** @@ -170,7 +245,12 @@ public function testRangeFilterWithoutToField() */ public function testTermFilter() { - parent::testTermFilter(); + $this->requestBuilder->bind('request.price', 18); + $this->requestBuilder->setRequestName('term_filter'); + + $queryResponse = $this->executeQuery(); + $this->assertEquals(1, $queryResponse->count()); + $this->assertEquals(4, $queryResponse->getIterator()->offsetGet(0)->getId()); } /** @@ -182,7 +262,27 @@ public function testTermFilter() */ public function testTermFilterArray() { - parent::testTermFilterArray(); + $this->requestBuilder->bind('request.price', [17, 18]); + $this->requestBuilder->setRequestName('term_filter'); + + $queryResponse = $this->executeQuery(); + $this->assertEquals(2, $queryResponse->count()); + } + + /** + * @param \Magento\Framework\Search\Response\QueryResponse $queryResponse + * @param array $expectedIds + */ + private function assertProductIds($queryResponse, $expectedIds) + { + $actualIds = []; + foreach ($queryResponse as $document) { + /** @var \Magento\Framework\Api\Search\Document $document */ + $actualIds[] = $document->getId(); + } + sort($actualIds); + sort($expectedIds); + $this->assertEquals($expectedIds, $actualIds); } /** @@ -194,7 +294,13 @@ public function testTermFilterArray() */ public function testWildcardFilter() { - parent::testWildcardFilter(); + $expectedIds = [1, 3, 5]; + $this->requestBuilder->bind('wildcard_filter', 're'); + $this->requestBuilder->setRequestName('one_wildcard'); + + $queryResponse = $this->executeQuery(); + $this->assertEquals(3, $queryResponse->count()); + $this->assertProductIds($queryResponse, $expectedIds); } /** @@ -206,7 +312,13 @@ public function testWildcardFilter() */ public function testSearchLimit() { - parent::testSearchLimit(); + $this->requestBuilder->bind('wildcard_filter', 're'); + $this->requestBuilder->setFrom(1); + $this->requestBuilder->setSize(2); + $this->requestBuilder->setRequestName('one_wildcard'); + + $queryResponse = $this->executeQuery(); + $this->assertEquals(2, $queryResponse->count()); } /** @@ -218,7 +330,20 @@ public function testSearchLimit() */ public function testBoolFilter() { - parent::testBoolFilter(); + $expectedIds = [2, 3]; + $this->requestBuilder->bind('must_range_filter1_from', 13); + $this->requestBuilder->bind('must_range_filter1_to', 22); + $this->requestBuilder->bind('should_term_filter1', 13); + $this->requestBuilder->bind('should_term_filter2', 15); + $this->requestBuilder->bind('should_term_filter3', 17); + $this->requestBuilder->bind('should_term_filter4', 18); + $this->requestBuilder->bind('not_term_filter1', 13); + $this->requestBuilder->bind('not_term_filter2', 18); + $this->requestBuilder->setRequestName('bool_filter'); + + $queryResponse = $this->executeQuery(); + $this->assertEquals(count($expectedIds), $queryResponse->count()); + $this->assertProductIds($queryResponse, $expectedIds); } /** @@ -230,7 +355,15 @@ public function testBoolFilter() */ public function testBoolFilterWithNestedNegativeBoolFilter() { - parent::testBoolFilterWithNestedNegativeBoolFilter(); + $expectedIds = [1]; + $this->requestBuilder->bind('not_range_filter_from', 14); + $this->requestBuilder->bind('not_range_filter_to', 20); + $this->requestBuilder->bind('nested_not_term_filter', 13); + $this->requestBuilder->setRequestName('bool_filter_with_nested_bool_filter'); + + $queryResponse = $this->executeQuery(); + $this->assertEquals(count($expectedIds), $queryResponse->count()); + $this->assertProductIds($queryResponse, $expectedIds); } /** @@ -242,7 +375,14 @@ public function testBoolFilterWithNestedNegativeBoolFilter() */ public function testBoolFilterWithNestedRangeInNegativeBoolFilter() { - parent::testBoolFilterWithNestedRangeInNegativeBoolFilter(); + $expectedIds = [1, 5]; + $this->requestBuilder->bind('nested_must_range_filter_from', 14); + $this->requestBuilder->bind('nested_must_range_filter_to', 18); + $this->requestBuilder->setRequestName('bool_filter_with_range_in_nested_negative_filter'); + + $queryResponse = $this->executeQuery(); + $this->assertEquals(count($expectedIds), $queryResponse->count()); + $this->assertProductIds($queryResponse, $expectedIds); } /** @@ -263,12 +403,14 @@ public function testSimpleAdvancedSearch( $rangeFilter, $expectedRecordsCount ) { - parent::testSimpleAdvancedSearch( - $nameQuery, - $descriptionQuery, - $rangeFilter, - $expectedRecordsCount - ); + $this->requestBuilder->bind('name_query', $nameQuery); + $this->requestBuilder->bind('description_query', $descriptionQuery); + $this->requestBuilder->bind('request.from_price', $rangeFilter['from']); + $this->requestBuilder->bind('request.to_price', $rangeFilter['to']); + $this->requestBuilder->setRequestName('advanced_search_test'); + + $queryResponse = $this->executeQuery(); + $this->assertEquals($expectedRecordsCount, $queryResponse->count()); } /** @@ -302,7 +444,28 @@ public function testCustomFilterableAttribute() { // Reindex Elastic Search since filterable_attribute data fixture added new fields to be indexed $this->reindexAll(); - parent::testCustomFilterableAttribute(); + /** @var Attribute $attribute */ + $attribute = $this->objectManager->get(Attribute::class) + ->loadByCode(Product::ENTITY, 'select_attribute'); + /** @var Collection $selectOptions */ + $selectOptions = $this->objectManager + ->create(Collection::class) + ->setAttributeFilter($attribute->getId()); + + $attribute->loadByCode(Product::ENTITY, 'multiselect_attribute'); + /** @var Collection $multiselectOptions */ + $multiselectOptions = $this->objectManager + ->create(Collection::class) + ->setAttributeFilter($attribute->getId()); + + $this->requestBuilder->bind('select_attribute', $selectOptions->getLastItem()->getId()); + $this->requestBuilder->bind('multiselect_attribute', $multiselectOptions->getLastItem()->getId()); + $this->requestBuilder->bind('price.from', 98); + $this->requestBuilder->bind('price.to', 100); + $this->requestBuilder->bind('category_ids', 2); + $this->requestBuilder->setRequestName('filterable_custom_attributes'); + $queryResponse = $this->executeQuery(); + $this->assertEquals(1, $queryResponse->count()); } /** @@ -320,7 +483,27 @@ public function testFilterByAttributeValues($requestName, $additionalData) { // Reindex Elastic Search since filterable_attribute data fixture added new fields to be indexed $this->reindexAll(); - parent::testFilterByAttributeValues($requestName, $additionalData); + /** @var Attribute $attribute */ + $attribute = $this->objectManager->get(Attribute::class) + ->loadByCode(Product::ENTITY, 'select_attribute_1'); + /** @var Collection $selectOptions1 */ + $selectOptions1 = $this->objectManager + ->create(Collection::class) + ->setAttributeFilter($attribute->getId()); + $attribute->loadByCode(Product::ENTITY, 'select_attribute_2'); + /** @var Collection $selectOptions2 */ + $selectOptions2 = $this->objectManager + ->create(Collection::class) + ->setAttributeFilter($attribute->getId()); + $this->requestBuilder->bind('select_attribute_1', $selectOptions1->getLastItem()->getId()); + $this->requestBuilder->bind('select_attribute_2', $selectOptions2->getLastItem()->getId()); + // Binds for specific containers. + foreach ($additionalData as $key => $value) { + $this->requestBuilder->bind($key, $value); + } + $this->requestBuilder->setRequestName($requestName); + $queryResponse = $this->executeQuery(); + $this->assertEquals(1, $queryResponse->count()); } /** @@ -337,7 +520,12 @@ public function testAdvancedSearchDateField($rangeFilter, $expectedRecordsCount) { // Reindex Elastic Search since date_attribute data fixture added new fields to be indexed $this->reindexAll(); - parent::testAdvancedSearchDateField($rangeFilter, $expectedRecordsCount); + $this->requestBuilder->bind('date.from', $rangeFilter['from']); + $this->requestBuilder->bind('date.to', $rangeFilter['to']); + $this->requestBuilder->setRequestName('advanced_search_date_field'); + + $queryResponse = $this->executeQuery(); + $this->assertEquals($expectedRecordsCount, $queryResponse->count()); } /** @@ -348,7 +536,36 @@ public function testAdvancedSearchDateField($rangeFilter, $expectedRecordsCount) */ public function testAdvancedSearchCompositeProductWithOutOfStockOption() { - parent::testAdvancedSearchCompositeProductWithOutOfStockOption(); + /** @var Attribute $attribute */ + $attribute = $this->objectManager->get(Attribute::class) + ->loadByCode(Product::ENTITY, 'test_configurable'); + /** @var Collection $selectOptions */ + $selectOptions = $this->objectManager + ->create(Collection::class) + ->setAttributeFilter($attribute->getId()); + + $visibility = [ + \Magento\Catalog\Model\Product\Visibility::VISIBILITY_IN_SEARCH, + \Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH, + ]; + + $firstOption = $selectOptions->getFirstItem(); + $firstOptionId = $firstOption->getId(); + $this->requestBuilder->bind('test_configurable', $firstOptionId); + $this->requestBuilder->bind('visibility', $visibility); + $this->requestBuilder->setRequestName('filter_out_of_stock_child'); + + $queryResponse = $this->executeQuery(); + $this->assertEquals(0, $queryResponse->count()); + + $secondOption = $selectOptions->getLastItem(); + $secondOptionId = $secondOption->getId(); + $this->requestBuilder->bind('test_configurable', $secondOptionId); + $this->requestBuilder->bind('visibility', $visibility); + $this->requestBuilder->setRequestName('filter_out_of_stock_child'); + + $queryResponse = $this->executeQuery(); + $this->assertEquals(1, $queryResponse->count()); } /** @@ -360,7 +577,29 @@ public function testAdvancedSearchCompositeProductWithDisabledChild() { // Reindex Elastic Search since date_attribute data fixture added new fields to be indexed $this->reindexAll(); - parent::testAdvancedSearchCompositeProductWithDisabledChild(); + /** @var Attribute $attribute */ + $attribute = $this->objectManager->get(Attribute::class) + ->loadByCode(Product::ENTITY, 'test_configurable'); + /** @var Collection $selectOptions */ + $selectOptions = $this->objectManager + ->create(Collection::class) + ->setAttributeFilter($attribute->getId()); + + $firstOption = $selectOptions->getFirstItem(); + $firstOptionId = $firstOption->getId(); + $this->requestBuilder->bind('test_configurable', $firstOptionId); + $this->requestBuilder->setRequestName('filter_out_of_stock_child'); + + $queryResponse = $this->executeQuery(); + $this->assertEquals(0, $queryResponse->count()); + + $secondOption = $selectOptions->getLastItem(); + $secondOptionId = $secondOption->getId(); + $this->requestBuilder->bind('test_configurable', $secondOptionId); + $this->requestBuilder->setRequestName('filter_out_of_stock_child'); + + $queryResponse = $this->executeQuery(); + $this->assertEquals(0, $queryResponse->count()); } /** @@ -372,7 +611,61 @@ public function testSearchQueryBoost() { // Reindex Elastic Search since date_attribute data fixture added new fields to be indexed $this->reindexAll(); - parent::testSearchQueryBoost(); + $this->requestBuilder->bind('query', 'antarctica'); + $this->requestBuilder->setRequestName('search_boost'); + $queryResponse = $this->executeQuery(); + $this->assertEquals(2, $queryResponse->count()); + + /** @var \Magento\Framework\Api\Search\DocumentInterface $products */ + $products = iterator_to_array($queryResponse); + /* + * Products now contain search query in two attributes which are boosted with the same value: 1 + * The search keyword (antarctica) is mentioned twice only in one of the products. + * And, as both attributes have the same search weight and boost, we expect that + * the product with doubled keyword should be prioritized by a search engine as a most relevant + * and therefore will be first in the search result. + */ + $firstProduct = reset($products); + $this->assertEquals(1222, $firstProduct->getId()); + $secondProduct = end($products); + $this->assertEquals(1221, $secondProduct->getId()); + + /** @var \Magento\Catalog\Api\ProductAttributeRepositoryInterface $productAttributeRepository */ + $productAttributeRepository = $this->objectManager->get( + \Magento\Catalog\Api\ProductAttributeRepositoryInterface::class + ); + + /** + * Now we're going to change search weight of one of the attributes to ensure that it will affect + * how products are ordered in the search result + */ + /** @var Attribute $attribute */ + $attribute = $productAttributeRepository->get('name'); + $attribute->setSearchWeight(20); + $productAttributeRepository->save($attribute); + + $this->requestBuilder->bind('query', 'antarctica'); + $this->requestBuilder->setRequestName('search_boost_name'); + $queryResponse = $this->executeQuery(); + $this->assertEquals(2, $queryResponse->count()); + + /** @var \Magento\Framework\Api\Search\DocumentInterface $products */ + $products = iterator_to_array($queryResponse); + /* + * As for the first case, we have two the same products. + * One of them has search keyword mentioned twice in the field which has search weight 1. + * However, we've changed the search weight of another attribute + * which has only one mention of the search keyword in another product. + * + * The case is mostly the same but search weight has been changed and we expect that + * less relevant (with only one mention) but more boosted (search weight = 20) product + * will be prioritized higher than more relevant, but less boosted product. + */ + $firstProduct = reset($products); + $this->assertEquals(1221, $firstProduct->getId()); + //$firstProduct + $secondProduct = end($products); + $this->assertEquals(1222, $secondProduct->getId()); } /** @@ -404,16 +697,34 @@ public function dateDataProvider() public function filterByAttributeValuesDataProvider() { - $variations = parent::filterByAttributeValuesDataProvider(); - - $variations['quick search by date'] = [ - 'quick_search_container', - [ - 'search_term' => '2000-10-30', + return [ + 'quick_search_container' => [ + 'quick_search_container', + [ + // Make sure search uses "should" cause. + 'search_term' => 'Simple Product', + ], + ], + 'advanced_search_container' => [ + 'advanced_search_container', + [ + // Make sure "wildcard" feature works. + 'sku' => 'simple_product', + ] + ], + 'catalog_view_container' => [ + 'catalog_view_container', + [ + 'category_ids' => 2 + ] + ], + 'quick search by date' => [ + 'quick_search_container', + [ + 'search_term' => '2000-10-30', + ], ], ]; - - return $variations; } /** diff --git a/dev/tests/integration/testsuite/Magento/Framework/Lock/Backend/CacheTest.php b/dev/tests/integration/testsuite/Magento/Framework/Lock/Backend/CacheTest.php new file mode 100644 index 0000000000000..306bda462820a --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Framework/Lock/Backend/CacheTest.php @@ -0,0 +1,123 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Framework\Lock\Backend; + +use Magento\Framework\Lock\Backend\Cache; + +/** + * \Magento\Framework\Lock\Backend\Cache test case. + */ +class CacheTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var Cache + */ + private $cacheInstance1; + + /** + * @var Cache + */ + private $cacheInstance2; + + /** + * @inheritDoc + */ + protected function setUp(): void + { + $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + + $frontendInterface1 = $objectManager->create(\Magento\Framework\App\Cache\Type\Config::class); + $this->cacheInstance1 = new Cache($frontendInterface1); + + $frontendInterface2 = $objectManager->create(\Magento\Framework\App\Cache\Type\Config::class); + $this->cacheInstance2 = new Cache($frontendInterface2); + } + + /** + * Verify lock mechanism in general. + * + * @return void + */ + public function testParallelLock(): void + { + $identifier1 = \uniqid('lock_name_1_', true); + + $this->assertTrue($this->cacheInstance1->lock($identifier1, 2)); + + $this->assertFalse($this->cacheInstance1->lock($identifier1, 2)); + $this->assertFalse($this->cacheInstance2->lock($identifier1, 2)); + sleep(4); + $this->assertFalse($this->cacheInstance1->isLocked($identifier1)); + + $this->assertTrue($this->cacheInstance2->lock($identifier1, -1)); + sleep(4); + $this->assertTrue($this->cacheInstance1->isLocked($identifier1)); + } + + /** + * Verify that lock will be released after timeout expiration. + * + * @return void + */ + public function testParallelLockExpired(): void + { + $identifier1 = \uniqid('lock_name_1_', true); + + $this->assertTrue($this->cacheInstance1->lock($identifier1, 1)); + sleep(2); + $this->assertFalse($this->cacheInstance1->isLocked($identifier1)); + + $this->assertTrue($this->cacheInstance1->lock($identifier1, 1)); + sleep(2); + $this->assertFalse($this->cacheInstance1->isLocked($identifier1)); + + $this->assertTrue($this->cacheInstance2->lock($identifier1, 1)); + sleep(2); + $this->assertFalse($this->cacheInstance1->isLocked($identifier1)); + } + + /** + * Verify that lock will not be released by another lock name. + * + * @return void + */ + public function testParallelUnlock(): void + { + $identifier1 = \uniqid('lock_name_1_', true); + $identifier2 = \uniqid('lock_name_2_', true); + + $this->assertTrue($this->cacheInstance1->lock($identifier1, 30)); + $this->assertTrue($this->cacheInstance2->lock($identifier2, 30)); + + $this->assertFalse($this->cacheInstance2->unlock($identifier1)); + $this->assertTrue($this->cacheInstance2->unlock($identifier2)); + + $this->assertTrue($this->cacheInstance2->isLocked($identifier1)); + $this->assertFalse($this->cacheInstance2->isLocked($identifier2)); + } + + /** + * Verify that lock will not be released by another lock name when both locks will never be expired. + * + * @return void + */ + public function testParallelUnlockNoExpiration(): void + { + $identifier1 = \uniqid('lock_name_1_', true); + $identifier2 = \uniqid('lock_name_2_', true); + + $this->assertTrue($this->cacheInstance1->lock($identifier1, -1)); + $this->assertTrue($this->cacheInstance2->lock($identifier2, -1)); + + $this->assertFalse($this->cacheInstance2->unlock($identifier1)); + $this->assertTrue($this->cacheInstance2->unlock($identifier2)); + + $this->assertTrue($this->cacheInstance2->isLocked($identifier1)); + $this->assertFalse($this->cacheInstance2->isLocked($identifier2)); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Framework/Lock/Backend/DatabaseTest.php b/dev/tests/integration/testsuite/Magento/Framework/Lock/Backend/DatabaseTest.php index bb0ac11f25d5d..385e43bcff013 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Lock/Backend/DatabaseTest.php +++ b/dev/tests/integration/testsuite/Magento/Framework/Lock/Backend/DatabaseTest.php @@ -11,7 +11,7 @@ use Magento\Framework\App\DeploymentConfig; /** - * \Magento\Framework\Lock\Backend\Database test case + * \Magento\Framework\Lock\Backend\Database test case. */ class DatabaseTest extends \PHPUnit\Framework\TestCase { diff --git a/dev/tests/integration/testsuite/Magento/Framework/Search/Adapter/Mysql/AdapterTest.php b/dev/tests/integration/testsuite/Magento/Framework/Search/Adapter/Mysql/AdapterTest.php deleted file mode 100644 index a41242e8a219e..0000000000000 --- a/dev/tests/integration/testsuite/Magento/Framework/Search/Adapter/Mysql/AdapterTest.php +++ /dev/null @@ -1,631 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -namespace Magento\Framework\Search\Adapter\Mysql; - -use Magento\Catalog\Model\Product; -use Magento\Catalog\Model\ResourceModel\Eav\Attribute; -use Magento\Eav\Model\ResourceModel\Entity\Attribute\Option\Collection; -use Magento\Framework\Search\EngineResolverInterface; -use Magento\Search\Model\EngineResolver; -use Magento\TestFramework\Helper\Bootstrap; - -/** - * Mysql search adapter test - * - * @magentoDbIsolation disabled - * @magentoAppIsolation enabled - * @SuppressWarnings(PHPMD.CouplingBetweenObjects) - */ -class AdapterTest extends \PHPUnit\Framework\TestCase -{ - /** - * @var \Magento\Framework\Search\AdapterInterface - */ - protected $adapter; - - /** - * @var \Magento\Framework\Search\Request\Builder - */ - protected $requestBuilder; - - /** - * @var \Magento\Framework\ObjectManagerInterface - */ - protected $objectManager; - - /** - * @var string - */ - protected $searchEngine = EngineResolver::CATALOG_SEARCH_MYSQL_ENGINE; - - protected function setUp(): void - { - $this->markTestSkipped("MC-18948: Mysql Adapter and Search Engine is deprecated"); - $this->objectManager = Bootstrap::getObjectManager(); - - /** @var \Magento\Framework\Search\Request\Config\Converter $converter */ - $converter = $this->objectManager->create(\Magento\Framework\Search\Request\Config\Converter::class); - - $document = new \DOMDocument(); - $document->load($this->getRequestConfigPath()); - $requestConfig = $converter->convert($document); - - /** @var \Magento\Framework\Search\Request\Config $config */ - $config = $this->objectManager->create(\Magento\Framework\Search\Request\Config::class); - $config->merge($requestConfig); - - $this->requestBuilder = $this->objectManager->create( - \Magento\Framework\Search\Request\Builder::class, - ['config' => $config] - ); - - $this->adapter = $this->createAdapter(); - - $indexer = $this->objectManager->create(\Magento\Indexer\Model\Indexer::class); - $indexer->load('catalogsearch_fulltext'); - $indexer->reindexAll(); - } - - /** - * Get request config path - * - * @return string - */ - protected function getRequestConfigPath() - { - return __DIR__ . '/../../_files/requests.xml'; - } - - /** - * Make sure that correct engine is set - */ - protected function assertPreConditions(): void - { - $currentEngine = $this->objectManager->get(EngineResolverInterface::class)->getCurrentSearchEngine(); - $this->assertEquals($this->searchEngine, $currentEngine); - } - - /** - * @return \Magento\Framework\Search\AdapterInterface - */ - protected function createAdapter() - { - return $this->objectManager->create(\Magento\Framework\Search\Adapter\Mysql\Adapter::class); - } - - /** - * @return \Magento\Framework\Search\Response\QueryResponse - */ - private function executeQuery() - { - /** @var \Magento\Framework\Search\RequestInterface $queryRequest */ - $queryRequest = $this->requestBuilder->create(); - - $queryResponse = $this->adapter->query($queryRequest); - - return $queryResponse; - } - - /** - * @param \Magento\Framework\Search\Response\QueryResponse $queryResponse - * @param array $expectedIds - */ - private function assertProductIds($queryResponse, $expectedIds) - { - $actualIds = []; - foreach ($queryResponse as $document) { - /** @var \Magento\Framework\Api\Search\Document $document */ - $actualIds[] = $document->getId(); - } - sort($actualIds); - sort($expectedIds); - $this->assertEquals($expectedIds, $actualIds); - } - - /** - * @param \Magento\Framework\Search\Response\QueryResponse $queryResponse - * @param array $expectedIds - */ - private function assertOrderedProductIds($queryResponse, $expectedIds) - { - $actualIds = []; - foreach ($queryResponse as $document) { - /** @var \Magento\Framework\Api\Search\Document $document */ - $actualIds[] = $document->getId(); - } - $this->assertEquals($expectedIds, $actualIds); - } - - public function testMatchQuery() - { - $this->requestBuilder->bind('fulltext_search_query', 'socks'); - $this->requestBuilder->setRequestName('one_match'); - - $queryResponse = $this->executeQuery(); - - $this->assertEquals(1, $queryResponse->count()); - } - - /** - * @magentoDataFixture Magento/Framework/Search/_files/products_multi_option.php - */ - public function testMatchOrderedQuery() - { - $expectedIds = [8, 7, 6, 5, 2]; - - //Verify that MySql randomized result of equal-weighted results - //consistently ordered by entity_id after multiple calls - $this->requestBuilder->bind('fulltext_search_query', 'shorts'); - $this->requestBuilder->setRequestName('one_match'); - $queryResponse = $this->executeQuery(); - - $this->assertEquals(5, $queryResponse->count()); - $this->assertOrderedProductIds($queryResponse, $expectedIds); - } - - public function testAggregationsQuery() - { - $this->requestBuilder->bind('fulltext_search_query', 'peoples'); - $this->requestBuilder->setRequestName('one_aggregations'); - - $queryResponse = $this->executeQuery(); - - $this->assertEquals(2, $queryResponse->count()); - $this->assertEquals( - ['weight_bucket', 'price_bucket', 'dynamic_price'], - $queryResponse->getAggregations()->getBucketNames() - ); - } - - public function testMatchQueryFilters() - { - $this->requestBuilder->bind('fulltext_search_query', 'socks'); - $this->requestBuilder->bind('pidm_from', 11); - $this->requestBuilder->bind('pidm_to', 17); - $this->requestBuilder->bind('pidsh', 18); - $this->requestBuilder->setRequestName('one_match_filters'); - - $queryResponse = $this->executeQuery(); - $this->assertEquals(1, $queryResponse->count()); - } - - /** - * Range filter test with all fields filled - */ - public function testRangeFilterWithAllFields() - { - $this->requestBuilder->bind('range_filter_from', 11); - $this->requestBuilder->bind('range_filter_to', 17); - $this->requestBuilder->setRequestName('range_filter'); - - $queryResponse = $this->executeQuery(); - $this->assertEquals(3, $queryResponse->count()); - } - - /** - * Range filter test with all fields filled - */ - public function testRangeFilterWithoutFromField() - { - $this->requestBuilder->bind('range_filter_to', 18); - $this->requestBuilder->setRequestName('range_filter_without_from_field'); - - $queryResponse = $this->executeQuery(); - $this->assertEquals(4, $queryResponse->count()); - } - - /** - * Range filter test with all fields filled - */ - public function testRangeFilterWithoutToField() - { - $this->requestBuilder->bind('range_filter_from', 14); - $this->requestBuilder->setRequestName('range_filter_without_to_field'); - - $queryResponse = $this->executeQuery(); - $this->assertEquals(4, $queryResponse->count()); - } - - /** - * Term filter test - */ - public function testTermFilter() - { - $this->requestBuilder->bind('request.price', 18); - $this->requestBuilder->setRequestName('term_filter'); - - $queryResponse = $this->executeQuery(); - $this->assertEquals(1, $queryResponse->count()); - $this->assertEquals(4, $queryResponse->getIterator()->offsetGet(0)->getId()); - } - - /** - * Term filter test - */ - public function testTermFilterArray() - { - $this->requestBuilder->bind('request.price', [17, 18]); - $this->requestBuilder->setRequestName('term_filter'); - - $queryResponse = $this->executeQuery(); - $this->assertEquals(2, $queryResponse->count()); - } - - /** - * Term filter test - */ - public function testWildcardFilter() - { - $expectedIds = [1, 3, 5]; - $this->requestBuilder->bind('wildcard_filter', 're'); - $this->requestBuilder->setRequestName('one_wildcard'); - - $queryResponse = $this->executeQuery(); - $this->assertEquals(3, $queryResponse->count()); - $this->assertProductIds($queryResponse, $expectedIds); - } - - /** - * Request limits test - */ - public function testSearchLimit() - { - $this->requestBuilder->bind('wildcard_filter', 're'); - $this->requestBuilder->setFrom(1); - $this->requestBuilder->setSize(2); - $this->requestBuilder->setRequestName('one_wildcard'); - - $queryResponse = $this->executeQuery(); - $this->assertEquals(2, $queryResponse->count()); - } - - /** - * Bool filter test - */ - public function testBoolFilter() - { - $expectedIds = [2, 3]; - $this->requestBuilder->bind('must_range_filter1_from', 13); - $this->requestBuilder->bind('must_range_filter1_to', 22); - $this->requestBuilder->bind('should_term_filter1', 13); - $this->requestBuilder->bind('should_term_filter2', 15); - $this->requestBuilder->bind('should_term_filter3', 17); - $this->requestBuilder->bind('should_term_filter4', 18); - $this->requestBuilder->bind('not_term_filter1', 13); - $this->requestBuilder->bind('not_term_filter2', 18); - $this->requestBuilder->setRequestName('bool_filter'); - - $queryResponse = $this->executeQuery(); - $this->assertEquals(count($expectedIds), $queryResponse->count()); - $this->assertProductIds($queryResponse, $expectedIds); - } - - /** - * Test bool filter with nested negative bool filter - */ - public function testBoolFilterWithNestedNegativeBoolFilter() - { - $expectedIds = [1]; - $this->requestBuilder->bind('not_range_filter_from', 14); - $this->requestBuilder->bind('not_range_filter_to', 20); - $this->requestBuilder->bind('nested_not_term_filter', 13); - $this->requestBuilder->setRequestName('bool_filter_with_nested_bool_filter'); - - $queryResponse = $this->executeQuery(); - $this->assertEquals(count($expectedIds), $queryResponse->count()); - $this->assertProductIds($queryResponse, $expectedIds); - } - - /** - * Test range inside nested negative bool filter - */ - public function testBoolFilterWithNestedRangeInNegativeBoolFilter() - { - $expectedIds = [1, 5]; - $this->requestBuilder->bind('nested_must_range_filter_from', 14); - $this->requestBuilder->bind('nested_must_range_filter_to', 18); - $this->requestBuilder->setRequestName('bool_filter_with_range_in_nested_negative_filter'); - - $queryResponse = $this->executeQuery(); - $this->assertEquals(count($expectedIds), $queryResponse->count()); - $this->assertProductIds($queryResponse, $expectedIds); - } - - /** - * Sample Advanced search request test - * - * @dataProvider advancedSearchDataProvider - * @param string $nameQuery - * @param string $descriptionQuery - * @param array $rangeFilter - * @param int $expectedRecordsCount - */ - public function testSimpleAdvancedSearch( - $nameQuery, - $descriptionQuery, - $rangeFilter, - $expectedRecordsCount - ) { - $this->requestBuilder->bind('name_query', $nameQuery); - $this->requestBuilder->bind('description_query', $descriptionQuery); - $this->requestBuilder->bind('request.from_price', $rangeFilter['from']); - $this->requestBuilder->bind('request.to_price', $rangeFilter['to']); - $this->requestBuilder->setRequestName('advanced_search_test'); - - $queryResponse = $this->executeQuery(); - $this->assertEquals($expectedRecordsCount, $queryResponse->count()); - } - - /** - * @return array - */ - public function advancedSearchDataProvider() - { - return [ - ['white', 'shorts', ['from' => '16', 'to' => '18'], 0], - ['white', 'shorts',['from' => '12', 'to' => '18'], 1], - ['black', 'tshirts', ['from' => '12', 'to' => '20'], 0], - ['shorts', 'green', ['from' => '12', 'to' => '22'], 1], - //Search with empty fields/values - ['white', ' ', ['from' => '12', 'to' => '22'], 1], - [' ', 'green', ['from' => '12', 'to' => '22'], 2] - ]; - } - - /** - * @magentoDataFixture Magento/Framework/Search/_files/filterable_attribute.php - */ - public function testCustomFilterableAttribute() - { - /** @var Attribute $attribute */ - $attribute = $this->objectManager->get(Attribute::class) - ->loadByCode(Product::ENTITY, 'select_attribute'); - /** @var Collection $selectOptions */ - $selectOptions = $this->objectManager - ->create(Collection::class) - ->setAttributeFilter($attribute->getId()); - - $attribute->loadByCode(Product::ENTITY, 'multiselect_attribute'); - /** @var Collection $multiselectOptions */ - $multiselectOptions = $this->objectManager - ->create(Collection::class) - ->setAttributeFilter($attribute->getId()); - - $this->requestBuilder->bind('select_attribute', $selectOptions->getLastItem()->getId()); - $this->requestBuilder->bind('multiselect_attribute', $multiselectOptions->getLastItem()->getId()); - $this->requestBuilder->bind('price.from', 98); - $this->requestBuilder->bind('price.to', 100); - $this->requestBuilder->bind('category_ids', 2); - $this->requestBuilder->setRequestName('filterable_custom_attributes'); - $queryResponse = $this->executeQuery(); - $this->assertEquals(1, $queryResponse->count()); - } - - /** - * Data provider for testFilterByAttributeValues. - * - * @return array - */ - public function filterByAttributeValuesDataProvider() - { - return [ - 'quick_search_container' => [ - 'quick_search_container', - [ - // Make sure search uses "should" cause. - 'search_term' => 'Simple Product', - ], - ], - 'advanced_search_container' => [ - 'advanced_search_container', - [ - // Make sure "wildcard" feature works. - 'sku' => 'simple_product', - ] - ], - 'catalog_view_container' => [ - 'catalog_view_container', - [ - 'category_ids' => 2 - ] - ] - ]; - } - - /** - * Test filtering by two attributes. - * - * @magentoDataFixture Magento/Framework/Search/_files/filterable_attributes.php - * @dataProvider filterByAttributeValuesDataProvider - * @param string $requestName - * @param array $additionalData - * @return void - */ - public function testFilterByAttributeValues($requestName, $additionalData) - { - /** @var Attribute $attribute */ - $attribute = $this->objectManager->get(Attribute::class) - ->loadByCode(Product::ENTITY, 'select_attribute_1'); - /** @var Collection $selectOptions1 */ - $selectOptions1 = $this->objectManager - ->create(Collection::class) - ->setAttributeFilter($attribute->getId()); - $attribute->loadByCode(Product::ENTITY, 'select_attribute_2'); - /** @var Collection $selectOptions2 */ - $selectOptions2 = $this->objectManager - ->create(Collection::class) - ->setAttributeFilter($attribute->getId()); - $this->requestBuilder->bind('select_attribute_1', $selectOptions1->getLastItem()->getId()); - $this->requestBuilder->bind('select_attribute_2', $selectOptions2->getLastItem()->getId()); - // Binds for specific containers. - foreach ($additionalData as $key => $value) { - $this->requestBuilder->bind($key, $value); - } - $this->requestBuilder->setRequestName($requestName); - $queryResponse = $this->executeQuery(); - $this->assertEquals(1, $queryResponse->count()); - } - - /** - * Advanced search request using date product attribute - * - * @param $rangeFilter - * @param $expectedRecordsCount - * @magentoDataFixture Magento/Framework/Search/_files/date_attribute.php - * @dataProvider dateDataProvider - */ - public function testAdvancedSearchDateField($rangeFilter, $expectedRecordsCount) - { - $this->requestBuilder->bind('date.from', $rangeFilter['from']); - $this->requestBuilder->bind('date.to', $rangeFilter['to']); - $this->requestBuilder->setRequestName('advanced_search_date_field'); - - $queryResponse = $this->executeQuery(); - $this->assertEquals($expectedRecordsCount, $queryResponse->count()); - } - - /** - * @magentoDataFixture Magento/Framework/Search/_files/product_configurable.php - */ - public function testAdvancedSearchCompositeProductWithOutOfStockOption() - { - /** @var Attribute $attribute */ - $attribute = $this->objectManager->get(Attribute::class) - ->loadByCode(Product::ENTITY, 'test_configurable'); - /** @var Collection $selectOptions */ - $selectOptions = $this->objectManager - ->create(Collection::class) - ->setAttributeFilter($attribute->getId()); - - $visibility = [ - \Magento\Catalog\Model\Product\Visibility::VISIBILITY_IN_SEARCH, - \Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH, - ]; - - $firstOption = $selectOptions->getFirstItem(); - $firstOptionId = $firstOption->getId(); - $this->requestBuilder->bind('test_configurable', $firstOptionId); - $this->requestBuilder->bind('visibility', $visibility); - $this->requestBuilder->setRequestName('filter_out_of_stock_child'); - - $queryResponse = $this->executeQuery(); - $this->assertEquals(0, $queryResponse->count()); - - $secondOption = $selectOptions->getLastItem(); - $secondOptionId = $secondOption->getId(); - $this->requestBuilder->bind('test_configurable', $secondOptionId); - $this->requestBuilder->bind('visibility', $visibility); - $this->requestBuilder->setRequestName('filter_out_of_stock_child'); - - $queryResponse = $this->executeQuery(); - $this->assertEquals(1, $queryResponse->count()); - } - - /** - * @magentoDataFixture Magento/Framework/Search/_files/product_configurable_with_disabled_child.php - */ - public function testAdvancedSearchCompositeProductWithDisabledChild() - { - /** @var Attribute $attribute */ - $attribute = $this->objectManager->get(Attribute::class) - ->loadByCode(Product::ENTITY, 'test_configurable'); - /** @var Collection $selectOptions */ - $selectOptions = $this->objectManager - ->create(Collection::class) - ->setAttributeFilter($attribute->getId()); - - $firstOption = $selectOptions->getFirstItem(); - $firstOptionId = $firstOption->getId(); - $this->requestBuilder->bind('test_configurable', $firstOptionId); - $this->requestBuilder->setRequestName('filter_out_of_stock_child'); - - $queryResponse = $this->executeQuery(); - $this->assertEquals(0, $queryResponse->count()); - - $secondOption = $selectOptions->getLastItem(); - $secondOptionId = $secondOption->getId(); - $this->requestBuilder->bind('test_configurable', $secondOptionId); - $this->requestBuilder->setRequestName('filter_out_of_stock_child'); - - $queryResponse = $this->executeQuery(); - $this->assertEquals(0, $queryResponse->count()); - } - - /** - * Test for search weight customization to ensure that search weight works correctly, - * and affects search results. - * - * @magentoDataFixture Magento/Framework/Search/_files/search_weight_products.php - */ - public function testSearchQueryBoost() - { - $this->requestBuilder->bind('query', 'antarctica'); - $this->requestBuilder->setRequestName('search_boost'); - $queryResponse = $this->executeQuery(); - $this->assertEquals(2, $queryResponse->count()); - - /** @var \Magento\Framework\Api\Search\DocumentInterface $products */ - $products = iterator_to_array($queryResponse); - /* - * Products now contain search query in two attributes which are boosted with the same value: 1 - * The search keyword (antarctica) is mentioned twice only in one of the products. - * And, as both attributes have the same search weight and boost, we expect that - * the product with doubled keyword should be prioritized by a search engine as a most relevant - * and therefore will be first in the search result. - */ - $firstProduct = reset($products); - $this->assertEquals(1222, $firstProduct->getId()); - $secondProduct = end($products); - $this->assertEquals(1221, $secondProduct->getId()); - - /** @var \Magento\Catalog\Api\ProductAttributeRepositoryInterface $productAttributeRepository */ - $productAttributeRepository = $this->objectManager->get( - \Magento\Catalog\Api\ProductAttributeRepositoryInterface::class - ); - - /** - * Now we're going to change search weight of one of the attributes to ensure that it will affect - * how products are ordered in the search result - */ - /** @var Attribute $attribute */ - $attribute = $productAttributeRepository->get('name'); - $attribute->setSearchWeight(20); - $productAttributeRepository->save($attribute); - - $this->requestBuilder->bind('query', 'antarctica'); - $this->requestBuilder->setRequestName('search_boost_name'); - $queryResponse = $this->executeQuery(); - $this->assertEquals(2, $queryResponse->count()); - - /** @var \Magento\Framework\Api\Search\DocumentInterface $products */ - $products = iterator_to_array($queryResponse); - /* - * As for the first case, we have two the same products. - * One of them has search keyword mentioned twice in the field which has search weight 1. - * However, we've changed the search weight of another attribute - * which has only one mention of the search keyword in another product. - * - * The case is mostly the same but search weight has been changed and we expect that - * less relevant (with only one mention) but more boosted (search weight = 20) product - * will be prioritized higher than more relevant, but less boosted product. - */ - $firstProduct = reset($products); - $this->assertEquals(1221, $firstProduct->getId()); - //$firstProduct - $secondProduct = end($products); - $this->assertEquals(1222, $secondProduct->getId()); - } - - public function dateDataProvider() - { - return [ - [['from' => '2000-01-01T00:00:00Z', 'to' => '2000-01-01T00:00:00Z'], 1], //Y-m-d - [['from' => '2000-01-01T00:00:00Z', 'to' => ''], 1], - [['from' => '1999-12-31T00:00:00Z', 'to' => '2000-01-01T00:00:00Z'], 1], - [['from' => '2000-02-01T00:00:00Z', 'to' => ''], 0], - ]; - } -} diff --git a/dev/tests/integration/testsuite/Magento/Framework/Search/Adapter/Mysql/Builder/Query/MatchTest.php b/dev/tests/integration/testsuite/Magento/Framework/Search/Adapter/Mysql/Builder/Query/MatchTest.php deleted file mode 100644 index fa3fb3a3698b3..0000000000000 --- a/dev/tests/integration/testsuite/Magento/Framework/Search/Adapter/Mysql/Builder/Query/MatchTest.php +++ /dev/null @@ -1,77 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -namespace Magento\Framework\Search\Adapter\Mysql\Builder\Query; - -use Magento\Framework\App\ResourceConnection\Config; -use Magento\Framework\Search\Request\Query\BoolExpression; -use Magento\Framework\Search\Adapter\Mysql\ScoreBuilder; -use Magento\TestFramework\Helper\Bootstrap; - -class MatchTest extends \PHPUnit\Framework\TestCase -{ - /** - * @var \Magento\Framework\ObjectManagerInterface - */ - private $objectManager; - - protected function setUp(): void - { - $this->objectManager = Bootstrap::getObjectManager(); - } - - /** - * @param string $conditionType - * @param string $expectedSuffix - * @dataProvider buildQueryProvider - */ - public function testBuildQuery($conditionType, $expectedSuffix) - { - $conditionPattern = "(LEAST((MATCH (data_index) AGAINST ('%ssomeValue*' IN BOOLEAN MODE)), 1000000)" - . " * POW(2, %s)) AS score"; - $expectedScoreCondition = sprintf($conditionPattern, $expectedSuffix, ScoreBuilder::WEIGHT_FIELD); - $expectedSql = "SELECT `someTable`.* FROM `someTable` WHERE (MATCH (data_index) " . - "AGAINST ('{$expectedSuffix}someValue*' IN BOOLEAN MODE))"; - - /** @var \Magento\Framework\Search\Adapter\Mysql\ScoreBuilder $scoreBuilder */ - $scoreBuilder = $this->objectManager->create(\Magento\Framework\Search\Adapter\Mysql\ScoreBuilder::class); - /** @var \Magento\Framework\Search\Adapter\Mysql\Query\Builder\Match $match */ - $match = $this->objectManager->create(\Magento\Framework\Search\Adapter\Mysql\Query\Builder\Match::class); - /** @var \Magento\Framework\Search\Request\Query\Match $query */ - $query = $this->objectManager->create( - \Magento\Framework\Search\Request\Query\Match::class, - [ - 'name' => 'Match query', - 'boost' => 3.14, - 'value' => 'someValue', - 'matches' => [ - ['field' => 'with_boost', 'boost' => 2.15], - ['field' => 'without_boost'], - ] - ] - ); - /** @var \Magento\Framework\App\ResourceConnection $resource */ - $resource = $this->objectManager->create(\Magento\Framework\App\ResourceConnection::class); - /** @var \Magento\Framework\DB\Select $select */ - $select = $resource->getConnection()->select(); - $select->from('someTable'); - - $resultSelect = $match->build($scoreBuilder, $select, $query, $conditionType); - $this->assertEquals($expectedScoreCondition, $scoreBuilder->build()); - $this->assertEquals($expectedSql, $resultSelect->assemble()); - } - - /** - * @return array - */ - public function buildQueryProvider() - { - return [ - [BoolExpression::QUERY_CONDITION_MUST, '+'], - [BoolExpression::QUERY_CONDITION_SHOULD, ''], - [BoolExpression::QUERY_CONDITION_NOT, '-'] - ]; - } -} diff --git a/dev/tests/integration/testsuite/Magento/Store/_files/multiple_websites_with_store_groups_stores.php b/dev/tests/integration/testsuite/Magento/Store/_files/multiple_websites_with_store_groups_stores.php new file mode 100644 index 0000000000000..fc0b091511db0 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Store/_files/multiple_websites_with_store_groups_stores.php @@ -0,0 +1,98 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +use Magento\TestFramework\Helper\Bootstrap; +use Magento\Store\Model\Website; +use Magento\Store\Model\Store; +use Magento\Store\Model\Group; + +$objectManager = Bootstrap::getObjectManager(); +//Creating second website with a store. +/** @var $website \Magento\Store\Model\Website */ +$website = $objectManager->create(Website::class); +$website->load('second', 'code'); + +if (!$website->getId()) { + $website->setData([ + 'code' => 'second', + 'name' => 'Second Test Website', + 'is_default' => '0', + ]); + $website->save(); +} + +/** + * @var Group $storeGroup + */ +$storeGroup = $objectManager->create(Group::class); +$storeGroup->setCode('second_store') + ->setName('Second store group') + ->setWebsite($website); +$storeGroup->save(); + +$website->setDefaultGroupId($storeGroup->getId()); +$website->save(); + +$websiteId = $website->getId(); +$store = $objectManager->create(Store::class); +$store->load('second_store_view', 'code'); + +if (!$store->getId()) { + $groupId = $website->getDefaultGroupId(); + $store->setData([ + 'code' => 'second_store_view', + 'website_id' => $websiteId, + 'group_id' => $groupId, + 'name' => 'Second Store View', + 'sort_order' => 10, + 'is_active' => 1, + ]); + $store->save(); +} + +//Creating third website with a store and a storeview +/** @var $website2 \Magento\Store\Model\Website */ +$website2 = $objectManager->create(Website::class); +$website2->load('third', 'code'); + +if (!$website2->getId()) { + $website2->setData([ + 'code' => 'third', + 'name' => 'Third test Website', + 'is_default' => '0', + ]); + $website2->save(); +} + +/** + * @var Group $storeGroup2 + */ +$storeGroup2 = $objectManager->create(Group::class); +$storeGroup2->setCode('third_store') + ->setName('Third store group') + ->setWebsite($website2); +$storeGroup2->save($storeGroup2); + +$website2->setDefaultGroupId($storeGroup2->getId()); +$website2->save($website2); + +$websiteId2 = $website2->getId(); +$store2 = $objectManager->create(Store::class); +$store2->load('third_store_view', 'code'); + +if (!$store2->getId()) { + $groupId = $website2->getDefaultGroupId(); + $store2->setData([ + 'code' => 'third_store_view', + 'website_id' => $websiteId2, + 'group_id' => $groupId, + 'name' => 'Third Store view', + 'sort_order' => 10, + 'is_active' => 1, + ]); + $store2->save(); +} diff --git a/dev/tests/integration/testsuite/Magento/Store/_files/multiple_websites_with_store_groups_stores_rollback.php b/dev/tests/integration/testsuite/Magento/Store/_files/multiple_websites_with_store_groups_stores_rollback.php new file mode 100644 index 0000000000000..110c93b620330 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Store/_files/multiple_websites_with_store_groups_stores_rollback.php @@ -0,0 +1,37 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +/** @var \Magento\Framework\Registry $registry */ +$registry = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get(\Magento\Framework\Registry::class); + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', true); +/** Delete the second website **/ +$website = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(\Magento\Store\Model\Website::class); +/** @var $website \Magento\Store\Model\Website */ +$websiteId = $website->load('second', 'code')->getId(); +if ($websiteId) { + $website->delete(); +} +$website2 = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(\Magento\Store\Model\Website::class); +/** @var $website \Magento\Store\Model\Website */ +$websiteId2 = $website2->load('third', 'code')->getId(); +if ($websiteId2) { + $website2->delete(); +} + +$store = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(\Magento\Store\Model\Store::class); +if ($store->load('second_store_view', 'code')->getId()) { + $store->delete(); +} + +$store2 = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(\Magento\Store\Model\Store::class); +if ($store2->load('third_store_view', 'code')->getId()) { + $store2->delete(); +} + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', false); diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/element/image-uploader.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/element/image-uploader.test.js index 34deb9fe04ba6..311e7f90813f8 100644 --- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/element/image-uploader.test.js +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/element/image-uploader.test.js @@ -75,7 +75,7 @@ define([ expect(browser.openDialog).toHaveBeenCalledWith( 'http://example.com/target_element_id/theTargetId/store/3/type/image/' + - '?isAjax=true¤t_tree_path=d3lzaXd5Zw,,', + '?isAjax=true¤t_tree_path=d3lzaXd5Zw--', null, null, 'Hello world', diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/columns/image-preview.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/columns/image-preview.test.js index 77ce2fb25f688..6a466f0c37872 100644 --- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/columns/image-preview.test.js +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/columns/image-preview.test.js @@ -51,14 +51,18 @@ define([ imagePreview.visibleRecord = ko.observable(1); }); - describe('show method', function () { + describe('verify show && hide record', function () { + it('show image', function () { - var mockImg = document.createElement('img'), - hide = spyOn(imagePreview, 'hide'); + var mockImg = document.createElement('img'); + imagePreview.visibleRecord(2); spyOn($.fn, 'get').and.returnValue(mockImg); imagePreview.show(record); - expect(hide).toHaveBeenCalledTimes(1); + expect(imagePreview.lastOpenedImage()).toBe(record._rowIndex); + + imagePreview.hide(); + expect(imagePreview.lastOpenedImage()).toBe(false); }); }); diff --git a/dev/tests/js/jasmine/tests/lib/mage/browser.test.js b/dev/tests/js/jasmine/tests/lib/mage/browser.test.js index d5687a0d9737d..53d06608b19ee 100644 --- a/dev/tests/js/jasmine/tests/lib/mage/browser.test.js +++ b/dev/tests/js/jasmine/tests/lib/mage/browser.test.js @@ -9,7 +9,8 @@ define([ ], function (browser, $) { 'use strict'; - var obj; + var obj, + openUrl = 'http://example.com/target_element_id/theTargetId/tree_path/wysiwyg¤t_tree_path=d3lzaXd5Zw,'; beforeEach(function () { /** @@ -41,8 +42,9 @@ define([ } }; }); - obj.openDialog('instance/url', 100, 100, 'title', options); - obj.openDialog('instance/url', 100, 100, 'title', options); + obj.openDialog(openUrl, 100, 100, 'title', options); + obj.openDialog(openUrl, 100, 100, 'title', options); + expect(obj.pathId).toBe('d3lzaXd5Zw,'); expect($.ajax.calls.count()).toBe(1); }); @@ -59,9 +61,10 @@ define([ } }; }); - obj.openDialog('instance/url/target_element_id/YDW2424/', 100, 100, 'title', undefined); - obj.openDialog('instance/target_element_id/Y45GDRg/', 100, 100, 'title', undefined); + obj.openDialog(openUrl, 100, 100, 'title', undefined); + obj.openDialog(openUrl, 100, 100, 'title', undefined); expect($.ajax.calls.count()).toBe(1); + expect(obj.pathId).toBe('d3lzaXd5Zw,'); }); }); }); diff --git a/lib/internal/Magento/Framework/App/Bootstrap.php b/lib/internal/Magento/Framework/App/Bootstrap.php index cb86552489472..500eebcf9a7a7 100644 --- a/lib/internal/Magento/Framework/App/Bootstrap.php +++ b/lib/internal/Magento/Framework/App/Bootstrap.php @@ -223,10 +223,12 @@ public function getParams() /** * Factory method for creating application instances * + * In case of failure, + * the application will be terminated by "exit(1)" + * * @param string $type * @param array $arguments * @return \Magento\Framework\AppInterface | void - * @throws \InvalidArgumentException */ public function createApplication($type, $arguments = []) { diff --git a/lib/internal/Magento/Framework/App/Cache/InMemoryState.php b/lib/internal/Magento/Framework/App/Cache/InMemoryState.php new file mode 100644 index 0000000000000..2cf82758f52da --- /dev/null +++ b/lib/internal/Magento/Framework/App/Cache/InMemoryState.php @@ -0,0 +1,70 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\App\Cache; + +/** + * In memory cache state + * + * Used to ease testing of cache state modifications + */ +class InMemoryState implements StateInterface +{ + /** @var bool[] */ + private $runtimeState = []; + + /** @var bool[] */ + private $persistedState = []; + + /** + * InMemoryState constructor. + * @param array $persistedState + */ + public function __construct(array $persistedState = []) + { + $this->persistedState = $persistedState; + } + + /** + * @inheritDoc + */ + public function isEnabled($cacheType) + { + return $this->runtimeState[$cacheType] + ?? $this->persistedState[$cacheType] + ?? false; + } + + /** + * @inheritDoc + */ + public function setEnabled($cacheType, $isEnabled) + { + $this->runtimeState[$cacheType] = $isEnabled; + } + + /** + * @inheritDoc + */ + public function persist() + { + $this->persistedState = $this->runtimeState + $this->persistedState; + $this->runtimeState = []; + } + + /** + * Creates new instance with persistent state updated values + * + * @param bool[] $state + * @return self + */ + public function withPersistedState(array $state): self + { + $newState = new self(); + $newState->persistedState = $state + $this->persistedState; + return $newState; + } +} diff --git a/lib/internal/Magento/Framework/App/Cache/RuntimeStaleCacheStateModifier.php b/lib/internal/Magento/Framework/App/Cache/RuntimeStaleCacheStateModifier.php new file mode 100644 index 0000000000000..29ee647a5c203 --- /dev/null +++ b/lib/internal/Magento/Framework/App/Cache/RuntimeStaleCacheStateModifier.php @@ -0,0 +1,41 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\App\Cache; + +use Magento\Framework\Cache\StaleCacheNotifierInterface; + +/** + * Modifier of runtime cache state based on stale data notification from cache loader + */ +class RuntimeStaleCacheStateModifier implements StaleCacheNotifierInterface +{ + /** @var StateInterface */ + private $cacheState; + + /** @var string[] */ + private $cacheTypes; + + /** + * @param StateInterface $cacheState + * @param string[] $cacheTypes + */ + public function __construct(StateInterface $cacheState, array $cacheTypes = []) + { + $this->cacheState = $cacheState; + $this->cacheTypes = $cacheTypes; + } + + /** + * Disabled configures cache types when stale cache was detected in the current request + */ + public function cacheLoaderIsUsingStaleCache() + { + foreach ($this->cacheTypes as $type) { + $this->cacheState->setEnabled($type, false); + } + } +} diff --git a/lib/internal/Magento/Framework/App/Test/Unit/Cache/InMemoryStateTest.php b/lib/internal/Magento/Framework/App/Test/Unit/Cache/InMemoryStateTest.php new file mode 100644 index 0000000000000..574256fc46fd4 --- /dev/null +++ b/lib/internal/Magento/Framework/App/Test/Unit/Cache/InMemoryStateTest.php @@ -0,0 +1,157 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\App\Test\Unit\Cache; + +use Magento\Framework\App\Cache\InMemoryState; +use PHPUnit\Framework\TestCase; + +/** + * InMemory Cache State manager + */ +class InMemoryStateTest extends TestCase +{ + /** @var InMemoryState */ + private $state; + + protected function setUp(): void + { + $this->state = new InMemoryState(); + } + + /** @test */ + public function allCachesAreDisabledByDefault() + { + $this->assertSame( + [false, false], + [$this->state->isEnabled('cache_type_one'), $this->state->isEnabled('cache_type_two')] + ); + } + + /** @test */ + public function enablesOnlySpecificCacheType() + { + $this->state->setEnabled('cache_type_two', true); + + $this->assertSame( + [ + false, + true, + false + ], + [ + $this->state->isEnabled('cache_type_one'), + $this->state->isEnabled('cache_type_two'), + $this->state->isEnabled('cache_type_three') + ] + ); + } + + /** @test */ + public function allowsToSpecifyCacheTypeConfiguration() + { + $state = $this->state->withPersistedState( + [ + 'cache_type_one' => true, + 'cache_type_three' => true + ] + ); + + $this->assertSame( + [ + true, + false, + true + ], + [ + $state->isEnabled('cache_type_one'), + $state->isEnabled('cache_type_two'), + $state->isEnabled('cache_type_three') + ] + ); + } + + /** @test */ + public function mergesPersistentStateInTheFinalObject() + { + $state = $this->state + ->withPersistedState( + [ + 'key2' => true, + 'key3' => false + ] + ) + ->withPersistedState( + [ + 'key1' => false, + 'key4' => true, + ] + ); + + $this->assertEquals( + new InMemoryState( + [ + 'key1' => false, + 'key2' => true, + 'key3' => false, + 'key4' => true + ] + ), + $state + ); + } + + /** @test */ + public function runtimeValuesAreAreNotPreservedWhenPersistedStateIsModified() + { + $state = $this->state + ->withPersistedState( + [ + 'key1' => true, + 'key2' => false + ] + ); + + $state->setEnabled('key1', false); + + $this->assertEquals( + new InMemoryState( + [ + 'key1' => true, + 'key2' => false + ] + ), + $state->withPersistedState([]) + ); + } + + /** @test */ + public function persistingStoresRuntimeValuesPersistedState() + { + $state = $this->state + ->withPersistedState( + [ + 'key1' => true, + 'key2' => false, + 'key3' => false + ] + ); + + $state->setEnabled('key2', true); + $state->persist(); + + $this->assertEquals( + new InMemoryState( + [ + 'key1' => true, + 'key2' => true, + 'key3' => false + ] + ), + $state + ); + } +} diff --git a/lib/internal/Magento/Framework/App/Test/Unit/Cache/RuntimeStaleCacheStateModifierTest.php b/lib/internal/Magento/Framework/App/Test/Unit/Cache/RuntimeStaleCacheStateModifierTest.php new file mode 100644 index 0000000000000..df94ae211e86c --- /dev/null +++ b/lib/internal/Magento/Framework/App/Test/Unit/Cache/RuntimeStaleCacheStateModifierTest.php @@ -0,0 +1,91 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\App\Test\Unit\Cache; + +use Magento\Framework\App\Cache\InMemoryState; +use Magento\Framework\App\Cache\RuntimeStaleCacheStateModifier; +use PHPUnit\Framework\TestCase; + +/** + * Test case for runtime state modifier + */ +class RuntimeStaleCacheStateModifierTest extends TestCase +{ + /** @var InMemoryState */ + private $cacheState; + + protected function setUp(): void + { + $this->cacheState = new InMemoryState( + [ + 'cache_one' => true, + 'cache_two' => true, + 'cache_three' => true, + 'cache_four' => false + ] + ); + } + + /** @test */ + public function doesNotModifyStateWithoutNotification() + { + new RuntimeStaleCacheStateModifier($this->cacheState, ['cache_one', 'cache_three']); + + $this->assertEquals( + new InMemoryState( + [ + 'cache_one' => true, + 'cache_two' => true, + 'cache_three' => true, + 'cache_four' => false + ] + ), + $this->cacheState + ); + } + + /** @test */ + public function modifiesOnlyConfiguredCacheTypesOnNotifiedStaleCache() + { + $stateModifier = new RuntimeStaleCacheStateModifier($this->cacheState, ['cache_one', 'cache_three']); + + $stateModifier->cacheLoaderIsUsingStaleCache(); + + $this->assertEquals( + [ + false, + true, + false + ], + [ + $this->cacheState->isEnabled('cache_one'), + $this->cacheState->isEnabled('cache_two'), + $this->cacheState->isEnabled('cache_three') + ] + ); + } + + /** @test */ + public function doesNotPersistModifiedCacheTypes() + { + $stateModifier = new RuntimeStaleCacheStateModifier($this->cacheState, ['cache_one', 'cache_three']); + + $stateModifier->cacheLoaderIsUsingStaleCache(); + + $this->assertEquals( + new InMemoryState( + [ + 'cache_one' => true, + 'cache_two' => true, + 'cache_three' => true, + 'cache_four' => false + ] + ), + $this->cacheState->withPersistedState([]) + ); + } +} diff --git a/lib/internal/Magento/Framework/Cache/Backend/RemoteSynchronizedCache.php b/lib/internal/Magento/Framework/Cache/Backend/RemoteSynchronizedCache.php index 90c1bf5808737..cd53516290252 100644 --- a/lib/internal/Magento/Framework/Cache/Backend/RemoteSynchronizedCache.php +++ b/lib/internal/Magento/Framework/Cache/Backend/RemoteSynchronizedCache.php @@ -6,6 +6,10 @@ namespace Magento\Framework\Cache\Backend; +use Magento\Framework\App\ObjectManager; +use Magento\Framework\Cache\CompositeStaleCacheNotifier; +use Magento\Framework\Cache\StaleCacheNotifierInterface; + /** * Remote synchronized cache * @@ -42,6 +46,11 @@ class RemoteSynchronizedCache extends \Zend_Cache_Backend implements \Zend_Cache */ private const HASH_SUFFIX = ':hash'; + /** + * Prefix for locks in case stale cache is used. + */ + private const REMOTE_SYNC_LOCK_PREFIX = 'rsl::'; + /** * @inheritdoc */ @@ -53,9 +62,29 @@ class RemoteSynchronizedCache extends \Zend_Cache_Backend implements \Zend_Cache 'local_backend' => '', 'local_backend_options' => [], 'local_backend_custom_naming' => true, - 'local_backend_autoload' => true + 'local_backend_autoload' => true, + 'use_stale_cache' => false, ]; + /** + * In memory state for locks. + * + * @var array + */ + private $lockList = []; + + /** + * Sign for locks, helps to avoid removing a lock that was created by another client + * + * @string + */ + private $lockSign; + + /** + * @var StaleCacheNotifierInterface + */ + private $notifier; + /** * @param array $options * @throws \Zend_Cache_Exception @@ -101,6 +130,8 @@ public function __construct(array $options = []) ); } } + + $this->lockSign = $this->generateLockSign(); } /** @@ -166,27 +197,28 @@ private function removeRemoteDataVersion($id) public function load($id, $doNotTestCacheValidity = false) { $localData = $this->local->load($id); - $remoteData = false; - - if (false === $localData) { - $remoteData = $this->remote->load($id); - if (false === $remoteData) { - return false; - } - } else { - if ($this->getDataVersion($localData) !== $this->loadRemoteDataVersion($id)) { - $localData = false; - $remoteData = $this->remote->load($id); + if ($localData) { + if ($this->getDataVersion($localData) === $this->loadRemoteDataVersion($id)) { + return $localData; } } - if ($remoteData !== false) { + $remoteData = $this->remote->load($id); + if ($remoteData) { $this->local->save($remoteData, $id); - $localData = $remoteData; + + return $remoteData; + } elseif ($localData && $this->_options['use_stale_cache']) { + if ($this->lock($id)) { + return false; + } else { + $this->notifyStaleCache(); + return $localData; + } } - return $localData; + return false; } /** @@ -212,6 +244,10 @@ public function save($data, $id, $tags = [], $specificLifetime = false) $this->saveRemoteDataVersion($data, $id, $tags, $specificLifetime); } + if ($this->_options['use_stale_cache']) { + $this->unlock($id); + } + return $this->local->save($dataToSave, $id, [], $specificLifetime); } @@ -304,4 +340,123 @@ public function getCapabilities() { return $this->local->getCapabilities(); } + + /** + * Sets a lock + * + * @param string $id + * @return bool + */ + private function lock(string $id): bool + { + $this->lockList[$id] = microtime(true); + + $data = $this->remote->load($this->getLockName($id)); + + if (false !== $data) { + return false; + } + + $this->remote->save($this->lockSign, $this->getLockName($id), [], 10); + + $data = $this->remote->load($this->getLockName($id)); + + if ($data === $this->lockSign) { + return true; + } + + return false; + } + + /** + * Release a lock. + * + * @param string $id + * @return bool + */ + private function unlock(string $id): bool + { + if (isset($this->lockList[$id])) { + unset($this->lockList[$id]); + } + + $data = $this->remote->load($this->getLockName($id)); + + if (false === $data) { + return false; + } + + $removeResult = false; + if ($data === $this->lockSign) { + $removeResult = (bool)$this->remote->remove($this->getLockName($id)); + } + + return $removeResult; + } + + /** + * Calculate lock name. + * + * @param string $id + * @return string + */ + private function getLockName(string $id): string + { + return self::REMOTE_SYNC_LOCK_PREFIX . $id; + } + + /** + * Release all locks. + * + * @return void + */ + private function unlockAll() + { + foreach ($this->lockList as $id) { + $this->unlock($id); + } + } + + /** + * Release all locks on destruct. + * + * @return void + */ + public function __destruct() + { + $this->unlockAll(); + } + + /** + * Function that generates lock sign that helps to avoid removing a lock that was created by another client. + * + * @return string + */ + private function generateLockSign() + { + $sign = \implode( + '-', + [ + \getmypid(), \crc32(\gethostname()) + ] + ); + + try { + $sign .= '-' . \bin2hex(\random_bytes(4)); + } catch (\Exception $e) { + $sign .= '-' . \uniqid('-uniqid-'); + } + + return $sign; + } + + /** + * Function that notifies configured cache types to be switched off. + */ + private function notifyStaleCache(): void + { + $this->notifier = $this->notifier ?? + ObjectManager::getInstance()->get(CompositeStaleCacheNotifier::class); + $this->notifier->cacheLoaderIsUsingStaleCache(); + } } diff --git a/lib/internal/Magento/Framework/Cache/CompositeStaleCacheNotifier.php b/lib/internal/Magento/Framework/Cache/CompositeStaleCacheNotifier.php new file mode 100644 index 0000000000000..801bd30620fb4 --- /dev/null +++ b/lib/internal/Magento/Framework/Cache/CompositeStaleCacheNotifier.php @@ -0,0 +1,40 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\Cache; + +/** + * Composite stale cache notifier + * + * Introduces an extension point to be used by other modules for disabling + * own cache write when stale cache load detected + */ +class CompositeStaleCacheNotifier implements StaleCacheNotifierInterface +{ + /** + * @var StaleCacheNotifierInterface[] + */ + private $notifiers = []; + + /** + * CompositeStaleCacheNotifier constructor. + * @param StaleCacheNotifierInterface[] $notifiers + */ + public function __construct(array $notifiers = []) + { + $this->notifiers = $notifiers; + } + + /** + * Notifies every added cache notifier of stale cache + */ + public function cacheLoaderIsUsingStaleCache() + { + foreach ($this->notifiers as $notifier) { + $notifier->cacheLoaderIsUsingStaleCache(); + } + } +} diff --git a/lib/internal/Magento/Framework/Cache/LockGuardedCacheLoader.php b/lib/internal/Magento/Framework/Cache/LockGuardedCacheLoader.php index d963e83396d19..bca23e0dcf31a 100644 --- a/lib/internal/Magento/Framework/Cache/LockGuardedCacheLoader.php +++ b/lib/internal/Magento/Framework/Cache/LockGuardedCacheLoader.php @@ -6,7 +6,9 @@ namespace Magento\Framework\Cache; +use Magento\Framework\App\ObjectManager; use Magento\Framework\Lock\LockManagerInterface; +use Magento\Framework\App\DeploymentConfig; /** * Default mutex that provide concurrent access to cache storage. @@ -55,24 +57,47 @@ class LockGuardedCacheLoader private $minimalDelayTimeout; /** + * @var DeploymentConfig + */ + private $deploymentConfig; + + /** + * Option that allows to switch off blocking for parallel generation. + * + * @var string + */ + private const CONFIG_NAME_ALLOW_PARALLEL_CACHE_GENERATION = 'allow_parallel_generation'; + + /** + * Config value of parallel generation. + * + * @var bool + */ + private $allowParallelGenerationConfigValue; + + /** + * LockGuardedCacheLoader constructor. * @param LockManagerInterface $locker * @param int $lockTimeout * @param int $delayTimeout * @param int $loadTimeout * @param int $minimalDelayTimeout + * @param DeploymentConfig|null $deploymentConfig */ public function __construct( LockManagerInterface $locker, int $lockTimeout = 10000, int $delayTimeout = 20, int $loadTimeout = 10000, - int $minimalDelayTimeout = 5 + int $minimalDelayTimeout = 5, + DeploymentConfig $deploymentConfig = null ) { $this->locker = $locker; $this->lockTimeout = $lockTimeout; $this->delayTimeout = $delayTimeout; $this->loadTimeout = $loadTimeout; $this->minimalDelayTimeout = $minimalDelayTimeout; + $this->deploymentConfig = $deploymentConfig ?? ObjectManager::getInstance()->get(DeploymentConfig::class); } /** @@ -93,6 +118,14 @@ public function lockedLoadData( $cachedData = $dataLoader(); //optimistic read $deadline = microtime(true) + $this->loadTimeout / 100; + if (empty($this->allowParallelGenerationConfigValue)) { + $cacheConfig = $this + ->deploymentConfig + ->getConfigData('cache'); + $this->allowParallelGenerationConfigValue = $cacheConfig[self::CONFIG_NAME_ALLOW_PARALLEL_CACHE_GENERATION] + ?? false; + } + while ($cachedData === false) { if ($deadline <= microtime(true)) { return $dataCollector(); @@ -106,6 +139,8 @@ public function lockedLoadData( } finally { $this->locker->unlock($lockName); } + } elseif ($this->allowParallelGenerationConfigValue === true) { + return $dataCollector(); } if ($cachedData === false) { diff --git a/lib/internal/Magento/Framework/Cache/StaleCacheNotifierInterface.php b/lib/internal/Magento/Framework/Cache/StaleCacheNotifierInterface.php new file mode 100644 index 0000000000000..135777d9d8d2a --- /dev/null +++ b/lib/internal/Magento/Framework/Cache/StaleCacheNotifierInterface.php @@ -0,0 +1,18 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\Cache; + +/** + * Notifier for stale cache retrieval detection + */ +interface StaleCacheNotifierInterface +{ + /** + * Notifies of stale cache being used by any cache loader + */ + public function cacheLoaderIsUsingStaleCache(); +} diff --git a/lib/internal/Magento/Framework/Cache/Test/Unit/CompositeStaleCacheNotifierTest.php b/lib/internal/Magento/Framework/Cache/Test/Unit/CompositeStaleCacheNotifierTest.php new file mode 100644 index 0000000000000..7d82b93129502 --- /dev/null +++ b/lib/internal/Magento/Framework/Cache/Test/Unit/CompositeStaleCacheNotifierTest.php @@ -0,0 +1,43 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\Cache\Test\Unit; + +use Magento\Framework\Cache\CompositeStaleCacheNotifier; +use Magento\Framework\Cache\StaleCacheNotifierInterface; +use PHPUnit\Framework\TestCase; + +/** Test case for composite cache notifier */ +class CompositeStaleCacheNotifierTest extends TestCase implements StaleCacheNotifierInterface +{ + /** @var string[] */ + private $notifications = []; + + /** @test */ + public function noNotifications() + { + new CompositeStaleCacheNotifier([$this, $this, $this]); + + $this->assertEquals([], $this->notifications); + } + + /** @test */ + public function notifiesAllRegisteredNotifiersOfStaleContent() + { + $notifier = new CompositeStaleCacheNotifier([$this, $this]); + $notifier->cacheLoaderIsUsingStaleCache(); + + $this->assertEquals(['staleCacheLoaded', 'staleCacheLoaded'], $this->notifications); + } + + /** + * Self-shunting notifier to test behavior of composite + */ + public function cacheLoaderIsUsingStaleCache(): void + { + $this->notifications[] = 'staleCacheLoaded'; + } +} diff --git a/lib/internal/Magento/Framework/Lock/Backend/Cache.php b/lib/internal/Magento/Framework/Lock/Backend/Cache.php index 451c0ba06ce13..612d8541281b0 100644 --- a/lib/internal/Magento/Framework/Lock/Backend/Cache.php +++ b/lib/internal/Magento/Framework/Lock/Backend/Cache.php @@ -55,7 +55,8 @@ public function lock(string $name, int $timeout = -1): bool return false; } - $this->cache->save($this->lockSign, $this->getIdentifier($name), [], $timeout * 100); + $timeout = $timeout <= 0 ? null : $timeout; + $this->cache->save($this->lockSign, $this->getIdentifier($name), [], $timeout); $data = $this->cache->load($this->getIdentifier($name)); diff --git a/lib/internal/Magento/Framework/Lock/Test/Unit/Backend/CacheTest.php b/lib/internal/Magento/Framework/Lock/Test/Unit/Backend/CacheTest.php index ca7ee101c4573..5b5c87ce454b3 100644 --- a/lib/internal/Magento/Framework/Lock/Test/Unit/Backend/CacheTest.php +++ b/lib/internal/Magento/Framework/Lock/Test/Unit/Backend/CacheTest.php @@ -85,8 +85,83 @@ public function testUnlockWithAnotherSign(): void $this->frontendCacheMock ->expects($this->once())->method('load') ->with(self::LOCK_PREFIX . $identifier) - ->willReturn(\uniqid('some_rand-')); + ->willReturn(\uniqid('some_rand-', true)); $this->assertFalse($this->cache->unlock($identifier)); } + + /** + * Verify that unlock method will be terminated if lockSign is empty. + * + * @return void + */ + public function testUnlockWithEmptyLockSign(): void + { + $identifier = 'lock_name'; + + $closure = \Closure::bind(function ($cacheInstance) { + $cacheInstance->lockSign = null; + }, null, $this->cache); + $closure($this->cache); + + $this->assertEquals(false, $this->cache->unlock($identifier)); + } + + /** + * Verify that lock will not be released when $data is empty + * + * @return void + */ + public function testUnlockWithEmptyData(): void + { + $identifier = 'lock_name'; + + $this->frontendCacheMock + ->expects($this->once())->method('load') + ->with(self::LOCK_PREFIX . $identifier) + ->willReturn(false); + + $this->assertEquals(false, $this->cache->unlock($identifier)); + } + + /** + * Verify that lockSign will be generated if empty during cache lock. + * + * @return void + */ + public function testLockWithEmptyLockSign(): void + { + $identifier = 'lock_name'; + + $closure = \Closure::bind(function ($cacheInstance) { + $cacheInstance->lockSign = null; + }, null, $this->cache); + $closure($this->cache); + + $this->cache->lock($identifier, 10); + + $closure = \Closure::bind(function ($cacheInstance) { + return $cacheInstance->lockSign; + }, null, $this->cache); + $lockSign = $closure($this->cache); + + $this->assertEquals(true, isset($lockSign)); + } + + /** + * Verify that lock will not be made when $data is not empty + * + * @return void + */ + public function testLockWithNotEmptyData(): void + { + $identifier = 'lock_name'; + + $this->frontendCacheMock + ->expects($this->once())->method('load') + ->with(self::LOCK_PREFIX . $identifier) + ->willReturn(\uniqid('some_rand-', true)); + + $this->assertEquals(false, $this->cache->lock($identifier)); + } } diff --git a/lib/internal/Magento/Framework/Search/Adapter/Mysql/Adapter.php b/lib/internal/Magento/Framework/Search/Adapter/Mysql/Adapter.php deleted file mode 100644 index e1b423d738a20..0000000000000 --- a/lib/internal/Magento/Framework/Search/Adapter/Mysql/Adapter.php +++ /dev/null @@ -1,164 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -namespace Magento\Framework\Search\Adapter\Mysql; - -use Magento\Framework\App\ResourceConnection; -use Magento\Framework\DB\Ddl\Table; -use Magento\Framework\DB\Select; -use Magento\Framework\Search\Adapter\Mysql\Aggregation\Builder as AggregationBuilder; -use Magento\Framework\Search\AdapterInterface; -use Magento\Framework\Search\RequestInterface; - -/** - * MySQL Search Adapter - * - * @deprecated - * @see \Magento\ElasticSearch - * @SuppressWarnings(PHPMD.CouplingBetweenObjects) - */ -class Adapter implements AdapterInterface -{ - /** - * Mapper instance - * - * @var Mapper - */ - protected $mapper; - - /** - * Response Factory - * - * @var ResponseFactory - */ - protected $responseFactory; - - /** - * @var \Magento\Framework\App\ResourceConnection - */ - private $resource; - - /** - * @var AggregationBuilder - */ - private $aggregationBuilder; - - /** - * @var TemporaryStorageFactory - */ - private $temporaryStorageFactory; - - /** - * Query Select Parts to be skipped when prepare query for count - * - * @var array - */ - private $countSqlSkipParts = [ - \Magento\Framework\DB\Select::LIMIT_COUNT => true, - \Magento\Framework\DB\Select::LIMIT_OFFSET => true, - ]; - - /** - * @param Mapper $mapper - * @param ResponseFactory $responseFactory - * @param ResourceConnection $resource - * @param AggregationBuilder $aggregationBuilder - * @param TemporaryStorageFactory $temporaryStorageFactory - */ - public function __construct( - Mapper $mapper, - ResponseFactory $responseFactory, - ResourceConnection $resource, - AggregationBuilder $aggregationBuilder, - TemporaryStorageFactory $temporaryStorageFactory - ) { - $this->mapper = $mapper; - $this->responseFactory = $responseFactory; - $this->resource = $resource; - $this->aggregationBuilder = $aggregationBuilder; - $this->temporaryStorageFactory = $temporaryStorageFactory; - } - - /** - * @inheritdoc - * @throws \LogicException - */ - public function query(RequestInterface $request) - { - $query = $this->mapper->buildQuery($request); - $temporaryStorage = $this->temporaryStorageFactory->create(); - $table = $temporaryStorage->storeDocumentsFromSelect($query); - - $documents = $this->getDocuments($table); - - $aggregations = $this->aggregationBuilder->build($request, $table, $documents); - $response = [ - 'documents' => $documents, - 'aggregations' => $aggregations, - 'total' => $this->getSize($query) - ]; - return $this->responseFactory->create($response); - } - - /** - * Executes query and return raw response - * - * @param Table $table - * @return array - * @throws \Zend_Db_Exception - */ - private function getDocuments(Table $table) - { - $connection = $this->getConnection(); - $select = $connection->select(); - $select->from($table->getName(), ['entity_id', 'score']); - return $connection->fetchAssoc($select); - } - - /** - * Get connection. - * - * @return false|\Magento\Framework\DB\Adapter\AdapterInterface - */ - private function getConnection() - { - return $this->resource->getConnection(); - } - - /** - * Get rows size - * - * @param Select $query - * @return int - */ - private function getSize(Select $query): int - { - $sql = $this->getSelectCountSql($query); - $parentSelect = $this->getConnection()->select(); - $parentSelect->from(['core_select' => $sql]); - $parentSelect->reset(\Magento\Framework\DB\Select::COLUMNS); - $parentSelect->columns('COUNT(*)'); - $totalRecords = $this->getConnection()->fetchOne($parentSelect); - - return intval($totalRecords); - } - - /** - * Reset limit and offset - * - * @param Select $query - * @return Select - */ - private function getSelectCountSql(Select $query): Select - { - foreach ($this->countSqlSkipParts as $part => $toSkip) { - if ($toSkip) { - $query->reset($part); - } - } - - return $query; - } -} diff --git a/lib/internal/Magento/Framework/Search/Adapter/Mysql/Aggregation/Builder.php b/lib/internal/Magento/Framework/Search/Adapter/Mysql/Aggregation/Builder.php deleted file mode 100644 index 4a5802dd44e04..0000000000000 --- a/lib/internal/Magento/Framework/Search/Adapter/Mysql/Aggregation/Builder.php +++ /dev/null @@ -1,147 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -namespace Magento\Framework\Search\Adapter\Mysql\Aggregation; - -use Magento\Framework\App\ResourceConnection; -use Magento\Framework\DB\Adapter\AdapterInterface; -use Magento\Framework\DB\Ddl\Table; -use Magento\Framework\Search\Adapter\Aggregation\AggregationResolverInterface; -use Magento\Framework\Search\Adapter\Mysql\Aggregation\Builder\Container as AggregationContainer; -use Magento\Framework\Search\Adapter\Mysql\TemporaryStorage; -use Magento\Framework\Search\EntityMetadata; -use Magento\Framework\Search\RequestInterface; - -/** - * MySQL search aggregation builder. - * - * @deprecated - * @see \Magento\ElasticSearch - * @api - */ -class Builder -{ - /** - * @var DataProviderContainer - */ - private $dataProviderContainer; - - /** - * @var Builder\Container - */ - private $aggregationContainer; - - /** - * @var EntityMetadata - */ - private $entityMetadata; - - /** - * @var Resource - */ - private $resource; - - /** - * @var AggregationResolverInterface - */ - private $aggregationResolver; - - /** - * @param ResourceConnection $resource - * @param DataProviderContainer $dataProviderContainer - * @param AggregationContainer $aggregationContainer - * @param EntityMetadata $entityMetadata - * @param AggregationResolverInterface $aggregationResolver - */ - public function __construct( - ResourceConnection $resource, - DataProviderContainer $dataProviderContainer, - AggregationContainer $aggregationContainer, - EntityMetadata $entityMetadata, - AggregationResolverInterface $aggregationResolver - ) { - $this->dataProviderContainer = $dataProviderContainer; - $this->aggregationContainer = $aggregationContainer; - $this->entityMetadata = $entityMetadata; - $this->resource = $resource; - $this->aggregationResolver = $aggregationResolver; - } - - /** - * Build aggregations. - * - * @param RequestInterface $request - * @param Table $documentsTable - * @param array $documents - * @return array - */ - public function build(RequestInterface $request, Table $documentsTable, array $documents = []) - { - return $this->processAggregations($request, $documentsTable, $documents); - } - - /** - * Process aggregations. - * - * @param RequestInterface $request - * @param Table $documentsTable - * @param array $documents - * @return array - */ - private function processAggregations(RequestInterface $request, Table $documentsTable, $documents) - { - $aggregations = []; - $documentIds = $documents ? $this->extractDocumentIds($documents) : $this->getDocumentIds($documentsTable); - $buckets = $this->aggregationResolver->resolve($request, $documentIds); - $dataProvider = $this->dataProviderContainer->get($request->getIndex()); - foreach ($buckets as $bucket) { - $aggregationBuilder = $this->aggregationContainer->get($bucket->getType()); - $aggregations[$bucket->getName()] = $aggregationBuilder->build( - $dataProvider, - $request->getDimensions(), - $bucket, - $documentsTable - ); - } - - return $aggregations; - } - - /** - * Extract document ids. - * - * @param array $documents - * @return array - */ - private function extractDocumentIds(array $documents) - { - return $documents ? array_keys($documents) : []; - } - - /** - * Get document ids. - * - * @param Table $documentsTable - * @return array - * @deprecated 100.1.0 Added for backward compatibility - */ - private function getDocumentIds(Table $documentsTable) - { - $select = $this->getConnection() - ->select() - ->from($documentsTable->getName(), TemporaryStorage::FIELD_ENTITY_ID); - return $this->getConnection()->fetchCol($select); - } - - /** - * Get Connection. - * - * @return AdapterInterface - */ - private function getConnection() - { - return $this->resource->getConnection(); - } -} diff --git a/lib/internal/Magento/Framework/Search/Adapter/Mysql/Aggregation/Builder/BucketInterface.php b/lib/internal/Magento/Framework/Search/Adapter/Mysql/Aggregation/Builder/BucketInterface.php deleted file mode 100644 index 4fa2474d2258e..0000000000000 --- a/lib/internal/Magento/Framework/Search/Adapter/Mysql/Aggregation/Builder/BucketInterface.php +++ /dev/null @@ -1,36 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -namespace Magento\Framework\Search\Adapter\Mysql\Aggregation\Builder; - -use Magento\Framework\DB\Ddl\Table; -use Magento\Framework\Search\Adapter\Mysql\Aggregation\DataProviderInterface; -use Magento\Framework\Search\Request\BucketInterface as RequestBucketInterface; -use Magento\Framework\Search\Request\Dimension; - -/** - * MySQL search aggregation bucket builder. - * - * @deprecated - * @see \Magento\ElasticSearch - */ -interface BucketInterface -{ - /** - * Build bucket. - * - * @param DataProviderInterface $dataProvider - * @param Dimension[] $dimensions - * @param RequestBucketInterface $bucket - * @param Table $entityIdsTable - * @return array - */ - public function build( - DataProviderInterface $dataProvider, - array $dimensions, - RequestBucketInterface $bucket, - Table $entityIdsTable - ); -} diff --git a/lib/internal/Magento/Framework/Search/Adapter/Mysql/Aggregation/Builder/Container.php b/lib/internal/Magento/Framework/Search/Adapter/Mysql/Aggregation/Builder/Container.php deleted file mode 100644 index 844cfc9f8741d..0000000000000 --- a/lib/internal/Magento/Framework/Search/Adapter/Mysql/Aggregation/Builder/Container.php +++ /dev/null @@ -1,39 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -namespace Magento\Framework\Search\Adapter\Mysql\Aggregation\Builder; - -/** - * MySQL search aggregation container builder. - * - * @deprecated - * @see \Magento\ElasticSearch - */ -class Container -{ - /** - * @var BucketInterface[] - */ - private $buckets; - - /** - * @param BucketInterface[] $buckets - */ - public function __construct(array $buckets) - { - $this->buckets = $buckets; - } - - /** - * Get bucket by type. - * - * @param string $bucketType - * @return BucketInterface - */ - public function get($bucketType) - { - return $this->buckets[$bucketType]; - } -} diff --git a/lib/internal/Magento/Framework/Search/Adapter/Mysql/Aggregation/Builder/Dynamic.php b/lib/internal/Magento/Framework/Search/Adapter/Mysql/Aggregation/Builder/Dynamic.php deleted file mode 100644 index 46828ab7a8c73..0000000000000 --- a/lib/internal/Magento/Framework/Search/Adapter/Mysql/Aggregation/Builder/Dynamic.php +++ /dev/null @@ -1,83 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -namespace Magento\Framework\Search\Adapter\Mysql\Aggregation\Builder; - -use Magento\Framework\DB\Ddl\Table; -use Magento\Framework\Search\Adapter\Mysql\Aggregation\DataProviderInterface; -use Magento\Framework\Search\Dynamic\Algorithm\Repository; -use Magento\Framework\Search\Dynamic\EntityStorageFactory; -use Magento\Framework\Search\Request\Aggregation\DynamicBucket; -use Magento\Framework\Search\Request\BucketInterface as RequestBucketInterface; - -/** - * MySQL search dynamic aggregation builder. - * - * @deprecated - * @see \Magento\ElasticSearch - */ -class Dynamic implements BucketInterface -{ - /** - * @var Repository - */ - private $algorithmRepository; - - /** - * @var EntityStorageFactory - */ - private $entityStorageFactory; - - /** - * @param Repository $algorithmRepository - * @param EntityStorageFactory $entityStorageFactory - */ - public function __construct( - Repository $algorithmRepository, - EntityStorageFactory $entityStorageFactory - ) { - $this->algorithmRepository = $algorithmRepository; - $this->entityStorageFactory = $entityStorageFactory; - } - - /** - * @inheritdoc - */ - public function build( - DataProviderInterface $dataProvider, - array $dimensions, - RequestBucketInterface $bucket, - Table $entityIdsTable - ) { - /** @var DynamicBucket $bucket */ - $algorithm = $this->algorithmRepository->get($bucket->getMethod()); - $data = $algorithm->getItems($bucket, $dimensions, $this->entityStorageFactory->create($entityIdsTable)); - - $resultData = $this->prepareData($data); - - return $resultData; - } - - /** - * Prepare result data - * - * @param array $data - * @return array - */ - private function prepareData($data) - { - $resultData = []; - foreach ($data as $value) { - $from = is_numeric($value['from']) ? $value['from'] : '*'; - $to = is_numeric($value['to']) ? $value['to'] : '*'; - unset($value['from'], $value['to']); - - $rangeName = "{$from}_{$to}"; - $resultData[$rangeName] = array_merge(['value' => $rangeName], $value); - } - - return $resultData; - } -} diff --git a/lib/internal/Magento/Framework/Search/Adapter/Mysql/Aggregation/Builder/Metrics.php b/lib/internal/Magento/Framework/Search/Adapter/Mysql/Aggregation/Builder/Metrics.php deleted file mode 100644 index e4cdb04052ef2..0000000000000 --- a/lib/internal/Magento/Framework/Search/Adapter/Mysql/Aggregation/Builder/Metrics.php +++ /dev/null @@ -1,46 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -namespace Magento\Framework\Search\Adapter\Mysql\Aggregation\Builder; - -use Magento\Framework\Search\Request\BucketInterface as RequestBucketInterface; - -/** - * MySQL search aggregation metrics builder. - * - * @deprecated - * @see \Magento\ElasticSearch - */ -class Metrics -{ - /** - * Available metrics - * - * @var string[] - */ - private $allowedMetrics = ['count', 'sum', 'min', 'max', 'avg']; - - /** - * Build metrics for Select->columns - * - * @param RequestBucketInterface $bucket - * @return string[] - */ - public function build(RequestBucketInterface $bucket) - { - $selectAggregations = []; - /** @var \Magento\Framework\Search\Request\Aggregation\Metric[] $metrics */ - $metrics = $bucket->getMetrics(); - - foreach ($metrics as $metric) { - $metricType = $metric->getType(); - if (in_array($metricType, $this->allowedMetrics, true)) { - $selectAggregations[$metricType] = "$metricType(main_table.value)"; - } - } - - return $selectAggregations; - } -} diff --git a/lib/internal/Magento/Framework/Search/Adapter/Mysql/Aggregation/Builder/Range.php b/lib/internal/Magento/Framework/Search/Adapter/Mysql/Aggregation/Builder/Range.php deleted file mode 100644 index aced57c100130..0000000000000 --- a/lib/internal/Magento/Framework/Search/Adapter/Mysql/Aggregation/Builder/Range.php +++ /dev/null @@ -1,109 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -namespace Magento\Framework\Search\Adapter\Mysql\Aggregation\Builder; - -use Magento\Framework\App\ResourceConnection; -use Magento\Framework\DB\Ddl\Table; -use Magento\Framework\DB\Select; -use Magento\Framework\Search\Adapter\Mysql\Aggregation\DataProviderInterface; -use Magento\Framework\Search\Request\Aggregation\Range as AggregationRange; -use Magento\Framework\Search\Request\Aggregation\RangeBucket; -use Magento\Framework\Search\Request\BucketInterface as RequestBucketInterface; -use Magento\Framework\Translate\AdapterInterface; - -/** - * MySQL search aggregation range builder. - * - * @deprecated - * @see \Magento\ElasticSearch - */ -class Range implements BucketInterface -{ - const GREATER_THAN = '>='; - const LOWER_THAN = '<'; - - /** - * @var Metrics - */ - private $metricsBuilder; - - /** - * @var Resource - */ - private $resource; - - /** - * @var AdapterInterface - */ - private $connection; - - /** - * @param Metrics $metricsBuilder - * @param ResourceConnection $resource - */ - public function __construct(Metrics $metricsBuilder, ResourceConnection $resource) - { - $this->metricsBuilder = $metricsBuilder; - $this->resource = $resource; - $this->connection = $resource->getConnection(); - } - - /** - * @inheritdoc - */ - public function build( - DataProviderInterface $dataProvider, - array $dimensions, - RequestBucketInterface $bucket, - Table $entityIdsTable - ) { - /** @var RangeBucket $bucket */ - $select = $dataProvider->getDataSet($bucket, $dimensions, $entityIdsTable); - $metrics = $this->metricsBuilder->build($bucket); - - /** @var Select $fullQuery */ - $fullQuery = $this->connection - ->select(); - $fullQuery->from(['main_table' => $select], null); - $fullQuery = $this->generateCase($fullQuery, $bucket->getRanges()); - $fullQuery->columns($metrics); - $fullQuery->group(new \Zend_Db_Expr('1')); - - return $dataProvider->execute($fullQuery); - } - - /** - * Generate case. - * - * @param Select $select - * @param AggregationRange[] $ranges - * @return Select - */ - private function generateCase(Select $select, array $ranges) - { - $casesResults = []; - $field = RequestBucketInterface::FIELD_VALUE; - foreach ($ranges as $range) { - $from = $range->getFrom(); - $to = $range->getTo(); - if ($from && $to) { - $casesResults = array_merge( - $casesResults, - ["`{$field}` BETWEEN {$from} AND {$to}" => "'{$from}_{$to}'"] - ); - } elseif ($from) { - $casesResults = array_merge($casesResults, ["`{$field}` >= {$from}" => "'{$from}_*'"]); - } elseif ($to) { - $casesResults = array_merge($casesResults, ["`{$field}` < {$to}" => "'*_{$to}'"]); - } - } - $cases = $this->connection - ->getCaseSql('', $casesResults); - $select->columns([RequestBucketInterface::FIELD_VALUE => $cases]); - - return $select; - } -} diff --git a/lib/internal/Magento/Framework/Search/Adapter/Mysql/Aggregation/Builder/Term.php b/lib/internal/Magento/Framework/Search/Adapter/Mysql/Aggregation/Builder/Term.php deleted file mode 100644 index 547526be43ccd..0000000000000 --- a/lib/internal/Magento/Framework/Search/Adapter/Mysql/Aggregation/Builder/Term.php +++ /dev/null @@ -1,50 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -namespace Magento\Framework\Search\Adapter\Mysql\Aggregation\Builder; - -use Magento\Framework\DB\Ddl\Table; -use Magento\Framework\Search\Adapter\Mysql\Aggregation\DataProviderInterface; -use Magento\Framework\Search\Request\BucketInterface as RequestBucketInterface; - -/** - * MySQL search aggregation term builder. - * - * @deprecated - * @see \Magento\ElasticSearch - */ -class Term implements BucketInterface -{ - /** - * @var Metrics - */ - private $metricsBuilder; - - /** - * @param Metrics $metricsBuilder - */ - public function __construct(Metrics $metricsBuilder) - { - $this->metricsBuilder = $metricsBuilder; - } - - /** - * @inheritdoc - */ - public function build( - DataProviderInterface $dataProvider, - array $dimensions, - RequestBucketInterface $bucket, - Table $entityIdsTable - ) { - $metrics = $this->metricsBuilder->build($bucket); - - $select = $dataProvider->getDataSet($bucket, $dimensions, $entityIdsTable); - $select->columns($metrics); - $select->group(RequestBucketInterface::FIELD_VALUE); - - return $dataProvider->execute($select); - } -} diff --git a/lib/internal/Magento/Framework/Search/Adapter/Mysql/Aggregation/DataProviderContainer.php b/lib/internal/Magento/Framework/Search/Adapter/Mysql/Aggregation/DataProviderContainer.php deleted file mode 100644 index 565b5eeef3351..0000000000000 --- a/lib/internal/Magento/Framework/Search/Adapter/Mysql/Aggregation/DataProviderContainer.php +++ /dev/null @@ -1,40 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -namespace Magento\Framework\Search\Adapter\Mysql\Aggregation; - -/** - * MySQL search data provider container. - * - * @deprecated - * @see \Magento\ElasticSearch - * @api - */ -class DataProviderContainer -{ - /** - * @var DataProviderInterface[] - */ - private $dataProvider; - - /** - * @param DataProviderInterface[] $dataProviders - */ - public function __construct(array $dataProviders) - { - $this->dataProvider = $dataProviders; - } - - /** - * Get data provider by index name. - * - * @param string $indexName - * @return DataProviderInterface - */ - public function get($indexName) - { - return $this->dataProvider[$indexName]; - } -} diff --git a/lib/internal/Magento/Framework/Search/Adapter/Mysql/Aggregation/DataProviderInterface.php b/lib/internal/Magento/Framework/Search/Adapter/Mysql/Aggregation/DataProviderInterface.php deleted file mode 100644 index c251265c694d2..0000000000000 --- a/lib/internal/Magento/Framework/Search/Adapter/Mysql/Aggregation/DataProviderInterface.php +++ /dev/null @@ -1,40 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -namespace Magento\Framework\Search\Adapter\Mysql\Aggregation; - -use Magento\Framework\DB\Ddl\Table; -use Magento\Framework\DB\Select; -use Magento\Framework\Search\Request\BucketInterface; -use Magento\Framework\Search\Request\Dimension; - -/** - * MySQL search data provider. - * - * @deprecated - * @see \Magento\ElasticSearch - */ -interface DataProviderInterface -{ - /** - * @param BucketInterface $bucket - * @param Dimension[] $dimensions - * @param Table $entityIdsTable - * @return Select - */ - public function getDataSet( - BucketInterface $bucket, - array $dimensions, - Table $entityIdsTable - ); - - /** - * Executes query and return raw response - * - * @param Select $select - * @return array - */ - public function execute(Select $select); -} diff --git a/lib/internal/Magento/Framework/Search/Adapter/Mysql/Aggregation/Interval.php b/lib/internal/Magento/Framework/Search/Adapter/Mysql/Aggregation/Interval.php deleted file mode 100644 index ba41a535f45c9..0000000000000 --- a/lib/internal/Magento/Framework/Search/Adapter/Mysql/Aggregation/Interval.php +++ /dev/null @@ -1,147 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -namespace Magento\Framework\Search\Adapter\Mysql\Aggregation; - -use Magento\Framework\DB\Select; -use Magento\Framework\Search\Dynamic\IntervalInterface; - -/** - * MySQL search aggregation interval. - * - * @deprecated - * @see \Magento\ElasticSearch - */ -class Interval implements IntervalInterface -{ - /** - * Minimal possible value - */ - const DELTA = 0.005; - - /** - * @var Select - */ - private $select; - - /** - * @param Select $select - */ - public function __construct(Select $select) - { - $this->select = $select; - } - - /** - * Get value field - * - * @return string - */ - private function getValueFiled() - { - $field = $this->select->getPart(Select::COLUMNS)[0]; - - return $field[1]; - } - - /** - * @inheritdoc - * @SuppressWarnings(PHPMD.UnusedLocalVariable) - */ - public function load($limit, $offset = null, $lower = null, $upper = null) - { - $select = clone $this->select; - $value = $this->getValueFiled(); - if ($lower !== null) { - $select->where("${value} >= ?", $lower - self::DELTA); - } - if ($upper !== null) { - $select->where("${value} < ?", $upper - self::DELTA); - } - $select->order("value ASC") - ->limit($limit, $offset); - - return $this->arrayValuesToFloat( - $this->select->getConnection() - ->fetchCol($select) - ); - } - - /** - * @inheritdoc - * @SuppressWarnings(PHPMD.UnusedLocalVariable) - */ - public function loadPrevious($data, $index, $lower = null) - { - $select = clone $this->select; - $value = $this->getValueFiled(); - $select->columns(['count' => 'COUNT(*)']) - ->where("${value} < ?", $data - self::DELTA); - if ($lower !== null) { - $select->where("${value} >= ?", $lower - self::DELTA); - } - $offset = $this->select->getConnection() - ->fetchRow($select)['count']; - if (!$offset) { - return false; - } - - return $this->load($index - $offset + 1, $offset - 1, $lower); - } - - /** - * @inheritdoc - * @SuppressWarnings(PHPMD.UnusedLocalVariable) - */ - public function loadNext($data, $rightIndex, $upper = null) - { - $select = clone $this->select; - $value = $this->getValueFiled(); - $select->columns(['count' => 'COUNT(*)']) - ->where("${value} > ?", $data + self::DELTA); - - if ($upper !== null) { - $select->where("${value} < ? ", $data - self::DELTA); - } - - $offset = $this->select->getConnection() - ->fetchRow($select)['count']; - - if (!$offset) { - return false; - } - - $select = clone $this->select; - $select->where("${value} >= ?", $data - self::DELTA); - if ($upper !== null) { - $select->where("${value} < ? ", $data - self::DELTA); - } - $select->order("${value} DESC") - ->limit($rightIndex - $offset + 1, $offset - 1); - - return $this->arrayValuesToFloat( - array_reverse( - $this->select->getConnection() - ->fetchCol($select) - ) - ); - } - - /** - * Convert array values to float. - * - * @param array $prices - * @return array - */ - private function arrayValuesToFloat($prices) - { - $returnPrices = []; - if (is_array($prices) && !empty($prices)) { - $returnPrices = array_map('floatval', $prices); - } - - return $returnPrices; - } -} diff --git a/lib/internal/Magento/Framework/Search/Adapter/Mysql/AggregationFactory.php b/lib/internal/Magento/Framework/Search/Adapter/Mysql/AggregationFactory.php deleted file mode 100644 index 756d9edc6fbe1..0000000000000 --- a/lib/internal/Magento/Framework/Search/Adapter/Mysql/AggregationFactory.php +++ /dev/null @@ -1,76 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -namespace Magento\Framework\Search\Adapter\Mysql; - -/** - * Aggregation Factory - * - * @deprecated - * @see \Magento\ElasticSearch - */ -class AggregationFactory -{ - /** - * Object Manager instance - * - * @var \Magento\Framework\ObjectManagerInterface - */ - protected $objectManager; - - /** - * @param \Magento\Framework\ObjectManagerInterface $objectManager - */ - public function __construct(\Magento\Framework\ObjectManagerInterface $objectManager) - { - $this->objectManager = $objectManager; - } - - /** - * Create Aggregation instance - * - * @param array $rawAggregation - * @return \Magento\Framework\Search\Response\Aggregation - */ - public function create(array $rawAggregation) - { - $buckets = []; - foreach ($rawAggregation as $rawBucketName => $rawBucket) { - /** @var \Magento\Framework\Search\Response\Bucket[] $buckets */ - $buckets[$rawBucketName] = $this->objectManager->create( - \Magento\Framework\Search\Response\Bucket::class, - [ - 'name' => $rawBucketName, - 'values' => $this->prepareValues((array)$rawBucket) - ] - ); - } - return $this->objectManager->create( - \Magento\Framework\Search\Response\Aggregation::class, - ['buckets' => $buckets] - ); - } - - /** - * Prepare values list - * - * @param array $values - * @return \Magento\Framework\Search\Response\Aggregation\Value[] - */ - private function prepareValues(array $values) - { - $valuesObjects = []; - foreach ($values as $name => $value) { - $valuesObjects[] = $this->objectManager->create( - \Magento\Framework\Search\Response\Aggregation\Value::class, - [ - 'value' => $name, - 'metrics' => $value, - ] - ); - } - return $valuesObjects; - } -} diff --git a/lib/internal/Magento/Framework/Search/Adapter/Mysql/DocumentFactory.php b/lib/internal/Magento/Framework/Search/Adapter/Mysql/DocumentFactory.php deleted file mode 100644 index 4e8854fad353a..0000000000000 --- a/lib/internal/Magento/Framework/Search/Adapter/Mysql/DocumentFactory.php +++ /dev/null @@ -1,79 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -namespace Magento\Framework\Search\Adapter\Mysql; - -use Magento\Framework\Api\AttributeInterface; -use Magento\Framework\Api\AttributeValue; -use Magento\Framework\Api\CustomAttributesDataInterface; -use Magento\Framework\Api\Search\Document; -use Magento\Framework\Api\Search\DocumentInterface; - -/** - * Document Factory - * - * @api - * @deprecated - * @see \Magento\ElasticSearch - */ -class DocumentFactory -{ - /** - * Object Manager instance - * - * @var \Magento\Framework\ObjectManagerInterface - * @deprecated 100.1.0 - */ - protected $objectManager; - - /** - * @var \Magento\Framework\Search\EntityMetadata - */ - private $entityMetadata; - - /** - * @param \Magento\Framework\ObjectManagerInterface $objectManager - * @param \Magento\Framework\Search\EntityMetadata $entityMetadata - * @SuppressWarnings(PHPMD.UnusedFormalParameter) - */ - public function __construct( - \Magento\Framework\ObjectManagerInterface $objectManager, - \Magento\Framework\Search\EntityMetadata $entityMetadata - ) { - $this->entityMetadata = $entityMetadata; - } - - /** - * Create Search Document instance - * - * @param mixed $rawDocument - * @return \Magento\Framework\Api\Search\Document - */ - public function create($rawDocument) - { - $documentId = null; - $entityId = $this->entityMetadata->getEntityId(); - $attributes = []; - foreach ($rawDocument as $fieldName => $value) { - if ($fieldName === $entityId) { - $documentId = $value; - } else { - $attributes[$fieldName] = new AttributeValue( - [ - AttributeInterface::ATTRIBUTE_CODE => $fieldName, - AttributeInterface::VALUE => $value, - ] - ); - } - } - - return new Document( - [ - DocumentInterface::ID => $documentId, - CustomAttributesDataInterface::CUSTOM_ATTRIBUTES => $attributes, - ] - ); - } -} diff --git a/lib/internal/Magento/Framework/Search/Adapter/Mysql/Field/Field.php b/lib/internal/Magento/Framework/Search/Adapter/Mysql/Field/Field.php deleted file mode 100644 index 0a340e7f76dc0..0000000000000 --- a/lib/internal/Magento/Framework/Search/Adapter/Mysql/Field/Field.php +++ /dev/null @@ -1,72 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -namespace Magento\Framework\Search\Adapter\Mysql\Field; - -/** - * @inheritdoc - * @deprecated - * @see \Magento\ElasticSearch - */ -class Field implements FieldInterface -{ - /** - * @var string - */ - private $column; - - /** - * @var int|null - */ - private $attributeId; - - /** - * @var int - */ - private $type; - - /** - * @param string $column - * @param int|null $attributeId - * @param int $type - */ - public function __construct($column, $attributeId = null, $type = self::TYPE_FULLTEXT) - { - $this->column = $column; - $this->attributeId = $attributeId; - $this->type = $type; - } - - /** - * Get column. - * - * @return string - */ - public function getColumn() - { - return $this->column; - } - - /** - * Get attribute ID. - * - * @return int|null - */ - public function getAttributeId() - { - return $this->attributeId; - } - - /** - * Get type. - * - * @return int - */ - public function getType() - { - return $this->type; - } -} diff --git a/lib/internal/Magento/Framework/Search/Adapter/Mysql/Field/FieldFactory.php b/lib/internal/Magento/Framework/Search/Adapter/Mysql/Field/FieldFactory.php deleted file mode 100644 index 066d1832aefbf..0000000000000 --- a/lib/internal/Magento/Framework/Search/Adapter/Mysql/Field/FieldFactory.php +++ /dev/null @@ -1,56 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -namespace Magento\Framework\Search\Adapter\Mysql\Field; - -/** - * MySQL search field factory. - * - * @api - * @deprecated - * @see \Magento\ElasticSearch - */ -class FieldFactory -{ - /** - * Object Manager instance - * - * @var \Magento\Framework\ObjectManagerInterface - */ - protected $_objectManager = null; - - /** - * Instance name to create - * - * @var string - */ - protected $_instanceName = null; - - /** - * Factory constructor - * - * @param \Magento\Framework\ObjectManagerInterface $objectManager - * @param string $instanceName - */ - public function __construct( - \Magento\Framework\ObjectManagerInterface $objectManager, - $instanceName = \Magento\Framework\Search\Adapter\Mysql\Field\FieldInterface::class - ) { - $this->_objectManager = $objectManager; - $this->_instanceName = $instanceName; - } - - /** - * Create class instance with specified parameters - * - * @param array $data - * @return \Magento\Framework\Search\Adapter\Mysql\Field\FieldInterface - */ - public function create(array $data = []) - { - return $this->_objectManager->create($this->_instanceName, $data); - } -} diff --git a/lib/internal/Magento/Framework/Search/Adapter/Mysql/Field/FieldInterface.php b/lib/internal/Magento/Framework/Search/Adapter/Mysql/Field/FieldInterface.php deleted file mode 100644 index 7dc74f39709f9..0000000000000 --- a/lib/internal/Magento/Framework/Search/Adapter/Mysql/Field/FieldInterface.php +++ /dev/null @@ -1,40 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -namespace Magento\Framework\Search\Adapter\Mysql\Field; - -/** - * MySQL search field. - * - * @deprecated - * @see \Magento\ElasticSearch - */ -interface FieldInterface -{ - const TYPE_FLAT = 1; - const TYPE_FULLTEXT = 2; - - /** - * Get type of index. - * - * @return int - */ - public function getType(); - - /** - * Get ID of attribute. - * - * @return int - */ - public function getAttributeId(); - - /** - * Get field nam. - * - * @return string - */ - public function getColumn(); -} diff --git a/lib/internal/Magento/Framework/Search/Adapter/Mysql/Field/Resolver.php b/lib/internal/Magento/Framework/Search/Adapter/Mysql/Field/Resolver.php deleted file mode 100644 index 908d6ccc50746..0000000000000 --- a/lib/internal/Magento/Framework/Search/Adapter/Mysql/Field/Resolver.php +++ /dev/null @@ -1,38 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -namespace Magento\Framework\Search\Adapter\Mysql\Field; - -/** - * @inheritdoc - */ -class Resolver implements ResolverInterface -{ - /** - * @var FieldFactory - */ - private $fieldFactory; - - /** - * @param FieldFactory $fieldFactory - */ - public function __construct(FieldFactory $fieldFactory) - { - $this->fieldFactory = $fieldFactory; - } - - /** - * @inheritdoc - */ - public function resolve(array $fields) - { - $resolvedFields = []; - foreach ($fields as $field) { - $resolvedFields[] = $this->fieldFactory->create(['column' => $field]); - } - - return $resolvedFields; - } -} diff --git a/lib/internal/Magento/Framework/Search/Adapter/Mysql/Field/ResolverInterface.php b/lib/internal/Magento/Framework/Search/Adapter/Mysql/Field/ResolverInterface.php deleted file mode 100644 index 5455b91d73020..0000000000000 --- a/lib/internal/Magento/Framework/Search/Adapter/Mysql/Field/ResolverInterface.php +++ /dev/null @@ -1,23 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -namespace Magento\Framework\Search\Adapter\Mysql\Field; - -/** - * MySQL search field resolver. - * - * @deprecated - * @see \Magento\ElasticSearch - */ -interface ResolverInterface -{ - /** - * Resolve field. - * - * @param array $fields - * @return FieldInterface[] - */ - public function resolve(array $fields); -} diff --git a/lib/internal/Magento/Framework/Search/Adapter/Mysql/Filter/Builder.php b/lib/internal/Magento/Framework/Search/Adapter/Mysql/Filter/Builder.php deleted file mode 100644 index ce02bef244fbb..0000000000000 --- a/lib/internal/Magento/Framework/Search/Adapter/Mysql/Filter/Builder.php +++ /dev/null @@ -1,146 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -namespace Magento\Framework\Search\Adapter\Mysql\Filter; - -use Magento\Framework\DB\Select; -use Magento\Framework\Search\Adapter\Mysql\ConditionManager; -use Magento\Framework\Search\Adapter\Mysql\Filter\Builder\FilterInterface; -use Magento\Framework\Search\Adapter\Mysql\Filter\Builder\Range; -use Magento\Framework\Search\Adapter\Mysql\Filter\Builder\Term; -use Magento\Framework\Search\Adapter\Mysql\Filter\Builder\Wildcard; -use Magento\Framework\Search\Request\FilterInterface as RequestFilterInterface; -use Magento\Framework\Search\Request\Query\BoolExpression; - -/** - * @inheritdoc - * @SuppressWarnings(PHPMD.CouplingBetweenObjects) - */ -class Builder implements BuilderInterface -{ - /** - * @var ConditionManager - */ - private $conditionManager; - - /** - * @var FilterInterface[] - */ - private $filters; - - /** - * @var PreprocessorInterface - */ - private $preprocessor; - - /** - * @param Range $range - * @param Term $term - * @param Wildcard $wildcard - * @param ConditionManager $conditionManager - * @param PreprocessorInterface $preprocessor - */ - public function __construct( - Range $range, - Term $term, - Wildcard $wildcard, - ConditionManager $conditionManager, - PreprocessorInterface $preprocessor - ) { - $this->filters = [ - RequestFilterInterface::TYPE_RANGE => $range, - RequestFilterInterface::TYPE_TERM => $term, - RequestFilterInterface::TYPE_WILDCARD => $wildcard, - ]; - $this->conditionManager = $conditionManager; - $this->preprocessor = $preprocessor; - } - - /** - * @inheritdoc - */ - public function build(RequestFilterInterface $filter, $conditionType) - { - return $this->processFilter($filter, $this->isNegation($conditionType)); - } - - /** - * Process filter. - * - * @param RequestFilterInterface $filter - * @param bool $isNegation - * @return string - */ - private function processFilter(RequestFilterInterface $filter, $isNegation) - { - if ($filter->getType() === RequestFilterInterface::TYPE_BOOL) { - $query = $this->processBoolFilter($filter, $isNegation); - $query = $this->conditionManager->wrapBrackets($query); - } else { - if (!isset($this->filters[$filter->getType()])) { - throw new \InvalidArgumentException('Unknown filter type ' . $filter->getType()); - } - $query = $this->filters[$filter->getType()]->buildFilter($filter, $isNegation); - $query = $this->preprocessor->process($filter, $isNegation, $query); - } - - return $query; - } - - /** - * Process boolean filter. - * - * @param RequestFilterInterface|\Magento\Framework\Search\Request\Filter\Bool $filter - * @param bool $isNegation - * @return string - */ - private function processBoolFilter(RequestFilterInterface $filter, $isNegation) - { - $must = $this->buildFilters($filter->getMust(), Select::SQL_AND, $isNegation); - $should = $this->buildFilters($filter->getShould(), Select::SQL_OR, $isNegation); - $mustNot = $this->buildFilters( - $filter->getMustNot(), - Select::SQL_AND, - !$isNegation - ); - - $queries = [ - $must, - $this->conditionManager->wrapBrackets($should), - $this->conditionManager->wrapBrackets($mustNot), - ]; - - return $this->conditionManager->combineQueries($queries, Select::SQL_AND); - } - - /** - * Build filters. - * - * @param \Magento\Framework\Search\Request\FilterInterface[] $filters - * @param string $unionOperator - * @param bool $isNegation - * @return string - */ - private function buildFilters(array $filters, $unionOperator, $isNegation) - { - $queries = []; - foreach ($filters as $filter) { - $filterQuery = $this->processFilter($filter, $isNegation); - $queries[] = $this->conditionManager->wrapBrackets($filterQuery); - } - return $this->conditionManager->combineQueries($queries, $unionOperator); - } - - /** - * Check if condition type is 'negative'. - * - * @param string $conditionType - * @return bool - */ - private function isNegation($conditionType) - { - return BoolExpression::QUERY_CONDITION_NOT === $conditionType; - } -} diff --git a/lib/internal/Magento/Framework/Search/Adapter/Mysql/Filter/Builder/FilterInterface.php b/lib/internal/Magento/Framework/Search/Adapter/Mysql/Filter/Builder/FilterInterface.php deleted file mode 100644 index 6f8b63955a0c1..0000000000000 --- a/lib/internal/Magento/Framework/Search/Adapter/Mysql/Filter/Builder/FilterInterface.php +++ /dev/null @@ -1,29 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -namespace Magento\Framework\Search\Adapter\Mysql\Filter\Builder; - -use Magento\Framework\Search\Request\FilterInterface as RequestFilterInterface; - -/** - * MySQL search filter builder. - * - * @deprecated - * @see \Magento\ElasticSearch - */ -interface FilterInterface -{ - /** - * Build filter. - * - * @param RequestFilterInterface $filter - * @param bool $isNegation - * @return string - */ - public function buildFilter( - RequestFilterInterface $filter, - $isNegation - ); -} diff --git a/lib/internal/Magento/Framework/Search/Adapter/Mysql/Filter/Builder/Range.php b/lib/internal/Magento/Framework/Search/Adapter/Mysql/Filter/Builder/Range.php deleted file mode 100644 index d14bfdcb548d3..0000000000000 --- a/lib/internal/Magento/Framework/Search/Adapter/Mysql/Filter/Builder/Range.php +++ /dev/null @@ -1,113 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -namespace Magento\Framework\Search\Adapter\Mysql\Filter\Builder; - -use Magento\Framework\Search\Adapter\Mysql\ConditionManager; -use Magento\Framework\Search\Request\Filter\Range as RangeFilterRequest; -use Magento\Framework\Search\Request\FilterInterface as RequestFilterInterface; - -/** - * Range filter builder. - * - * @deprecated - * @see \Magento\ElasticSearch - */ -class Range implements FilterInterface -{ - const CONDITION_PART_GREATER_THAN = '>='; - const CONDITION_PART_LOWER_THAN = '<='; - const CONDITION_NEGATION_PART_GREATER_THAN = '>'; - const CONDITION_NEGATION_PART_LOWER_THAN = '<'; - - /** - * @var ConditionManager - */ - private $conditionManager; - - /** - * @param ConditionManager $conditionManager - */ - public function __construct( - ConditionManager $conditionManager - ) { - $this->conditionManager = $conditionManager; - } - - /** - * @inheritdoc - */ - public function buildFilter( - RequestFilterInterface $filter, - $isNegation - ) { - /** @var RangeFilterRequest $filter */ - $queries = [ - $this->getLeftConditionPart($filter, $isNegation), - $this->getRightConditionPart($filter, $isNegation), - ]; - $unionOperator = $this->getConditionUnionOperator($isNegation); - - return $this->conditionManager->combineQueries($queries, $unionOperator); - } - - /** - * Get left condition filter part. - * - * @param RequestFilterInterface|RangeFilterRequest $filter - * @param bool $isNegation - * @return string - */ - private function getLeftConditionPart(RequestFilterInterface $filter, $isNegation) - { - return $this->getPart( - $filter->getField(), - ($isNegation ? self::CONDITION_NEGATION_PART_LOWER_THAN : self::CONDITION_PART_GREATER_THAN), - $filter->getFrom() - ); - } - - /** - * Get right condition filter part. - * - * @param RequestFilterInterface|RangeFilterRequest $filter - * @param bool $isNegation - * @return string - */ - private function getRightConditionPart(RequestFilterInterface $filter, $isNegation) - { - return $this->getPart( - $filter->getField(), - ($isNegation ? self::CONDITION_NEGATION_PART_GREATER_THAN : self::CONDITION_PART_LOWER_THAN), - $filter->getTo() - ); - } - - /** - * Get filter part. - * - * @param string $field - * @param string $operator - * @param string $value - * @return string - */ - private function getPart($field, $operator, $value) - { - return $value === null - ? '' - : $this->conditionManager->generateCondition($field, $operator, $value); - } - - /** - * Get condition union operator. - * - * @param bool $isNegation - * @return string - */ - private function getConditionUnionOperator($isNegation) - { - return $isNegation ? \Magento\Framework\DB\Select::SQL_OR : \Magento\Framework\DB\Select::SQL_AND; - } -} diff --git a/lib/internal/Magento/Framework/Search/Adapter/Mysql/Filter/Builder/Term.php b/lib/internal/Magento/Framework/Search/Adapter/Mysql/Filter/Builder/Term.php deleted file mode 100644 index c89ef50f3cb35..0000000000000 --- a/lib/internal/Magento/Framework/Search/Adapter/Mysql/Filter/Builder/Term.php +++ /dev/null @@ -1,70 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -namespace Magento\Framework\Search\Adapter\Mysql\Filter\Builder; - -use Magento\Framework\Search\Adapter\Mysql\ConditionManager; -use Magento\Framework\Search\Request\FilterInterface as RequestFilterInterface; - -/** - * Term filter builder. - * - * @deprecated - * @see \Magento\ElasticSearch - */ -class Term implements FilterInterface -{ - const CONDITION_OPERATOR_EQUALS = '='; - const CONDITION_OPERATOR_NOT_EQUALS = '!='; - const CONDITION_OPERATOR_IN = 'IN'; - const CONDITION_OPERATOR_NOT_IN = 'NOT IN'; - - /** - * @var ConditionManager - */ - private $conditionManager; - - /** - * @param ConditionManager $conditionManager - */ - public function __construct( - ConditionManager $conditionManager - ) { - $this->conditionManager = $conditionManager; - } - - /** - * @inheritdoc - */ - public function buildFilter( - RequestFilterInterface $filter, - $isNegation - ) { - /** @var \Magento\Framework\Search\Request\Filter\Term $filter */ - - return $this->conditionManager->generateCondition( - $filter->getField(), - $this->getConditionOperator($filter->getValue(), $isNegation), - $filter->getValue() - ); - } - - /** - * Get condition operator. - * - * @param string|array $value - * @param bool $isNegation - * @return string - */ - private function getConditionOperator($value, $isNegation) - { - if (is_array($value)) { - $operator = $isNegation ? self::CONDITION_OPERATOR_NOT_IN : self::CONDITION_OPERATOR_IN; - } else { - $operator = $isNegation ? self::CONDITION_OPERATOR_NOT_EQUALS : self::CONDITION_OPERATOR_EQUALS; - } - return $operator; - } -} diff --git a/lib/internal/Magento/Framework/Search/Adapter/Mysql/Filter/Builder/Wildcard.php b/lib/internal/Magento/Framework/Search/Adapter/Mysql/Filter/Builder/Wildcard.php deleted file mode 100644 index 9a2776ac20b2c..0000000000000 --- a/lib/internal/Magento/Framework/Search/Adapter/Mysql/Filter/Builder/Wildcard.php +++ /dev/null @@ -1,51 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -namespace Magento\Framework\Search\Adapter\Mysql\Filter\Builder; - -use Magento\Framework\Search\Adapter\Mysql\ConditionManager; - -/** - * Wildcard filter builder. - * - * @deprecated - * @see \Magento\ElasticSearch - */ -class Wildcard implements FilterInterface -{ - const CONDITION_LIKE = 'LIKE'; - const CONDITION_NOT_LIKE = 'NOT LIKE'; - - /** - * @var ConditionManager - */ - private $conditionManager; - - /** - * @param ConditionManager $conditionManager - */ - public function __construct( - ConditionManager $conditionManager - ) { - $this->conditionManager = $conditionManager; - } - - /** - * @inheritdoc - */ - public function buildFilter( - \Magento\Framework\Search\Request\FilterInterface $filter, - $isNegation - ) { - /** @var \Magento\Framework\Search\Request\Filter\Wildcard $filter */ - - $searchValue = '%' . $filter->getValue() . '%'; - return $this->conditionManager->generateCondition( - $filter->getField(), - ($isNegation ? self::CONDITION_NOT_LIKE : self::CONDITION_LIKE), - $searchValue - ); - } -} diff --git a/lib/internal/Magento/Framework/Search/Adapter/Mysql/Filter/BuilderInterface.php b/lib/internal/Magento/Framework/Search/Adapter/Mysql/Filter/BuilderInterface.php deleted file mode 100644 index 3da989333d668..0000000000000 --- a/lib/internal/Magento/Framework/Search/Adapter/Mysql/Filter/BuilderInterface.php +++ /dev/null @@ -1,26 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -namespace Magento\Framework\Search\Adapter\Mysql\Filter; - -use Magento\Framework\Search\Request\FilterInterface as RequestFilterInterface; - -/** - * MySQL search filter builder. - * - * @deprecated - * @see \Magento\ElasticSearch - */ -interface BuilderInterface -{ - /** - * Buil filter. - * - * @param RequestFilterInterface $filter - * @param string $conditionType - * @return string - */ - public function build(RequestFilterInterface $filter, $conditionType); -} diff --git a/lib/internal/Magento/Framework/Search/Adapter/Mysql/Filter/Preprocessor.php b/lib/internal/Magento/Framework/Search/Adapter/Mysql/Filter/Preprocessor.php deleted file mode 100644 index 32d134cfe8d6d..0000000000000 --- a/lib/internal/Magento/Framework/Search/Adapter/Mysql/Filter/Preprocessor.php +++ /dev/null @@ -1,36 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -namespace Magento\Framework\Search\Adapter\Mysql\Filter; - -use Magento\Framework\Search\Adapter\Mysql\ConditionManager; -use Magento\Framework\Search\Request\FilterInterface; - -/** - * @inheritdoc - */ -class Preprocessor implements PreprocessorInterface -{ - /** - * @var ConditionManager - */ - private $conditionManager; - - /** - * @param ConditionManager $conditionManager - */ - public function __construct(ConditionManager $conditionManager) - { - $this->conditionManager = $conditionManager; - } - - /** - * @inheritdoc - */ - public function process(FilterInterface $filter, $isNegation, $query) - { - return $query; - } -} diff --git a/lib/internal/Magento/Framework/Search/Adapter/Mysql/Filter/PreprocessorInterface.php b/lib/internal/Magento/Framework/Search/Adapter/Mysql/Filter/PreprocessorInterface.php deleted file mode 100644 index eb0bbc6f3b563..0000000000000 --- a/lib/internal/Magento/Framework/Search/Adapter/Mysql/Filter/PreprocessorInterface.php +++ /dev/null @@ -1,27 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -namespace Magento\Framework\Search\Adapter\Mysql\Filter; - -use Magento\Framework\Search\Request\FilterInterface; - -/** - * MySQL search filter pre-processor. - * - * @deprecated - * @see \Magento\ElasticSearch - */ -interface PreprocessorInterface -{ - /** - * Process filter. - * - * @param FilterInterface $filter - * @param bool $isNegation - * @param string $query - * @return string - */ - public function process(FilterInterface $filter, $isNegation, $query); -} diff --git a/lib/internal/Magento/Framework/Search/Adapter/Mysql/IndexBuilderInterface.php b/lib/internal/Magento/Framework/Search/Adapter/Mysql/IndexBuilderInterface.php deleted file mode 100644 index fbd35455c2294..0000000000000 --- a/lib/internal/Magento/Framework/Search/Adapter/Mysql/IndexBuilderInterface.php +++ /dev/null @@ -1,26 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -namespace Magento\Framework\Search\Adapter\Mysql; - -use Magento\Framework\DB\Select; -use Magento\Framework\Search\RequestInterface; - -/** - * Build base Query for Index - * - * @deprecated - * @see \Magento\ElasticSearch - */ -interface IndexBuilderInterface -{ - /** - * Build index query - * - * @param RequestInterface $request - * @return Select - */ - public function build(RequestInterface $request); -} diff --git a/lib/internal/Magento/Framework/Search/Adapter/Mysql/Mapper.php b/lib/internal/Magento/Framework/Search/Adapter/Mysql/Mapper.php deleted file mode 100644 index e97a6690dbcc2..0000000000000 --- a/lib/internal/Magento/Framework/Search/Adapter/Mysql/Mapper.php +++ /dev/null @@ -1,458 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -namespace Magento\Framework\Search\Adapter\Mysql; - -use Magento\Framework\App\ResourceConnection; -use Magento\Framework\DB\Ddl\Table; -use Magento\Framework\DB\Select; -use Magento\Framework\Search\Adapter\Mysql\Filter\Builder; -use Magento\Framework\Search\Adapter\Mysql\Query\Builder\Match; -use Magento\Framework\Search\Adapter\Mysql\Query\MatchContainer; -use Magento\Framework\Search\Adapter\Mysql\Query\QueryContainer; -use Magento\Framework\Search\Adapter\Mysql\Query\QueryContainerFactory; -use Magento\Framework\Search\EntityMetadata; -use Magento\Framework\Search\Request\Query\BoolExpression as BoolQuery; -use Magento\Framework\Search\Request\Query\Filter as FilterQuery; -use Magento\Framework\Search\Request\Query\Match as MatchQuery; -use Magento\Framework\Search\Request\QueryInterface as RequestQueryInterface; -use Magento\Framework\Search\RequestInterface; - -/** - * Mapper class. Maps library request to specific adapter dependent query - * - * @SuppressWarnings(PHPMD.CouplingBetweenObjects) - * @api - * @deprecated - * @see \Magento\ElasticSearch - */ -class Mapper -{ - /** - * @var ScoreBuilder - */ - private $scoreBuilderFactory; - - /** - * @var Filter\Builder - */ - private $filterBuilder; - - /** - * @var ConditionManager - */ - private $conditionManager; - - /** - * @var IndexBuilderInterface[] - */ - private $indexProviders; - - /** - * @var Resource - */ - private $resource; - - /** - * @var EntityMetadata - */ - private $entityMetadata; - - /** - * @var QueryContainerFactory - */ - private $queryContainerFactory; - - /** - * @var Query\Builder\Match - */ - private $matchBuilder; - - /** - * @var TemporaryStorage - */ - private $temporaryStorage; - - /** - * @var string - */ - private $relevanceCalculationMethod; - - /** - * @var TemporaryStorageFactory - */ - private $temporaryStorageFactory; - - /** - * @param ScoreBuilderFactory $scoreBuilderFactory - * @param Builder $filterBuilder - * @param ConditionManager $conditionManager - * @param ResourceConnection $resource - * @param EntityMetadata $entityMetadata - * @param QueryContainerFactory $queryContainerFactory - * @param Query\Builder\Match $matchBuilder - * @param TemporaryStorageFactory $temporaryStorageFactory - * @param IndexBuilderInterface[] $indexProviders - * @param string $relevanceCalculationMethod - * - * @SuppressWarnings(PHPMD.ExcessiveParameterList) - */ - public function __construct( - ScoreBuilderFactory $scoreBuilderFactory, - Builder $filterBuilder, - ConditionManager $conditionManager, - ResourceConnection $resource, - EntityMetadata $entityMetadata, - QueryContainerFactory $queryContainerFactory, - Match $matchBuilder, - TemporaryStorageFactory $temporaryStorageFactory, - array $indexProviders, - $relevanceCalculationMethod = 'SUM' - ) { - $this->scoreBuilderFactory = $scoreBuilderFactory; - $this->filterBuilder = $filterBuilder; - $this->conditionManager = $conditionManager; - $this->resource = $resource; - $this->entityMetadata = $entityMetadata; - $this->indexProviders = $indexProviders; - $this->queryContainerFactory = $queryContainerFactory; - $this->matchBuilder = $matchBuilder; - $this->temporaryStorage = $temporaryStorageFactory->create(); - $this->temporaryStorageFactory = $temporaryStorageFactory; - if (!in_array($relevanceCalculationMethod, ['SUM', 'MAX'], true)) { - throw new \LogicException('Unsupported relevance calculation method used. Only SUM and MAX are allowed'); - } - $this->relevanceCalculationMethod = $relevanceCalculationMethod; - } - - /** - * Build adapter dependent query - * - * @param RequestInterface $request - * @return Select - * @throws \LogicException - * @throws \Zend_Db_Exception - * @throws \InvalidArgumentException - */ - public function buildQuery(RequestInterface $request) - { - if (!array_key_exists($request->getIndex(), $this->indexProviders)) { - throw new \LogicException('Index provider not configured'); - } - - $indexBuilder = $this->indexProviders[$request->getIndex()]; - - $queryContainer = $this->queryContainerFactory->create( - [ - 'indexBuilder' => $indexBuilder, - 'request' => $request, - ] - ); - $select = $indexBuilder->build($request); - /** @var ScoreBuilder $scoreBuilder */ - $scoreBuilder = $this->scoreBuilderFactory->create(); - $select = $this->processQuery( - $scoreBuilder, - $request->getQuery(), - $select, - BoolQuery::QUERY_CONDITION_MUST, - $queryContainer - ); - - $select = $this->addDerivedQueries( - $request, - $queryContainer, - $scoreBuilder, - $select, - $indexBuilder - ); - - $select->limit($request->getSize(), $request->getFrom()); - $select->order('relevance ' . Select::SQL_DESC)->order('entity_id ' . Select::SQL_DESC); - return $select; - } - - /** - * Creates Select which wraps search result select - * - * It is used to group search results by entity id. - * - * @param Select $select - * @param ScoreBuilder $scoreBuilder - * @return Select - */ - private function createAroundSelect(Select $select, ScoreBuilder $scoreBuilder) - { - $parentSelect = $this->getConnection()->select(); - $parentSelect->from( - ['main_select' => $select], - [ - $this->entityMetadata->getEntityId() => 'entity_id', - 'relevance' => sprintf('%s(%s)', $this->relevanceCalculationMethod, $scoreBuilder->getScoreAlias()), - ] - )->group($this->entityMetadata->getEntityId()); - return $parentSelect; - } - - /** - * Process query - * - * @param ScoreBuilder $scoreBuilder - * @param RequestQueryInterface $query - * @param Select $select - * @param string $conditionType - * @param QueryContainer $queryContainer - * @return Select - * @throws \InvalidArgumentException - */ - protected function processQuery( - ScoreBuilder $scoreBuilder, - RequestQueryInterface $query, - Select $select, - $conditionType, - QueryContainer $queryContainer - ) { - switch ($query->getType()) { - case RequestQueryInterface::TYPE_MATCH: - /** @var MatchQuery $query */ - $select = $queryContainer->addMatchQuery( - $select, - $query, - $conditionType - ); - break; - case RequestQueryInterface::TYPE_BOOL: - /** @var BoolQuery $query */ - $select = $this->processBoolQuery($scoreBuilder, $query, $select, $queryContainer); - break; - case RequestQueryInterface::TYPE_FILTER: - /** @var FilterQuery $query */ - $select = $this->processFilterQuery($scoreBuilder, $query, $select, $conditionType, $queryContainer); - break; - default: - throw new \InvalidArgumentException(sprintf('Unknown query type \'%s\'', $query->getType())); - } - return $select; - } - - /** - * Process bool query - * - * @param ScoreBuilder $scoreBuilder - * @param BoolQuery $query - * @param Select $select - * @param QueryContainer $queryContainer - * @return Select - */ - private function processBoolQuery( - ScoreBuilder $scoreBuilder, - BoolQuery $query, - Select $select, - QueryContainer $queryContainer - ) { - $scoreBuilder->startQuery(); - - $select = $this->processBoolQueryCondition( - $scoreBuilder, - $query->getMust(), - $select, - BoolQuery::QUERY_CONDITION_MUST, - $queryContainer - ); - - $select = $this->processBoolQueryCondition( - $scoreBuilder, - $query->getShould(), - $select, - BoolQuery::QUERY_CONDITION_SHOULD, - $queryContainer - ); - - $select = $this->processBoolQueryCondition( - $scoreBuilder, - $query->getMustNot(), - $select, - BoolQuery::QUERY_CONDITION_NOT, - $queryContainer - ); - - $scoreBuilder->endQuery($query->getBoost()); - - return $select; - } - - /** - * Process bool query condition (must, should, must_not) - * - * @param ScoreBuilder $scoreBuilder - * @param RequestQueryInterface[] $subQueryList - * @param Select $select - * @param string $conditionType - * @param QueryContainer $queryContainer - * @return Select - */ - private function processBoolQueryCondition( - ScoreBuilder $scoreBuilder, - array $subQueryList, - Select $select, - $conditionType, - QueryContainer $queryContainer - ) { - foreach ($subQueryList as $subQuery) { - $select = $this->processQuery($scoreBuilder, $subQuery, $select, $conditionType, $queryContainer); - } - return $select; - } - - /** - * Process filter query - * - * @param ScoreBuilder $scoreBuilder - * @param FilterQuery $query - * @param Select $select - * @param string $conditionType - * @param QueryContainer $queryContainer - * @return Select - */ - private function processFilterQuery( - ScoreBuilder $scoreBuilder, - FilterQuery $query, - Select $select, - $conditionType, - QueryContainer $queryContainer - ) { - $scoreBuilder->startQuery(); - switch ($query->getReferenceType()) { - case FilterQuery::REFERENCE_QUERY: - $select = $this->processQuery( - $scoreBuilder, - $query->getReference(), - $select, - $conditionType, - $queryContainer - ); - $scoreBuilder->endQuery($query->getBoost()); - break; - case FilterQuery::REFERENCE_FILTER: - $filterCondition = $this->filterBuilder->build($query->getReference(), $conditionType); - if ($filterCondition) { - $select->where($filterCondition); - } - break; - } - $scoreBuilder->endQuery($query->getBoost()); - return $select; - } - - /** - * Add match queries to select. - * - * @param RequestInterface $request - * @param QueryContainer $queryContainer - * @param ScoreBuilder $scoreBuilder - * @param Select $select - * @param IndexBuilderInterface $indexBuilder - * @return Select - * @throws \Zend_Db_Exception - */ - private function addDerivedQueries( - RequestInterface $request, - QueryContainer $queryContainer, - ScoreBuilder $scoreBuilder, - Select $select, - IndexBuilderInterface $indexBuilder - ) { - $matchQueries = $queryContainer->getMatchQueries(); - if (!$matchQueries) { - $select->columns($scoreBuilder->build()); - $select = $this->createAroundSelect($select, $scoreBuilder); - } else { - $matchContainer = array_shift($matchQueries); - $this->matchBuilder->build( - $scoreBuilder, - $select, - $matchContainer->getRequest(), - $matchContainer->getConditionType() - ); - $select->columns($scoreBuilder->build()); - $select = $this->createAroundSelect($select, $scoreBuilder); - $select = $this->addMatchQueries($request, $select, $indexBuilder, $matchQueries); - } - - return $select; - } - - /** - * Get connection. - * - * @return false|\Magento\Framework\DB\Adapter\AdapterInterface - */ - private function getConnection() - { - return $this->resource->getConnection(); - } - - /** - * Add match queries to select. - * - * @param RequestInterface $request - * @param Select $select - * @param IndexBuilderInterface $indexBuilder - * @param MatchContainer[] $matchQueries - * @return Select - */ - private function addMatchQueries( - RequestInterface $request, - Select $select, - IndexBuilderInterface $indexBuilder, - array $matchQueries - ) { - $queriesCount = count($matchQueries); - if ($queriesCount) { - $table = $this->temporaryStorage->storeDocumentsFromSelect($select); - foreach ($matchQueries as $matchContainer) { - $queriesCount--; - $matchScoreBuilder = $this->scoreBuilderFactory->create(); - $matchSelect = $this->matchBuilder->build( - $matchScoreBuilder, - $indexBuilder->build($request), - $matchContainer->getRequest(), - $matchContainer->getConditionType() - ); - $select = $this->joinPreviousResultToSelect($matchSelect, $table, $matchScoreBuilder); - if ($queriesCount) { - $previousResultTable = $table; - $table = $this->temporaryStorage->storeDocumentsFromSelect($select); - $this->getConnection()->dropTable($previousResultTable->getName()); - } - } - } - return $select; - } - - /** - * Join previous result to select. - * - * @param Select $query - * @param Table $previousResultTable - * @param ScoreBuilder $scoreBuilder - * @return Select - * @throws \Zend_Db_Exception - */ - private function joinPreviousResultToSelect(Select $query, Table $previousResultTable, ScoreBuilder $scoreBuilder) - { - $query->joinInner( - ['previous_results' => $previousResultTable->getName()], - 'previous_results.entity_id = search_index.entity_id', - [] - ); - $scoreBuilder->addCondition('previous_results.score', false); - $query->columns($scoreBuilder->build()); - - $query = $this->createAroundSelect($query, $scoreBuilder); - - return $query; - } -} diff --git a/lib/internal/Magento/Framework/Search/Adapter/Mysql/Query/Builder/Match.php b/lib/internal/Magento/Framework/Search/Adapter/Mysql/Query/Builder/Match.php deleted file mode 100644 index d4c98cda17e12..0000000000000 --- a/lib/internal/Magento/Framework/Search/Adapter/Mysql/Query/Builder/Match.php +++ /dev/null @@ -1,160 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -declare(strict_types=1); - -namespace Magento\Framework\Search\Adapter\Mysql\Query\Builder; - -use Magento\Framework\DB\Helper\Mysql\Fulltext; -use Magento\Framework\DB\Select; -use Magento\Framework\Search\Adapter\Mysql\Field\FieldInterface; -use Magento\Framework\Search\Adapter\Mysql\Field\ResolverInterface; -use Magento\Framework\Search\Adapter\Mysql\ScoreBuilder; -use Magento\Framework\Search\Request\Query\BoolExpression; -use Magento\Framework\Search\Request\QueryInterface as RequestQueryInterface; -use Magento\Framework\Search\Adapter\Preprocessor\PreprocessorInterface; - -/** - * MySQL search query match. - * - * @api - * @deprecated - * @see \Magento\ElasticSearch - */ -class Match implements QueryInterface -{ - /** - * @var string - */ - const SPECIAL_CHARACTERS = '-+~/\\<>\'":*$#@()!,.?`=%&^'; - - const MINIMAL_CHARACTER_LENGTH = 1; - - /** - * @var string[] - */ - private $replaceSymbols = []; - - /** - * @var ResolverInterface - */ - private $resolver; - - /** - * @var Fulltext - */ - private $fulltextHelper; - - /** - * @var string - */ - private $fulltextSearchMode; - - /** - * @var PreprocessorInterface[] - * @since 100.1.0 - */ - protected $preprocessors; - - /** - * @param ResolverInterface $resolver - * @param Fulltext $fulltextHelper - * @param string $fulltextSearchMode - * @param PreprocessorInterface[] $preprocessors - */ - public function __construct( - ResolverInterface $resolver, - Fulltext $fulltextHelper, - $fulltextSearchMode = Fulltext::FULLTEXT_MODE_BOOLEAN, - array $preprocessors = [] - ) { - $this->resolver = $resolver; - $this->replaceSymbols = str_split(self::SPECIAL_CHARACTERS, 1); - $this->fulltextHelper = $fulltextHelper; - $this->fulltextSearchMode = $fulltextSearchMode; - $this->preprocessors = $preprocessors; - } - - /** - * @inheritdoc - */ - public function build( - ScoreBuilder $scoreBuilder, - Select $select, - RequestQueryInterface $query, - $conditionType - ) { - /** @var $query \Magento\Framework\Search\Request\Query\Match */ - $queryValue = $this->prepareQuery($query->getValue(), $conditionType); - - $fieldList = []; - foreach ($query->getMatches() as $match) { - $fieldList[] = $match['field']; - } - $resolvedFieldList = $this->resolver->resolve($fieldList); - - $fieldIds = []; - $columns = []; - foreach ($resolvedFieldList as $field) { - if ($field->getType() === FieldInterface::TYPE_FULLTEXT && $field->getAttributeId()) { - $fieldIds[] = $field->getAttributeId(); - } - $column = $field->getColumn(); - $columns[$column] = $column; - } - - $matchQuery = $this->fulltextHelper->getMatchQuery( - $columns, - $queryValue, - $this->fulltextSearchMode - ); - $scoreBuilder->addCondition($matchQuery, true); - - if ($fieldIds) { - $matchQuery = sprintf('(%s AND search_index.attribute_id IN (%s))', $matchQuery, implode(',', $fieldIds)); - } - - $select->where($matchQuery); - - return $select; - } - - /** - * Prepare query value for build function. - * - * @param string $queryValue - * @param string $conditionType - * @return string - */ - protected function prepareQuery($queryValue, $conditionType) - { - $queryValue = str_replace($this->replaceSymbols, ' ', $queryValue); - foreach ($this->preprocessors as $preprocessor) { - $queryValue = $preprocessor->process($queryValue); - } - - $stringPrefix = ''; - if ($conditionType === BoolExpression::QUERY_CONDITION_MUST) { - $stringPrefix = '+'; - } elseif ($conditionType === BoolExpression::QUERY_CONDITION_NOT) { - $stringPrefix = '-'; - } - - $queryValues = explode(' ', $queryValue); - - foreach ($queryValues as $queryKey => $queryValue) { - if (empty($queryValue)) { - unset($queryValues[$queryKey]); - } else { - $stringSuffix = self::MINIMAL_CHARACTER_LENGTH > strlen($queryValue) ? '' : '*'; - $queryValues[$queryKey] = $stringPrefix . $queryValue . $stringSuffix; - } - } - - $queryValue = implode(' ', $queryValues); - - return $queryValue; - } -} diff --git a/lib/internal/Magento/Framework/Search/Adapter/Mysql/Query/Builder/QueryInterface.php b/lib/internal/Magento/Framework/Search/Adapter/Mysql/Query/Builder/QueryInterface.php deleted file mode 100644 index 6796a1f995e4f..0000000000000 --- a/lib/internal/Magento/Framework/Search/Adapter/Mysql/Query/Builder/QueryInterface.php +++ /dev/null @@ -1,33 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -namespace Magento\Framework\Search\Adapter\Mysql\Query\Builder; - -use Magento\Framework\Search\Adapter\Mysql\ScoreBuilder; - -/** - * MySQL search query builder. - * - * @deprecated - * @see \Magento\ElasticSearch - */ -interface QueryInterface -{ - /** - * Build query. - * - * @param \Magento\Framework\Search\Adapter\Mysql\ScoreBuilder $scoreBuilder - * @param \Magento\Framework\DB\Select $select - * @param \Magento\Framework\Search\Request\QueryInterface $query - * @param string $conditionType - * @return \Magento\Framework\DB\Select - */ - public function build( - ScoreBuilder $scoreBuilder, - \Magento\Framework\DB\Select $select, - \Magento\Framework\Search\Request\QueryInterface $query, - $conditionType - ); -} diff --git a/lib/internal/Magento/Framework/Search/Adapter/Mysql/Query/MatchContainer.php b/lib/internal/Magento/Framework/Search/Adapter/Mysql/Query/MatchContainer.php deleted file mode 100644 index 6ed3338c040e2..0000000000000 --- a/lib/internal/Magento/Framework/Search/Adapter/Mysql/Query/MatchContainer.php +++ /dev/null @@ -1,61 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -namespace Magento\Framework\Search\Adapter\Mysql\Query; - -use Magento\Framework\Search\Request\QueryInterface; - -// @codeCoverageIgnore - -/** - * MySQL search query match container. - * - * @deprecated - * @see \Magento\ElasticSearch - */ -class MatchContainer -{ - /** - * @var QueryInterface - */ - private $request; - - /** - * @var string - */ - private $conditionType; - - /** - * @param QueryInterface $request - * @param string $conditionType - * @internal param string $name - */ - public function __construct(QueryInterface $request, $conditionType) - { - $this->request = $request; - $this->conditionType = $conditionType; - } - - /** - * Get request. - * - * @return QueryInterface - */ - public function getRequest() - { - return $this->request; - } - - /** - * Get condition type. - * - * @return string - */ - public function getConditionType() - { - return $this->conditionType; - } -} diff --git a/lib/internal/Magento/Framework/Search/Adapter/Mysql/Query/MatchContainerFactory.php b/lib/internal/Magento/Framework/Search/Adapter/Mysql/Query/MatchContainerFactory.php deleted file mode 100644 index cb10de7bdcbbc..0000000000000 --- a/lib/internal/Magento/Framework/Search/Adapter/Mysql/Query/MatchContainerFactory.php +++ /dev/null @@ -1,54 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -namespace Magento\Framework\Search\Adapter\Mysql\Query; - -/** - * MatchContainer Factory - * - * @deprecated - * @see \Magento\ElasticSearch - */ -class MatchContainerFactory -{ - /** - * Object Manager instance - * - * @var \Magento\Framework\ObjectManagerInterface - */ - protected $objectManager = null; - - /** - * Instance name to create - * - * @var string - */ - protected $instanceName = null; - - /** - * Factory constructor - * - * @param \Magento\Framework\ObjectManagerInterface $objectManager - * @param string $instanceName - */ - public function __construct( - \Magento\Framework\ObjectManagerInterface $objectManager, - $instanceName = \Magento\Framework\Search\Adapter\Mysql\Query\MatchContainer::class - ) { - $this->objectManager = $objectManager; - $this->instanceName = $instanceName; - } - - /** - * Create class instance with specified parameters - * - * @param array $data - * @return \Magento\Framework\Search\Adapter\Mysql\Query\QueryContainer - */ - public function create(array $data = []) - { - return $this->objectManager->create($this->instanceName, $data); - } -} diff --git a/lib/internal/Magento/Framework/Search/Adapter/Mysql/Query/QueryContainer.php b/lib/internal/Magento/Framework/Search/Adapter/Mysql/Query/QueryContainer.php deleted file mode 100644 index 9161a30f9bc51..0000000000000 --- a/lib/internal/Magento/Framework/Search/Adapter/Mysql/Query/QueryContainer.php +++ /dev/null @@ -1,73 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -namespace Magento\Framework\Search\Adapter\Mysql\Query; - -use Magento\Framework\DB\Select; -use Magento\Framework\Search\Request\QueryInterface as RequestQueryInterface; - -/** - * MySQL search query container. - * - * @deprecated - * @see \Magento\ElasticSearch - */ -class QueryContainer -{ - const DERIVED_QUERY_PREFIX = 'derived_'; - - /** - * @var array - */ - private $queries = []; - - /** - * @var \Magento\Framework\Search\Adapter\Mysql\Query\MatchContainerFactory - */ - private $matchContainerFactory; - - /** - * @param MatchContainerFactory $matchContainerFactory - */ - public function __construct(MatchContainerFactory $matchContainerFactory) - { - $this->matchContainerFactory = $matchContainerFactory; - } - - /** - * Add query to select. - * - * @param Select $select - * @param RequestQueryInterface $query - * @param string $conditionType - * @return Select - */ - public function addMatchQuery( - Select $select, - RequestQueryInterface $query, - $conditionType - ) { - $container = $this->matchContainerFactory->create( - [ - 'request' => $query, - 'conditionType' => $conditionType, - ] - ); - $name = self::DERIVED_QUERY_PREFIX . count($this->queries); - $this->queries[$name] = $container; - return $select; - } - - /** - * Get queries. - * - * @return MatchContainer[] - */ - public function getMatchQueries() - { - return $this->queries; - } -} diff --git a/lib/internal/Magento/Framework/Search/Adapter/Mysql/Query/QueryContainerFactory.php b/lib/internal/Magento/Framework/Search/Adapter/Mysql/Query/QueryContainerFactory.php deleted file mode 100644 index 59ee4bb045b2a..0000000000000 --- a/lib/internal/Magento/Framework/Search/Adapter/Mysql/Query/QueryContainerFactory.php +++ /dev/null @@ -1,54 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -namespace Magento\Framework\Search\Adapter\Mysql\Query; - -/** - * MatchContainer Factory - * - * @deprecated - * @see \Magento\ElasticSearch - */ -class QueryContainerFactory -{ - /** - * Object Manager instance - * - * @var \Magento\Framework\ObjectManagerInterface - */ - protected $objectManager = null; - - /** - * Instance name to create - * - * @var string - */ - protected $instanceName = null; - - /** - * Factory constructor - * - * @param \Magento\Framework\ObjectManagerInterface $objectManager - * @param string $instanceName - */ - public function __construct( - \Magento\Framework\ObjectManagerInterface $objectManager, - $instanceName = \Magento\Framework\Search\Adapter\Mysql\Query\QueryContainer::class - ) { - $this->objectManager = $objectManager; - $this->instanceName = $instanceName; - } - - /** - * Create class instance with specified parameters - * - * @param array $data - * @return \Magento\Framework\Search\Adapter\Mysql\Query\QueryContainer - */ - public function create(array $data = []) - { - return $this->objectManager->create($this->instanceName, $data); - } -} diff --git a/lib/internal/Magento/Framework/Search/Adapter/Mysql/ResponseFactory.php b/lib/internal/Magento/Framework/Search/Adapter/Mysql/ResponseFactory.php deleted file mode 100644 index b41a43883fde5..0000000000000 --- a/lib/internal/Magento/Framework/Search/Adapter/Mysql/ResponseFactory.php +++ /dev/null @@ -1,76 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -namespace Magento\Framework\Search\Adapter\Mysql; - -/** - * Response Factory - * - * @deprecated - * @see \Magento\ElasticSearch - */ -class ResponseFactory -{ - /** - * Object Manager instance - * - * @var \Magento\Framework\ObjectManagerInterface - */ - protected $objectManager; - - /** - * Document Factory - * - * @var DocumentFactory - */ - protected $documentFactory; - - /** - * Aggregation Factory - * - * @var AggregationFactory - */ - protected $aggregationFactory; - - /** - * @param \Magento\Framework\ObjectManagerInterface $objectManager - * @param DocumentFactory $documentFactory - * @param AggregationFactory $aggregationFactory - */ - public function __construct( - \Magento\Framework\ObjectManagerInterface $objectManager, - DocumentFactory $documentFactory, - AggregationFactory $aggregationFactory - ) { - $this->objectManager = $objectManager; - $this->documentFactory = $documentFactory; - $this->aggregationFactory = $aggregationFactory; - } - - /** - * Create Query Response instance - * - * @param mixed $rawResponse - * @return \Magento\Framework\Search\Response\QueryResponse - */ - public function create($rawResponse) - { - $documents = []; - foreach ($rawResponse['documents'] as $rawDocument) { - /** @var \Magento\Framework\Api\Search\Document[] $documents */ - $documents[] = $this->documentFactory->create($rawDocument); - } - /** @var \Magento\Framework\Search\Response\Aggregation $aggregations */ - $aggregations = $this->aggregationFactory->create($rawResponse['aggregations']); - return $this->objectManager->create( - \Magento\Framework\Search\Response\QueryResponse::class, - [ - 'documents' => $documents, - 'aggregations' => $aggregations, - 'total' => $rawResponse['total'] - ] - ); - } -} diff --git a/lib/internal/Magento/Framework/Search/Adapter/Mysql/ScoreBuilder.php b/lib/internal/Magento/Framework/Search/Adapter/Mysql/ScoreBuilder.php deleted file mode 100644 index 1cc417f891c19..0000000000000 --- a/lib/internal/Magento/Framework/Search/Adapter/Mysql/ScoreBuilder.php +++ /dev/null @@ -1,115 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -namespace Magento\Framework\Search\Adapter\Mysql; - -/** - * Class for generating sql condition for calculating store manager - * - * @api - * @deprecated - * @see \Magento\ElasticSearch - */ -class ScoreBuilder -{ - /** - * @var string - */ - private $scoreCondition = ''; - - /** - * @var string - */ - const WEIGHT_FIELD = 'search_weight'; - - /** - * Get column alias for global score query in sql - * - * @return string - */ - public function getScoreAlias() - { - return 'score'; - } - - /** - * Get generated sql condition for global score - * - * @return string - */ - public function build() - { - $scoreCondition = $this->scoreCondition; - $this->clear(); - $scoreAlias = $this->getScoreAlias(); - - return "({$scoreCondition}) AS {$scoreAlias}"; - } - - /** - * Start Query - * - * @return void - */ - public function startQuery() - { - $this->addPlus(); - $this->scoreCondition .= '('; - } - - /** - * End Query - * - * @param float $boost - * @return void - */ - public function endQuery($boost) - { - if (!empty($this->scoreCondition) && substr($this->scoreCondition, -1) !== '(') { - $this->scoreCondition .= ") * {$boost}"; - } else { - $this->scoreCondition .= '0)'; - } - } - - /** - * Add Condition for score calculation - * - * @param string $score - * @param bool $useWeights - * @return void - */ - public function addCondition($score, $useWeights = true) - { - $this->addPlus(); - $condition = "{$score}"; - if ($useWeights) { - $condition = "LEAST(($condition), 1000000) * POW(2, " . self::WEIGHT_FIELD . ')'; - } - $this->scoreCondition .= $condition; - } - - /** - * Add Plus sign for Score calculation - * - * @return void - */ - private function addPlus() - { - if (!empty($this->scoreCondition) && substr($this->scoreCondition, -1) !== '(') { - $this->scoreCondition .= ' + '; - } - } - - /** - * Clear score manager - * - * @return void - */ - private function clear() - { - $this->scoreCondition = ''; - } -} diff --git a/lib/internal/Magento/Framework/Search/Adapter/Mysql/ScoreBuilderFactory.php b/lib/internal/Magento/Framework/Search/Adapter/Mysql/ScoreBuilderFactory.php deleted file mode 100644 index 70aa749fd859f..0000000000000 --- a/lib/internal/Magento/Framework/Search/Adapter/Mysql/ScoreBuilderFactory.php +++ /dev/null @@ -1,54 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -namespace Magento\Framework\Search\Adapter\Mysql; - -/** - * ScoreBuilder Factory - * - * @deprecated - * @see \Magento\ElasticSearch - */ -class ScoreBuilderFactory -{ - /** - * Object Manager instance - * - * @var \Magento\Framework\ObjectManagerInterface - */ - protected $_objectManager = null; - - /** - * Instance name to create - * - * @var string - */ - protected $_instanceName = null; - - /** - * Factory constructor - * - * @param \Magento\Framework\ObjectManagerInterface $objectManager - * @param string $instanceName - */ - public function __construct( - \Magento\Framework\ObjectManagerInterface $objectManager, - $instanceName = \Magento\Framework\Search\Adapter\Mysql\ScoreBuilder::class - ) { - $this->_objectManager = $objectManager; - $this->_instanceName = $instanceName; - } - - /** - * Create class instance with specified parameters - * - * @param array $data - * @return \Magento\Framework\Search\Adapter\Mysql\ScoreBuilder - */ - public function create(array $data = []) - { - return $this->_objectManager->create($this->_instanceName, $data); - } -} diff --git a/lib/internal/Magento/Framework/Search/Test/Unit/Adapter/Mysql/AdapterTest.php b/lib/internal/Magento/Framework/Search/Test/Unit/Adapter/Mysql/AdapterTest.php deleted file mode 100644 index 03d1461a5b946..0000000000000 --- a/lib/internal/Magento/Framework/Search/Test/Unit/Adapter/Mysql/AdapterTest.php +++ /dev/null @@ -1,217 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -declare(strict_types=1); - -namespace Magento\Framework\Search\Test\Unit\Adapter\Mysql; - -use Magento\Framework\App\ResourceConnection; -use Magento\Framework\DB\Adapter\AdapterInterface; -use Magento\Framework\DB\Ddl\Table; -use Magento\Framework\DB\Select; -use Magento\Framework\Search\Adapter\Mysql\Adapter; -use Magento\Framework\Search\Adapter\Mysql\Aggregation\Builder; -use Magento\Framework\Search\Adapter\Mysql\Mapper; -use Magento\Framework\Search\Adapter\Mysql\ResponseFactory; -use Magento\Framework\Search\Adapter\Mysql\TemporaryStorage; -use Magento\Framework\Search\Adapter\Mysql\TemporaryStorageFactory; -use Magento\Framework\Search\Request\BucketInterface; -use Magento\Framework\Search\RequestInterface; -use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; -use PHPUnit\Framework\MockObject\MockObject; -use PHPUnit\Framework\TestCase; - -/** - * Mysql search adapter test - * - * @SuppressWarnings(PHPMD.CouplingBetweenObjects) - */ -class AdapterTest extends TestCase -{ - /** - * @var ResponseFactory|MockObject - */ - protected $responseFactory; - - /** - * @var AdapterInterface|MockObject - */ - private $connectionAdapter; - - /** - * @var Mapper|MockObject - */ - private $mapper; - - /** - * @var Adapter - */ - private $adapter; - - /** - * @var ObjectManager - */ - private $objectManager; - - /** - * @var RequestInterface|MockObject - */ - private $request; - - /** - * @var Select|MockObject - */ - private $select; - - /** - * @var ResourceConnection|MockObject - */ - private $resource; - - /** - * @var BucketInterface|MockObject - */ - private $bucket; - - /** - * @var Builder|MockObject - */ - private $aggregatioBuilder; - - /** - * @var TemporaryStorage|MockObject - */ - private $temporaryStorage; - - protected function setUp(): void - { - $this->markTestSkipped("MC-18948: Mysql Adapter and Search Engine is deprecated"); - $this->objectManager = new ObjectManager($this); - - $this->request = $this->getMockBuilder(RequestInterface::class) - ->setMethods(['getAggregation']) - ->disableOriginalConstructor() - ->getMockForAbstractClass(); - - $this->resource = $this->getMockBuilder(ResourceConnection::class) - ->setMethods(['getConnection']) - ->disableOriginalConstructor() - ->getMock(); - $this->select = $this->getMockBuilder(Select::class) - ->setMethods([]) - ->disableOriginalConstructor() - ->getMock(); - $this->connectionAdapter = $this->getMockBuilder(AdapterInterface::class) - ->setMethods(['fetchAssoc']) - ->disableOriginalConstructor() - ->getMockForAbstractClass(); - $this->resource->expects($this->any()) - ->method('getConnection') - ->willReturn($this->connectionAdapter); - - $this->mapper = $this->getMockBuilder(Mapper::class) - ->setMethods(['buildQuery']) - ->disableOriginalConstructor() - ->getMock(); - - $this->responseFactory = $this->getMockBuilder(ResponseFactory::class) - ->setMethods([]) - ->disableOriginalConstructor() - ->getMock(); - - $this->aggregatioBuilder = $this->getMockBuilder( - Builder::class - )->setMethods(['build']) - ->disableOriginalConstructor() - ->getMock(); - - $this->bucket = $this->getMockBuilder(BucketInterface::class) - ->setMethods(['getType', 'getName']) - ->disableOriginalConstructor() - ->getMockForAbstractClass(); - - $this->temporaryStorage = $this->getMockBuilder(TemporaryStorage::class) - ->disableOriginalConstructor() - ->getMock(); - - $temporaryStorageFactoryName = TemporaryStorageFactory::class; - $temporaryStorageFactory = $this->getMockBuilder($temporaryStorageFactoryName) - ->setMethods(['create']) - ->disableOriginalConstructor() - ->getMock(); - $temporaryStorageFactory->expects($this->any()) - ->method('create') - ->willReturn($this->temporaryStorage); - - $this->adapter = $this->objectManager->getObject( - Adapter::class, - [ - 'mapper' => $this->mapper, - 'responseFactory' => $this->responseFactory, - 'resource' => $this->resource, - 'aggregationBuilder' => $this->aggregatioBuilder, - 'temporaryStorageFactory' => $temporaryStorageFactory, - ] - ); - } - - public function testQuery() - { - $selectResult = [ - 'documents' => [ - [ - 'product_id' => 1, - 'sku' => 'Product', - ], - ], - 'aggregations' => [ - 'aggregation_name' => [ - 'aggregation1' => [1, 3], - 'aggregation2' => [2, 4], - ], - ], - 'total' => 1 - ]; - - $select = $this->getMockBuilder(Select::class) - ->disableOriginalConstructor() - ->getMock(); - - $this->connectionAdapter->expects($this->exactly(2)) - ->method('select') - ->willReturn($select); - - $this->connectionAdapter->expects($this->once()) - ->method('fetchOne') - ->with($select) - ->willReturn($selectResult['total']); - - $table = $this->getMockBuilder(Table::class) - ->disableOriginalConstructor() - ->getMock(); - - $this->temporaryStorage->expects($this->any()) - ->method('storeDocumentsFromSelect') - ->willReturn($table); - - $this->connectionAdapter->expects($this->any()) - ->method('fetchAssoc') - ->willReturn($selectResult['documents']); - $this->mapper->expects($this->once()) - ->method('buildQuery') - ->with($this->request) - ->willReturn($this->select); - $this->responseFactory->expects($this->once()) - ->method('create') - ->with($selectResult) - ->willReturnArgument(0); - $this->aggregatioBuilder->expects($this->once()) - ->method('build') - ->with($this->request, $table, $selectResult['documents']) - ->willReturn($selectResult['aggregations']); - $response = $this->adapter->query($this->request); - $this->assertEquals($selectResult, $response); - } -} diff --git a/lib/internal/Magento/Framework/Search/Test/Unit/Adapter/Mysql/Aggregation/Builder/ContainerTest.php b/lib/internal/Magento/Framework/Search/Test/Unit/Adapter/Mysql/Aggregation/Builder/ContainerTest.php deleted file mode 100644 index b04db348fd687..0000000000000 --- a/lib/internal/Magento/Framework/Search/Test/Unit/Adapter/Mysql/Aggregation/Builder/ContainerTest.php +++ /dev/null @@ -1,37 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -declare(strict_types=1); - -namespace Magento\Framework\Search\Test\Unit\Adapter\Mysql\Aggregation\Builder; - -use Magento\Framework\Search\Adapter\Mysql\Aggregation\Builder\Container; -use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; -use PHPUnit\Framework\TestCase; - -class ContainerTest extends TestCase -{ - /** - * @var ObjectManager - */ - private $objectManager; - - protected function setUp(): void - { - $this->objectManager = new ObjectManager($this); - } - - public function testGet() - { - $bucketName = 'providerName'; - $bucketValue = 'dataProvider'; - /** @var Container $provider */ - $provider = $this->objectManager->getObject( - Container::class, - ['buckets' => [$bucketName => $bucketValue]] - ); - $this->assertEquals($bucketValue, $provider->get($bucketName)); - } -} diff --git a/lib/internal/Magento/Framework/Search/Test/Unit/Adapter/Mysql/Aggregation/Builder/MetricsTest.php b/lib/internal/Magento/Framework/Search/Test/Unit/Adapter/Mysql/Aggregation/Builder/MetricsTest.php deleted file mode 100644 index 49ea5ea928c85..0000000000000 --- a/lib/internal/Magento/Framework/Search/Test/Unit/Adapter/Mysql/Aggregation/Builder/MetricsTest.php +++ /dev/null @@ -1,60 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -declare(strict_types=1); - -namespace Magento\Framework\Search\Test\Unit\Adapter\Mysql\Aggregation\Builder; - -use Magento\Framework\Search\Adapter\Mysql\Aggregation\Builder\Metrics; -use Magento\Framework\Search\Request\Aggregation\Metric; -use Magento\Framework\Search\Request\BucketInterface as RequestBucketInterface; -use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; -use PHPUnit\Framework\MockObject\MockObject; -use PHPUnit\Framework\TestCase; - -class MetricsTest extends TestCase -{ - /** - * @var Metrics - */ - private $metrics; - - /** - * @var RequestBucketInterface|MockObject - */ - private $requestBucket; - - /** - * @var Metric|MockObject - */ - private $metric; - - protected function setUp(): void - { - $helper = new ObjectManager($this); - - $this->requestBucket = $this->getMockBuilder(\Magento\Framework\Search\Request\BucketInterface::class) - ->setMethods(['getMetrics']) - ->disableOriginalConstructor() - ->getMockForAbstractClass(); - - $this->metric = $this->getMockBuilder(Metric::class) - ->setMethods(['getType']) - ->disableOriginalConstructor() - ->getMockForAbstractClass(); - - $this->metrics = $helper->getObject(Metrics::class); - } - - public function testBuild() - { - $expectedResult = ['count' => 'count(main_table.value)']; - $this->requestBucket->expects($this->once())->method('getMetrics')->willReturn([$this->metric]); - $this->metric->expects($this->once())->method('getType')->willReturn('count'); - $metrics = $this->metrics->build($this->requestBucket); - - $this->assertEquals($expectedResult, $metrics); - } -} diff --git a/lib/internal/Magento/Framework/Search/Test/Unit/Adapter/Mysql/Aggregation/Builder/RangeTest.php b/lib/internal/Magento/Framework/Search/Test/Unit/Adapter/Mysql/Aggregation/Builder/RangeTest.php deleted file mode 100644 index 3b3eff0db5a71..0000000000000 --- a/lib/internal/Magento/Framework/Search/Test/Unit/Adapter/Mysql/Aggregation/Builder/RangeTest.php +++ /dev/null @@ -1,174 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -declare(strict_types=1); - -namespace Magento\Framework\Search\Test\Unit\Adapter\Mysql\Aggregation\Builder; - -use Magento\Framework\App\ResourceConnection; -use Magento\Framework\DB\Adapter\AdapterInterface; -use Magento\Framework\DB\Ddl\Table; -use Magento\Framework\DB\Select; -use Magento\Framework\Search\Adapter\Mysql\Aggregation\Builder\Metrics; -use Magento\Framework\Search\Adapter\Mysql\Aggregation\DataProviderInterface; -use Magento\Framework\Search\Request\Aggregation\Range; -use Magento\Framework\Search\Request\BucketInterface; -use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; -use PHPUnit\Framework\MockObject\MockObject; -use PHPUnit\Framework\TestCase; - -class RangeTest extends TestCase -{ - /** - * @var Metrics|MockObject - */ - private $metricsBuilder; - - /** - * @var ResourceConnection|MockObject - */ - private $resource; - - /** - * @var AdapterInterface|MockObject - */ - private $connectionMock; - - /** - * @var Select|MockObject - */ - private $select; - - /** - * @var BucketInterface|MockObject - */ - private $bucket; - - /** - * @var Range|MockObject - */ - private $range; - - /** - * @var \Magento\Framework\Search\Adapter\Mysql\Aggregation\Builder\Range - */ - private $builder; - - /** - * @var DataProviderInterface|MockObject - */ - private $dataProvider; - - /** - * SetUP method - */ - protected function setUp(): void - { - $helper = new ObjectManager($this); - - $this->metricsBuilder = $this->getMockBuilder( - Metrics::class - ) - ->setMethods(['build']) - ->disableOriginalConstructor() - ->getMock(); - - $this->select = $this->getMockBuilder(Select::class) - ->disableOriginalConstructor() - ->getMock(); - - $this->connectionMock = $this->getMockBuilder(AdapterInterface::class) - ->setMethods(['fetchAssoc', 'select', 'getCaseSql']) - ->disableOriginalConstructor() - ->getMockForAbstractClass(); - $this->connectionMock->expects($this->any()) - ->method('select') - ->willReturn($this->select); - - $this->resource = $this->getMockBuilder(ResourceConnection::class) - ->disableOriginalConstructor() - ->getMock(); - $this->resource->expects($this->any()) - ->method('getConnection') - ->willReturn($this->connectionMock); - - $this->bucket = $this->getMockBuilder(BucketInterface::class) - ->setMethods(['getName', 'getRanges']) - ->disableOriginalConstructor() - ->getMockForAbstractClass(); - - $this->range = $this->getMockBuilder(Range::class) - ->setMethods(['getFrom', 'getTo']) - ->disableOriginalConstructor() - ->getMock(); - - $this->dataProvider = $this->getMockBuilder( - DataProviderInterface::class - ) - ->setMethods(['getDataSet', 'execute']) - ->disableOriginalConstructor() - ->getMockForAbstractClass(); - - $this->builder = $helper->getObject( - \Magento\Framework\Search\Adapter\Mysql\Aggregation\Builder\Range::class, - ['metricsBuilder' => $this->metricsBuilder, 'resource' => $this->resource] - ); - } - - /** - * Test for method "build" - */ - public function testBuild() - { - $this->metricsBuilder->expects($this->once()) - ->method('build') - ->willReturn(['metrics']); - $this->bucket->expects($this->once()) - ->method('getRanges') - ->willReturn( - [$this->range, $this->range, $this->range] - ); - $this->range->expects($this->at(0)) - ->method('getFrom') - ->willReturn(''); - $this->range->expects($this->at(1)) - ->method('getTo') - ->willReturn(50); - $this->range->expects($this->at(2)) - ->method('getFrom') - ->willReturn(50); - $this->range->expects($this->at(3)) - ->method('getTo') - ->willReturn(100); - $this->range->expects($this->at(4)) - ->method('getFrom') - ->willReturn(100); - $this->range->expects($this->at(5)) - ->method('getTo') - ->willReturn(''); - $this->connectionMock->expects($this->once()) - ->method('getCaseSql') - ->withConsecutive( - [''], - [ - [ - '`value` < 50' => "'*_50'", - '`value` BETWEEN 50 AND 100' => "'50_100'", - '`value` >= 100' => "'100_*'", - ] - ] - ); - $this->dataProvider->expects($this->once())->method('getDataSet')->willReturn($this->select); - $this->dataProvider->expects($this->once())->method('execute')->willReturn($this->select); - - /** @var Table|MockObject $table */ - $table = $this->getMockBuilder(Table::class) - ->disableOriginalConstructor() - ->getMock(); - - $result = $this->builder->build($this->dataProvider, [], $this->bucket, $table); - $this->assertEquals($this->select, $result); - } -} diff --git a/lib/internal/Magento/Framework/Search/Test/Unit/Adapter/Mysql/Aggregation/Builder/TermTest.php b/lib/internal/Magento/Framework/Search/Test/Unit/Adapter/Mysql/Aggregation/Builder/TermTest.php deleted file mode 100644 index 1c945239e11bc..0000000000000 --- a/lib/internal/Magento/Framework/Search/Test/Unit/Adapter/Mysql/Aggregation/Builder/TermTest.php +++ /dev/null @@ -1,113 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -declare(strict_types=1); - -namespace Magento\Framework\Search\Test\Unit\Adapter\Mysql\Aggregation\Builder; - -use Magento\Framework\DB\Ddl\Table; -use Magento\Framework\DB\Select; -use Magento\Framework\Search\Adapter\Mysql\Aggregation\Builder\Metrics; -use Magento\Framework\Search\Adapter\Mysql\Aggregation\Builder\Term; -use Magento\Framework\Search\Adapter\Mysql\Aggregation\DataProviderInterface; -use Magento\Framework\Search\Request\BucketInterface as RequestBucketInterface; -use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; -use PHPUnit\Framework\MockObject\MockObject; -use PHPUnit\Framework\TestCase; - -class TermTest extends TestCase -{ - /** - * @var Term - */ - private $term; - - /** - * @var Metrics|MockObject - */ - private $metricsBuilder; - - /** - * @var Select|MockObject - */ - private $select; - - /** - * @var RequestBucketInterface|MockObject - */ - private $bucket; - - /** - * @var DataProviderInterface|MockObject - */ - private $dataProvider; - - /** - * SetUP method - */ - protected function setUp(): void - { - $helper = new ObjectManager($this); - - $this->metricsBuilder = $this->getMockBuilder( - Metrics::class - ) - ->setMethods(['build']) - ->disableOriginalConstructor() - ->getMock(); - - $this->select = $this->getMockBuilder(Select::class) - ->setMethods(['where', 'columns', 'group']) - ->disableOriginalConstructor() - ->getMock(); - - $this->bucket = $this->getMockBuilder(\Magento\Framework\Search\Request\BucketInterface::class) - ->disableOriginalConstructor() - ->getMockForAbstractClass(); - - $this->dataProvider = $this->getMockBuilder( - DataProviderInterface::class - ) - ->setMethods(['getDataSet', 'execute']) - ->disableOriginalConstructor() - ->getMockForAbstractClass(); - - $this->term = $helper->getObject( - Term::class, - ['metricsBuilder' => $this->metricsBuilder] - ); - } - - /** - * Test for method "build" - */ - public function testBuild() - { - $metrics = ['count' => 'count(*)']; - - $this->select->expects($this->once()) - ->method('columns') - ->withConsecutive([$metrics]); - $this->select->expects($this->once()) - ->method('group') - ->withConsecutive(['value']); - - $this->metricsBuilder->expects($this->once()) - ->method('build') - ->willReturn($metrics); - - $this->dataProvider->expects($this->once())->method('getDataSet')->willReturn($this->select); - $this->dataProvider->expects($this->once())->method('execute')->willReturn($this->select); - - /** @var Table|MockObject $table */ - $table = $this->getMockBuilder(Table::class) - ->disableOriginalConstructor() - ->getMock(); - - $result = $this->term->build($this->dataProvider, [], $this->bucket, $table); - - $this->assertEquals($this->select, $result); - } -} diff --git a/lib/internal/Magento/Framework/Search/Test/Unit/Adapter/Mysql/Aggregation/BuilderTest.php b/lib/internal/Magento/Framework/Search/Test/Unit/Adapter/Mysql/Aggregation/BuilderTest.php deleted file mode 100644 index 93345f5b1d313..0000000000000 --- a/lib/internal/Magento/Framework/Search/Test/Unit/Adapter/Mysql/Aggregation/BuilderTest.php +++ /dev/null @@ -1,231 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -declare(strict_types=1); - -namespace Magento\Framework\Search\Test\Unit\Adapter\Mysql\Aggregation; - -use Magento\Framework\App\ResourceConnection; -use Magento\Framework\DB\Adapter\AdapterInterface; -use Magento\Framework\DB\Ddl\Table; -use Magento\Framework\DB\Select; -use Magento\Framework\Search\Adapter\Aggregation\AggregationResolverInterface; -use Magento\Framework\Search\Adapter\Mysql\Aggregation\Builder; -use Magento\Framework\Search\Adapter\Mysql\Aggregation\Builder\Container; -use Magento\Framework\Search\Adapter\Mysql\Aggregation\DataProviderContainer; -use Magento\Framework\Search\Adapter\Mysql\Aggregation\DataProviderInterface; -use Magento\Framework\Search\Adapter\Mysql\TemporaryStorage; -use Magento\Framework\Search\EntityMetadata; -use Magento\Framework\Search\Request\BucketInterface; -use Magento\Framework\Search\RequestInterface; -use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; -use PHPUnit\Framework\MockObject\MockObject; -use PHPUnit\Framework\TestCase; - -/** - * @SuppressWarnings(PHPMD.CouplingBetweenObjects) - */ -class BuilderTest extends TestCase -{ - /** - * @var EntityMetadata|MockObject - */ - private $entityMetadata; - - /** - * @var ResourceConnection|MockObject - */ - private $resource; - - /** - * @var AdapterInterface|MockObject - */ - private $connectionMock; - - /** - * @var RequestInterface|MockObject - */ - private $request; - - /** - * @var BucketInterface|MockObject - */ - private $bucket; - - /** - * @var DataProviderContainer|MockObject - */ - private $dataProviderContainer; - - /** - * @var DataProviderInterface|MockObject - */ - private $dataProvider; - - /** - * @var Builder\Container|MockObject - */ - private $aggregationContainer; - - /** - * @var Builder\BucketInterface|MockObject - */ - private $bucketBuilder; - - /** - * @var Select|MockObject - */ - private $select; - - /** - * @var AggregationResolverInterface|MockObject - */ - private $aggregationResolver; - - /** - * @var Table|MockObject - */ - private $table; - - /** - * @var \Magento\Framework\Search\Adapter\Mysql\Aggregation\Builder - */ - private $builder; - - /** - * SetUP method - */ - protected function setUp(): void - { - $helper = new ObjectManager($this); - - $this->entityMetadata = $this->getMockBuilder(EntityMetadata::class) - ->setMethods(['getEntityId']) - ->disableOriginalConstructor() - ->getMock(); - - $this->request = $this->getMockBuilder(RequestInterface::class) - ->setMethods(['getAggregation']) - ->disableOriginalConstructor() - ->getMockForAbstractClass(); - - $this->bucket = $this->getMockBuilder(BucketInterface::class) - ->setMethods(['getName']) - ->disableOriginalConstructor() - ->getMockForAbstractClass(); - - $this->select = $this->getMockBuilder(Select::class) - ->disableOriginalConstructor() - ->getMock(); - - $this->bucketBuilder = $this->getMockBuilder( - \Magento\Framework\Search\Adapter\Mysql\Aggregation\Builder\BucketInterface::class - ) - ->setMethods(['build']) - ->disableOriginalConstructor() - ->getMockForAbstractClass(); - - $this->aggregationContainer = $this->getMockBuilder( - Container::class - ) - ->setMethods(['get']) - ->disableOriginalConstructor() - ->getMock(); - $this->aggregationContainer->expects($this->any())->method('get')->willReturn($this->bucketBuilder); - - $this->connectionMock = $this->getMockBuilder(AdapterInterface::class) - ->setMethods(['fetchAssoc']) - ->disableOriginalConstructor() - ->getMockForAbstractClass(); - - $this->dataProvider = $this->getMockBuilder( - DataProviderInterface::class - ) - ->setMethods(['getDataSet']) - ->disableOriginalConstructor() - ->getMockForAbstractClass(); - - $this->dataProviderContainer = $this->getMockBuilder( - DataProviderContainer::class - ) - ->setMethods(['get']) - ->disableOriginalConstructor() - ->getMock(); - $this->dataProviderContainer->expects($this->any())->method('get')->willReturn($this->dataProvider); - - $this->resource = $this->getMockBuilder(ResourceConnection::class) - ->disableOriginalConstructor() - ->getMock(); - $this->resource->expects($this->any())->method('getConnection')->willReturn($this->connectionMock); - - $this->aggregationResolver = $this->getMockForAbstractClass(AggregationResolverInterface::class); - $this->table = $this->getMockBuilder(Table::class) - ->disableOriginalConstructor() - ->getMock(); - - $this->builder = $helper->getObject( - Builder::class, - [ - 'entityMetadata' => $this->entityMetadata, - 'dataProviderContainer' => $this->dataProviderContainer, - 'resource' => $this->resource, - 'aggregationContainer' => $this->aggregationContainer, - 'aggregationResolver' => $this->aggregationResolver, - ] - ); - } - - /** - * Test for method "build" - */ - public function testBuild() - { - $fetchResult = ['name' => ['some', 'result']]; - $documents = [1 => 'document_1', 2 => 'document_2']; - - $this->aggregationResolver->expects($this->once()) - ->method('resolve') - ->with($this->request, array_keys($documents)) - ->willReturn([$this->bucket]); - $this->bucket->expects($this->once())->method('getName')->willReturn('name'); - $this->request->expects($this->once())->method('getDimensions')->willReturn([]); - $this->bucketBuilder->expects($this->once())->method('build')->willReturn($fetchResult['name']); - - $result = $this->builder->build($this->request, $this->table, $documents); - - $this->assertEquals($fetchResult, $result); - } - - public function testBuildWithoutPassedDocuments() - { - $documentIds = [1, 2]; - $tableName = 'table_name'; - - $select = $this->getMockBuilder(Select::class) - ->disableOriginalConstructor() - ->getMock(); - $select->expects($this->once()) - ->method('from') - ->with($tableName, TemporaryStorage::FIELD_ENTITY_ID) - ->willReturnSelf(); - - $this->table->expects($this->once())->method('getName')->willReturn($tableName); - $this->connectionMock - ->expects($this->once()) - ->method('select') - ->willReturn($select); - $this->connectionMock - ->expects($this->once()) - ->method('fetchCol') - ->willReturn($documentIds); - - $this->aggregationResolver->expects($this->once()) - ->method('resolve') - ->with($this->request, $documentIds) - ->willReturn([]); - - $this->builder->build($this->request, $this->table); - } -} diff --git a/lib/internal/Magento/Framework/Search/Test/Unit/Adapter/Mysql/Aggregation/DataProviderContainerTest.php b/lib/internal/Magento/Framework/Search/Test/Unit/Adapter/Mysql/Aggregation/DataProviderContainerTest.php deleted file mode 100644 index ad560aed7f3f1..0000000000000 --- a/lib/internal/Magento/Framework/Search/Test/Unit/Adapter/Mysql/Aggregation/DataProviderContainerTest.php +++ /dev/null @@ -1,37 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -declare(strict_types=1); - -namespace Magento\Framework\Search\Test\Unit\Adapter\Mysql\Aggregation; - -use Magento\Framework\Search\Adapter\Mysql\Aggregation\DataProviderContainer; -use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; -use PHPUnit\Framework\TestCase; - -class DataProviderContainerTest extends TestCase -{ - /** - * @var ObjectManager - */ - private $objectManager; - - protected function setUp(): void - { - $this->objectManager = new ObjectManager($this); - } - - public function testGet() - { - $bucketName = 'providerName'; - $bucketValue = 'dataProvider'; - /** @var DataProviderContainer $provider */ - $provider = $this->objectManager->getObject( - DataProviderContainer::class, - ['dataProviders' => [$bucketName => $bucketValue]] - ); - $this->assertEquals($bucketValue, $provider->get($bucketName)); - } -} diff --git a/lib/internal/Magento/Framework/Search/Test/Unit/Adapter/Mysql/Filter/Builder/RangeTest.php b/lib/internal/Magento/Framework/Search/Test/Unit/Adapter/Mysql/Filter/Builder/RangeTest.php deleted file mode 100644 index c1ce5260b8557..0000000000000 --- a/lib/internal/Magento/Framework/Search/Test/Unit/Adapter/Mysql/Filter/Builder/RangeTest.php +++ /dev/null @@ -1,169 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -declare(strict_types=1); - -namespace Magento\Framework\Search\Test\Unit\Adapter\Mysql\Filter\Builder; - -use Magento\Framework\Search\Adapter\Mysql\ConditionManager; -use Magento\Framework\Search\Adapter\Mysql\Filter\Builder\Range; -use Magento\Framework\Search\Request\Filter\Term; -use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; -use PHPUnit\Framework\MockObject\MockObject; -use PHPUnit\Framework\TestCase; - -class RangeTest extends TestCase -{ - /** - * @var Term|MockObject - */ - private $requestFilter; - - /** - * @var Range - */ - private $filter; - - /** - * @var ConditionManager|MockObject - */ - private $conditionManager; - - /** - * Set Up - */ - protected function setUp(): void - { - $objectManager = new ObjectManager($this); - $this->requestFilter = $this->getMockBuilder(\Magento\Framework\Search\Request\Filter\Range::class) - ->setMethods(['getField', 'getFrom', 'getTo']) - ->disableOriginalConstructor() - ->getMock(); - - $this->conditionManager = $this->getMockBuilder(ConditionManager::class) - ->disableOriginalConstructor() - ->setMethods(['generateCondition']) - ->getMock(); - $this->conditionManager->expects($this->any()) - ->method('generateCondition') - ->willReturnCallback( - function ($field, $operator, $value) { - return sprintf('%s %s \'%s\'', $field, $operator, $value); - } - ); - - $this->filter = $objectManager->getObject( - Range::class, - [ - 'conditionManager' => $this->conditionManager, - ] - ); - } - - /** - * @param string $field - * @param string $from - * @param string $to - * @param bool $isNegation - * @param string $expectedResult - * @dataProvider buildQueryDataProvider - */ - public function testBuildQuery($field, $from, $to, $isNegation, $expectedResult) - { - $this->requestFilter->expects($this->any()) - ->method('getField') - ->willReturn($field); - $this->requestFilter->expects($this->atLeastOnce()) - ->method('getFrom') - ->willReturn($from); - $this->requestFilter->expects($this->atLeastOnce()) - ->method('getTo') - ->willReturn($to); - - $actualResult = $this->filter->buildFilter($this->requestFilter, $isNegation); - $this->assertEquals($expectedResult, $actualResult); - } - - /** - * Data provider for BuildQuery - * - * @return array - */ - public function buildQueryDataProvider() - { - return [ - 'rangeWithStrings' => [ - 'field' => 'testField', - 'from' => '0', - 'to' => '10', - 'isNegation' => false, - 'expectedResult' => 'testField >= \'0\' AND testField <= \'10\'', - ], - 'rangeWithIntegers' => [ - 'field' => 'testField', - 'from' => 50, - 'to' => 50, - 'isNegation' => false, - 'expectedResult' => 'testField >= \'50\' AND testField <= \'50\'', - ], - 'rangeWithFloats' => [ - 'field' => 'testField', - 'from' => 50.5, - 'to' => 55.5, - 'isNegation' => false, - 'expectedResult' => 'testField >= \'50.5\' AND testField <= \'55.5\'', - ], - 'rangeWithStringsNegative' => [ - 'field' => 'testField', - 'from' => '0', - 'to' => '10', - 'isNegation' => true, - 'expectedResult' => 'testField < \'0\' OR testField > \'10\'', - ], - 'rangeWithoutFromValue' => [ - 'field' => 'testField', - 'from' => null, - 'to' => 50, - 'isNegation' => false, - 'expectedResult' => 'testField <= \'50\'', - ], - 'rangeWithoutFromValueNegative' => [ - 'field' => 'testField', - 'from' => null, - 'to' => 50, - 'isNegation' => true, - 'expectedResult' => 'testField > \'50\'', - ], - 'rangeWithoutToValue' => [ - 'field' => 'testField', - 'from' => 50, - 'to' => null, - 'isNegation' => false, - 'expectedResult' => 'testField >= \'50\'', - ], - 'rangeWithoutToValueNegative' => [ - 'field' => 'testField', - 'from' => 50, - 'to' => null, - 'isNegation' => true, - 'expectedResult' => 'testField < \'50\'', - ], - 'rangeWithEmptyValues' => [ - 'field' => 'testField', - 'from' => null, - 'to' => null, - 'isNegation' => false, - 'expectedResult' => '', - ], - 'rangeWithEmptyValuesNegative' => [ - 'field' => 'testField', - 'from' => null, - 'to' => null, - 'isNegation' => true, - 'expectedResult' => '', - ], - ]; - } -} diff --git a/lib/internal/Magento/Framework/Search/Test/Unit/Adapter/Mysql/Filter/Builder/TermTest.php b/lib/internal/Magento/Framework/Search/Test/Unit/Adapter/Mysql/Filter/Builder/TermTest.php deleted file mode 100644 index 13e341787e3a8..0000000000000 --- a/lib/internal/Magento/Framework/Search/Test/Unit/Adapter/Mysql/Filter/Builder/TermTest.php +++ /dev/null @@ -1,123 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -declare(strict_types=1); - -namespace Magento\Framework\Search\Test\Unit\Adapter\Mysql\Filter\Builder; - -use Magento\Framework\Search\Adapter\Mysql\ConditionManager; -use Magento\Framework\Search\Request\Filter\Term; -use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; -use PHPUnit\Framework\MockObject\MockObject; -use PHPUnit\Framework\TestCase; - -class TermTest extends TestCase -{ - /** - * @var Term|MockObject - */ - private $requestFilter; - - /** - * @var \Magento\Framework\Search\Adapter\Mysql\Filter\Builder\Term - */ - private $filter; - - /** - * @var ConditionManager|MockObject - */ - private $conditionManager; - - /** - * Set up - */ - protected function setUp(): void - { - $objectManager = new ObjectManager($this); - $this->requestFilter = $this->getMockBuilder(Term::class) - ->setMethods(['getField', 'getValue']) - ->disableOriginalConstructor() - ->getMock(); - - $this->conditionManager = $this->getMockBuilder(ConditionManager::class) - ->disableOriginalConstructor() - ->setMethods(['generateCondition']) - ->getMock(); - $this->conditionManager->expects($this->any()) - ->method('generateCondition') - ->willReturnCallback( - function ($field, $operator, $value) { - return sprintf( - is_array($value) ? '%s %s (%s)' : '%s %s %s', - $field, - $operator, - is_array($value) ? implode(', ', $value) : $value - ); - } - ); - - $this->filter = $objectManager->getObject( - \Magento\Framework\Search\Adapter\Mysql\Filter\Builder\Term::class, - [ - 'conditionManager' => $this->conditionManager, - ] - ); - } - - /** - * @param string $field - * @param string $value - * @param bool $isNegation - * @param string $expectedResult - * @dataProvider buildQueryDataProvider - */ - public function testBuildQuery($field, $value, $isNegation, $expectedResult) - { - $this->requestFilter->expects($this->once()) - ->method('getField') - ->willReturn($field); - $this->requestFilter->expects($this->atLeastOnce()) - ->method('getValue') - ->willReturn($value); - - $actualResult = $this->filter->buildFilter($this->requestFilter, $isNegation); - $this->assertEquals($expectedResult, $actualResult); - } - - /** - * Data provider for BuildQuery - * - * @return array - */ - public function buildQueryDataProvider() - { - return [ - 'positive' => [ - 'field' => 'testField', - 'value' => 'testValue', - 'isNegation' => false, - 'expectedResult' => 'testField = testValue', - ], - 'negative' => [ - 'field' => 'testField2', - 'value' => 'testValue2', - 'isNegation' => true, - 'expectedResult' => 'testField2 != testValue2', - ], - 'positiveIn' => [ - 'field' => 'testField2', - 'value' => ['testValue2'], - 'isNegation' => false, - 'expectedResult' => 'testField2 IN (testValue2)', - ], - 'negativeIn' => [ - 'field' => 'testField2', - 'value' => ['testValue2'], - 'isNegation' => true, - 'expectedResult' => 'testField2 NOT IN (testValue2)', - ] - ]; - } -} diff --git a/lib/internal/Magento/Framework/Search/Test/Unit/Adapter/Mysql/Filter/Builder/WildcardTest.php b/lib/internal/Magento/Framework/Search/Test/Unit/Adapter/Mysql/Filter/Builder/WildcardTest.php deleted file mode 100644 index 41463c38dab92..0000000000000 --- a/lib/internal/Magento/Framework/Search/Test/Unit/Adapter/Mysql/Filter/Builder/WildcardTest.php +++ /dev/null @@ -1,105 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -declare(strict_types=1); - -namespace Magento\Framework\Search\Test\Unit\Adapter\Mysql\Filter\Builder; - -use Magento\Framework\Search\Adapter\Mysql\ConditionManager; -use Magento\Framework\Search\Adapter\Mysql\Filter\Builder\Wildcard as WildcardBuilder; -use Magento\Framework\Search\Request\Filter\Term; -use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; -use PHPUnit\Framework\MockObject\MockObject; -use PHPUnit\Framework\TestCase; - -class WildcardTest extends TestCase -{ - /** - * @var \Magento\Framework\Search\Request\Filter\Wildcard|MockObject - */ - private $requestFilter; - - /** - * @var WildcardBuilder - */ - private $filter; - - /** - * @var ConditionManager|MockObject - */ - private $conditionManager; - - /** - * Set up - */ - protected function setUp(): void - { - $objectManager = new ObjectManager($this); - $this->requestFilter = $this->getMockBuilder(Term::class) - ->setMethods(['getField', 'getValue']) - ->disableOriginalConstructor() - ->getMock(); - - $this->conditionManager = $this->getMockBuilder(ConditionManager::class) - ->disableOriginalConstructor() - ->setMethods(['generateCondition']) - ->getMock(); - $this->conditionManager->expects($this->any()) - ->method('generateCondition') - ->willReturnCallback( - function ($field, $operator, $value) { - return sprintf('%s %s %s', $field, $operator, $value); - } - ); - - $this->filter = $objectManager->getObject( - WildcardBuilder::class, - [ - 'conditionManager' => $this->conditionManager, - ] - ); - } - - /** - * @param string $field - * @param string $value - * @param $isNegation - * @param string $expectedResult - * @dataProvider buildQueryDataProvider - */ - public function testBuildQuery($field, $value, $isNegation, $expectedResult) - { - $this->requestFilter->expects($this->once()) - ->method('getField') - ->willReturn($field); - $this->requestFilter->expects($this->once())->method('getValue')->willReturn($value); - - $actualResult = $this->filter->buildFilter($this->requestFilter, $isNegation); - $this->assertEquals($expectedResult, $actualResult); - } - - /** - * Data provider for BuildQuery - * - * @return array - */ - public function buildQueryDataProvider() - { - return [ - 'positive' => [ - 'field' => 'testField', - 'value' => 'testValue', - 'isNegation' => false, - 'expectedResult' => "testField LIKE %testValue%", - ], - 'negative' => [ - 'field' => 'testField2', - 'value' => 'testValue2', - 'isNegation' => true, - 'expectedResult' => "testField2 NOT LIKE %testValue2%", - ], - ]; - } -} diff --git a/lib/internal/Magento/Framework/Search/Test/Unit/Adapter/Mysql/Filter/BuilderTest.php b/lib/internal/Magento/Framework/Search/Test/Unit/Adapter/Mysql/Filter/BuilderTest.php deleted file mode 100644 index 7769f62e47e29..0000000000000 --- a/lib/internal/Magento/Framework/Search/Test/Unit/Adapter/Mysql/Filter/BuilderTest.php +++ /dev/null @@ -1,414 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -declare(strict_types=1); - -namespace Magento\Framework\Search\Test\Unit\Adapter\Mysql\Filter; - -use Magento\Framework\DB\Adapter\AdapterInterface; -use Magento\Framework\DB\Select; -use Magento\Framework\Search\Adapter\Mysql\ConditionManager; -use Magento\Framework\Search\Adapter\Mysql\Filter\Builder; -use Magento\Framework\Search\Adapter\Mysql\Filter\Builder\Range; -use Magento\Framework\Search\Adapter\Mysql\Filter\Builder\Term; -use Magento\Framework\Search\Adapter\Mysql\Filter\PreprocessorInterface; -use Magento\Framework\Search\Request\FilterInterface; -use Magento\Framework\Search\Request\Query\BoolExpression as RequestBoolQuery; -use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; -use PHPUnit\Framework\MockObject\MockObject; -use PHPUnit\Framework\TestCase; - -/** - * @SuppressWarnings(PHPMD.CouplingBetweenObjects) - */ -class BuilderTest extends TestCase -{ - /** - * @var Builder - */ - private $builder; - - /** - * @var MockObject|PreprocessorInterface - */ - private $preprocessor; - - /** - * @var ConditionManager|MockObject - */ - private $conditionManager; - - /** - * @SuppressWarnings(PHPMD.NPathComplexity) - * @SuppressWarnings(PHPMD.ExcessiveMethodLength) - */ - protected function setUp(): void - { - $objectManager = new ObjectManager($this); - - $this->conditionManager = $this->getMockBuilder(ConditionManager::class) - ->disableOriginalConstructor() - ->setMethods(['generateCondition', 'combineQueries', 'wrapBrackets']) - ->getMock(); - $this->conditionManager->expects($this->any()) - ->method('generateCondition') - ->willReturnCallback( - function ($field, $operator, $value) { - return sprintf('%s %s %s', $field, $operator, $value); - } - ); - $this->conditionManager->expects($this->any()) - ->method('combineQueries') - ->willReturnCallback( - function ($queries, $operator) { - return implode( - ' ' . $operator . ' ', - array_filter($queries, 'strlen') - ); - } - ); - $this->conditionManager->expects($this->any()) - ->method('wrapBrackets') - ->willReturnCallback( - function ($query) { - return !empty($query) ? sprintf('(%s)', $query) : ''; - } - ); - - $rangeBuilder = $this->getMockBuilder(Range::class) - ->setMethods(['buildFilter']) - ->disableOriginalConstructor() - ->getMock(); - $rangeBuilder->expects($this->any()) - ->method('buildFilter') - ->willReturnCallback( - function (FilterInterface $filter, $isNegation) { - /** - * @var \Magento\Framework\Search\Request\Filter\Range $filter - * @var AdapterInterface $adapter - */ - $fromCondition = ''; - if ($filter->getFrom() !== null) { - $fromCondition = $this->conditionManager->generateCondition( - $filter->getField(), - ($isNegation ? '<' : '>='), - $filter->getFrom() - ); - } - $toCondition = ''; - if ($filter->getTo() !== null) { - $toCondition = $this->conditionManager->generateCondition( - $filter->getField(), - ($isNegation ? '>=' : '<'), - $filter->getTo() - ); - } - $unionOperator = $isNegation ? Select::SQL_OR : Select::SQL_AND; - - return $this->conditionManager->combineQueries([$fromCondition, $toCondition], $unionOperator); - } - ); - - $termBuilder = $this->getMockBuilder(Term::class) - ->setMethods(['buildFilter']) - ->disableOriginalConstructor() - ->getMock(); - $termBuilder->expects($this->any()) - ->method('buildFilter') - ->willReturnCallback( - function (FilterInterface $filter, $isNegation) { - /** - * @var \Magento\Framework\Search\Request\Filter\Term $filter - * @var AdapterInterface $adapter - */ - return $this->conditionManager->generateCondition( - $filter->getField(), - ($isNegation ? '!=' : '='), - $filter->getValue() - ); - } - ); - - $this->preprocessor = $this->getMockBuilder( - PreprocessorInterface::class - ) - ->setMethods(['process']) - ->disableOriginalConstructor() - ->getMockForAbstractClass(); - $this->preprocessor->expects($this->any())->method('process')->willReturnCallback( - function ($filter, $isNegation, $queryString) { - return $this->conditionManager->wrapBrackets($queryString); - } - ); - - $this->builder = $objectManager->getObject( - Builder::class, - [ - 'range' => $rangeBuilder, - 'term' => $termBuilder, - 'conditionManager' => $this->conditionManager, - 'preprocessor' => $this->preprocessor - ] - ); - } - - /** - * @param FilterInterface|MockObject $filter - * @param string $conditionType - * @param string $expectedResult - * @dataProvider buildFilterDataProvider - */ - public function testBuildFilter($filter, $conditionType, $expectedResult) - { - $actualResult = $this->builder->build($filter, $conditionType); - $this->assertEquals($expectedResult, $actualResult); - } - - /** - * @return array - */ - public function buildFilterDataProvider() - { - return array_merge( - $this->buildTermFilterDataProvider(), - $this->buildRangeFilterDataProvider(), - $this->buildBoolFilterDataProvider() - ); - } - - /** - * @return array - */ - public function buildTermFilterDataProvider() - { - return [ - 'termFilter' => [ - 'filter' => $this->createTermFilter('term1', 123), - 'conditionType' => RequestBoolQuery::QUERY_CONDITION_MUST, - 'expectedResult' => '(term1 = 123)', - ], - 'termFilterNegative' => [ - 'filter' => $this->createTermFilter('term1', 123), - 'conditionType' => RequestBoolQuery::QUERY_CONDITION_NOT, - 'expectedResult' => '(term1 != 123)', - ], - ]; - } - - /** - * @param $field - * @param $value - * @return \Magento\Framework\Search\Request\Filter\BoolExpression|MockObject - */ - private function createTermFilter($field, $value) - { - $filter = $this->getMockBuilder(\Magento\Framework\Search\Request\Filter\Term::class) - ->setMethods(['getField', 'getValue']) - ->disableOriginalConstructor() - ->getMock(); - - $filter->expects($this->exactly(1)) - ->method('getField') - ->willReturn($field); - $filter->expects($this->once()) - ->method('getValue') - ->willReturn($value); - return $filter; - } - - /** - * Data provider for BuildFilter - * - * @return array - */ - public function buildRangeFilterDataProvider() - { - return [ - 'rangeFilter' => [ - 'filter' => $this->createRangeFilter('range1', 0, 10), - 'conditionType' => RequestBoolQuery::QUERY_CONDITION_MUST, - 'expectedResult' => '(range1 >= 0 AND range1 < 10)', - ], - 'rangeFilterNegative' => [ - 'filter' => $this->createRangeFilter('range1', 0, 10), - 'conditionType' => RequestBoolQuery::QUERY_CONDITION_NOT, - 'expectedResult' => '(range1 < 0 OR range1 >= 10)', - ] - - ]; - } - - /** - * @param $field - * @param $from - * @param $to - * @return \Magento\Framework\Search\Request\Filter\BoolExpression|MockObject - */ - private function createRangeFilter($field, $from, $to) - { - $filter = $this->getMockBuilder(\Magento\Framework\Search\Request\Filter\Range::class) - ->setMethods(['getField', 'getFrom', 'getTo']) - ->disableOriginalConstructor() - ->getMock(); - - $filter->expects($this->exactly(2)) - ->method('getField') - ->willReturn($field); - $filter->expects($this->atLeastOnce()) - ->method('getFrom') - ->willReturn($from); - $filter->expects($this->atLeastOnce()) - ->method('getTo') - ->willReturn($to); - return $filter; - } - - /** - * @return array - * - * @SuppressWarnings(PHPMD.ExcessiveMethodLength) - */ - public function buildBoolFilterDataProvider() - { - return [ - 'boolFilterWithMust' => [ - 'filter' => $this->createBoolFilter( - [ //must - $this->createTermFilter('term1', 1), - $this->createRangeFilter('range1', 0, 10), - ], - [], //should - [] // mustNot - ), - 'conditionType' => RequestBoolQuery::QUERY_CONDITION_MUST, - 'expectedResult' => '(((term1 = 1)) AND ((range1 >= 0 AND range1 < 10)))', - ], - 'boolFilterWithShould' => [ - 'filter' => $this->createBoolFilter( - [], //must - [ //should - $this->createTermFilter('term1', 1), - $this->createRangeFilter('range1', 0, 10), - ], - [] // mustNot - ), - 'conditionType' => RequestBoolQuery::QUERY_CONDITION_MUST, - 'expectedResult' => '((((term1 = 1)) OR ((range1 >= 0 AND range1 < 10))))', - ], - 'boolFilterWithMustNot' => [ - 'filter' => $this->createBoolFilter( - [], //must - [], //should - [ // mustNot - $this->createTermFilter('term1', 1), - $this->createRangeFilter('range1', 0, 10), - ] - ), - 'conditionType' => RequestBoolQuery::QUERY_CONDITION_MUST, - 'expectedResult' => '((((term1 != 1)) AND ((range1 < 0 OR range1 >= 10))))', - ], - 'boolFilterWithAllFields' => [ - 'filter' => $this->createBoolFilter( - [ //must - $this->createTermFilter('term1', 1), - $this->createRangeFilter('range1', 0, 10), - ], - [ //should - $this->createTermFilter('term2', 1), - $this->createRangeFilter('range2', 0, 10), - ], - [ // mustNot - $this->createTermFilter('term3', 1), - $this->createRangeFilter('range3', 0, 10), - ] - ), - 'conditionType' => RequestBoolQuery::QUERY_CONDITION_MUST, - 'expectedResult' => '(((term1 = 1)) AND ((range1 >= 0 AND range1 < 10))' - . ' AND (((term2 = 1)) OR ((range2 >= 0 AND range2 < 10)))' - . ' AND (((term3 != 1)) AND ((range3 < 0 OR range3 >= 10))))' - ], - 'boolFilterInBoolFilter' => [ - 'filter' => $this->createBoolFilter( - [ //must - $this->createTermFilter('term1', 1), - $this->createRangeFilter('range1', 0, 10), - ], - [ //should - $this->createTermFilter('term2', 1), - $this->createRangeFilter('range2', 0, 10), - ], - [ // mustNot - $this->createTermFilter('term3', 1), - $this->createRangeFilter('range3', 0, 10), - $this->createBoolFilter( - [ //must - $this->createTermFilter('term4', 1), - $this->createRangeFilter('range4', 0, 10), - ], - [ //should - $this->createTermFilter('term5', 1), - $this->createRangeFilter('range5', 0, 10), - ], - [ // mustNot - $this->createTermFilter('term6', 1), - $this->createRangeFilter('range6', 0, 10), - ] - ), - ] - ), - 'conditionType' => RequestBoolQuery::QUERY_CONDITION_MUST, - 'expectedResult' => '(((term1 = 1)) AND ((range1 >= 0 AND range1 < 10))' - . ' AND (((term2 = 1)) OR ((range2 >= 0 AND range2 < 10)))' - . ' AND (((term3 != 1)) AND ((range3 < 0 OR range3 >= 10))' - . ' AND ((((term4 != 1)) AND ((range4 < 0 OR range4 >= 10))' - . ' AND (((term5 != 1)) OR ((range5 < 0 OR range5 >= 10)))' - . ' AND (((term6 = 1)) AND ((range6 >= 0 AND range6 < 10)))))))', - ], - 'boolEmpty' => [ - 'filter' => $this->createBoolFilter([], [], []), - 'conditionType' => RequestBoolQuery::QUERY_CONDITION_MUST, - 'expectedResult' => '', - ] - ]; - } - - /** - * @param array $must - * @param array $should - * @param array $mustNot - * @return \Magento\Framework\Search\Request\Filter\BoolExpression|MockObject - */ - private function createBoolFilter(array $must, array $should, array $mustNot) - { - $filter = $this->getMockBuilder(\Magento\Framework\Search\Request\Filter\BoolExpression::class) - ->setMethods(['getMust', 'getShould', 'getMustNot']) - ->disableOriginalConstructor() - ->getMock(); - - $filter->expects($this->once()) - ->method('getMust') - ->willReturn($must); - $filter->expects($this->once()) - ->method('getShould') - ->willReturn($should); - $filter->expects($this->once()) - ->method('getMustNot') - ->willReturn($mustNot); - return $filter; - } - - public function testUnknownFilterType() - { - $this->expectException('InvalidArgumentException'); - /** @var FilterInterface|MockObject $filter */ - $filter = $this->getMockBuilder(FilterInterface::class) - ->setMethods(['getType']) - ->getMockForAbstractClass(); - $filter->expects($this->any()) - ->method('getType') - ->willReturn('unknownType'); - $this->builder->build($filter, RequestBoolQuery::QUERY_CONDITION_MUST); - } -} diff --git a/lib/internal/Magento/Framework/Search/Test/Unit/Adapter/Mysql/MapperTest.php b/lib/internal/Magento/Framework/Search/Test/Unit/Adapter/Mysql/MapperTest.php deleted file mode 100644 index aa74e7037c604..0000000000000 --- a/lib/internal/Magento/Framework/Search/Test/Unit/Adapter/Mysql/MapperTest.php +++ /dev/null @@ -1,573 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -declare(strict_types=1); - -namespace Magento\Framework\Search\Test\Unit\Adapter\Mysql; - -use Magento\Framework\App\ResourceConnection; -use Magento\Framework\DB\Adapter\AdapterInterface; -use Magento\Framework\DB\Ddl\Table; -use Magento\Framework\DB\Select; -use Magento\Framework\Search\Adapter\Mysql\Filter\Builder; -use Magento\Framework\Search\Adapter\Mysql\IndexBuilderInterface; -use Magento\Framework\Search\Adapter\Mysql\Mapper; -use Magento\Framework\Search\Adapter\Mysql\Query\Builder\Match; -use Magento\Framework\Search\Adapter\Mysql\Query\MatchContainer; -use Magento\Framework\Search\Adapter\Mysql\Query\QueryContainer; -use Magento\Framework\Search\Adapter\Mysql\Query\QueryContainerFactory; -use Magento\Framework\Search\Adapter\Mysql\ScoreBuilder; -use Magento\Framework\Search\Adapter\Mysql\ScoreBuilderFactory; -use Magento\Framework\Search\Adapter\Mysql\TemporaryStorage; -use Magento\Framework\Search\Adapter\Mysql\TemporaryStorageFactory; -use Magento\Framework\Search\EntityMetadata; -use Magento\Framework\Search\Request\FilterInterface; -use Magento\Framework\Search\Request\Query\BoolExpression; -use Magento\Framework\Search\Request\Query\Filter; -use Magento\Framework\Search\Request\Query\Match as SearchQueryMatch; -use Magento\Framework\Search\Request\QueryInterface; -use Magento\Framework\Search\RequestInterface; -use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; -use PHPUnit\Framework\MockObject\MockObject; -use PHPUnit\Framework\TestCase; - -/** - * @SuppressWarnings(PHPMD.CouplingBetweenObjects) - */ -class MapperTest extends TestCase -{ - const INDEX_NAME = 'test_index_fulltext'; - const REQUEST_LIMIT = 120321; - const METADATA_ENTITY_ID = 'some_entity_id'; - - /** - * @var AdapterInterface|\PHPUnit\Framework\MockObject\MockObject - */ - private $connectionAdapter; - - /** - * @var IndexBuilderInterface|MockObject - */ - private $indexBuilder; - - /** - * @var TemporaryStorage|MockObject - */ - private $temporaryStorage; - - /** - * @var Match|MockObject - */ - private $matchBuilder; - - /** - * @var RequestInterface|MockObject - */ - private $request; - - /** - * @var ScoreBuilder|MockObject - */ - private $scoreBuilder; - - /** - * @var ScoreBuilderFactory|MockObject - */ - private $scoreBuilderFactory; - - /** - * @var ResourceConnection|MockObject - */ - private $resource; - - /** - * @var Match|MockObject - */ - private $queryContainer; - - /** - * @var Builder|MockObject - */ - private $filterBuilder; - - /** - * @var Mapper - */ - private $mapper; - - protected function setUp(): void - { - $this->connectionAdapter = $this->getMockBuilder(AdapterInterface::class) - ->setMethods(['select', 'dropTable']) - ->disableOriginalConstructor() - ->getMockForAbstractClass(); - - $this->resource = $this->getMockBuilder(ResourceConnection::class) - ->disableOriginalConstructor() - ->getMock(); - $this->resource->expects($this->any())->method('getConnection') - ->willReturn($this->connectionAdapter); - - $this->request = $this->getMockBuilder(RequestInterface::class) - ->setMethods(['getQuery', 'getIndex', 'getSize']) - ->disableOriginalConstructor() - ->getMockForAbstractClass(); - $this->request->expects($this->any()) - ->method('getIndex') - ->willReturn(self::INDEX_NAME); - - $this->queryContainer = $this->getMockBuilder( - QueryContainer::class - ) - ->setMethods(['addMatchQuery', 'getMatchQueries']) - ->disableOriginalConstructor() - ->getMock(); - $this->queryContainer->expects($this->any()) - ->method('addMatchQuery') - ->willReturnArgument(0); - - $this->temporaryStorage = $this->getMockBuilder(TemporaryStorage::class) - ->setMethods(['storeDocumentsFromSelect']) - ->disableOriginalConstructor() - ->getMock(); - } - - public function testBuildMatchQuery() - { - $query = $this->createMatchQuery(); - - $select = $this->createSelectMock(null, false, false); - $this->mockBuilders($select); - $parentSelect = $this->createSelectMock($select, true); - $this->addSelects([$parentSelect]); - - $this->request->expects($this->once()) - ->method('getSize') - ->willReturn(self::REQUEST_LIMIT); - - $this->queryContainer->expects($this->once()) - ->method('getMatchQueries') - ->willReturn([]); - - $this->queryContainer->expects($this->any())->method('addMatchQuery') - ->with( - $select, - $query, - BoolExpression::QUERY_CONDITION_MUST - ) - ->willReturn($select); - - $this->request->expects($this->once())->method('getQuery')->willReturn($query); - - $select->expects($this->any())->method('columns')->willReturnSelf(); - - $response = $this->mapper->buildQuery($this->request); - - $this->assertEquals($select, $response); - } - - public function testBuildFilterQuery() - { - $query = $this->createFilterQuery(Filter::REFERENCE_FILTER, $this->createFilter()); - - $select = $this->createSelectMock(null, false, false); - $this->mockBuilders($select); - $parentSelect = $this->createSelectMock($select, true); - $this->addSelects([$parentSelect]); - - $this->request->expects($this->once()) - ->method('getSize') - ->willReturn(self::REQUEST_LIMIT); - - $select->expects($this->any())->method('columns')->willReturnSelf(); - - $this->request->expects($this->once())->method('getQuery')->willReturn($query); - - $this->filterBuilder->expects($this->once())->method('build')->willReturn('(1)'); - - $response = $this->mapper->buildQuery($this->request); - - $this->assertEquals($select, $response); - } - - /** - * @param $query - * @param array $derivedQueries - * @param int $queriesCount - * @throws \Exception - * @dataProvider buildQueryDataProvider - */ - public function testBuildQuery($query, array $derivedQueries = [], $queriesCount = 0) - { - $select = $this->createSelectMock(null, false, false); - - $this->mockBuilders($select); - - $previousSelect = $select; - $selects = []; - for ($i = $queriesCount; $i >= 0; $i--) { - $isLast = $i === 0; - $select = $this->createSelectMock($previousSelect, $isLast, true); - $previousSelect = $select; - $selects[] = $select; - } - - $this->addSelects($selects); - - $this->request->expects($this->once()) - ->method('getSize') - ->willReturn(self::REQUEST_LIMIT); - - $this->filterBuilder->expects($this->any())->method('build')->willReturn('(1)'); - - $table = $this->getMockBuilder(Table::class) - ->disableOriginalConstructor() - ->getMock(); - $this->temporaryStorage->expects($this->any()) - ->method('storeDocumentsFromSelect') - ->willReturn($table); - $table->expects($this->any()) - ->method('getName') - ->willReturn('table_name'); - - $this->queryContainer->expects($this->any()) - ->method('getMatchQueries') - ->willReturn($derivedQueries); - - $this->request->expects($this->once())->method('getQuery')->willReturn($query); - - $response = $this->mapper->buildQuery($this->request); - $this->assertEquals(end($selects), $response); - } - - /** - * @return array - */ - public function buildQueryDataProvider() - { - return [ - 'one' => [ - $this->createBoolQuery( - [ - $this->createMatchQuery(), - $this->createFilterQuery(Filter::REFERENCE_QUERY, $this->createMatchQuery()), - ], - [ - $this->createMatchQuery(), - $this->createFilterQuery(Filter::REFERENCE_FILTER, $this->createFilter()), - ], - [ - $this->createMatchQuery(), - $this->createFilterQuery(Filter::REFERENCE_FILTER, $this->createFilter()), - ] - ), - ], - 'two' => [ - $this->createBoolQuery( - [ - $this->createMatchQuery(), - $this->createMatchQuery(), - ], - [], - [] - ), - [ - $this->createMatchContainer( - $this->createMatchQuery(), - 'mustNot' - ), - ], - ], - 'three' => [ - $this->createBoolQuery( - [ - $this->createMatchQuery(), - $this->createMatchQuery(), - ], - [], - [] - ), - [ - $this->createMatchContainer( - $this->createMatchQuery(), - 'mustNot' - ), - $this->createMatchContainer( - $this->createMatchQuery(), - 'must' - ), - ], - 1 - ], - ]; - } - - public function testGetUnknownQueryType() - { - $this->expectException('InvalidArgumentException'); - $this->expectExceptionMessage('Unknown query type \'unknownQuery\''); - $select = $this->createSelectMock(null, false, false); - $this->mockBuilders($select); - $query = $this->getMockBuilder(QueryInterface::class) - ->setMethods(['getType']) - ->disableOriginalConstructor() - ->getMockForAbstractClass(); - $query->expects($this->exactly(2)) - ->method('getType') - ->willReturn('unknownQuery'); - $this->connectionAdapter->expects($this->never())->method('select'); - $this->connectionAdapter->expects($this->never())->method('dropTable'); - - $this->request->expects($this->once())->method('getQuery')->willReturn($query); - - $this->mapper->buildQuery($this->request); - } - - /** - * @param array $selects - */ - protected function addSelects(array $selects) - { - $this->connectionAdapter->method('select') - ->will(call_user_func_array([$this, 'onConsecutiveCalls'], $selects)); - } - - /** - * @param array $tables - */ - protected function addDroppedTables(array $tables) - { - $this->connectionAdapter->method('select') - ->will(call_user_func_array([$this, 'onConsecutiveCalls'], $tables)); - } - - /** - * @return MockObject|SearchQueryMatch - */ - private function createMatchQuery() - { - $query = $this->getMockBuilder(SearchQueryMatch::class) - ->setMethods(['getType']) - ->disableOriginalConstructor() - ->getMockForAbstractClass(); - $query->expects($this->once())->method('getType') - ->willReturn(QueryInterface::TYPE_MATCH); - return $query; - } - - /** - * @param string $referenceType - * @param mixed $reference - * @return MockObject|Filter - */ - private function createFilterQuery($referenceType, $reference) - { - $query = $this->getMockBuilder(Filter::class) - ->setMethods(['getType', 'getReferenceType', 'getReference']) - ->disableOriginalConstructor() - ->getMockForAbstractClass(); - $query->expects($this->exactly(1)) - ->method('getType') - ->willReturn(QueryInterface::TYPE_FILTER); - $query->expects($this->once())->method('getReferenceType') - ->willReturn($referenceType); - $query->expects($this->once())->method('getReference') - ->willReturn($reference); - return $query; - } - - /** - * @param array $must - * @param array $should - * @param array $mustNot - * @return BoolExpression|MockObject - */ - private function createBoolQuery(array $must, array $should, array $mustNot) - { - $query = $this->getMockBuilder(BoolExpression::class) - ->setMethods(['getMust', 'getShould', 'getMustNot', 'getType']) - ->disableOriginalConstructor() - ->getMockForAbstractClass(); - $query->expects($this->exactly(1)) - ->method('getType') - ->willReturn(QueryInterface::TYPE_BOOL); - $query->expects($this->once()) - ->method('getMust') - ->willReturn($must); - $query->expects($this->once()) - ->method('getShould') - ->willReturn($should); - $query->expects($this->once()) - ->method('getMustNot') - ->willReturn($mustNot); - return $query; - } - - /** - * @return MockObject|FilterInterface - */ - private function createFilter() - { - return $this->getMockBuilder(FilterInterface::class) - ->disableOriginalConstructor() - ->getMockForAbstractClass(); - } - - /** - * @param $request - * @param $conditionType - * @return MockObject|MatchContainer - */ - private function createMatchContainer($request, $conditionType) - { - $matchContainer = $this->getMockBuilder(MatchContainer::class) - ->setMethods(['getRequest', 'getConditionType']) - ->disableOriginalConstructor() - ->getMock(); - $matchContainer->expects($this->any()) - ->method('getRequest') - ->willReturn($request); - $matchContainer->expects($this->any()) - ->method('getConditionType') - ->willReturn($conditionType); - return $matchContainer; - } - - /** - * @param Select $select - */ - private function mockBuilders(Select $select) - { - $helper = new ObjectManager($this); - - $this->scoreBuilder = $this->getMockBuilder(ScoreBuilder::class) - ->setMethods(['clear']) - ->disableOriginalConstructor() - ->getMock(); - $this->scoreBuilderFactory = $this->getMockBuilder( - ScoreBuilderFactory::class - ) - ->setMethods(['create']) - ->disableOriginalConstructor() - ->getMock(); - $this->scoreBuilderFactory->expects($this->any())->method('create') - ->willReturn($this->scoreBuilder); - $this->filterBuilder = $this->getMockBuilder(Builder::class) - ->setMethods(['build']) - ->disableOriginalConstructor() - ->getMock(); - $this->matchBuilder = $this->getMockBuilder(Match::class) - ->setMethods(['build']) - ->disableOriginalConstructor() - ->getMock(); - $this->matchBuilder->expects($this->any()) - ->method('build') - ->willReturnArgument(1); - $this->indexBuilder = $this->getMockBuilder( - IndexBuilderInterface::class - ) - ->disableOriginalConstructor() - ->setMethods(['build']) - ->getMockForAbstractClass(); - $this->indexBuilder->expects($this->any()) - ->method('build') - ->willReturn($select); - $temporaryStorageFactory = $this->getMockBuilder( - TemporaryStorageFactory::class - ) - ->setMethods(['create']) - ->disableOriginalConstructor() - ->getMock(); - $temporaryStorageFactory->expects($this->any()) - ->method('create') - ->willReturn($this->temporaryStorage); - $queryContainerFactory = $this->getMockBuilder( - QueryContainerFactory::class - ) - ->setMethods(['create']) - ->disableOriginalConstructor() - ->getMock(); - $queryContainerFactory->expects($this->any()) - ->method('create') - ->willReturn($this->queryContainer); - $entityMetadata = $this->getMockBuilder(EntityMetadata::class) - ->setMethods(['getEntityId']) - ->disableOriginalConstructor() - ->getMock(); - $entityMetadata->expects($this->any()) - ->method('getEntityId') - ->willReturn(self::METADATA_ENTITY_ID); - $this->mapper = $helper->getObject( - Mapper::class, - [ - 'resource' => $this->resource, - 'scoreBuilderFactory' => $this->scoreBuilderFactory, - 'queryContainerFactory' => $queryContainerFactory, - 'filterBuilder' => $this->filterBuilder, - 'matchBuilder' => $this->matchBuilder, - 'indexProviders' => [self::INDEX_NAME => $this->indexBuilder], - 'temporaryStorageFactory' => $temporaryStorageFactory, - 'entityMetadata' => $entityMetadata, - ] - ); - } - - /** - * @param MockObject|Select|null $from - * @param bool $isInternal - * @param bool $isGrouped - * @return Select|MockObject - * @internal param bool $isOrderExpected - * @SuppressWarnings(PHPMD.NPathComplexity) - */ - private function createSelectMock(Select $from = null, $isInternal = true, $isGrouped = true) - { - $select = $this->getMockBuilder(Select::class) - ->setMethods(['group', 'limit', 'where', 'columns', 'from', 'join', 'joinInner', 'order']) - ->disableOriginalConstructor() - ->getMock(); - - if ($from) { - $select->expects($this->once()) - ->method('from') - ->with(['main_select' => $from]) - ->willReturnSelf(); - } - - $select->expects($this->any()) - ->method('limit') - ->with($isInternal ? self::REQUEST_LIMIT : 10000000000) - ->willReturnSelf(); - $select->expects($isInternal ? $this->exactly(2) : $this->never()) - ->method('order') - ->with( - $this->logicalOr( - 'relevance DESC', - 'entity_id DESC' - ) - ) - ->willReturnSelf(); - $select->expects($isGrouped ? $this->once() : $this->never()) - ->method('group') - ->with(self::METADATA_ENTITY_ID) - ->willReturnSelf(); - - return $select; - } - - public function testUnsupportedRelevanceCalculationMethod() - { - $this->expectException('LogicException'); - $this->expectExceptionMessage('Unsupported relevance calculation method used.'); - $helper = new ObjectManager($this); - $helper->getObject( - Mapper::class, - [ - 'indexProviders' => [], - 'relevanceCalculationMethod' => 'UNSUPPORTED' - ] - ); - } -} diff --git a/lib/internal/Magento/Framework/Search/Test/Unit/Adapter/Mysql/Query/Builder/MatchTest.php b/lib/internal/Magento/Framework/Search/Test/Unit/Adapter/Mysql/Query/Builder/MatchTest.php deleted file mode 100644 index 75b31a4934095..0000000000000 --- a/lib/internal/Magento/Framework/Search/Test/Unit/Adapter/Mysql/Query/Builder/MatchTest.php +++ /dev/null @@ -1,144 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -declare(strict_types=1); - -namespace Magento\Framework\Search\Test\Unit\Adapter\Mysql\Query\Builder; - -use Magento\Framework\DB\Helper\Mysql\Fulltext; -use Magento\Framework\DB\Select; -use Magento\Framework\Search\Adapter\Mysql\Field\FieldInterface; -use Magento\Framework\Search\Adapter\Mysql\Field\ResolverInterface; -use Magento\Framework\Search\Adapter\Mysql\Query\Builder\Match; -use Magento\Framework\Search\Adapter\Mysql\ScoreBuilder; -use Magento\Framework\Search\Adapter\Preprocessor\PreprocessorInterface; -use Magento\Framework\Search\Request\Query\BoolExpression; -use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; -use Magento\Search\Adapter\Query\Preprocessor\Synonyms; -use PHPUnit\Framework\MockObject\MockObject; -use PHPUnit\Framework\TestCase; - -class MatchTest extends TestCase -{ - /** - * @var ScoreBuilder|MockObject - */ - private $scoreBuilder; - - /** - * @var ResolverInterface|MockObject - */ - private $resolver; - - /** - * @var Match - */ - private $match; - - /** - * @var Fulltext|MockObject - */ - private $fulltextHelper; - - /** - * @var PreprocessorInterface|MockObject - */ - private $preprocessor; - - protected function setUp(): void - { - $helper = new ObjectManager($this); - - $this->scoreBuilder = $this->getMockBuilder(ScoreBuilder::class) - ->setMethods(['addCondition']) - ->disableOriginalConstructor() - ->getMock(); - - $this->resolver = $this->getMockBuilder(ResolverInterface::class) - ->setMethods(['resolve']) - ->disableOriginalConstructor() - ->getMockForAbstractClass(); - - $this->fulltextHelper = $this->getMockBuilder(Fulltext::class) - ->disableOriginalConstructor() - ->getMock(); - - $this->preprocessor = $this->getMockBuilder(Synonyms::class) - ->setMethods(['process']) - ->disableOriginalConstructor() - ->getMock(); - - $this->match = $helper->getObject( - Match::class, - [ - 'resolver' => $this->resolver, - 'fulltextHelper' => $this->fulltextHelper, - 'preprocessors' => [$this->preprocessor] - ] - ); - } - - public function testBuild() - { - /** @var Select|MockObject $select */ - $select = $this->getMockBuilder(Select::class) - ->setMethods(['getMatchQuery', 'match', 'where']) - ->disableOriginalConstructor() - ->getMock(); - $this->preprocessor->expects($this->once()) - ->method('process') - ->with('some_value ') - ->willReturn('some_value '); - $this->fulltextHelper->expects($this->once()) - ->method('getMatchQuery') - ->with(['some_field' => 'some_field'], '-some_value*') - ->willReturn('matchedQuery'); - $select->expects($this->once()) - ->method('where') - ->with('matchedQuery') - ->willReturnSelf(); - - $this->resolver->expects($this->once()) - ->method('resolve') - ->willReturnCallback(function ($fieldList) { - $resolvedFields = []; - foreach ($fieldList as $column) { - $field = $this->getMockBuilder(FieldInterface::class) - ->disableOriginalConstructor() - ->getMockForAbstractClass(); - $field->expects($this->any()) - ->method('getColumn') - ->willReturn($column); - $resolvedFields[] = $field; - } - return $resolvedFields; - }); - - /** @var \Magento\Framework\Search\Request\Query\Match|MockObject $query */ - $query = $this->getMockBuilder(\Magento\Framework\Search\Request\Query\Match::class) - ->setMethods(['getMatches', 'getValue']) - ->disableOriginalConstructor() - ->getMock(); - $query->expects($this->once()) - ->method('getValue') - ->willReturn('some_value '); - $query->expects($this->once()) - ->method('getMatches') - ->willReturn([['field' => 'some_field']]); - - $this->scoreBuilder->expects($this->once()) - ->method('addCondition'); - - $result = $this->match->build( - $this->scoreBuilder, - $select, - $query, - BoolExpression::QUERY_CONDITION_NOT, - [$this->preprocessor] - ); - - $this->assertEquals($select, $result); - } -} diff --git a/lib/internal/Magento/Framework/Search/Test/Unit/Adapter/Mysql/Query/QueryContainerTest.php b/lib/internal/Magento/Framework/Search/Test/Unit/Adapter/Mysql/Query/QueryContainerTest.php deleted file mode 100644 index 8fcbc7d2085ba..0000000000000 --- a/lib/internal/Magento/Framework/Search/Test/Unit/Adapter/Mysql/Query/QueryContainerTest.php +++ /dev/null @@ -1,89 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -declare(strict_types=1); - -namespace Magento\Framework\Search\Test\Unit\Adapter\Mysql\Query; - -use Magento\Framework\DB\Select; -use Magento\Framework\Search\Adapter\Mysql\Query\MatchContainerFactory; -use Magento\Framework\Search\Adapter\Mysql\Query\QueryContainer; -use Magento\Framework\Search\Request\Query\BoolExpression; -use Magento\Framework\Search\Request\QueryInterface; -use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; -use PHPUnit\Framework\MockObject\MockObject; -use PHPUnit\Framework\TestCase; - -class QueryContainerTest extends TestCase -{ - /** @var Select|MockObject */ - private $select; - - /** @var MatchContainerFactory|MockObject */ - private $matchContainerFactory; - - /** @var QueryInterface|MockObject */ - private $requestQuery; - - /** @var QueryContainer */ - private $queryContainer; - - protected function setUp(): void - { - $helper = new ObjectManager($this); - - $this->select = $this->getMockBuilder(Select::class) - ->disableOriginalConstructor() - ->getMock(); - - $this->matchContainerFactory = $this->getMockBuilder( - MatchContainerFactory::class - ) - ->setMethods(['create']) - ->disableOriginalConstructor() - ->getMock(); - - $this->requestQuery = $this->getMockBuilder(QueryInterface::class) - ->disableOriginalConstructor() - ->getMockForAbstractClass(); - - $this->queryContainer = $helper->getObject( - QueryContainer::class, - [ - 'matchContainerFactory' => $this->matchContainerFactory, - ] - ); - } - - public function testBuild() - { - $this->matchContainerFactory->expects($this->once())->method('create') - ->willReturn('asdf'); - - $result = $this->queryContainer->addMatchQuery( - $this->select, - $this->requestQuery, - BoolExpression::QUERY_CONDITION_MUST - ); - $this->assertEquals($this->select, $result); - } - - public function testGetDerivedQueries() - { - $this->matchContainerFactory->expects($this->once())->method('create') - ->willReturn('asdf'); - - $result = $this->queryContainer->addMatchQuery( - $this->select, - $this->requestQuery, - BoolExpression::QUERY_CONDITION_MUST - ); - $this->assertEquals($this->select, $result); - - $queries = $this->queryContainer->getMatchQueries(); - $this->assertCount(1, $queries); - $this->assertEquals('asdf', reset($queries)); - } -} diff --git a/lib/internal/Magento/Framework/Search/Test/Unit/Adapter/Mysql/ResponseFactoryTest.php b/lib/internal/Magento/Framework/Search/Test/Unit/Adapter/Mysql/ResponseFactoryTest.php deleted file mode 100644 index 4e01d8cadf501..0000000000000 --- a/lib/internal/Magento/Framework/Search/Test/Unit/Adapter/Mysql/ResponseFactoryTest.php +++ /dev/null @@ -1,80 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -declare(strict_types=1); - -namespace Magento\Framework\Search\Test\Unit\Adapter\Mysql; - -use Magento\Framework\ObjectManagerInterface; -use Magento\Framework\Search\Adapter\Mysql\DocumentFactory; -use Magento\Framework\Search\Adapter\Mysql\ResponseFactory; -use Magento\Framework\Search\Response\QueryResponse; -use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; -use PHPUnit\Framework\MockObject\MockObject; -use PHPUnit\Framework\TestCase; - -class ResponseFactoryTest extends TestCase -{ - /** - * @var ResponseFactory - */ - private $factory; - - /** - * @var DocumentFactory|MockObject - */ - private $documentFactory; - - /** - * @var ObjectManagerInterface|MockObject - */ - private $objectManager; - - protected function setUp(): void - { - $helper = new ObjectManager($this); - - $this->documentFactory = $this->getMockBuilder(DocumentFactory::class) - ->setMethods(['create']) - ->disableOriginalConstructor() - ->getMock(); - - $this->objectManager = $this->getMockForAbstractClass(ObjectManagerInterface::class); - - $this->factory = $helper->getObject( - ResponseFactory::class, - ['documentFactory' => $this->documentFactory, 'objectManager' => $this->objectManager] - ); - } - - public function testCreate() - { - $rawResponse = [ - 'documents' => [ - ['title' => 'oneTitle', 'description' => 'oneDescription'], - ['title' => 'twoTitle', 'description' => 'twoDescription'], - ], - 'aggregations' => [], - 'total' => 2 - ]; - - $this->documentFactory->expects($this->at(0))->method('create') - ->with($rawResponse['documents'][0]) - ->willReturn('document1'); - $this->documentFactory->expects($this->at(1))->method('create') - ->with($rawResponse['documents'][1]) - ->willReturn('document2'); - - $this->objectManager->expects($this->once())->method('create') - ->with( - QueryResponse::class, - ['documents' => ['document1', 'document2'], 'aggregations' => null, 'total' => 2] - ) - ->willReturn('QueryResponseObject'); - - $result = $this->factory->create($rawResponse); - $this->assertEquals('QueryResponseObject', $result); - } -} diff --git a/lib/internal/Magento/Framework/Search/Test/Unit/Adapter/Mysql/ScoreBuilderTest.php b/lib/internal/Magento/Framework/Search/Test/Unit/Adapter/Mysql/ScoreBuilderTest.php deleted file mode 100644 index 93d2bef336b4e..0000000000000 --- a/lib/internal/Magento/Framework/Search/Test/Unit/Adapter/Mysql/ScoreBuilderTest.php +++ /dev/null @@ -1,60 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -declare(strict_types=1); - -namespace Magento\Framework\Search\Test\Unit\Adapter\Mysql; - -use Magento\Framework\Search\Adapter\Mysql\ScoreBuilder; -use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; -use PHPUnit\Framework\TestCase; - -class ScoreBuilderTest extends TestCase -{ - public function testBuild() - { - /** @var ScoreBuilder $builder */ - $builder = (new ObjectManager($this))->getObject(ScoreBuilder::class); - - $builder->startQuery(); // start one query - - $builder->addCondition('someCondition1'); - - $builder->startQuery(); // start two query - - $builder->addCondition('someCondition2'); - $builder->addCondition('someCondition3'); - - $builder->startQuery(); // start three query - - $builder->addCondition('someCondition4'); - $builder->addCondition('someCondition5'); - - $builder->endQuery(10.1); // end three query - - $builder->startQuery(); // start four query - - $builder->addCondition('someCondition6'); - $builder->addCondition('someCondition7'); - - $builder->endQuery(10.2); // end four query - $builder->endQuery(10.3); // start two query - $builder->endQuery(10.4); // start one query - - $builder->startQuery(); - $builder->endQuery(1); - - $result = $builder->build(); - - $weightExpression = 'POW(2, ' . ScoreBuilder::WEIGHT_FIELD . ')'; - $expected = '((LEAST((someCondition1), 1000000) * %1$s + (LEAST((someCondition2), 1000000) * %1$s' - . ' + LEAST((someCondition3), 1000000) * %1$s + ' - . '(LEAST((someCondition4), 1000000) * %1$s + LEAST((someCondition5), 1000000) * %1$s) * 10.1' - . ' + (LEAST((someCondition6), 1000000) * %1$s + ' - . 'LEAST((someCondition7), 1000000) * %1$s) * 10.2) * 10.3) * 10.4 + (0)) AS ' . $builder->getScoreAlias(); - $expected = sprintf($expected, $weightExpression); - $this->assertEquals($expected, $result); - } -} diff --git a/lib/internal/Magento/Framework/Search/etc/requests.xsd b/lib/internal/Magento/Framework/Search/etc/requests.xsd index 7d277382b698f..5dea45ea41c96 100644 --- a/lib/internal/Magento/Framework/Search/etc/requests.xsd +++ b/lib/internal/Magento/Framework/Search/etc/requests.xsd @@ -225,6 +225,7 @@ <xs:simpleContent> <xs:extension base="xs:string"> <xs:attribute type="xs:string" name="field" use="required" /> + <xs:attribute type="xs:string" name="matchCondition" /> </xs:extension> </xs:simpleContent> </xs:complexType> diff --git a/lib/web/mage/adminhtml/browser.js b/lib/web/mage/adminhtml/browser.js index 3ca01dd5e0826..604680e0bf8d5 100644 --- a/lib/web/mage/adminhtml/browser.js +++ b/lib/web/mage/adminhtml/browser.js @@ -21,6 +21,7 @@ define([ windowId: 'modal_dialog_message', modalLoaded: false, targetElementId: false, + pathId: '', /** * @return {Number} @@ -61,6 +62,7 @@ define([ this.modal.modal('openModal'); this.setTargetElementId(options, url); + this.setPathId(url); $(window).trigger('reload.MediaGallery'); return; @@ -85,10 +87,18 @@ define([ this.modal.html(data).trigger('contentUpdated'); this.modalLoaded = true; this.setTargetElementId(options, url); + this.setPathId(url); }.bind(this)); }, + /** + * Setter for endcoded path id + */ + setPathId: function (url) { + this.pathId = url.match(/(&|\/|%26)current_tree_path(=|\/)([\s\S].*?)(\/|$)/)[3]; + }, + /** * Setter for targetElementId property * diff --git a/setup/src/Magento/Setup/Model/ConfigOptionsList/Cache.php b/setup/src/Magento/Setup/Model/ConfigOptionsList/Cache.php index ea0b35d7ffd63..72699c4acb0bd 100644 --- a/setup/src/Magento/Setup/Model/ConfigOptionsList/Cache.php +++ b/setup/src/Magento/Setup/Model/ConfigOptionsList/Cache.php @@ -3,6 +3,7 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); namespace Magento\Setup\Model\ConfigOptionsList; @@ -10,6 +11,7 @@ use Magento\Framework\App\DeploymentConfig; use Magento\Framework\Config\Data\ConfigData; use Magento\Framework\Config\File\ConfigFilePool; +use Magento\Framework\Setup\Option\FlagConfigOption; use Magento\Framework\Setup\Option\SelectConfigOption; use Magento\Framework\Setup\Option\TextConfigOption; use Magento\Setup\Validator\RedisConnectionValidator; @@ -20,7 +22,7 @@ class Cache implements ConfigOptionsListInterface { const INPUT_VALUE_CACHE_REDIS = 'redis'; - const CONFIG_VALUE_CACHE_REDIS = '\\Magento\\Framework\\Cache\\Backend\Redis'; + const CONFIG_VALUE_CACHE_REDIS = \Magento\Framework\Cache\Backend\Redis::class; const INPUT_KEY_CACHE_BACKEND = 'cache-backend'; const INPUT_KEY_CACHE_BACKEND_REDIS_SERVER = 'cache-backend-redis-server'; @@ -30,6 +32,7 @@ class Cache implements ConfigOptionsListInterface const INPUT_KEY_CACHE_BACKEND_REDIS_COMPRESS_DATA = 'cache-backend-redis-compress-data'; const INPUT_KEY_CACHE_BACKEND_REDIS_COMPRESSION_LIB = 'cache-backend-redis-compression-lib'; const INPUT_KEY_CACHE_ID_PREFIX = 'cache-id-prefix'; + const INPUT_KEY_CACHE_ALLOW_PARALLEL_CACHE_GENERATION = 'allow-parallel-generation'; const CONFIG_PATH_CACHE_BACKEND = 'cache/frontend/default/backend'; const CONFIG_PATH_CACHE_BACKEND_SERVER = 'cache/frontend/default/backend_options/server'; @@ -39,6 +42,7 @@ class Cache implements ConfigOptionsListInterface const CONFIG_PATH_CACHE_BACKEND_COMPRESS_DATA = 'cache/frontend/default/backend_options/compress_data'; const CONFIG_PATH_CACHE_BACKEND_COMPRESSION_LIB = 'cache/frontend/default/backend_options/compression_lib'; const CONFIG_PATH_CACHE_ID_PREFIX = 'cache/frontend/default/id_prefix'; + const CONFIG_PATH_ALLOW_PARALLEL_CACHE_GENERATION = 'cache/allow_parallel_generation'; /** * @var array @@ -50,6 +54,7 @@ class Cache implements ConfigOptionsListInterface self::INPUT_KEY_CACHE_BACKEND_REDIS_PASSWORD => '', self::INPUT_KEY_CACHE_BACKEND_REDIS_COMPRESS_DATA => '1', self::INPUT_KEY_CACHE_BACKEND_REDIS_COMPRESSION_LIB => '', + self::INPUT_KEY_CACHE_ALLOW_PARALLEL_CACHE_GENERATION => 'false', ]; /** @@ -69,6 +74,7 @@ class Cache implements ConfigOptionsListInterface self::INPUT_KEY_CACHE_BACKEND_REDIS_PASSWORD => self::CONFIG_PATH_CACHE_BACKEND_PASSWORD, self::INPUT_KEY_CACHE_BACKEND_REDIS_COMPRESS_DATA => self::CONFIG_PATH_CACHE_BACKEND_COMPRESS_DATA, self::INPUT_KEY_CACHE_BACKEND_REDIS_COMPRESSION_LIB => self::CONFIG_PATH_CACHE_BACKEND_COMPRESSION_LIB, + self::INPUT_KEY_CACHE_ALLOW_PARALLEL_CACHE_GENERATION => self::CONFIG_PATH_ALLOW_PARALLEL_CACHE_GENERATION, ]; /** @@ -141,6 +147,11 @@ public function getOptions() self::CONFIG_PATH_CACHE_ID_PREFIX, 'ID prefix for cache keys' ), + new FlagConfigOption( + self::INPUT_KEY_CACHE_ALLOW_PARALLEL_CACHE_GENERATION, + self::CONFIG_PATH_ALLOW_PARALLEL_CACHE_GENERATION, + 'Allow generate cache in non-blocking way' + ), ]; } diff --git a/setup/src/Magento/Setup/Model/ConfigOptionsList/PageCache.php b/setup/src/Magento/Setup/Model/ConfigOptionsList/PageCache.php index b97909fa5e791..69d5bb934f479 100644 --- a/setup/src/Magento/Setup/Model/ConfigOptionsList/PageCache.php +++ b/setup/src/Magento/Setup/Model/ConfigOptionsList/PageCache.php @@ -20,7 +20,7 @@ class PageCache implements ConfigOptionsListInterface { const INPUT_VALUE_PAGE_CACHE_REDIS = 'redis'; - const CONFIG_VALUE_PAGE_CACHE_REDIS = '\\Magento\\Framework\\Cache\\Backend\Redis'; + const CONFIG_VALUE_PAGE_CACHE_REDIS = \Magento\Framework\Cache\Backend\Redis::class; const INPUT_KEY_PAGE_CACHE_BACKEND = 'page-cache'; const INPUT_KEY_PAGE_CACHE_BACKEND_REDIS_SERVER = 'page-cache-redis-server'; diff --git a/setup/src/Magento/Setup/Test/Unit/Model/ConfigOptionsList/CacheTest.php b/setup/src/Magento/Setup/Test/Unit/Model/ConfigOptionsList/CacheTest.php index cf3030ce44195..0707f99d67976 100644 --- a/setup/src/Magento/Setup/Test/Unit/Model/ConfigOptionsList/CacheTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Model/ConfigOptionsList/CacheTest.php @@ -8,6 +8,7 @@ namespace Magento\Setup\Test\Unit\Model\ConfigOptionsList; use Magento\Framework\App\DeploymentConfig; +use Magento\Framework\Setup\Option\FlagConfigOption; use Magento\Framework\Setup\Option\SelectConfigOption; use Magento\Framework\Setup\Option\TextConfigOption; use Magento\Setup\Model\ConfigOptionsList\Cache as CacheConfigOptionsList; @@ -48,7 +49,7 @@ protected function setUp(): void public function testGetOptions() { $options = $this->configOptionsList->getOptions(); - $this->assertCount(8, $options); + $this->assertCount(9, $options); $this->assertArrayHasKey(0, $options); $this->assertInstanceOf(SelectConfigOption::class, $options[0]); @@ -81,6 +82,10 @@ public function testGetOptions() $this->assertArrayHasKey(7, $options); $this->assertInstanceOf(TextConfigOption::class, $options[7]); $this->assertEquals('cache-id-prefix', $options[7]->getName()); + + $this->assertArrayHasKey(8, $options); + $this->assertInstanceOf(FlagConfigOption::class, $options[8]); + $this->assertEquals('allow-parallel-generation', $options[8]->getName()); } /** @@ -94,7 +99,7 @@ public function testCreateConfigCacheRedis() 'cache' => [ 'frontend' => [ 'default' => [ - 'backend' => '\\Magento\\Framework\\Cache\\Backend\Redis', + 'backend' => \Magento\Framework\Cache\Backend\Redis::class, 'backend_options' => [ 'server' => '', 'port' => '', @@ -105,11 +110,13 @@ public function testCreateConfigCacheRedis() ], 'id_prefix' => $this->expectedIdPrefix(), ] - ] + ], + 'allow_parallel_generation' => '', ] ]; - $configData = $this->configOptionsList->createConfig(['cache-backend'=>'redis'], $this->deploymentConfigMock); + $configData = $this->configOptionsList + ->createConfig(['cache-backend' => 'redis'], $this->deploymentConfigMock); $this->assertEquals($expectedConfigData, $configData->getData()); } @@ -123,7 +130,7 @@ public function testCreateConfigWithRedisConfig() 'cache' => [ 'frontend' => [ 'default' => [ - 'backend' => '\\Magento\\Framework\\Cache\\Backend\Redis', + 'backend' => \Magento\Framework\Cache\Backend\Redis::class, 'backend_options' => [ 'server' => 'localhost', 'port' => '1234', @@ -134,7 +141,8 @@ public function testCreateConfigWithRedisConfig() ], 'id_prefix' => $this->expectedIdPrefix(), ] - ] + ], + 'allow_parallel_generation' => null, ] ]; @@ -211,7 +219,7 @@ public function testValidateWithValidInput() ]; $this->validatorMock->expects($this->once()) ->method('isValidConnection') - ->with(['host'=>'localhost', 'db'=>'', 'port'=>'', 'password'=>'']) + ->with(['host' => 'localhost', 'db' => '', 'port' => '', 'password' => '']) ->willReturn(true); $errors = $this->configOptionsList->validate($options, $this->deploymentConfigMock); diff --git a/setup/src/Magento/Setup/Test/Unit/Model/ConfigOptionsList/PageCacheTest.php b/setup/src/Magento/Setup/Test/Unit/Model/ConfigOptionsList/PageCacheTest.php index 7fc6444364ff6..0aa2ced6e0e34 100644 --- a/setup/src/Magento/Setup/Test/Unit/Model/ConfigOptionsList/PageCacheTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Model/ConfigOptionsList/PageCacheTest.php @@ -91,9 +91,9 @@ public function testCreateConfigWithRedis() 'cache' => [ 'frontend' => [ 'page_cache' => [ - 'backend' => '\\Magento\\Framework\\Cache\\Backend\Redis', + 'backend' => \Magento\Framework\Cache\Backend\Redis::class, 'backend_options' => [ - 'server'=> '', + 'server' => '', 'port' => '', 'database' => '', 'compress_data' => '', @@ -120,7 +120,7 @@ public function testCreateConfigWithRedisConfiguration() 'cache' => [ 'frontend' => [ 'page_cache' => [ - 'backend' => '\\Magento\\Framework\\Cache\\Backend\Redis', + 'backend' => \Magento\Framework\Cache\Backend\Redis::class, 'backend_options' => [ 'server' => 'foo.bar', 'port' => '9000',