feat: new settings and mainpage blocks

This commit is contained in:
2025-11-11 00:30:39 +03:00
parent 5fb45000ac
commit 6176c720b1
97 changed files with 1842 additions and 1658 deletions

View File

@@ -361,13 +361,11 @@ class ControllerExtensionModuleTgshop extends Controller
'module_tgshop_owner_notification_template' => 'telegram.owner_notification_template',
'module_tgshop_text_order_created_success' => 'texts.text_order_created_success',
'module_tgshop_enable_store' => 'store.enable_store',
'module_tgshop_mainpage_products' => 'store.mainpage_products',
'module_tgshop_yandex_metrika' => 'metrics.yandex_metrika_counter',
'module_tgshop_customer_notification_template' => 'telegram.customer_notification_template',
'module_tgshop_feature_vouchers' => 'store.feature_vouchers',
'module_tgshop_order_default_status_id' => 'orders.order_default_status_id',
'module_tgshop_feature_coupons' => 'store.feature_coupons',
'module_tgshop_mainpage_categories' => 'store.mainpage_categories',
'module_tgshop_text_no_more_products' => 'texts.text_no_more_products',
'module_tgshop_text_empty_cart' => 'texts.text_empty_cart',
];

View File

@@ -7,38 +7,6 @@ $_['text_module'] = 'Модули';
$_['text_success'] = 'Настройки успешно изменены!';
$_['text_edit'] = 'Настройки';
$_['tab_telegram'] = 'Telegram';
$_['tab_statistics'] = 'Статистика';
$_['tab_shop'] = 'Магазин';
$_['tab_orders'] = 'Заказы';
$_['tab_texts'] = 'Тексты';
$_['lbl_module_tgshop_status'] = 'Статус';
$_['lbl_module_tgshop_app_name'] = 'Название приложения';
$_['lbl_module_tgshop_app_icon'] = 'Иконка приложения';
$_['lbl_module_tgshop_bot_token'] = 'Telegram Bot Token';
$_['lbl_module_tgshop_chat_id'] = 'Chat ID для уведомлений';
$_['lbl_module_tgshop_owner_notification_template'] = 'Шаблон уведомления о новом заказе владельцу';
$_['lbl_module_tgshop_customer_notification_template'] = 'Шаблон уведомления о новом заказе покупателю';
$_['lbl_module_tgshop_yandex_metrika'] = 'Код счётчика Яндекс Метрики';
$_['lbl_module_tgshop_theme_light'] = 'Светлая тема';
$_['lbl_module_tgshop_theme_dark'] = 'Тёмная тема';
$_['lbl_module_tgshop_mainpage_products'] = 'Товары на главной';
$_['lbl_module_tgshop_featured_products'] = 'Избранные товары';
$_['lbl_module_tgshop_order_customer_group_id'] = 'Группа покупателей';
$_['lbl_module_tgshop_order_default_status_id'] = 'Статус заказов';
$_['lbl_module_tgshop_mini_app_url'] = 'Ссылка на Telegram Mini App';
$_['lbl_module_tgshop_mainpage_categories'] = 'Категории на главной';
$_['lbl_module_tgshop_featured_categories'] = 'Избранные категории';
$_['lbl_module_tgshop_enable_store'] = 'Разрешить покупки';
$_['lbl_module_tgshop_feature_coupons'] = 'Промокоды';
$_['lbl_module_tgshop_feature_vouchers'] = 'Подарочные сертификаты';
$_['lbl_module_tgshop_home_banner_id'] = 'Баннер на главной';
$_['lbl_module_tgshop_debug'] = 'Режим разработчика';
$_['lbl_module_tgshop_text_no_more_products'] = 'Текст в конце списка товаров';
$_['lbl_module_tgshop_text_empty_cart'] = 'Текст пустой корзины';
$_['lbl_module_tgshop_text_order_created_success'] = 'Текст для успешного заказа';
// Entry
$_['entry_status'] = 'Статус';

View File

@@ -33,18 +33,9 @@
order_statuses: '{{ order_statuses | json_encode }}',
};
</script>
<div id="app">App Loading...</div>
<div id="app" class="telecart-admin-app">App Loading...</div>
</div>
</div>
</div>
</div>
{{ footer }}
<script>
const $element = $('#thumb-image-module_tgshop_app_icon');
$('#button-clear').on('click', function () {
$element.find('img').attr('src', $element.find('img').attr('data-placeholder'));
$element.parent().find('input').val('');
$element.popover('destroy');
});
</script>

View File

