Created
April 7, 2021 16:34
-
-
Save satishgumudavelli/cb561d598a21f97ffa9ca17fe46df602 to your computer and use it in GitHub Desktop.
Unique constraint violent issue in Magento2
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Copyright © All rights reserved. | |
* See COPYING.txt for license details. | |
*/ | |
declare(strict_types=1); | |
namespace Mageseller\Utility\Rewrite\Magento\UrlRewrite\Model\Storage; | |
use Magento\Framework\DB\Select; | |
use Magento\UrlRewrite\Service\V1\Data\UrlRewrite; | |
class DbStorage extends \Magento\UrlRewrite\Model\Storage\DbStorage | |
{ | |
/** | |
* @inheritDoc | |
*/ | |
protected function doReplace(array $urls): array | |
{ | |
$this->connection->beginTransaction(); | |
try { | |
$this->deleteOldUrls($urls); | |
$data = []; | |
$requestPaths = []; | |
foreach ($urls as $url) { | |
if (!isset($requestPaths[strtolower($url->getRequestPath())])) { | |
$requestPaths[strtolower($url->getRequestPath())] = $url->getTargetPath(); | |
$data[] = $url->toArray(); | |
} | |
} | |
$this->insertMultiple($data); | |
$this->connection->commit(); | |
// @codingStandardsIgnoreStart | |
} catch (\Magento\Framework\Exception\AlreadyExistsException $e) { | |
// @codingStandardsIgnoreEnd | |
$this->connection->rollBack(); | |
/** @var \Magento\UrlRewrite\Service\V1\Data\UrlRewrite[] $urlConflicted */ | |
$urlConflicted = []; | |
foreach ($urls as $url) { | |
$urlFound = $this->doFindOneByData( | |
[ | |
UrlRewrite::REQUEST_PATH => $url->getRequestPath(), | |
UrlRewrite::STORE_ID => $url->getStoreId(), | |
] | |
); | |
if (isset($urlFound[UrlRewrite::URL_REWRITE_ID])) { | |
$urlConflicted[$urlFound[UrlRewrite::URL_REWRITE_ID]] = $url->toArray(); | |
} | |
} | |
if ($urlConflicted) { | |
throw new \Magento\UrlRewrite\Model\Exception\UrlAlreadyExistsException( | |
__('URL key for specified store already exists.'), | |
$e, | |
$e->getCode(), | |
$urlConflicted | |
); | |
} else { | |
throw $e->getPrevious() ?: $e; | |
} | |
} catch (\Exception $e) { | |
$this->connection->rollBack(); | |
throw $e; | |
} | |
return $urls; | |
} | |
/** | |
* Delete old URLs from DB. | |
* | |
* @param UrlRewrite[] $urls | |
* @return void | |
*/ | |
private function deleteOldUrls(array $urls): void | |
{ | |
$oldUrlsSelect = $this->connection->select(); | |
$oldUrlsSelect->from( | |
$this->resource->getTableName(self::TABLE_NAME) | |
); | |
$uniqueEntities = $this->prepareUniqueEntities($urls); | |
foreach ($uniqueEntities as $storeId => $entityTypes) { | |
foreach ($entityTypes as $entityType => $entities) { | |
$oldUrlsSelect->orWhere( | |
$this->connection->quoteIdentifier( | |
UrlRewrite::STORE_ID | |
) . ' = ' . $this->connection->quote($storeId, 'INTEGER') . | |
' AND ' . $this->connection->quoteIdentifier( | |
UrlRewrite::ENTITY_ID | |
) . ' IN (' . $this->connection->quote($entities, 'INTEGER') . ')' . | |
' AND ' . $this->connection->quoteIdentifier( | |
UrlRewrite::ENTITY_TYPE | |
) . ' = ' . $this->connection->quote($entityType) | |
); | |
} | |
} | |
// prevent query locking in a case when nothing to delete | |
$checkOldUrlsSelect = clone $oldUrlsSelect; | |
$checkOldUrlsSelect->reset(Select::COLUMNS); | |
$checkOldUrlsSelect->columns('count(*)'); | |
$hasOldUrls = (bool)$this->connection->fetchOne($checkOldUrlsSelect); | |
if ($hasOldUrls) { | |
$this->connection->query( | |
$oldUrlsSelect->deleteFromSelect( | |
$this->resource->getTableName(self::TABLE_NAME) | |
) | |
); | |
} | |
} | |
/** | |
* Prepare array with unique entities | |
* | |
* @param UrlRewrite[] $urls | |
* @return array | |
*/ | |
private function prepareUniqueEntities(array $urls): array | |
{ | |
$uniqueEntities = []; | |
/** @var UrlRewrite $url */ | |
foreach ($urls as $url) { | |
$entityIds = (!empty($uniqueEntities[$url->getStoreId()][$url->getEntityType()])) ? | |
$uniqueEntities[$url->getStoreId()][$url->getEntityType()] : []; | |
if (!\in_array($url->getEntityId(), $entityIds)) { | |
$entityIds[] = $url->getEntityId(); | |
} | |
$uniqueEntities[$url->getStoreId()][$url->getEntityType()] = $entityIds; | |
} | |
return $uniqueEntities; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" ?> | |
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd"> | |
<preference for="Magento\UrlRewrite\Model\Storage\DbStorage" type="Mageseller\Utility\Rewrite\Magento\UrlRewrite\Model\Storage\DbStorage"/> | |
</config> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment