Skip to content

Instantly share code, notes, and snippets.

@satishgumudavelli
Created April 7, 2021 16:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save satishgumudavelli/cb561d598a21f97ffa9ca17fe46df602 to your computer and use it in GitHub Desktop.
Save satishgumudavelli/cb561d598a21f97ffa9ca17fe46df602 to your computer and use it in GitHub Desktop.
Unique constraint violent issue in Magento2
<?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;
}
}
<?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