Spamworldpro Mini Shell
Spamworldpro


Server : Apache
System : Linux server2.corals.io 4.18.0-348.2.1.el8_5.x86_64 #1 SMP Mon Nov 15 09:17:08 EST 2021 x86_64
User : corals ( 1002)
PHP Version : 7.4.33
Disable Function : exec,passthru,shell_exec,system
Directory :  /home/corals/cartforge.co/vendor/magento/module-url-rewrite/Model/Storage/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Current File : /home/corals/cartforge.co/vendor/magento/module-url-rewrite/Model/Storage/DbStorage.php
<?php
/**
 * Copyright © Magento, Inc. All rights reserved.
 * See COPYING.txt for license details.
 */

namespace Magento\UrlRewrite\Model\Storage;

use Magento\Framework\Api\DataObjectHelper;
use Magento\Framework\App\ResourceConnection;
use Magento\Framework\DB\Select;
use Magento\UrlRewrite\Model\OptionProvider;
use Magento\UrlRewrite\Service\V1\Data\UrlRewrite;
use Magento\UrlRewrite\Service\V1\Data\UrlRewriteFactory;
use Psr\Log\LoggerInterface;
use Magento\Framework\App\ObjectManager;
use Magento\Framework\DB\Adapter\AdapterInterface;

/**
 * Url rewrites DB storage.
 *
 * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
 */
class DbStorage extends AbstractStorage
{
    /**
     * DB Storage table name
     */
    public const TABLE_NAME = 'url_rewrite';

    /**
     * Code of "Integrity constraint violation: 1062 Duplicate entry" error
     */
    public const ERROR_CODE_DUPLICATE_ENTRY = 1062;

    /**
     * @var AdapterInterface
     */
    protected $connection;

    /**
     * @var Resource
     */
    protected $resource;

    /**
     * @var LoggerInterface
     */
    private $logger;

    /**
     * @var int
     */
    private $maxRetryCount;

    /**
     * @param UrlRewriteFactory $urlRewriteFactory
     * @param DataObjectHelper $dataObjectHelper
     * @param ResourceConnection $resource
     * @param LoggerInterface|null $logger
     * @param int $maxRetryCount
     */
    public function __construct(
        UrlRewriteFactory $urlRewriteFactory,
        DataObjectHelper $dataObjectHelper,
        ResourceConnection $resource,
        LoggerInterface $logger = null,
        int $maxRetryCount = 5
    ) {
        $this->connection = $resource->getConnection();
        $this->resource = $resource;
        $this->logger = $logger ?: ObjectManager::getInstance()
            ->get(LoggerInterface::class);
        $this->maxRetryCount = $maxRetryCount;
        parent::__construct($urlRewriteFactory, $dataObjectHelper);
    }

    /**
     * Prepare select statement for specific filter
     *
     * @param  array $data
     * @return Select
     */
    protected function prepareSelect(array $data)
    {
        $select = $this->connection->select();
        $select->from($this->resource->getTableName(self::TABLE_NAME));

        foreach ($data as $column => $value) {
            $select->where($this->connection->quoteIdentifier($column) . ' IN (?)', $value);
        }

        return $select;
    }

    /**
     * @inheritdoc
     */
    protected function doFindAllByData(array $data)
    {
        return $this->connection->fetchAll($this->prepareSelect($data));
    }

    /**
     * @inheritdoc
     */
    protected function doFindOneByData(array $data)
    {
        if (array_key_exists(UrlRewrite::REQUEST_PATH, $data)
            && is_string($data[UrlRewrite::REQUEST_PATH])
        ) {
            $result = null;
            $requestPath = $data[UrlRewrite::REQUEST_PATH];
            $decodedRequestPath = urldecode($requestPath);
            $data[UrlRewrite::REQUEST_PATH] = array_unique(
                [
                rtrim($requestPath, '/'),
                rtrim($requestPath, '/') . '/',
                rtrim($decodedRequestPath, '/'),
                rtrim($decodedRequestPath, '/') . '/',
                ]
            );
            $resultsFromDb = $this->connection->fetchAll($this->prepareSelect($data));
            if ($resultsFromDb) {
                $urlRewrite = $this->extractMostRelevantUrlRewrite($requestPath, $resultsFromDb);
                $result = $this->prepareUrlRewrite($requestPath, $urlRewrite);
            }
            return $result;
        }
        return $this->connection->fetchRow($this->prepareSelect($data));
    }