@@ -5,11 +5,13 @@ use App\ApplicationFactory;
use Cart\Cart;
use Cart\Currency;
use Cart\Tax;
use Openguru\OpenCartFramework\Http\Response as HttpResponse;
use Openguru\OpenCartFramework\ImageTool\ImageTool;
use Openguru\OpenCartFramework\ImageTool\ImageToolInterface;
use Openguru\OpenCartFramework\Logger\LoggerInterface;
use Openguru\OpenCartFramework\Logger\OpenCartLogAdapter;
use Openguru\OpenCartFramework\OpenCart\Decorators\OcRegistryDecorator;
use Openguru\OpenCartFramework\Support\Arr;
$sysLibPath = rtrim(DIR_SYSTEM, '/') . '/library/oc_telegram_shop';
$basePath = rtrim(DIR_APPLICATION, '/') . '/..';
@@ -23,6 +25,7 @@ if (is_readable($sysLibPath . '/oc_telegram_shop.phar')) {
/**
* @property Config $config
* @property Log $log
*/
class ControllerExtensionTgshopHandle extends Controller
{
@@ -32,98 +35,79 @@ class ControllerExtensionTgshopHandle extends Controller
$this->load->model('catalog/product');
$this->load->model('checkout/order');
$this->load->model('setting/setting');
}
public function index(): void
{
$this->session->data['language'] = $this->config->get('config_language');
try {
$this->session->data['language'] = $this->config->get('config_language');
$appDebug = filter_var($this->config->get('module_tgshop_debug'), FILTER_VALIDATE_BOOLEAN);
$json = $this->model_setting_setting->getSetting('module_telecart');
if (! isset($json['module_telecart_settings'])) {
$json['module_telecart_settings'] = [];
}
$app = ApplicationFactory::create([
'app_enabled' => filter_var($this->config->get('module_tgshop_status'), FILTER_VALIDATE_BOOLEAN),
'app_debug' => $appDebug,
'oc_config_tax' => $this->config->get('config_tax'),
'oc_default_currency' => $this->config->get('config_currency'),
'oc_customer_group_id' => $this->config->get('config_customer_group_id'),
// ID магазина, для которого будут создаваться заказы из Телеграм
'oc_store_id' => 0,
// Название магазина, для которого будут создаваться заказы из Телеграм
'oc_store_name' => $this->config->get('config_name'),
// ID статуса, с которым будут создаваться заказы через Телеграм по умолчанию.
'oc_order_status_id' => (int) $this->config->get('module_tgshop_order_default_status_id'),
'timezone' => $this->config->get('config_timezone', 'UTC'),
'language_id' => (int) $this->config->get('config_language_id'),
'shop_base_url' => HTTPS_SERVER,
'dir_image' => DIR_IMAGE,
'app_name' => $this->config->get('module_tgshop_app_name'),
'app_icon' => $this->config->get('module_tgshop_app_icon'),
'theme_light' => $this->config->get('module_tgshop_theme_light'),
'theme_dark' => $this->config->get('module_tgshop_theme_dark'),
'mainpage_products' => $this->config->get('module_tgshop_mainpage_products'),
'featured_products' => (array) $this->config->get('module_tgshop_featured_products'),
'mainpage_categories' => $this->config->get('module_tgshop_mainpage_categories'),
'featured_categories' => (array) $this->config->get('module_tgshop_featured_categories'),
'store_enabled' => filter_var($this->config->get('module_tgshop_enable_store'), FILTER_VALIDATE_BOOLEAN),
'base_url' => HTTPS_SERVER,
'ya_metrika_counter' => trim($this->config->get('module_tgshop_yandex_metrika')),
'ya_metrika_enabled' => ! empty(trim($this->config->get('module_tgshop_yandex_metrika'))),
'telegram' => [
'bot_token' => $this->config->get('module_tgshop_bot_token'),
'chat_id' => $this->config->get('module_tgshop_chat_id'),
'owner_notification_template' => $this->config->get('module_tgshop_owner_notification_template'),
'customer_notification_template' => $this->config->get('module_tgshop_customer_notification_template'),
],
'db' => [
'host' => DB_HOSTNAME,
'database' => DB_DATABASE,
'username' => DB_USERNAME,
'password' => DB_PASSWORD,
'prefix' => DB_PREFIX,
'port' => DB_PORT,
],
'logs' => [
'path' => DIR_LOGS,
],
'cache_categories_main' => 60 * 10,
'cache_products_main' => 60 * 10,
'feature_coupons' => filter_var(
$this->config->get('module_tgshop_feature_coupons'),
FILTER_VALIDATE_BOOLEAN
),
'feature_vouchers' => filter_var(
$this->config->get('module_tgshop_feature_vouchers'),
FILTER_VALIDATE_BOOLEAN
),
'mainpage_slider' => $this->safeJsonDecode($this->config->get('module_tgshop_mainpage_slider'), []),
'texts' => [
'no_more_products' => $this->config->get('module_tgshop_text_no_more_products'),
'empty_cart' => $this->config->get('module_tgshop_text_empty_cart'),
'order_created_success' => $this->config->get('module_tgshop_text_order_created_success'),
],
]);
$items = Arr::mergeArraysRecursively($json['module_telecart_settings'], [
'app' => [
'shop_base_url' => HTTPS_SERVER, // for catalog: HTTPS_SERVER, for admin: HTTPS_CATALOG
'language_id' => (int) $this->config->get('config_language_id'),
],
'logs' => [
'path' => DIR_LOGS,
],
'database' => [
'host' => DB_HOSTNAME,
'database' => DB_DATABASE,
'username' => DB_USERNAME,
'password' => DB_PASSWORD,
'prefix' => DB_PREFIX,
'port' => (int) DB_PORT,
],
'store' => [
'oc_store_id' => 0,
'oc_default_currency' => $this->config->get('config_currency'),
'oc_config_tax' => filter_var($this->config->get('config_tax'), FILTER_VALIDATE_BOOLEAN),
],
'orders' => [
'oc_customer_group_id' => (int) $this->config->get('config_customer_group_id'),
],
]);
$app->bind(OcModelCatalogProductAdapter::class, function () {
return new OcModelCatalogProductAdapter($this->model_catalog_product);
});
$appDebug = Arr::get($items, 'app.app_debug');
$app->bind(Url::class, fn() => $this->url);
$app->bind(Currency::class, fn() => $this->currency);
$app->bind(Tax::class, fn() => $this->tax);
$app->bind(ImageToolInterface::class, fn() => new ImageTool(DIR_IMAGE, HTTPS_SERVER));
$app->bind(Cart::class, fn() => $this->cart);
$app->bind(OcRegistryDecorator::class, fn() => new OcRegistryDecorator($this->registry));
$app->singleton(Log::class, fn() => $this->log);
$app = ApplicationFactory::create($items);
$app
->withLogger(
fn() => new OpenCartLogAdapter(
$this->log,
'TeleCart',
$appDebug ? LoggerInterface::LEVEL_DEBUG : LoggerInterface::LEVEL_WARNING,
$app->bind(OcModelCatalogProductAdapter::class, function () {
return new OcModelCatalogProductAdapter($this->model_catalog_product);
});
$app->bind(Url::class, fn() => $this->url);
$app->bind(Currency::class, fn() => $this->currency);
$app->bind(Tax::class, fn() => $this->tax);
$app->bind(ImageToolInterface::class, fn() => new ImageTool(DIR_IMAGE, HTTPS_SERVER));
$app->bind(Cart::class, fn() => $this->cart);
$app->bind(OcRegistryDecorator::class, fn() => new OcRegistryDecorator($this->registry));
$app->singleton(Log::class, fn() => $this->log);
$app
->withLogger(
fn() => new OpenCartLogAdapter(
$this->log,
'TeleCart',
$appDebug ? LoggerInterface::LEVEL_DEBUG : LoggerInterface::LEVEL_WARNING,
)
)
)
->bootAndHandleRequest();
->bootAndHandleRequest();
} catch (Exception $e) {
$logger = new OpenCartLogAdapter($this->log, 'TeleCart');
$logger->logException($e);
http_response_code(HttpResponse::HTTP_INTERNAL_SERVER_ERROR);
header('Content-Type: application/json');
echo json_encode([
'error' => 'Server Error.',
], JSON_THROW_ON_ERROR);
}
}
function extractPureJs($input)
@@ -153,15 +137,20 @@ class ControllerExtensionTgshopHandle extends Controller
public function ya_metrika(): void
{
$raw = html_entity_decode($this->config->get('module_tgshop_yandex_metrika'), ENT_QUOTES | ENT_HTML5);
$raw = $this->extractPureJs($raw);
$json = $this->model_setting_setting->getSetting('module_telecart');
if (isset($json['module_telecart_settings'])) {
$raw = Arr::get($json, 'module_telecart_settings.metrics.yandex_metrika_counter');
$raw = $this->extractPureJs($raw);
http_response_code(200);
header('Content-Type: application/javascript');
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET, POST');
header('Access-Control-Allow-Headers: Content-Type, Authorization');
header('Access-Control-Allow-Credentials: true');
echo $raw;
http_response_code(200);
header('Content-Type: application/javascript');
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET, POST');
header('Access-Control-Allow-Headers: Content-Type, Authorization');
header('Access-Control-Allow-Credentials: true');
echo $raw;
} else {
http_response_code(404);
}
}
}

View File

@@ -17,7 +17,7 @@ class ApplicationFactory
{
public static function create(array $settings): Application
{
$defaultConfig = require __DIR__ . '/config.php';
$defaultConfig = require __DIR__ . '/../src/config.php';
$routes = require __DIR__ . '/routes.php';
$merged = Arr::mergeArraysRecursively($defaultConfig, $settings);

View File

@@ -51,6 +51,7 @@ class SettingsHandler
'orders',
'texts',
'sliders',
'mainpage_blocks',
]);
return new JsonResponse(compact('data'));

View File

@@ -1,84 +0,0 @@
<?php
return [
'app' => [
'app_enabled' => true,
'app_name' => 'Telecart',
'app_icon' => null,
"theme_light" => "light",
"theme_dark" => "dark",
"app_debug" => false
],
'telegram' => [
"bot_token" => "",
"chat_id" => null,
"owner_notification_template" => <<<TEXT
*Новый заказ \#{order_id}* в магазине *{store_name}*
*Покупатель:* {customer}
*Email:* {email}
*Телефон:* {phone}
*IP:* {ip}
*Адрес доставки:*
{address}
*Комментарий:*
{comment}
*Сумма заказа:* {total}
*Дата оформления:* {created_at}
TEXT,
"customer_notification_template" => <<<TEXT
Спасибо за Ваш заказ в магазине *{store_name}*
*Номер заказа* \#{order_id}
*Сумма заказа:* {total}
*Дата оформления:* {created_at}
Мы свяжемся с вами при необходимости\.
Хорошего дня\!
TEXT,
"mini_app_url" => "",
],
"metrics" => [
"yandex_metrika_enabled" => false,
"yandex_metrika_counter" => "",
],
'store' => [
'enable_store' => true,
'mainpage_products' => 'most_viewed',
'featured_products' => [],
'mainpage_categories' => 'latest10',
'featured_categories' => [],
'feature_coupons' => true,
'feature_vouchers' => true,
],
'texts' => [
'text_no_more_products' => 'Это всё по текущему запросу. Попробуйте уточнить фильтры или поиск.',
'text_empty_cart' => 'Ваша корзина пуста.',
'text_order_created_success' => 'Ваш заказ успешно оформлен и будет обработан в ближайшее время.'
],
'orders' => [
'order_default_status_id' => 1,
],
'sliders' => [
'mainpage_slider' => [
'is_enabled' => false,
'effect' => 'slide',
'pagination' => true,
'scrollbar' => false,
'free_mode' => false,
'space_between' => 30,
'autoplay' => false,
'loop' => false,
'slides' => [],
],
],
];

View File

@@ -10,7 +10,6 @@ final class ConfigDTO
private StoreDTO $store;
private OrdersDTO $orders;
private TextsDTO $texts;
private SlidersDTO $sliders;
private DatabaseDTO $database;
private LogsDTO $logs;
@@ -21,7 +20,6 @@ final class ConfigDTO
StoreDTO $store,
OrdersDTO $orders,
TextsDTO $texts,
SlidersDTO $sliders,
DatabaseDTO $database,
LogsDTO $logs
) {
@@ -31,7 +29,6 @@ final class ConfigDTO
$this->store = $store;
$this->orders = $orders;
$this->texts = $texts;
$this->sliders = $sliders;
$this->database = $database;
$this->logs = $logs;
}
@@ -66,11 +63,6 @@ final class ConfigDTO
return $this->texts;
}
public function getSliders(): SlidersDTO
{
return $this->sliders;
}
public function getDatabase(): DatabaseDTO
{
return $this->database;
@@ -89,7 +81,6 @@ final class ConfigDTO
'logs' => $this->logs->toArray(),
'metrics' => $this->metrics->toArray(),
'orders' => $this->orders->toArray(),
'sliders' => $this->sliders->toArray(),
'store' => $this->store->toArray(),
'telegram' => $this->telegram->toArray(),
'texts' => $this->texts->toArray(),

View File

@@ -1,42 +0,0 @@
<?php
namespace App\DTO\Settings\MainpageSlider;
final class LinkDTO
{
private string $type;
private ?LinkValueDTO $value;
public function __construct(
string $type,
?LinkValueDTO $value
) {
$this->type = $type;
$this->value = $value;
}
public function getType(): string
{
return $this->type;
}
public function getValue(): ?LinkValueDTO
{
return $this->value;
}
public function toArray(): array
{
$result = [
'type' => $this->type,
'value' => null,
];
if ($this->value !== null) {
$result['value'] = $this->value->toArray();
}
return $result;
}
}

View File

@@ -1,10 +0,0 @@
<?php
namespace App\DTO\Settings\MainpageSlider;
final class LinkType
{
public const NONE = 'none';
public const CATEGORY = 'category';
public const PRODUCT = 'product';
}

View File

@@ -1,55 +0,0 @@
<?php
namespace App\DTO\Settings\MainpageSlider;
final class LinkValueDTO
{
private ?int $categoryId;
private ?string $name;
private ?int $productId;
public function __construct(
?int $categoryId = null,
?string $name = null,
?int $productId = null
) {
$this->categoryId = $categoryId;
$this->name = $name;
$this->productId = $productId;
}
public function getCategoryId(): ?int
{
return $this->categoryId;
}
public function getName(): ?string
{
return $this->name;
}
public function getProductId(): ?int
{
return $this->productId;
}
public function toArray(): array
{
$result = [];
if ($this->categoryId !== null) {
$result['category_id'] = $this->categoryId;
}
if ($this->name !== null) {
$result['name'] = $this->name;
}
if ($this->productId !== null) {
$result['product_id'] = $this->productId;
}
return $result;
}
}

View File

@@ -1,111 +0,0 @@
<?php
namespace App\DTO\Settings\MainpageSlider;
final class MainpageSliderDTO
{
private bool $isEnabled;
private string $effect;
private bool $pagination;
private bool $scrollbar;
private bool $freeMode;
private int $spaceBetween;
private bool $autoplay;
private bool $loop;
/** @var SlideDTO[] */
private array $slides;
/**
* @param SlideDTO[] $slides
*/
public function __construct(
bool $isEnabled,
string $effect,
bool $pagination,
bool $scrollbar,
bool $freeMode,
int $spaceBetween,
bool $autoplay,
bool $loop,
array $slides
) {
$this->isEnabled = $isEnabled;
$this->effect = $effect;
$this->pagination = $pagination;
$this->scrollbar = $scrollbar;
$this->freeMode = $freeMode;
$this->spaceBetween = $spaceBetween;
$this->autoplay = $autoplay;
$this->loop = $loop;
$this->slides = $slides;
}
public function isEnabled(): bool
{
return $this->isEnabled;
}
public function getEffect(): string
{
return $this->effect;
}
public function isPagination(): bool
{
return $this->pagination;
}
public function isScrollbar(): bool
{
return $this->scrollbar;
}
public function isFreeMode(): bool
{
return $this->freeMode;
}
public function getSpaceBetween(): int
{
return $this->spaceBetween;
}
public function isAutoplay(): bool
{
return $this->autoplay;
}
public function isLoop(): bool
{
return $this->loop;
}
/**
* @return SlideDTO[]
*/
public function getSlides(): array
{
return $this->slides;
}
public function toArray(): array
{
$slides = [];
foreach ($this->slides as $slide) {
$slides[] = $slide->toArray();
}
return [
'is_enabled' => $this->isEnabled,
'effect' => $this->effect,
'pagination' => $this->pagination,
'scrollbar' => $this->scrollbar,
'free_mode' => $this->freeMode,
'space_between' => $this->spaceBetween,
'autoplay' => $this->autoplay,
'loop' => $this->loop,
'slides' => $slides,
];
}
}

View File

@@ -1,45 +0,0 @@
<?php
namespace App\DTO\Settings\MainpageSlider;
final class SlideDTO
{
private string $title;
private LinkDTO $link;
private string $image;
public function __construct(
string $title,
LinkDTO $link,
string $image
) {
$this->title = $title;
$this->link = $link;
$this->image = $image;
}
public function getTitle(): string
{
return $this->title;
}
public function getLink(): LinkDTO
{
return $this->link;
}
public function getImage(): string
{
return $this->image;
}
public function toArray(): array
{
return [
'title' => $this->title,
'link' => $this->link->toArray(),
'image' => $this->image,
];
}
}

View File

@@ -1,28 +0,0 @@
<?php
namespace App\DTO\Settings;
use App\DTO\Settings\MainpageSlider\MainpageSliderDTO;
final class SlidersDTO
{
private MainpageSliderDTO $mainpageSlider;
public function __construct(MainpageSliderDTO $mainpageSlider)
{
$this->mainpageSlider = $mainpageSlider;
}
public function getMainpageSlider(): MainpageSliderDTO
{
return $this->mainpageSlider;
}
public function toArray(): array
{
return [
'mainpage_slider' => $this->mainpageSlider->toArray(),
];
}
}

View File

@@ -5,28 +5,14 @@ namespace App\DTO\Settings;
final class StoreDTO
{
private bool $enableStore;
private string $mainpageProducts;
/** @var int[] */
private array $featuredProducts;
private string $mainpageCategories;
/** @var int[] */
private array $featuredCategories;
private bool $featureCoupons;
private bool $featureVouchers;
private string $ocDefaultCurrency;
private bool $ocConfigTax;
private int $ocStoreId;
/**
* @param int[] $featuredProducts
* @param int[] $featuredCategories
*/
public function __construct(
bool $enableStore,
string $mainpageProducts,
array $featuredProducts,
string $mainpageCategories,
array $featuredCategories,
bool $featureCoupons,
bool $featureVouchers,
string $ocDefaultCurrency,
@@ -34,10 +20,6 @@ final class StoreDTO
int $ocStoreId
) {
$this->enableStore = $enableStore;
$this->mainpageProducts = $mainpageProducts;
$this->featuredProducts = $featuredProducts;
$this->mainpageCategories = $mainpageCategories;
$this->featuredCategories = $featuredCategories;
$this->featureCoupons = $featureCoupons;
$this->featureVouchers = $featureVouchers;
$this->ocDefaultCurrency = $ocDefaultCurrency;
@@ -50,32 +32,6 @@ final class StoreDTO
return $this->enableStore;
}
public function getMainpageProducts(): string
{
return $this->mainpageProducts;
}
/**
* @return int[]
*/
public function getFeaturedProducts(): array
{
return $this->featuredProducts;
}
public function getMainpageCategories(): string
{
return $this->mainpageCategories;
}
/**
* @return int[]
*/
public function getFeaturedCategories(): array
{
return $this->featuredCategories;
}
public function isFeatureCoupons(): bool
{
return $this->featureCoupons;
@@ -105,10 +61,6 @@ final class StoreDTO
{
return [
'enable_store' => $this->enableStore,
'mainpage_products' => $this->mainpageProducts,
'featured_products' => $this->featuredProducts,
'mainpage_categories' => $this->mainpageCategories,
'featured_categories' => $this->featuredCategories,
'feature_coupons' => $this->featureCoupons,
'feature_vouchers' => $this->featureVouchers,
'oc_default_currency' => $this->ocDefaultCurrency,

View File

@@ -1,51 +0,0 @@
<?php
declare(strict_types=1);
namespace App\Filters;
use Openguru\OpenCartFramework\CriteriaBuilder\Criterion;
use Openguru\OpenCartFramework\CriteriaBuilder\Rules\BaseRule;
use Openguru\OpenCartFramework\QueryBuilder\Builder;
class ProductForMainPage extends BaseRule
{
public const NAME = 'RULE_PRODUCT_FOR_MAIN_PAGE';
public static function initWithDefaults(): BaseRule
{
return new static(static::NAME, [
'product_for_main_page' => new Criterion(static::CRITERIA_OPTION_PRODUCT_MODEL, [
'operator' => static::CRITERIA_OPERATOR_EQUALS,
'value' => false,
]),
]);
}
public function apply(Builder $builder, $operand): void
{
$criterion = $this->criteria[static::CRITERIA_OPTION_PRODUCT_FOR_MAIN_PAGE] ?? false;
if (! $criterion || $criterion->params['value'] === false) {
return;
}
$featuredProducts = config('featured_products', []);
$mainpageProducts = config('mainpage_products');
if ($mainpageProducts === 'featured' && $featuredProducts) {
$builder->whereIn('products.product_id', $featuredProducts);
return;
}
if ($mainpageProducts === 'latest') {
$builder->orders = [];
$builder->orderBy('products.date_modified', 'DESC');
return;
}
if ($mainpageProducts === 'most_viewed') {
$builder->orders = [];
$builder->orderBy('products.viewed', 'DESC');
}
}
}

View File

@@ -1,43 +0,0 @@
<?php
namespace App\Handlers;
use App\Services\SettingsService;
use Openguru\OpenCartFramework\Http\JsonResponse;
use Openguru\OpenCartFramework\ImageTool\ImageToolInterface;
use Openguru\OpenCartFramework\OpenCart\Decorators\OcRegistryDecorator;
class BannerHandler
{
private OcRegistryDecorator $registry;
private ImageToolInterface $imageTool;
private SettingsService $settings;
public function __construct(OcRegistryDecorator $registry, ImageToolInterface $imageTool, SettingsService $settings)
{
$this->registry = $registry;
$this->imageTool = $imageTool;
$this->settings = $settings;
$this->registry->load->model('design/banner');
}
public function show(): JsonResponse
{
$slider = $this->settings->config()->getSliders()->getMainpageSlider();
$data = [];
foreach ($slider->getSlides() as $index => $slide) {
if (is_file(DIR_IMAGE . $slide->getImage())) {
$data['slides'][$index] = [
'id' => $index,
'title' => $slide->getTitle(),
'link' => $slide->getLink(),
'image' => $this->imageTool->cover($slide->getImage(), 1110, 600),
];
}
}
return new JsonResponse(compact('data'));
}
}

View File

@@ -0,0 +1,26 @@
<?php
namespace App\Handlers;
use App\Services\BlocksService;
use Openguru\OpenCartFramework\Http\JsonResponse;
use Openguru\OpenCartFramework\Http\Request;
class BlocksHandler
{
private BlocksService $blocksService;
public function __construct(BlocksService $blocksService)
{
$this->blocksService = $blocksService;
}
public function processBlock(Request $request): JsonResponse
{
$block = $request->json();
$data = $this->blocksService->process($block);
return new JsonResponse(compact('data'));
}
}

View File

@@ -32,17 +32,6 @@ class CategoriesHandler
$languageId = $this->settings->config()->getApp()->getLanguageId();
$perPage = $request->get('perPage', 100);
$forMainPage = filter_var($request->get('forMainPage', false), FILTER_VALIDATE_BOOLEAN);
$featuredCategories = $this->settings->config()->getStore()->getFeaturedCategories();
$mainpageCategories = $this->settings->config()->getStore()->getMainpageCategories();
if ($forMainPage && $mainpageCategories === 'no_categories') {
return new JsonResponse(['data' => []]);
}
if ($forMainPage && $mainpageCategories === 'latest10') {
$perPage = 10;
}
$categoriesFlat = $this->queryBuilder->newQuery()
->select([
@@ -61,12 +50,6 @@ class CategoriesHandler
}
)
->where('categories.status', '=', 1)
->when(
$forMainPage && $mainpageCategories === 'featured' && $featuredCategories,
function (Builder $query) use ($featuredCategories) {
$query->whereIn('categories.category_id', $featuredCategories);
}
)
->orderBy('parent_id')
->orderBy('sort_order')
->get();

View File

@@ -3,7 +3,6 @@
namespace App\Handlers;
use App\Filters\ProductCategory;
use App\Filters\ProductForMainPage;
use App\Filters\ProductPrice;
use Openguru\OpenCartFramework\Http\JsonResponse;
@@ -29,18 +28,6 @@ class FiltersHandler
],
],
ProductForMainPage::NAME => [
'criteria' => [
'product_for_main_page' => [
'type' => 'boolean',
'params' => [
'operator' => 'equals',
'value' => true,
],
],
],
],
ProductCategory::NAME => [
'criteria' => [
'product_category_id' => [

View File

@@ -31,12 +31,13 @@ class ProductsHandler
{
$page = (int) $request->json('page', 1);
$perPage = min((int) $request->json('perPage', 6), 15);
$maxPages = (int) $request->json('maxPages', 10);
$search = trim($request->get('search', ''));
$filters = $request->json('filters');
$languageId = $this->settings->config()->getApp()->getLanguageId();
$response = $this->productsService->getProductsResponse(
compact('page', 'perPage', 'search', 'filters'),
compact('page', 'perPage', 'search', 'filters', 'maxPages'),
$languageId,
);

View File

@@ -64,17 +64,13 @@ class SettingsHandler
'feature_vouchers' => $this->settings->config()->getStore()->isFeatureVouchers(),
'currency_code' => $this->settings->config()->getStore()->getOcDefaultCurrency(),
'texts' => $this->settings->config()->getTexts()->toArray(),
'mainpage_slider' => $this->settings->config()->getSliders()->getMainpageSlider()->toArray(),
'mainpage_blocks' => $this->settings->get('mainpage_blocks', []),
]);
}
public function manifest(): JsonResponse
{
$appIcon = $this->settings->config()->getApp()->getAppIcon();
$icon192 = $this->imageTool->resize($appIcon, 192, 192, 'no_image.png', 'png');
$icon512 = $this->imageTool->resize($appIcon, 512, 512, 'no_image.png', 'png');
return new JsonResponse([
$manifest = [
'name' => $this->settings->config()->getApp()->getAppName(),
'short_name' => $this->settings->config()->getApp()->getAppName(),
'start_url' => '/image/catalog/tgshopspa/',
@@ -82,7 +78,13 @@ class SettingsHandler
'background_color' => '#ffffff',
'theme_color' => '#000000',
'orientation' => 'portrait',
'icons' => [
];
$appIcon = $this->settings->config()->getApp()->getAppIcon();
if ($appIcon) {
$icon192 = $this->imageTool->resize($appIcon, 192, 192, 'no_image.png', 'png');
$icon512 = $this->imageTool->resize($appIcon, 512, 512, 'no_image.png', 'png');
$manifest['icons'] = [
[
'src' => $icon192,
'sizes' => '192x192',
@@ -93,8 +95,10 @@ class SettingsHandler
'sizes' => '512x512',
'type' => 'image/png',
]
]
]);
];
}
return new JsonResponse($manifest);
}
public function testTgMessage(Request $request): JsonResponse

View File

@@ -6,7 +6,6 @@ use App\Exceptions\CustomExceptionHandler;
use App\Filters\ProductAttribute;
use App\Filters\ProductCategories;
use App\Filters\ProductCategory;
use App\Filters\ProductForMainPage;
use App\Filters\ProductManufacturer;
use App\Filters\ProductModel;
use App\Filters\ProductPrice;
@@ -64,7 +63,6 @@ class AppServiceProvider extends ServiceProvider
ProductPrice::NAME => ProductPrice::class,
ProductQuantity::NAME => ProductQuantity::class,
ProductStatus::NAME => ProductStatus::class,
ProductForMainPage::NAME => ProductForMainPage::class,
ProductCategory::NAME => ProductCategory::class,
]);
}

View File

@@ -0,0 +1,110 @@
<?php
namespace App\Services;
use Openguru\OpenCartFramework\Cache\CacheInterface;
use Openguru\OpenCartFramework\ImageTool\ImageToolInterface;
use Openguru\OpenCartFramework\Logger\LoggerInterface;
use Openguru\OpenCartFramework\QueryBuilder\Builder;
use Openguru\OpenCartFramework\QueryBuilder\JoinClause;
use RuntimeException;
class BlocksService
{
private static array $processors = [
'slider' => [self::class, 'processSlider'],
'categories_top' => [self::class, 'processCategoriesTop'],
'products_feed' => [self::class, 'processProductsFeed'],
];
private LoggerInterface $logger;
private ImageToolInterface $imageTool;
private CacheInterface $cache;
private SettingsService $settings;
private Builder $queryBuilder;
public function __construct(
LoggerInterface $logger,
ImageToolInterface $imageTool,
CacheInterface $cache,
SettingsService $settings,
Builder $queryBuilder
) {
$this->logger = $logger;
$this->imageTool = $imageTool;
$this->cache = $cache;
$this->settings = $settings;
$this->queryBuilder = $queryBuilder;
}
public function process(array $block): array
{
$method = self::$processors[$block['type']] ?? null;
if (! $method) {
throw new RuntimeException('Processor for block type ' . $block['type'] . ' does not exist');
}
return call_user_func_array($method, [$block]);
}
private function processSlider(array $block): array
{
$slides = $block['data']['slides'];
foreach ($slides as $slideIndex => $slide) {
if (is_file(DIR_IMAGE . $slide['image'])) {
$block['data']['slides'][$slideIndex]['image'] = $this->imageTool->cover(
$slide['image'],
1110,
600
);
}
}
return $block;
}
private function processCategoriesTop(array $block): array
{
$count = $block['data']['count'];
$languageId = $this->settings->config()->getApp()->getLanguageId();
$categories = [];
if ($count > 0) {
$categories = $this->queryBuilder->newQuery()
->select([
'categories.category_id' => 'id',
'descriptions.name' => 'name',
])
->from(db_table('category'), 'categories')
->join(
db_table('category_description') . ' AS descriptions',
function (JoinClause $join) use ($languageId) {
$join->on('categories.category_id', '=', 'descriptions.category_id')
->where('descriptions.language_id', '=', $languageId);
}
)
->where('categories.status', '=', 1)
->where('categories.parent_id', '=', 0)
->orderBy('sort_order')
->orderBy('descriptions.name')
->limit($count)
->get();
$categories = array_map(static function ($category) {
$category['id'] = (int) $category['id'];
return $category;
}, $categories);
}
$block['data']['categories'] = $categories;
return $block;
}
private function processProductsFeed(array $block): array
{
return $block;
}
}

View File

@@ -6,13 +6,8 @@ use App\DTO\Settings\AppDTO;
use App\DTO\Settings\ConfigDTO;
use App\DTO\Settings\DatabaseDTO;
use App\DTO\Settings\LogsDTO;
use App\DTO\Settings\MainpageSlider\LinkDTO;
use App\DTO\Settings\MainpageSlider\LinkValueDTO;
use App\DTO\Settings\MainpageSlider\MainpageSliderDTO;
use App\DTO\Settings\MainpageSlider\SlideDTO;
use App\DTO\Settings\MetricsDTO;
use App\DTO\Settings\OrdersDTO;
use App\DTO\Settings\SlidersDTO;
use App\DTO\Settings\StoreDTO;
use App\DTO\Settings\TelegramDTO;
use App\DTO\Settings\TextsDTO;
@@ -22,7 +17,7 @@ class SettingsSerializerService
{
public function fromArray(array $data): ConfigDTO
{
$keys = ['app', 'telegram', 'metrics', 'store', 'orders', 'texts', 'sliders', 'database', 'logs'];
$keys = ['app', 'telegram', 'metrics', 'store', 'orders', 'texts', 'database', 'logs'];
foreach ($keys as $key) {
if (! array_key_exists($key, $data)) {
throw new InvalidArgumentException("Settings key '$key' is required!");
@@ -35,7 +30,6 @@ class SettingsSerializerService
$this->validateStore($data['store']);
$this->validateOrders($data['orders']);
$this->validateTexts($data['texts']);
$this->validateSliders($data['sliders']);
$this->validateDatabase($data['database']);
$this->validateLogs($data['logs']);
@@ -46,7 +40,6 @@ class SettingsSerializerService
$this->deserializeStore($data['store']),
$this->deserializeOrders($data['orders']),
$this->deserializeTexts($data['texts']),
$this->deserializeSliders($data['sliders']),
$this->deserializeDatabase($data['database']),
$this->deserializeLogs($data['logs']),
);
@@ -146,10 +139,6 @@ class SettingsSerializerService
return new StoreDTO(
$data['enable_store'] ?? true,
$data['mainpage_products'] ?? 'most_viewed',
$data['featured_products'] ?? [],
$data['mainpage_categories'] ?? 'latest10',
$data['featured_categories'] ?? [],
$data['feature_coupons'] ?? true,
$data['feature_vouchers'] ?? true,
$data['oc_default_currency'],
@@ -183,66 +172,6 @@ class SettingsSerializerService
);
}
private function deserializeSliders(array $data): SlidersDTO
{
return new SlidersDTO(
$this->deserializeMainpageSlider($data['mainpage_slider'] ?? [])
);
}
private function deserializeMainpageSlider(array $data): MainpageSliderDTO
{
$slides = [];
if (isset($data['slides']) && is_array($data['slides'])) {
foreach ($data['slides'] as $slideData) {
$slides[] = $this->deserializeSlide($slideData);
}
}
return new MainpageSliderDTO(
$data['is_enabled'] ?? false,
$data['effect'] ?? 'slide',
$data['pagination'] ?? true,
$data['scrollbar'] ?? false,
$data['free_mode'] ?? false,
$data['space_between'] ?? 30,
$data['autoplay'] ?? false,
$data['loop'] ?? false,
$slides
);
}
private function deserializeSlide(array $data): SlideDTO
{
return new SlideDTO(
$data['title'] ?? '',
$this->deserializeLink($data['link'] ?? []),
$data['image'] ?? ''
);
}
private function deserializeLink(array $data): LinkDTO
{
$value = null;
if (isset($data['value'])) {
$value = $this->deserializeLinkValue($data['value']);
}
return new LinkDTO(
$data['type'] ?? 'none',
$value
);
}
private function deserializeLinkValue(array $data): LinkValueDTO
{
return new LinkValueDTO(
$data['category_id'] ?? null,
$data['name'] ?? null,
$data['product_id'] ?? null
);
}
// ==================== Validation Methods ====================
private function validateApp(array $data): void
@@ -340,44 +269,6 @@ class SettingsSerializerService
throw new InvalidArgumentException('store.enable_store must be a boolean');
}
if (isset($data['mainpage_products']) && ! is_string($data['mainpage_products'])) {
throw new InvalidArgumentException('store.mainpage_products must be a string');
}
if (isset($data['featured_products'])) {
if (! is_array($data['featured_products'])) {
throw new InvalidArgumentException('store.featured_products must be an array');
}
foreach ($data['featured_products'] as $index => $productId) {
if (! is_int($productId)) {
throw new InvalidArgumentException("store.featured_products[$index] must be an integer");
}
if ($productId <= 0) {
throw new InvalidArgumentException("store.featured_products[$index] must be a positive integer");
}
}
}
if (isset($data['mainpage_categories']) && ! is_string($data['mainpage_categories'])) {
throw new InvalidArgumentException('store.mainpage_categories must be a string');
}
if (isset($data['featured_categories'])) {
if (! is_array($data['featured_categories'])) {
throw new InvalidArgumentException('store.featured_categories must be an array');
}
foreach ($data['featured_categories'] as $index => $categoryId) {
if (! is_int($categoryId)) {
throw new InvalidArgumentException("store.featured_categories[$index] must be an integer");
}
if ($categoryId <= 0) {
throw new InvalidArgumentException(
"store.featured_categories[$index] must be a positive integer"
);
}
}
}
if (isset($data['feature_coupons']) && ! is_bool($data['feature_coupons'])) {
throw new InvalidArgumentException('store.feature_coupons must be a boolean');
}
@@ -454,178 +345,6 @@ class SettingsSerializerService
}
}
private function validateSliders(array $data): void
{
if (isset($data['mainpage_slider'])) {
if (! is_array($data['mainpage_slider'])) {
throw new InvalidArgumentException('sliders.mainpage_slider must be an object');
}
$this->validateMainpageSlider($data['mainpage_slider']);
}
}
private function validateMainpageSlider(array $data): void
{
if (isset($data['is_enabled']) && ! is_bool($data['is_enabled'])) {
throw new InvalidArgumentException('sliders.mainpage_slider.is_enabled must be a boolean');
}
if (isset($data['effect'])) {
if (! is_string($data['effect'])) {
throw new InvalidArgumentException('sliders.mainpage_slider.effect must be a string');
}
$allowedEffects = ['slide', 'fade', 'cube', 'coverflow', 'flip'];
if (! in_array($data['effect'], $allowedEffects, true)) {
throw new InvalidArgumentException(
'sliders.mainpage_slider.effect must be one of: ' . implode(', ', $allowedEffects)
);
}
}
if (isset($data['pagination']) && ! is_bool($data['pagination'])) {
throw new InvalidArgumentException('sliders.mainpage_slider.pagination must be a boolean');
}
if (isset($data['scrollbar']) && ! is_bool($data['scrollbar'])) {
throw new InvalidArgumentException('sliders.mainpage_slider.scrollbar must be a boolean');
}
if (isset($data['free_mode']) && ! is_bool($data['free_mode'])) {
throw new InvalidArgumentException('sliders.mainpage_slider.free_mode must be a boolean');
}
if (isset($data['space_between'])) {
if (! is_int($data['space_between'])) {
throw new InvalidArgumentException('sliders.mainpage_slider.space_between must be an integer');
}
if ($data['space_between'] < 0) {
throw new InvalidArgumentException(
'sliders.mainpage_slider.space_between must be a non-negative integer'
);
}
}
if (isset($data['autoplay']) && ! is_bool($data['autoplay'])) {
throw new InvalidArgumentException('sliders.mainpage_slider.autoplay must be a boolean');
}
if (isset($data['loop']) && ! is_bool($data['loop'])) {
throw new InvalidArgumentException('sliders.mainpage_slider.loop must be a boolean');
}
if (isset($data['slides'])) {
if (! is_array($data['slides'])) {
throw new InvalidArgumentException('sliders.mainpage_slider.slides must be an array');
}
foreach ($data['slides'] as $index => $slideData) {
if (! is_array($slideData)) {
throw new InvalidArgumentException("sliders.mainpage_slider.slides[$index] must be an object");
}
$this->validateSlide($slideData, $index);
}
}
}
private function validateSlide(array $data, int $index): void
{
if (isset($data['title']) && ! is_string($data['title'])) {
throw new InvalidArgumentException("sliders.mainpage_slider.slides[$index].title must be a string");
}
if (isset($data['link'])) {
if (! is_array($data['link'])) {
throw new InvalidArgumentException("sliders.mainpage_slider.slides[$index].link must be an object");
}
$this->validateLink($data['link'], $index);
}
if (isset($data['image']) && ! is_string($data['image'])) {
throw new InvalidArgumentException("sliders.mainpage_slider.slides[$index].image must be a string");
}
}
private function validateLink(array $data, int $slideIndex): void
{
if (isset($data['type'])) {
if (! is_string($data['type'])) {
throw new InvalidArgumentException(
"sliders.mainpage_slider.slides[$slideIndex].link.type must be a string"
);
}
$allowedTypes = ['none', 'category', 'product'];
if (! in_array($data['type'], $allowedTypes, true)) {
throw new InvalidArgumentException(
"sliders.mainpage_slider.slides[$slideIndex].link.type must be one of: " . implode(
', ',
$allowedTypes
)
);
}
}
if (isset($data['value'])) {
if ($data['value'] !== null) {
if (! is_array($data['value'])) {
throw new InvalidArgumentException(
"sliders.mainpage_slider.slides[$slideIndex].link.value must be an object or null"
);
}
$this->validateLinkValue($data['value'], $data['type'] ?? 'none', $slideIndex);
}
}
}
private function validateLinkValue(array $data, string $linkType, int $slideIndex): void
{
if ($linkType === 'category') {
if (isset($data['category_id'])) {
if (! is_int($data['category_id'])) {
throw new InvalidArgumentException(
"sliders.mainpage_slider.slides[$slideIndex].link.value.category_id must be an integer"
);
}
if ($data['category_id'] <= 0) {
throw new InvalidArgumentException(
"sliders.mainpage_slider.slides[$slideIndex].link.value.category_id must be a positive integer"
);
}
}
if (isset($data['name']) && ! is_string($data['name'])) {
throw new InvalidArgumentException(
"sliders.mainpage_slider.slides[$slideIndex].link.value.name must be a string"
);
}
} elseif ($linkType === 'product') {
if (isset($data['product_id'])) {
if (! is_int($data['product_id'])) {
throw new InvalidArgumentException(
"sliders.mainpage_slider.slides[$slideIndex].link.value.product_id must be an integer"
);
}
if ($data['product_id'] <= 0) {
throw new InvalidArgumentException(
"sliders.mainpage_slider.slides[$slideIndex].link.value.product_id must be a positive integer"
);
}
}
if (isset($data['name']) && ! is_string($data['name'])) {
throw new InvalidArgumentException(
"sliders.mainpage_slider.slides[$slideIndex].link.value.name must be a string"
);
}
}
// Проверяем, что не переданы лишние поля
$allowedFields = ['category_id', 'product_id', 'name'];
foreach (array_keys($data) as $field) {
if (! in_array($field, $allowedFields, true)) {
throw new InvalidArgumentException(
"sliders.mainpage_slider.slides[$slideIndex].link.value contains unknown field: $field"
);
}
}
}
private function deserializeLogs(array $logs): LogsDTO
{
return new LogsDTO(

View File

@@ -1,20 +1,79 @@
<?php
return [
'config_timezone' => 'UTC',
'lang' => 'en-gb',
'language_id' => 1,
'auth_user_id' => 0,
'base_url' => 'http://localhost',
'db' => [
'host' => 'localhost',
'database' => 'not_set',
'username' => 'not_set',
'password' => 'not_set',
'app' => [
'app_enabled' => true,
'app_name' => 'Telecart',
'app_icon' => null,
"theme_light" => "light",
"theme_dark" => "dark",
"app_debug" => false
],
'logs' => [
'path' => 'not_set',
'telegram' => [
"bot_token" => "",
"chat_id" => null,
"owner_notification_template" => <<<TEXT
*Новый заказ \#{order_id}* в магазине *{store_name}*
*Покупатель:* {customer}
*Email:* {email}
*Телефон:* {phone}
*IP:* {ip}
*Адрес доставки:*
{address}
*Комментарий:*
{comment}
*Сумма заказа:* {total}
*Дата оформления:* {created_at}
TEXT,
"customer_notification_template" => <<<TEXT
Спасибо за Ваш заказ в магазине *{store_name}*
*Номер заказа* \#{order_id}
*Сумма заказа:* {total}
*Дата оформления:* {created_at}
Мы свяжемся с вами при необходимости\.
Хорошего дня\!
TEXT,
"mini_app_url" => "",
],
"metrics" => [
"yandex_metrika_enabled" => false,
"yandex_metrika_counter" => "",
],
'store' => [
'enable_store' => true,
'feature_coupons' => true,
'feature_vouchers' => true,
],
'texts' => [
'text_no_more_products' => 'Это всё по текущему запросу. Попробуйте уточнить фильтры или поиск.',
'text_empty_cart' => 'Ваша корзина пуста.',
'text_order_created_success' => 'Ваш заказ успешно оформлен и будет обработан в ближайшее время.'
],
'orders' => [
'order_default_status_id' => 1,
],
'mainpage_blocks' => [
[
'type' => 'products_feed',
'title' => '',
'description' => '',
'is_enabled' => true,
'goal_name' => '',
'data' => [
'max_page_count' => 10,
],
],
],
];

View File

@@ -1,6 +1,7 @@
<?php
use App\Handlers\BannerHandler;
use App\Handlers\BlocksHandler;
use App\Handlers\CartHandler;
use App\Handlers\CategoriesHandler;
use App\Handlers\FiltersHandler;
@@ -27,7 +28,6 @@ return [
'manifest' => [SettingsHandler::class, 'manifest'],
'testTgMessage' => [SettingsHandler::class, 'testTgMessage'],
'banner' => [BannerHandler::class, 'show'],
'webhook' => [TelegramHandler::class, 'webhook'],
'processBlock' => [BlocksHandler::class, 'processBlock'],
];

View File

@@ -5,7 +5,6 @@ namespace Tests\Unit\Framework;
use App\Filters\ProductAttribute;
use App\Filters\ProductCategories;
use App\Filters\ProductCategory;
use App\Filters\ProductForMainPage;
use App\Filters\ProductManufacturer;
use App\Filters\ProductModel;
use App\Filters\ProductPrice;
@@ -89,7 +88,6 @@ class CriteriaBuilderTest extends TestCase
$rulesRegistry->register(ProductManufacturer::NAME, ProductManufacturer::class);
$rulesRegistry->register(ProductQuantity::NAME, ProductQuantity::class);
$rulesRegistry->register(ProductAttribute::NAME, ProductAttribute::class);
$rulesRegistry->register(ProductForMainPage::NAME, ProductForMainPage::class);
$rulesRegistry->register(ProductCategory::NAME, ProductCategory::class);
$this->builder = $application->get(Builder::class);

View File

@@ -1,16 +0,0 @@
{
"operand": "AND",
"rules": {
"RULE_PRODUCT_FOR_MAIN_PAGE": {
"criteria": {
"product_for_main_page": {
"type": "boolean",
"params": {
"operator": "equals",
"value": true
}
}
}
}
}
}

View File

@@ -1,13 +0,0 @@
SELECT
products.product_id AS product_id,
products.image AS image,
product_description.name AS name,
products.model AS model,
products.price AS price,
products.quantity AS quantity,
products.status AS STATUS,
products.noindex AS noindex
FROM
oc_product AS products
INNER JOIN oc_product_description AS product_description ON products.product_id = product_description.product_id
AND product_description.language_id = 1

View File

@@ -1,4 +0,0 @@
{
"mainpage_products": "featured",
"featured_products": [1, 2, 3]
}

View File

@@ -1,16 +0,0 @@
{
"operand": "AND",
"rules": {
"RULE_PRODUCT_FOR_MAIN_PAGE": {
"criteria": {
"product_for_main_page": {
"type": "boolean",
"params": {
"operator": "equals",
"value": true
}
}
}
}
}
}

View File

@@ -1,13 +0,0 @@
SELECT
products.product_id AS product_id,
products.image AS image,
product_description.name AS name,
products.model AS model,
products.price AS price,
products.quantity AS quantity,
products.status AS STATUS,
products.noindex AS noindex
FROM
oc_product AS products
INNER JOIN oc_product_description AS product_description ON products.product_id = product_description.product_id
AND product_description.language_id = 1

View File

@@ -1,4 +0,0 @@
{
"mainpage_products": "featured",
"featured_products": []
}

View File

@@ -1,16 +0,0 @@
{
"operand": "AND",
"rules": {
"RULE_PRODUCT_FOR_MAIN_PAGE": {
"criteria": {
"product_for_main_page": {
"type": "boolean",
"params": {
"operator": "equals",
"value": true
}
}
}
}
}
}

View File

@@ -1,13 +0,0 @@
SELECT
products.product_id AS product_id,
products.image AS image,
product_description.name AS name,
products.model AS model,
products.price AS price,
products.quantity AS quantity,
products.status AS STATUS,
products.noindex AS noindex
FROM
oc_product AS products
INNER JOIN oc_product_description AS product_description ON products.product_id = product_description.product_id
AND product_description.language_id = 1

View File

@@ -1,16 +0,0 @@
{
"operand": "AND",
"rules": {
"RULE_PRODUCT_FOR_MAIN_PAGE": {
"criteria": {
"product_for_main_page": {
"type": "boolean",
"params": {
"operator": "equals",
"value": true
}
}
}
}
}
}

View File

@@ -1,13 +0,0 @@
SELECT
products.product_id AS product_id,
products.image AS image,
product_description.name AS name,
products.model AS model,
products.price AS price,
products.quantity AS quantity,
products.status AS STATUS,
products.noindex AS noindex
FROM
oc_product AS products
INNER JOIN oc_product_description AS product_description ON products.product_id = product_description.product_id
AND product_description.language_id = 1