How to fix the related product issue in admin after migrated to magento 1 to magento 2.3
-
25-02-2021 - |
题
I am using Magento 2.3.0
I have migrated products from Magento 1 to Magento 2. I can see related products in product detail page in the front end and it is proper and also I can find related products entry in the database as well but when I checked related products in admin I found that there are some related products missing in some of the products
For Ex. When I checked one product in the front end. I saw three related products there as well as in the database but I can find only 2 products in admin there is one product missing in admin.
I checked two tables in database for related products: "catalog_product_link
" and "catalog_product_link_attribute_int
".
I have found some values in the "value" column in "catalog_product_link_attribute_int
" table which represents the position of the related products in admin and in front end but I found value 0 in "value" column of this table for some of the products and when I checked these products I found that only those products which do have only 0 in "value" column in "catalog_product_link_attribute_int
" table are missing related products in admin.
So, How can I solve this issue?
Check my below question as well:
How to override product model files in Magento 2?
I have created a new module to solve the related product issue which I mentioned in this question but I got an error.
解决方案
Why it happens
This happens when there are inconsistent positions for the related products. This might happen after a migration from magento 1. It was the case for me also.
The problem is cause by the method Magento\Catalog\Model\ProductLink\CollectionProvider::getCollection()
.
That's the one responsible for retrieving the products.
The part that does not behave as expected is this:
foreach ($output as $item) {
$itemPosition = $item['position'];
if (!isset($sorterItems[$itemPosition])) {
$sorterItems[$itemPosition] = $item;
} else {
$newPosition = $itemPosition + 1;
$sorterItems[$newPosition] = $item;
}
}
Let's take 2 cases.
THe one that works:
Let's say
$output = [
['position' => 0],
['position' => 2],
['position' => 1],
];
(I ignored the other values for the related items as they are not important).
After running the code above this results in
Array
(
[0] => Array
(
[position] => 0
)
[2] => Array
(
[position] => 2
)
[1] => Array
(
[position] => 1
)
)
which is later sorted by the ksort
function.
So 3 items on input, 3 on output. So far so good.
But let's take this case:
$output = [
['position' => 0], // or null
['position' => 1],
['position' => 0], // or null
];
The same piece of code returns:
Array
(
[0] => Array
(
[position] => 0
)
[1] => Array
(
[position] => 0
)
)
So 3 items in, 2 out.
Solution
I solve this by rewriting the method mentioned above and ensuring there are no position clashes.
To override it, add this in the di.xml
file in one of your custom modules
<preference for="Magento\Catalog\Model\ProductLink\CollectionProvider" type="[Vendor]\[Module]\Model\ProductLink\CollectionProvider" />
Then create the class [Vendor]\[Module]\Model\ProductLink\CollectionProvider
in the file [Vendor]/[Module]/Model/ProductLink/CollectionProvider.php
The class should look like this:
<?php
namespace [Vendor]\[Module]\Model\ProductLink;
use Magento\Framework\Exception\NoSuchEntityException;
class CollectionProvider extends \Magento\Catalog\Model\ProductLink\CollectionProvider
{
/**
* Get product collection by link type
*
* @param \Magento\Catalog\Model\Product $product
* @param string $type
* @return array
* @throws NoSuchEntityException
*/
public function getCollection(\Magento\Catalog\Model\Product $product, $type)
{
if (!isset($this->providers[$type])) {
throw new NoSuchEntityException(__('Collection provider is not registered'));
}
$products = $this->providers[$type]->getLinkedProducts($product);
$converter = $this->converterPool->getConverter($type);
$output = [];
$sorterItems = [];
foreach ($products as $item) {
$output[$item->getId()] = $converter->convert($item);
}
foreach ($output as $item) {
$itemPosition = (int)$item['position'];
while (isset($sorterItems[$itemPosition])) {
$itemPosition++;
}
$sorterItems[$itemPosition] = $item;
}
ksort($sorterItems);
return $sorterItems;
}
}