    /**
     * Extract most relevant url rewrite from url rewrites list
     *
     * @param string $requestPath
     * @param array $urlRewrites
     * @return array|null
     */
    private function extractMostRelevantUrlRewrite(string $requestPath, array $urlRewrites): ?array
    {
        $prioritizedUrlRewrites = [];
        foreach ($urlRewrites as $urlRewrite) {
            $urlRewriteRequestPath = $urlRewrite[UrlRewrite::REQUEST_PATH];
            $urlRewriteTargetPath = $urlRewrite[UrlRewrite::TARGET_PATH] ?? '';
            $trimmedUrlRewriteRequestPath = rtrim($urlRewriteRequestPath ?? '', '/');
            switch (true) {
                case $trimmedUrlRewriteRequestPath === rtrim($urlRewriteTargetPath, '/'):
                    $priority = 99;
                    break;
                case $urlRewriteRequestPath === $requestPath:
                    $priority = 1;
                    break;
                case $urlRewriteRequestPath === urldecode($requestPath):
                    $priority = 2;
                    break;
                case $trimmedUrlRewriteRequestPath === rtrim($requestPath, '/'):
                    $priority = 3;
                    break;
                case $trimmedUrlRewriteRequestPath === rtrim(urldecode($requestPath), '/'):
                    $priority = 4;
                    break;
                default:
                    $priority = 5;
                    break;
            }
            $prioritizedUrlRewrites[$priority] = $urlRewrite;
        }
        ksort($prioritizedUrlRewrites);

        return array_shift($prioritizedUrlRewrites);
    }

    /**
     * Prepare url rewrite
     *
     * If request path matches the DB value or it's redirect - we can return result from DB
     * Otherwise return 301 redirect to request path from DB results
     *
     * @param string $requestPath
     * @param array $urlRewrite
     * @return array
     */
    private function prepareUrlRewrite(string $requestPath, array $urlRewrite): array
    {
        $redirectTypes = [OptionProvider::TEMPORARY, OptionProvider::PERMANENT];
        $canReturnResultFromDb = (
            in_array($urlRewrite[UrlRewrite::REQUEST_PATH], [$requestPath, urldecode($requestPath)], true)
            || in_array((int) $urlRewrite[UrlRewrite::REDIRECT_TYPE], $redirectTypes, true)
        );
        if (!$canReturnResultFromDb) {
            $urlRewrite = [
                UrlRewrite::ENTITY_TYPE => 'custom',
                UrlRewrite::ENTITY_ID => '0',
                UrlRewrite::REQUEST_PATH => $requestPath,
                UrlRewrite::TARGET_PATH => $urlRewrite[UrlRewrite::REQUEST_PATH],
                UrlRewrite::REDIRECT_TYPE => OptionProvider::PERMANENT,
                UrlRewrite::STORE_ID => $urlRewrite[UrlRewrite::STORE_ID],
                UrlRewrite::DESCRIPTION => null,
                UrlRewrite::IS_AUTOGENERATED => '0',
                UrlRewrite::METADATA => null,
            ];
        }

        return $urlRewrite;
    }

