first commit
This commit is contained in:
183
classes/PrettyURL.php
Normal file
183
classes/PrettyURL.php
Normal file
@@ -0,0 +1,183 @@
|
||||
<?php
|
||||
|
||||
|
||||
|
||||
class PrettyURL
|
||||
{
|
||||
public static function getController(string $uri, $fallbackController)
|
||||
{
|
||||
$idLang = (int) Context::getContext()->language->id;
|
||||
$idShop = (int) Context::getContext()->shop->id;
|
||||
$parsedURL = self::parseURL($uri, $idLang, $idShop);
|
||||
|
||||
if (empty($parsedURL['controller'])) {
|
||||
return $fallbackController; // No route to add if controller is not determined
|
||||
}
|
||||
$_GET['id_product'] = $parsedURL['id_product'];
|
||||
$_GET['id_product_attribute'] = $parsedURL['id_product_attribute'];
|
||||
$_GET['id_category'] = $parsedURL['id_category'];
|
||||
|
||||
return $parsedURL['controller'];
|
||||
}
|
||||
|
||||
public static function parseURL(string $url, int $idLang, int $idShop): array
|
||||
{
|
||||
$path = urldecode(parse_url($url, PHP_URL_PATH));
|
||||
$result = ['id_product' => null, 'id_category' => null, 'id_product_attribute' => null, 'path' => $path, 'rewrite' => null, 'rule' => null, 'controller' => null];
|
||||
|
||||
if (!$path) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
$parts = explode('/', trim($path, '/'));
|
||||
// $result['path'] = $parts;
|
||||
|
||||
$lastPart = end($parts);
|
||||
|
||||
// Check if last part is a product link rewrite
|
||||
$productId = self::getProductIdByLinkRewrite($lastPart, $idLang, $idShop);
|
||||
if ($productId !== null) {
|
||||
$result['id_product'] = $productId;
|
||||
$result['rule'] = '{categories}/{rewrite}';
|
||||
$result['rewrite'] = $lastPart;
|
||||
$result['controller'] = 'product';
|
||||
return $result;
|
||||
}
|
||||
|
||||
// Check if last part is a category link rewrite
|
||||
$categoryId = self::getCategoryIdByLinkRewrite($parts, $idLang, $idShop);
|
||||
if ($categoryId !== null) {
|
||||
$result['id_category'] = $categoryId;
|
||||
$result['rule'] = '{rewrite}';
|
||||
$result['rewrite'] = $lastPart;
|
||||
$result['controller'] = 'category';
|
||||
return $result;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Simulates a function to get product ID by link rewrite.
|
||||
* Replace with your actual implementation.
|
||||
*/
|
||||
public static function getProductIdByLinkRewrite(string $linkRewrite, int $idLang, int $idShop): ?int
|
||||
{
|
||||
|
||||
$sql = new DbQuery();
|
||||
$sql->select('pl.id_product');
|
||||
$sql->from('product_lang', 'pl');
|
||||
$sql->where('pl.link_rewrite = "' . pSQL($linkRewrite) . '"');
|
||||
$sql->where('pl.id_lang = ' . $idLang);
|
||||
$sql->where('pl.id_shop = ' . $idShop);
|
||||
|
||||
$productId = Db::getInstance()->getValue($sql);
|
||||
|
||||
if ($productId) {
|
||||
return (int) $productId;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* public static function getCategoryIdByLinkRewrite(string $linkRewrite, int $idLang, int $idShop): ?int
|
||||
{
|
||||
|
||||
$sql = new DbQuery();
|
||||
$sql->select('cl.id_category');
|
||||
$sql->from('category_lang', 'cl');
|
||||
$sql->where('cl.link_rewrite = "' . pSQL($linkRewrite) . '"');
|
||||
$sql->where('cl.id_lang = ' . $idLang);
|
||||
$sql->where('cl.id_shop = ' . $idShop);
|
||||
|
||||
$categoryId = Db::getInstance()->getValue($sql);
|
||||
|
||||
if ($categoryId) {
|
||||
return (int) $categoryId;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//////////////
|
||||
|
||||
public static function getCategoryIdByLinkRewrite(array $parts, int $idLang, int $idShop): ?int
|
||||
{
|
||||
$linkRewrite = end($parts);
|
||||
$sql = new DbQuery();
|
||||
$sql->select('cl.id_category');
|
||||
$sql->from('category_lang', 'cl');
|
||||
$sql->where('cl.link_rewrite = "' . pSQL($linkRewrite) . '"');
|
||||
$sql->where('cl.id_lang = ' . $idLang);
|
||||
$sql->where('cl.id_shop = ' . $idShop);
|
||||
|
||||
$categoryIds = Db::getInstance()->executeS($sql);
|
||||
|
||||
if (!$categoryIds) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (count($categoryIds) === 1) {
|
||||
return (int) $categoryIds[0]['id_category'];
|
||||
}
|
||||
|
||||
// Multiple categories with the same link_rewrite, resolve by parent categories
|
||||
return self::resolveCategoryIdByParentCategories($categoryIds, $parts, $idLang, $idShop);
|
||||
}
|
||||
|
||||
private static function resolveCategoryIdByParentCategories(array $categoryIds, array $parts, int $idLang, int $idShop): ?int
|
||||
{
|
||||
// Remove the last part (current category link_rewrite)
|
||||
array_pop($parts);
|
||||
|
||||
$idCategory = null;
|
||||
foreach ($categoryIds as $categoryData) {
|
||||
$categoryId = (int) $categoryData['id_category'];
|
||||
if (self::checkCategoryPath($categoryId, $parts, $idLang, $idShop)) {
|
||||
$idCategory = $categoryId;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $idCategory;
|
||||
}
|
||||
|
||||
private static function checkCategoryPath(int $categoryId, array $parts, int $idLang, int $idShop): bool
|
||||
{
|
||||
$currentCategoryId = $categoryId;
|
||||
$parts = array_reverse($parts); // Reverse parts to iterate from parent to child
|
||||
|
||||
foreach ($parts as $linkRewrite) {
|
||||
$sql = new DbQuery();
|
||||
$sql->select('c.id_parent');
|
||||
$sql->from('category', 'c');
|
||||
$sql->leftJoin('category_lang', 'cl', 'c.id_category = cl.id_category AND cl.id_lang = ' . (int)$idLang . ' AND cl.id_shop = '.(int)$idShop);
|
||||
$sql->where('c.id_category = ' . (int)$currentCategoryId);
|
||||
$sql->where('cl.link_rewrite = "' . pSQL($linkRewrite) . '"');
|
||||
|
||||
|
||||
$parentId = (int) Db::getInstance()->getValue($sql);
|
||||
|
||||
if (!$parentId) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$currentCategoryId = $parentId; // Move to the parent category
|
||||
}
|
||||
|
||||
// If we reached the top of the path without failing, it's a match
|
||||
return true;
|
||||
}
|
||||
}
|
||||
15
classes/ProductForTemplate.php
Normal file
15
classes/ProductForTemplate.php
Normal file
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
class ProductForTemplate
|
||||
{
|
||||
public $name;
|
||||
public $price_without_reduction;
|
||||
public $price;
|
||||
public $product;
|
||||
public $combination;
|
||||
public $quantity;
|
||||
public $orderOutOfStock;
|
||||
public $group_name;
|
||||
public $id_attribute_group;
|
||||
public $id_attribute;
|
||||
}
|
||||
156
classes/URLRedirect.php
Normal file
156
classes/URLRedirect.php
Normal file
@@ -0,0 +1,156 @@
|
||||
<?php
|
||||
|
||||
use PrestaShop\PrestaShop\Adapter\ObjectManager;
|
||||
use PrestaShop\PrestaShop\Core\Localization\TranslatorInterface;
|
||||
|
||||
class URLRedirect extends ObjectModel
|
||||
{
|
||||
public $url;
|
||||
public $object_name;
|
||||
public $object_id;
|
||||
public $date_add;
|
||||
public $date_upd;
|
||||
|
||||
public static $definition = [
|
||||
'table' => 'url_redirection',
|
||||
'primary' => 'id_url_redirection',
|
||||
'multilang' => false,
|
||||
'fields' => [
|
||||
'url' => ['type' => self::TYPE_STRING, 'validate' => 'isString', 'required' => true, 'size' => 255],
|
||||
'object_name' => ['type' => self::TYPE_STRING, 'validate' => 'isString', 'required' => true, 'size' => 64],
|
||||
'object_id' => ['type' => self::TYPE_INT, 'validate' => 'isInt', 'required' => true],
|
||||
'date_add' => ['type' => self::TYPE_DATE, 'validate' => 'isDate', 'required' => false],
|
||||
'date_upd' => ['type' => self::TYPE_DATE, 'validate' => 'isDate', 'required' => false],
|
||||
],
|
||||
];
|
||||
|
||||
/**
|
||||
* @param string $url
|
||||
* @param string $object_name
|
||||
* @param int $object_id
|
||||
* @param bool $updateExisting
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function saveUrl(string $url, string $object_name, int $object_id, bool $updateExisting = false): bool
|
||||
{
|
||||
// $url = trim($url, '/'); // Remove leading/trailing slashes
|
||||
$url = trim(str_replace(Context::getContext()->shop->getBaseURL(true, false), '', $url), '/');
|
||||
|
||||
if (empty($url) || empty($object_name) || $object_id <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$redirection = URLRedirect::getByUrl($url);
|
||||
if ($redirection->id) {
|
||||
if (!$updateExisting) {
|
||||
return false; // Do not update if we shouldn't.
|
||||
}
|
||||
|
||||
// Update existing entry
|
||||
$redirection->object_name = $object_name;
|
||||
$redirection->object_id = $object_id;
|
||||
$redirection->date_upd = date('Y-m-d H:i:s');
|
||||
return $redirection->update();
|
||||
}
|
||||
|
||||
|
||||
|
||||
$redirection->url = $url;
|
||||
$redirection->object_name = $object_name;
|
||||
$redirection->object_id = $object_id;
|
||||
$redirection->date_add = date('Y-m-d H:i:s');
|
||||
|
||||
return $redirection->add();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get redirection by URL.
|
||||
*
|
||||
* @param string $url
|
||||
* @return URLRedirect
|
||||
*/
|
||||
public static function getByUrl(string $url): URLRedirect
|
||||
{
|
||||
$url = trim(urldecode($url), '/');
|
||||
$sql = new DbQuery();
|
||||
$sql->select('*');
|
||||
$sql->from(self::$definition['table']);
|
||||
$sql->where('url = "' . pSQL($url) . '"');
|
||||
$object = new self();
|
||||
if ($result = Db::getInstance()->getRow($sql)) {
|
||||
|
||||
$object->id = (int) $result['id_url_redirection'];
|
||||
$object->url = $result['url'];
|
||||
$object->object_name = $result['object_name'];
|
||||
$object->object_id = (int) $result['object_id'];
|
||||
$object->date_add = $result['date_add'];
|
||||
$object->date_upd = $result['date_upd'];
|
||||
}
|
||||
|
||||
return $object;
|
||||
}
|
||||
public static function extractPath($requestUri)
|
||||
{
|
||||
// Remove query string if present
|
||||
$uri = parse_url($requestUri, PHP_URL_PATH);
|
||||
$segments = explode('/', trim($uri, '/'));
|
||||
|
||||
// If the first segment is 2 letters, ignore it
|
||||
if (isset($segments[0]) && preg_match('/^[a-zA-Z]{2}$/', $segments[0])) {
|
||||
array_shift($segments);
|
||||
}
|
||||
|
||||
return strtolower(implode('/', $segments));
|
||||
}
|
||||
/**
|
||||
* This method hooks into the dispatcher to check if the current URL
|
||||
* is a 404 and if there's a redirection available for it.
|
||||
* This hook needs to be called `hookActionDispatcherBefore` in a module.
|
||||
*
|
||||
* @param array $params
|
||||
* @return void
|
||||
*/
|
||||
public static function hookActionDispatcher(array $params): void
|
||||
{
|
||||
if (!defined('_PS_ADMIN_DIR_') && $params['controller_class'] === 'PageNotFoundController') {
|
||||
$url = trim(str_replace(Context::getContext()->shop->getBaseURL(true, false), '', $_SERVER['REQUEST_URI']), '/');
|
||||
|
||||
if (!empty($url)) {
|
||||
|
||||
$redirection = URLRedirect::getByUrl($url);
|
||||
if ($redirection->id) {
|
||||
$targetUrl = '';
|
||||
|
||||
switch ($redirection->object_name) {
|
||||
case 'category':
|
||||
$targetUrl = Context::getContext()->link->getCategoryLink($redirection->object_id);
|
||||
break;
|
||||
case 'product':
|
||||
$targetUrl = Context::getContext()->link->getProductLink($redirection->object_id);
|
||||
break;
|
||||
case 'cms':
|
||||
$targetUrl = Context::getContext()->link->getCMSLink($redirection->object_id);
|
||||
break;
|
||||
// Add more cases for other object types (cms_category, supplier, manufacturer etc.)
|
||||
default:
|
||||
// Log the invalid object_name or maybe remove the redirection.
|
||||
PrestaShopLogger::addLog(
|
||||
'Invalid object_name in URLRedirect table: ' . $redirection->object_name . ' URL: ' . $url,
|
||||
3, // Severity: WARNING
|
||||
0, // Error Code
|
||||
'URLRedirect', // Object Class
|
||||
$redirection->id, // Object ID
|
||||
true
|
||||
);
|
||||
return; // Don't redirect if the object name is invalid.
|
||||
}
|
||||
|
||||
if (!empty($targetUrl)) {
|
||||
Tools::redirect($targetUrl);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user