Url.php 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. namespace Magento\Catalog\Model\ResourceModel;
  7. /**
  8. * Catalog url rewrite resource model
  9. *
  10. * @author Magento Core Team <core@magentocommerce.com>
  11. */
  12. use Magento\CatalogUrlRewrite\Model\ProductUrlRewriteGenerator;
  13. use Magento\Catalog\Api\Data\CategoryInterface;
  14. use Magento\Framework\EntityManager\MetadataPool;
  15. use Magento\Framework\App\ObjectManager;
  16. use Magento\Catalog\Model\Indexer\Category\Product\TableMaintainer;
  17. /**
  18. * Class Url
  19. * @package Magento\Catalog\Model\ResourceModel
  20. *
  21. * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  22. */
  23. class Url extends \Magento\Framework\Model\ResourceModel\Db\AbstractDb
  24. {
  25. /**
  26. * Stores configuration array
  27. *
  28. * @var array
  29. */
  30. protected $_stores;
  31. /**
  32. * Category attribute properties cache
  33. *
  34. * @var array
  35. */
  36. protected $_categoryAttributes = [];
  37. /**
  38. * Product attribute properties cache
  39. *
  40. * @var array
  41. */
  42. protected $_productAttributes = [];
  43. /**
  44. * Limit products for select
  45. *
  46. * @var int
  47. */
  48. protected $_productLimit = 250;
  49. /**
  50. * Cache of root category children ids
  51. *
  52. * @var array
  53. */
  54. protected $_rootChildrenIds = [];
  55. /**
  56. * @var \Psr\Log\LoggerInterface
  57. */
  58. protected $_logger;
  59. /**
  60. * Catalog category
  61. *
  62. * @var \Magento\Catalog\Model\Category
  63. */
  64. protected $_catalogCategory;
  65. /**
  66. * Catalog product
  67. *
  68. * @var \Magento\Catalog\Model\Product
  69. */
  70. protected $_catalogProduct;
  71. /**
  72. * Eav config
  73. *
  74. * @var \Magento\Eav\Model\Config
  75. */
  76. protected $_eavConfig;
  77. /**
  78. * Store manager
  79. *
  80. * @var \Magento\Store\Model\StoreManagerInterface
  81. */
  82. protected $_storeManager;
  83. /**
  84. * @var Product
  85. */
  86. protected $productResource;
  87. /**
  88. * @var MetadataPool
  89. */
  90. protected $metadataPool;
  91. /**
  92. * @var TableMaintainer
  93. */
  94. private $tableMaintainer;
  95. /**
  96. * Url constructor.
  97. * @param \Magento\Framework\Model\ResourceModel\Db\Context $context
  98. * @param \Magento\Store\Model\StoreManagerInterface $storeManager
  99. * @param \Magento\Eav\Model\Config $eavConfig
  100. * @param Product $productResource
  101. * @param \Magento\Catalog\Model\Category $catalogCategory
  102. * @param \Psr\Log\LoggerInterface $logger
  103. * @param null $connectionName
  104. * @param TableMaintainer|null $tableMaintainer
  105. */
  106. public function __construct(
  107. \Magento\Framework\Model\ResourceModel\Db\Context $context,
  108. \Magento\Store\Model\StoreManagerInterface $storeManager,
  109. \Magento\Eav\Model\Config $eavConfig,
  110. Product $productResource,
  111. \Magento\Catalog\Model\Category $catalogCategory,
  112. \Psr\Log\LoggerInterface $logger,
  113. $connectionName = null,
  114. TableMaintainer $tableMaintainer = null
  115. ) {
  116. $this->_storeManager = $storeManager;
  117. $this->_eavConfig = $eavConfig;
  118. $this->productResource = $productResource;
  119. $this->_catalogCategory = $catalogCategory;
  120. $this->_logger = $logger;
  121. parent::__construct($context, $connectionName);
  122. $this->tableMaintainer = $tableMaintainer ?: ObjectManager::getInstance()->get(TableMaintainer::class);
  123. }
  124. /**
  125. * Load core Url rewrite model
  126. *
  127. * @return void
  128. */
  129. protected function _construct()
  130. {
  131. $this->_init('url_rewrite', 'url_rewrite_id');
  132. }
  133. /**
  134. * Retrieve stores array or store model
  135. *
  136. * @param int $storeId
  137. * @return \Magento\Store\Model\Store|\Magento\Store\Model\Store[]
  138. */
  139. public function getStores($storeId = null)
  140. {
  141. if ($this->_stores === null) {
  142. $this->_stores = $this->_prepareStoreRootCategories($this->_storeManager->getStores());
  143. }
  144. if ($storeId && isset($this->_stores[$storeId])) {
  145. return $this->_stores[$storeId];
  146. }
  147. return $this->_stores;
  148. }
  149. /**
  150. * Retrieve category attributes
  151. *
  152. * @param string $attributeCode
  153. * @param int|array $categoryIds
  154. * @param int $storeId
  155. * @return array
  156. */
  157. protected function _getCategoryAttribute($attributeCode, $categoryIds, $storeId)
  158. {
  159. $linkField = $this->getMetadataPool()->getMetadata(CategoryInterface::class)->getLinkField();
  160. $identifierFiled = $this->getMetadataPool()->getMetadata(CategoryInterface::class)->getIdentifierField();
  161. $connection = $this->getConnection();
  162. if (!isset($this->_categoryAttributes[$attributeCode])) {
  163. $attribute = $this->_catalogCategory->getResource()->getAttribute($attributeCode);
  164. $this->_categoryAttributes[$attributeCode] = [
  165. 'entity_type_id' => $attribute->getEntityTypeId(),
  166. 'attribute_id' => $attribute->getId(),
  167. 'table' => $attribute->getBackend()->getTable(),
  168. 'is_global' => $attribute->getIsGlobal(),
  169. 'is_static' => $attribute->isStatic(),
  170. ];
  171. unset($attribute);
  172. }
  173. if (!is_array($categoryIds)) {
  174. $categoryIds = [$categoryIds];
  175. }
  176. $attributeTable = $this->_categoryAttributes[$attributeCode]['table'];
  177. $select = $connection->select();
  178. $bind = [];
  179. if ($this->_categoryAttributes[$attributeCode]['is_static']) {
  180. $select->from(
  181. $this->getTable('catalog_category_entity'),
  182. ['value' => $attributeCode, 'entity_id' => 'entity_id']
  183. )->where(
  184. 'entity_id IN(?)',
  185. $categoryIds
  186. );
  187. } elseif ($this->_categoryAttributes[$attributeCode]['is_global'] || $storeId == 0) {
  188. $select->from(
  189. ['t1' =>$this->getTable('catalog_category_entity')],
  190. [$identifierFiled]
  191. )->joinLeft(
  192. ['e' => $attributeTable],
  193. "t1.{$linkField} = e.{$linkField}",
  194. ['value']
  195. )->where(
  196. "t1.{$identifierFiled} IN(?)",
  197. $categoryIds
  198. )->where(
  199. 'e.attribute_id = :attribute_id'
  200. )->where(
  201. 'e.store_id = ?',
  202. 0
  203. );
  204. $bind['attribute_id'] = $this->_categoryAttributes[$attributeCode]['attribute_id'];
  205. } else {
  206. $valueExpr = $connection->getCheckSql('t2.value_id > 0', 't2.value', 't1.value');
  207. $select->from(
  208. ['t1' => $attributeTable],
  209. [$identifierFiled => 'e.'.$identifierFiled, 'value' => $valueExpr]
  210. )->joinLeft(
  211. ['t2' => $attributeTable],
  212. "t1.{$linkField} = t2.{$linkField} AND t1.attribute_id = t2.attribute_id AND t2.store_id = :store_id",
  213. []
  214. )->joinLeft(
  215. ['e' => $this->getTable('catalog_category_entity')],
  216. "e.{$linkField} = t1.{$linkField}",
  217. []
  218. )->where(
  219. 't1.store_id = ?',
  220. 0
  221. )->where(
  222. 't1.attribute_id = :attribute_id'
  223. )->where(
  224. "e.entity_id IN(?)",
  225. $categoryIds
  226. )->group('e.entity_id');
  227. $bind['attribute_id'] = $this->_categoryAttributes[$attributeCode]['attribute_id'];
  228. $bind['store_id'] = $storeId;
  229. }
  230. $rowSet = $connection->fetchAll($select, $bind);
  231. $attributes = [];
  232. foreach ($rowSet as $row) {
  233. $attributes[$row[$identifierFiled]] = $row['value'];
  234. }
  235. unset($rowSet);
  236. foreach ($categoryIds as $categoryId) {
  237. if (!isset($attributes[$categoryId])) {
  238. $attributes[$categoryId] = null;
  239. }
  240. }
  241. return $attributes;
  242. }
  243. /**
  244. * Retrieve product attribute
  245. *
  246. * @param string $attributeCode
  247. * @param int|array $productIds
  248. * @param string $storeId
  249. * @return array
  250. */
  251. public function _getProductAttribute($attributeCode, $productIds, $storeId)
  252. {
  253. $connection = $this->getConnection();
  254. if (!isset($this->_productAttributes[$attributeCode])) {
  255. $attribute = $this->productResource->getAttribute($attributeCode);
  256. $this->_productAttributes[$attributeCode] = [
  257. 'entity_type_id' => $attribute->getEntityTypeId(),
  258. 'attribute_id' => $attribute->getId(),
  259. 'table' => $attribute->getBackend()->getTable(),
  260. 'is_global' => $attribute->getIsGlobal(),
  261. ];
  262. unset($attribute);
  263. }
  264. if (!is_array($productIds)) {
  265. $productIds = [$productIds];
  266. }
  267. $bind = ['attribute_id' => $this->_productAttributes[$attributeCode]['attribute_id']];
  268. $select = $connection->select();
  269. $attributeTable = $this->_productAttributes[$attributeCode]['table'];
  270. if ($this->_productAttributes[$attributeCode]['is_global'] || $storeId == 0) {
  271. $select->from(
  272. $attributeTable,
  273. ['entity_id', 'value']
  274. )->where(
  275. 'attribute_id = :attribute_id'
  276. )->where(
  277. 'store_id = ?',
  278. 0
  279. )->where(
  280. 'entity_id IN(?)',
  281. $productIds
  282. );
  283. } else {
  284. $valueExpr = $connection->getCheckSql('t2.value_id > 0', 't2.value', 't1.value');
  285. $select->from(
  286. ['t1' => $attributeTable],
  287. ['entity_id', 'value' => $valueExpr]
  288. )->joinLeft(
  289. ['t2' => $attributeTable],
  290. 't1.entity_id = t2.entity_id AND t1.attribute_id = t2.attribute_id AND t2.store_id=:store_id',
  291. []
  292. )->where(
  293. 't1.store_id = ?',
  294. 0
  295. )->where(
  296. 't1.attribute_id = :attribute_id'
  297. )->where(
  298. 't1.entity_id IN(?)',
  299. $productIds
  300. );
  301. $bind['store_id'] = $storeId;
  302. }
  303. $rowSet = $connection->fetchAll($select, $bind);
  304. $attributes = [];
  305. foreach ($rowSet as $row) {
  306. $attributes[$row['entity_id']] = $row['value'];
  307. }
  308. unset($rowSet);
  309. foreach ($productIds as $productId) {
  310. if (!isset($attributes[$productId])) {
  311. $attributes[$productId] = null;
  312. }
  313. }
  314. return $attributes;
  315. }
  316. /**
  317. * Prepare category parentId
  318. *
  319. * @param \Magento\Framework\DataObject $category
  320. * @return $this
  321. */
  322. protected function _prepareCategoryParentId(\Magento\Framework\DataObject $category)
  323. {
  324. if ($category->getPath() != $category->getId()) {
  325. $split = explode('/', $category->getPath());
  326. $category->setParentId($split[count($split) - 2]);
  327. } else {
  328. $category->setParentId(0);
  329. }
  330. return $this;
  331. }
  332. /**
  333. * Prepare stores root categories
  334. *
  335. * @param \Magento\Store\Model\Store[] $stores
  336. * @return \Magento\Store\Model\Store[]
  337. */
  338. protected function _prepareStoreRootCategories($stores)
  339. {
  340. $rootCategoryIds = [];
  341. foreach ($stores as $store) {
  342. /* @var $store \Magento\Store\Model\Store */
  343. $rootCategoryIds[$store->getRootCategoryId()] = $store->getRootCategoryId();
  344. }
  345. if ($rootCategoryIds) {
  346. $categories = $this->_getCategories($rootCategoryIds);
  347. }
  348. foreach ($stores as $store) {
  349. /* @var $store \Magento\Store\Model\Store */
  350. $rootCategoryId = $store->getRootCategoryId();
  351. if (isset($categories[$rootCategoryId])) {
  352. $store->setRootCategoryPath($categories[$rootCategoryId]->getPath());
  353. $store->setRootCategory($categories[$rootCategoryId]);
  354. } else {
  355. unset($stores[$store->getId()]);
  356. }
  357. }
  358. return $stores;
  359. }
  360. /**
  361. * Retrieve categories objects
  362. * Either $categoryIds or $path (with ending slash) must be specified
  363. *
  364. * @param int|array $categoryIds
  365. * @param int $storeId
  366. * @param string $path
  367. * @return array
  368. * @SuppressWarnings(PHPMD.CyclomaticComplexity)
  369. * @SuppressWarnings(PHPMD.NPathComplexity)
  370. */
  371. protected function _getCategories($categoryIds, $storeId = null, $path = null)
  372. {
  373. $isActiveAttribute = $this->_eavConfig->getAttribute(\Magento\Catalog\Model\Category::ENTITY, 'is_active');
  374. $categories = [];
  375. $connection = $this->getConnection();
  376. $meta = $this->getMetadataPool()->getMetadata(CategoryInterface::class);
  377. $linkField = $meta->getLinkField();
  378. if (!is_array($categoryIds)) {
  379. $categoryIds = [$categoryIds];
  380. }
  381. $isActiveExpr = $connection->getCheckSql('c.value_id > 0', 'c.value', 'c.value');
  382. $select = $connection->select()->from(
  383. ['main_table' => $this->getTable('catalog_category_entity')],
  384. [
  385. 'main_table.entity_id',
  386. 'main_table.parent_id',
  387. 'main_table.level',
  388. 'is_active' => $isActiveExpr,
  389. 'main_table.path'
  390. ]
  391. );
  392. // Prepare variables for checking whether categories belong to store
  393. if ($path === null) {
  394. $select->where('main_table.entity_id IN(?)', $categoryIds);
  395. } else {
  396. // Ensure that path ends with '/', otherwise we can get wrong results - e.g. $path = '1/2' will get '1/20'
  397. if (substr($path, -1) != '/') {
  398. $path .= '/';
  399. }
  400. $select->where('main_table.path LIKE ?', $path . '%')->order('main_table.path');
  401. }
  402. $table = $this->getTable('catalog_category_entity_int');
  403. $select->joinLeft(
  404. ['d' => $table],
  405. "d.attribute_id = :attribute_id AND d.store_id = 0 AND d.{$linkField} = main_table.{$linkField}",
  406. []
  407. )->joinLeft(
  408. ['c' => $table],
  409. "c.attribute_id = :attribute_id AND c.store_id = :store_id AND c.{$linkField} = main_table.{$linkField}",
  410. []
  411. );
  412. if ($storeId !== null) {
  413. $rootCategoryPath = $this->getStores($storeId)->getRootCategoryPath();
  414. $rootCategoryPathLength = strlen($rootCategoryPath);
  415. }
  416. $bind = ['attribute_id' => (int)$isActiveAttribute->getId(), 'store_id' => (int)$storeId];
  417. $rowSet = $connection->fetchAll($select, $bind);
  418. foreach ($rowSet as $row) {
  419. if ($storeId !== null) {
  420. // Check the category to be either store's root or its descendant
  421. // First - check that category's start is the same as root category
  422. if (substr($row['path'], 0, $rootCategoryPathLength) != $rootCategoryPath) {
  423. continue;
  424. }
  425. // Second - check non-root category - that it's really a descendant, not a simple string match
  426. if (strlen($row['path']) > $rootCategoryPathLength && $row['path'][$rootCategoryPathLength] != '/') {
  427. continue;
  428. }
  429. }
  430. $category = new \Magento\Framework\DataObject($row);
  431. $category->setId($row['entity_id']);
  432. $category->setEntityId($row['entity_id']);
  433. $category->setStoreId($storeId);
  434. $this->_prepareCategoryParentId($category);
  435. $categories[$category->getId()] = $category;
  436. }
  437. unset($rowSet);
  438. if ($storeId !== null && $categories) {
  439. foreach (['name', 'url_key', 'url_path'] as $attributeCode) {
  440. $attributes = $this->_getCategoryAttribute(
  441. $attributeCode,
  442. array_keys($categories),
  443. $category->getStoreId()
  444. );
  445. foreach ($attributes as $categoryId => $attributeValue) {
  446. $categories[$categoryId]->setData($attributeCode, $attributeValue);
  447. }
  448. }
  449. }
  450. return $categories;
  451. }
  452. /**
  453. * Retrieve category data object
  454. *
  455. * @param int $categoryId
  456. * @param int $storeId
  457. * @return \Magento\Framework\DataObject|false
  458. */
  459. public function getCategory($categoryId, $storeId)
  460. {
  461. if (!$categoryId || !$storeId) {
  462. return false;
  463. }
  464. $categories = $this->_getCategories($categoryId, $storeId);
  465. if (isset($categories[$categoryId])) {
  466. return $categories[$categoryId];
  467. }
  468. return false;
  469. }
  470. /**
  471. * Retrieve categories data objects by their ids. Return only categories that belong to specified store.
  472. *
  473. * @param int|array $categoryIds
  474. * @param int $storeId
  475. * @return array|false
  476. */
  477. public function getCategories($categoryIds, $storeId)
  478. {
  479. if (!$categoryIds || !$storeId) {
  480. return false;
  481. }
  482. return $this->_getCategories($categoryIds, $storeId);
  483. }
  484. /**
  485. * Retrieve Product data objects
  486. *
  487. * @param int|array $productIds
  488. * @param int $storeId
  489. * @param int $entityId
  490. * @param int &$lastEntityId
  491. * @return array
  492. */
  493. protected function _getProducts($productIds, $storeId, $entityId, &$lastEntityId)
  494. {
  495. $products = [];
  496. $websiteId = $this->_storeManager->getStore($storeId)->getWebsiteId();
  497. $connection = $this->getConnection();
  498. if ($productIds !== null) {
  499. if (!is_array($productIds)) {
  500. $productIds = [$productIds];
  501. }
  502. }
  503. $bind = ['website_id' => (int)$websiteId, 'entity_id' => (int)$entityId];
  504. $select = $connection->select()->useStraightJoin(
  505. true
  506. )->from(
  507. ['e' => $this->getTable('catalog_product_entity')],
  508. ['entity_id']
  509. )->join(
  510. ['w' => $this->getTable('catalog_product_website')],
  511. 'e.entity_id = w.product_id AND w.website_id = :website_id',
  512. []
  513. )->where(
  514. 'e.entity_id > :entity_id'
  515. )->order(
  516. 'e.entity_id'
  517. )->limit(
  518. $this->_productLimit
  519. );
  520. if ($productIds !== null) {
  521. $select->where('e.entity_id IN(?)', $productIds);
  522. }
  523. $rowSet = $connection->fetchAll($select, $bind);
  524. foreach ($rowSet as $row) {
  525. $product = new \Magento\Framework\DataObject($row);
  526. $product->setId($row['entity_id']);
  527. $product->setEntityId($row['entity_id']);
  528. $product->setCategoryIds([]);
  529. $product->setStoreId($storeId);
  530. $products[$product->getId()] = $product;
  531. $lastEntityId = $product->getId();
  532. }
  533. unset($rowSet);
  534. if ($products) {
  535. $select = $connection->select()->from(
  536. $this->getTable('catalog_category_product'),
  537. ['product_id', 'category_id']
  538. )->where(
  539. 'product_id IN(?)',
  540. array_keys($products)
  541. );
  542. $categories = $connection->fetchAll($select);
  543. foreach ($categories as $category) {
  544. $productId = $category['product_id'];
  545. $categoryIds = $products[$productId]->getCategoryIds();
  546. $categoryIds[] = $category['category_id'];
  547. $products[$productId]->setCategoryIds($categoryIds);
  548. }
  549. foreach (['name', 'url_key', 'url_path'] as $attributeCode) {
  550. $attributes = $this->_getProductAttribute($attributeCode, array_keys($products), $storeId);
  551. foreach ($attributes as $productId => $attributeValue) {
  552. $products[$productId]->setData($attributeCode, $attributeValue);
  553. }
  554. }
  555. }
  556. return $products;
  557. }
  558. /**
  559. * Retrieve Product data object
  560. *
  561. * @param int $productId
  562. * @param int $storeId
  563. * @return \Magento\Framework\DataObject|false
  564. */
  565. public function getProduct($productId, $storeId)
  566. {
  567. $entityId = 0;
  568. $products = $this->_getProducts($productId, $storeId, 0, $entityId);
  569. if (isset($products[$productId])) {
  570. return $products[$productId];
  571. }
  572. return false;
  573. }
  574. /**
  575. * Retrieve Product data objects for store
  576. *
  577. * @param int $storeId
  578. * @param int &$lastEntityId
  579. * @return array
  580. */
  581. public function getProductsByStore($storeId, &$lastEntityId)
  582. {
  583. return $this->_getProducts(null, $storeId, $lastEntityId, $lastEntityId);
  584. }
  585. /**
  586. * Get rewrite by product store
  587. *
  588. * Retrieve rewrites and visibility by store
  589. * Input array format:
  590. * product_id as key and store_id as value
  591. * Output array format (product_id as key)
  592. * store_id int; store id
  593. * visibility int; visibility for store
  594. * url_rewrite string; rewrite URL for store
  595. *
  596. * @param array $products
  597. * @return array
  598. */
  599. public function getRewriteByProductStore(array $products)
  600. {
  601. $result = [];
  602. if (empty($products)) {
  603. return $result;
  604. }
  605. $connection = $this->getConnection();
  606. $storesProducts = [];
  607. foreach ($products as $productId => $storeId) {
  608. $storesProducts[$storeId][] = $productId;
  609. }
  610. foreach ($storesProducts as $storeId => $productIds) {
  611. $select = $connection->select()->from(
  612. ['i' => $this->tableMaintainer->getMainTable($storeId)],
  613. ['product_id', 'store_id', 'visibility']
  614. )->joinLeft(
  615. ['u' => $this->getMainTable()],
  616. 'i.product_id = u.entity_id AND i.store_id = u.store_id'
  617. . ' AND u.entity_type = "' . ProductUrlRewriteGenerator::ENTITY_TYPE . '"',
  618. ['request_path']
  619. )->joinLeft(
  620. ['r' => $this->getTable('catalog_url_rewrite_product_category')],
  621. 'u.url_rewrite_id = r.url_rewrite_id AND r.category_id is NULL',
  622. []
  623. );
  624. $bind = [];
  625. foreach ($productIds as $productId) {
  626. $catId = $this->_storeManager->getStore($storeId)->getRootCategoryId();
  627. $productBind = 'product_id' . $productId;
  628. $storeBind = 'store_id' . $storeId;
  629. $catBind = 'category_id' . $catId;
  630. $bindArray = [
  631. 'i.product_id = :' . $productBind,
  632. 'i.store_id = :' . $storeBind,
  633. 'i.category_id = :' . $catBind
  634. ];
  635. $cond = '(' . implode(' AND ', $bindArray) . ')';
  636. $bind[$productBind] = $productId;
  637. $bind[$storeBind] = $storeId;
  638. $bind[$catBind] = $catId;
  639. $select->orWhere($cond);
  640. }
  641. $rowSet = $connection->fetchAll($select, $bind);
  642. foreach ($rowSet as $row) {
  643. $result[$row['product_id']] = [
  644. 'store_id' => $row['store_id'],
  645. 'visibility' => $row['visibility'],
  646. 'url_rewrite' => $row['request_path'],
  647. ];
  648. }
  649. }
  650. return $result;
  651. }
  652. /**
  653. * @return \Magento\Framework\EntityManager\MetadataPool
  654. */
  655. private function getMetadataPool()
  656. {
  657. if (null === $this->metadataPool) {
  658. $this->metadataPool = \Magento\Framework\App\ObjectManager::getInstance()
  659. ->get(\Magento\Framework\EntityManager\MetadataPool::class);
  660. }
  661. return $this->metadataPool;
  662. }
  663. }