    /**
     * Delete old URLs from DB.
     *
     * @param array $uniqueEntities
     * @return void
     */
    private function deleteOldUrls(array $uniqueEntities): void
    {
        $oldUrlsSelect = $this->connection->select();
        $oldUrlsSelect->from(
            $this->resource->getTableName(self::TABLE_NAME)
        );
        foreach ($uniqueEntities as $storeId => $entityTypes) {
            foreach ($entityTypes as $entityType => $entities) {
                // phpcs:ignore Magento2.Performance.ForeachArrayMerge
                $requestPaths = array_merge(...$entities);
                $requestPathFilter = '';
                if (!empty($requestPaths)) {
                    $requestPathFilter = ' AND ' . $this->connection->quoteIdentifier(UrlRewrite::REQUEST_PATH)
                    . ' NOT IN (' . $this->connection->quote($requestPaths) . ')';
                }
                $oldUrlsSelect->orWhere(
                    $this->connection->quoteIdentifier(UrlRewrite::STORE_ID)
                    . ' = ' . $this->connection->quote($storeId, 'INTEGER')
                    . ' AND ' . $this->connection->quoteIdentifier(UrlRewrite::ENTITY_ID)
                    . ' IN (' . $this->connection->quote(array_keys($entities), 'INTEGER') . ')'
                    . ' AND ' . $this->connection->quoteIdentifier(UrlRewrite::ENTITY_TYPE)
                    . ' = ' . $this->connection->quote($entityType)
                    . $requestPathFilter
                );
            }
        }
        // prevent query locking in a case when nothing to delete
        $checkOldUrlsSelect = clone $oldUrlsSelect;
        $checkOldUrlsSelect->reset(Select::COLUMNS);
        $checkOldUrlsSelect->columns([new \Zend_Db_Expr('1')]);
        $checkOldUrlsSelect->limit(1);
        $hasOldUrls = false !== $this->connection->fetchOne($checkOldUrlsSelect);
        if ($hasOldUrls) {
            $this->connection->query(
                $oldUrlsSelect->deleteFromSelect(
                    $this->resource->getTableName(self::TABLE_NAME)
                )
            );
        }
    }

    /**
     * Checks for duplicates both inside the new urls, and outside.
     * Because we are using INSERT ON DUPLICATE UPDATE, the insert won't give us an error.
     * So, we have to check for existing requestPaths in database with different entity_id.
     * And also, we need to check to make sure we don't have same requestPath more than once in our new rewrites.
     *
     * @param array $uniqueEntities
     * @return void
     */
    private function checkDuplicates(array $uniqueEntities): void
    {
        $oldUrlsSelect = $this->connection->select();
        $oldUrlsSelect->from(
            $this->resource->getTableName(self::TABLE_NAME),
            [new \Zend_Db_Expr('1')]
        );
        $allEmpty = true;
        foreach ($uniqueEntities as $storeId => $entityTypes) {
            $newRequestPaths = [];
            foreach ($entityTypes as $entityType => $entities) {
                // phpcs:ignore Magento2.Performance.ForeachArrayMerge
                $requestPaths = array_merge(...$entities);
                if (empty($requestPaths)) {
                    continue;
                }
                $allEmpty = false;
                $oldUrlsSelect->orWhere(
                    $this->connection->quoteIdentifier(UrlRewrite::STORE_ID)
                    . ' = ' . $this->connection->quote($storeId, 'INTEGER')
                    . ' AND (' . $this->connection->quoteIdentifier(UrlRewrite::ENTITY_ID)
                    . ' NOT IN (' . $this->connection->quote(array_keys($entities), 'INTEGER') . ')'
                    . ' OR ' . $this->connection->quoteIdentifier(UrlRewrite::ENTITY_TYPE)
                    . ' != ' . $this->connection->quote($entityType)
                    . ') AND ' . $this->connection->quoteIdentifier(UrlRewrite::REQUEST_PATH)
                    . ' IN (' . $this->connection->quote($requestPaths) . ')'
                );
                foreach ($requestPaths as $requestPath) {
                    if (isset($newRequestPaths[$requestPath])) {
                        throw new \Magento\Framework\Exception\AlreadyExistsException();
                    }
                    $newRequestPaths[$requestPath] = true;
                }
            }
        }
        if ($allEmpty) {
            return;
        }
        $oldUrlsSelect->limit(1);
        if (false !== $this->connection->fetchOne($oldUrlsSelect)) {
            throw new \Magento\Framework\Exception\AlreadyExistsException();
        }
    }

    /**
     * Prepare array with unique entities
     *
     * @param UrlRewrite[] $urls
     * @return array
     */
    private function prepareUniqueEntities(array $urls): array
    {
        $uniqueEntities = [];
        foreach ($urls as $url) {
            $storeId = $url->getStoreId();
            $entityType = $url->getEntityType();
            $entityId = $url->getEntityId();
            $requestPath = $url->getRequestPath();
            if (null === $requestPath) {  // Note: because SQL unique keys allow multiple nulls, we skip it.
                if (!isset($uniqueEntities[$storeId][$entityType][$entityId])) {
                    $uniqueEntities[$storeId][$entityType][$entityId] = [];
                }
            }
            $uniqueEntities[$storeId][$entityType][$entityId][] = $requestPath;
        }
        return $uniqueEntities;
    }

