skip to Main Content

I am facing this issue while saving a product programmatically on Magento 2.2.5

In any module, if I do $product->save(); OR $this->productRepository->save($product); inside a loop for multiple products. I get:

PDOException: SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry ‘the-lipstick.html-1’ for key ‘URL_REWRITE_REQUEST_PATH_STORE_ID’ in /home/dev3/www/vendor/magento/zendframework1/library/Zend/Db/Statement/Pdo.php:228

The error is similar to the one described here : https://www.human-element.com/url-key-specified-store-already-exists-magento-2/

Products save fine with admin area login.

Any suggested fixes so far including the ones modifying the core files (DBStorage.php) do not work on 2.2.5.

What I tried so far:
1. Fix from https://www.human-element.com/url-key-specified-store-already-exists-magento-2/
2. Fix from https://magento.stackexchange.com/questions/210359/magento-2-product-url-rewrite-issue

Please suggest a solution/fix for M 2.2.5

3

Answers


  1. Chosen as BEST ANSWER

    My Fix : In di.xml -

    <preference for="MagentoUrlRewriteModelStorageDbStorage" type="MyCompanyFixUrlsModelProductUrlFix" />

    In ProductFixUrl write these two functions :

    protected function doReplace(array $urls){
    
        $this->deleteOld($urls);
            $data = [];
            $storeId_requestPaths = [];
    
            foreach ($urls as $url) {
                $storeId = $url->getStoreId();
                $requestPath = $url->getRequestPath();
                // Skip if is exist in the database
                $sql = "SELECT * FROM url_rewrite where store_id = $storeId and request_path = '$requestPath'";
                $exists = $this->connection->fetchOne($sql);
    
                if ($exists) {
                    continue;
                }
    
                $storeId_requestPaths[] = $storeId . '-' . $requestPath;
                $data[] = $url->toArray();
            }
            try {
    
                $n = count($storeId_requestPaths);
                for ($i = 0; $i < $n - 1; $i++) {
                    for ($j = $i + 1; $j < $n; $j++) {
                        if ($storeId_requestPaths[$i] == $storeId_requestPaths[$j]) {
                            unset($data[$j]);
                        }
                    }
                }
                parent::insertMultiple($data);
    
            } catch (MagentoFrameworkExceptionAlreadyExistsException $e) {
                /** @var MagentoUrlRewriteServiceV1DataUrlRewrite[] $urlConflicted */
                $urlConflicted = [];
                foreach ($urls as $url) {
                    $urlFound = parent::doFindOneByData(
                        [
                            UrlRewriteData::REQUEST_PATH => $url->getRequestPath(),
                            UrlRewriteData::STORE_ID => $url->getStoreId(),
                        ]
                    );
                    if (isset($urlFound[UrlRewriteData::URL_REWRITE_ID])) {
                        $urlConflicted[$urlFound[UrlRewriteData::URL_REWRITE_ID]] = $url->toArray();
                    }
                }
                if ($urlConflicted) {
                    throw new MagentoUrlRewriteModelExceptionUrlAlreadyExistsException(
                        __('URL key for specified store already exists.'),
                        $e,
                        $e->getCode(),
                        $urlConflicted
                    );
                } else {
                    throw $e->getPrevious() ?: $e;
                }
            }
    
            return $urls;
        }
    
        /**
         * @param UrlRewrite[] $urls
         *
         * @return void
         */
        public function deleteOld(array $urls)
        {
            $oldUrlsSelect = $this->connection->select();
            $oldUrlsSelect->from(
                $this->resource->getTableName(self::TABLE_NAME)
            );
            /** @var UrlRewrite $url */
            foreach ($urls as $url) {
                $oldUrlsSelect->orWhere(
                    $this->connection->quoteIdentifier(
                        UrlRewrite::ENTITY_TYPE
                    ) . ' = ?',
                    $url->getEntityType()
                );
                $oldUrlsSelect->where(
                    $this->connection->quoteIdentifier(
                        UrlRewrite::ENTITY_ID
                    ) . ' = ?',
                    $url->getEntityId()
                );
                $oldUrlsSelect->where(
                    $this->connection->quoteIdentifier(
                        UrlRewrite::STORE_ID
                    ) . ' = ?',
                    $url->getStoreId()
                );
            }
    
            // 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)
                    )
                );
            }
        }
    

  2. After a migration and a week digging into the problem the only thing that worked for me was https://www.safemage.com/url-optimization-after-migration-magento-2.html

    I had to downgrade to 2.2.7 to use it. It says it works on 2.3 but it does not.

    Login or Signup to reply.
  3. After looking on internet for days i can’t find exact solution of this.
    Then i found if we change the URLKEY of the category it will not show this error so i have done this.

    $category->setPath($parentCategory->getPath())
                ->setParentId($parentId)
                ->setName('test1')
                ->setIsActive(true)
                ->setUrlKey(rand(1,1000000000));
    
            $category->save();
    

    I use random function to add category in database with random no using ->setUrlKey(rand(1,1000000000)); you can add any thing in this like duplicate category name with some random no etc.
    and errors gone if it helps you give an UP. thanks

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search