    /**
     * @inheritDoc
     */
    protected function doReplace(array $urls): array
    {
        $uniqueEntities = $this->prepareUniqueEntities($urls);
        $data = [];
        foreach ($urls as $url) {
            $data[] = $url->toArray();
        }
        for ($tries = 0;; $tries++) {
            $this->connection->beginTransaction();
            try {
                $this->deleteOldUrls($uniqueEntities);
                $this->checkDuplicates($uniqueEntities);
                $this->upsertMultiple($data);
                $this->connection->commit();
            } catch (\Magento\Framework\DB\Adapter\DeadlockException $deadlockException) {
                $this->connection->rollBack();
                if ($tries >= $this->maxRetryCount) {
                    throw $deadlockException;
                }
                continue;
            } catch (\Magento\Framework\Exception\AlreadyExistsException $e) {
                $this->connection->rollBack();
                $urlConflicted = $this->findUrlConflicted($urls, $uniqueEntities);
                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;
            }
            break;
        }
        return $urls;
    }

    /**
     * Searches existing rewrites with same requestPath & store, but ignores ones to be updated.
     *
     * @param array $urls
     * @param array $uniqueEntities
     * @return array
     */
    private function findUrlConflicted(array $urls, array $uniqueEntities): array
    {
        $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])) {
                if (isset($uniqueEntities
                    [$urlFound[UrlRewrite::STORE_ID]]
                    [$urlFound[UrlRewrite::ENTITY_TYPE]]
                    [$urlFound[UrlRewrite::ENTITY_ID]
                    ])) {
                    continue; // Note: If it's one of the entities we are updating, then it is okay.
                }
                $urlConflicted[$urlFound[UrlRewrite::URL_REWRITE_ID]] = $url->toArray();
            }
        }
        return $urlConflicted;
    }

    /**
     * Insert multiple
     *
     * @param array $data
     * @return void
     * @throws \Magento\Framework\Exception\AlreadyExistsException|\Exception
     * @throws \Exception
     * @deprecated Not used anymore.
     * @see upsertMultiple
     */
    protected function insertMultiple($data): void
    {
        try {
            $this->connection->insertMultiple($this->resource->getTableName(self::TABLE_NAME), $data);
        } catch (\Exception $e) {
            if (($e->getCode() === self::ERROR_CODE_DUPLICATE_ENTRY)
                && preg_match('#SQLSTATE\[23000\]: [^:]+: 1062[^\d]#', $e->getMessage())
            ) {
                throw new \Magento\Framework\Exception\AlreadyExistsException(
                    __('URL key for specified store already exists.'),
                    $e
                );
            }
            throw $e;
        }
    }

    /**
     * Upsert multiple
     *
     * @param  array $data
     * @return void
     */
    private function upsertMultiple(array $data): void
    {

        $this->connection->insertOnDuplicate($this->resource->getTableName(self::TABLE_NAME), $data);
    }

    /**
     * Get filter for url rows deletion due to provided urls
     *
     * @param UrlRewrite[] $urls
     * @return array
     * @deprecated 101.0.3 Not used anymore.
     * @see nothing
     */
    protected function createFilterDataBasedOnUrls($urls): array
    {
        $data = [];
        foreach ($urls as $url) {
            $entityType = $url->getEntityType();
            foreach ([UrlRewrite::ENTITY_ID, UrlRewrite::STORE_ID] as $key) {
                $fieldValue = $url->getByKey($key);
                if (!isset($data[$entityType][$key]) || !in_array($fieldValue, $data[$entityType][$key])) {
                    $data[$entityType][$key][] = $fieldValue;
                }
            }
        }

        return $data;
    }

    /**
     * @inheritdoc
     */
    public function deleteByData(array $data)
    {
        $this->connection->query(
            $this->prepareSelect($data)->deleteFromSelect($this->resource->getTableName(self::TABLE_NAME))
        );
    }
}

Spamworldpro Mini