diff --git a/composer.json b/composer.json index 420d7d1..b634633 100644 --- a/composer.json +++ b/composer.json @@ -11,7 +11,7 @@ } ], "require": { - "php": "^8", + "php": "^8.1", "seiger/sgallery": "*" }, "autoload": { diff --git a/config/sCommerceSettings.php b/config/sCommerceSettings.php index 9fd9f0b..18348ac 100644 --- a/config/sCommerceSettings.php +++ b/config/sCommerceSettings.php @@ -1 +1,30 @@ - [ + "catalog_root" => 1, + "in_main_menu" => 1, + "main_menu_order" => 11, + "orders_on" => 0, + ], + "product" => [ + "link_rule" => "root", + "quantity_on" => 0, + "rating_on" => 0, + "show_field_availability" => 0, + "show_field_price" => 1, + "show_field_sku" => 1, + "views_on" => 1, + ], + "products" => [ + "show_field_availability" => 1, + "show_field_category" => 1, + "show_field_id" => 1, + "show_field_price" => 1, + "show_field_price_opt" => 0, + "show_field_price_opt_special" => 0, + "show_field_price_special" => 0, + "show_field_quantity" => 0, + "show_field_sku" => 1, + "show_field_views" => 1, + "show_field_visibility" => 1, + ], +]; \ No newline at end of file diff --git a/database/migrations/2023_12_27_190234_ecommerce_structure_tables.php b/database/migrations/2023_12_27_190234_ecommerce_structure_tables.php index 06b5326..9435898 100644 --- a/database/migrations/2023_12_27_190234_ecommerce_structure_tables.php +++ b/database/migrations/2023_12_27_190234_ecommerce_structure_tables.php @@ -28,10 +28,10 @@ public function up(): void $table->unsignedInteger('views')->default(0)->comment('Count view the product'); $table->integer('quantity')->default(0)->comment('Quantity products in stock'); $table->unsignedDecimal('price_regular', 9, 2)->default(0); - $table->unsignedDecimal('price_special', 9, 2)->nullable(); + $table->unsignedDecimal('price_special', 9, 2)->default(0); $table->unsignedDecimal('price_opt_regular', 9, 2)->default(0); - $table->unsignedDecimal('price_opt_special', 9, 2)->nullable(); - $table->unsignedDecimal('weight', 11, 4)->default(0.00); + $table->unsignedDecimal('price_opt_special', 9, 2)->default(0); + $table->unsignedDecimal('weight', 11, 4)->default(0); $table->string('cover', 512)->default('')->comment('Cover image file link'); $table->jsonb('relevants')->default(new Expression('(JSON_ARRAY())')); $table->jsonb('similar')->default(new Expression('(JSON_ARRAY())')); diff --git a/lang/en/global.php b/lang/en/global.php index d30b1e7..c832d94 100644 --- a/lang/en/global.php +++ b/lang/en/global.php @@ -55,4 +55,18 @@ 'price_help' => 'The main price of the product is in the currency of the store.', 'categories' => 'Categories', 'categories_help' => 'List of categories in which the product should be displayed. Formed from the resource tree from the root, which is designated as a directory. If a subcategory is selected, the product will be displayed in all higher categories.', + 'gallery' => 'File gallery', + 'gallery_help' => 'The first image of the gallery is used as a product preview. You can sort the images by moving them with the mouse.', + 'content' => 'Content', + 'management_product_functionality' => 'Product functionality management', + 'views_on_help' => 'Enable the function of counting product views.', + 'rating_on_help' => 'Enable product rating calculation functionality.', + 'quantity_on_help' => 'Enable the product balance functionality.', + 'orders_on' => 'Order', + 'orders_on_help' => 'Enable the functionality of orders on the site.', + 'product_link' => 'Link to the product', + 'product_link_rule_help' => 'Choose a rule for forming a link to the product.', + 'product_link_rule_root' => 'from the root of the site', + 'product_link_rule_catalog' => 'from the root of catalog directory', + 'product_link_rule_category' => 'from the product category', ]; \ No newline at end of file diff --git a/lang/ru/global.php b/lang/ru/global.php index 60362d7..1aff960 100644 --- a/lang/ru/global.php +++ b/lang/ru/global.php @@ -55,4 +55,18 @@ 'price_help' => 'Основная стоимость товара в валюте магазина.', 'categories' => 'Категории', 'categories_help' => 'Список категорий в которых должен отображаться товар. Формируется из дерева ресурсов от корня, который обозначен как каталог. Если выбрана подкатегория - товар будет отображен во всех вышестоящих категориях.', + 'gallery' => 'Галерея файлов', + 'gallery_help' => 'Первое изображение галереи используется в качестве превью товара. Вы можете сортировать изображение путем их перемещения мышкой.', + 'content' => 'Контент', + 'management_product_functionality' => 'Управление функционалом товара', + 'views_on_help' => 'Включить функционал подсчета просмотров товара.', + 'rating_on_help' => 'Включить функционал подсчета рейтинга продукта.', + 'quantity_on_help' => 'Включить функционал остатка товаров.', + 'orders_on' => 'Заказ', + 'orders_on_help' => 'Включите функционал заказов на сайте.', + 'product_link' => 'Ссылка на товар', + 'product_link_rule_help' => 'Выберите правило для формирования ссылки на товар.', + 'product_link_rule_root' => 'от корня сайта', + 'product_link_rule_catalog' => 'от корня каталога', + 'product_link_rule_category' => 'от категории товара', ]; \ No newline at end of file diff --git a/lang/uk/global.php b/lang/uk/global.php index 0981618..897ba5d 100644 --- a/lang/uk/global.php +++ b/lang/uk/global.php @@ -55,4 +55,18 @@ 'price_help' => 'Основна ціна товару в валюті магазину.', 'categories' => 'Категорії', 'categories_help' => 'Список категорій, у яких повинен відображатися товар. Формується із дерева ресурсів від кореня, який позначено як каталог. Якщо обрано підкатегорію - товар буде відображено у всіх батьківських категоріях.', + 'gallery' => 'Галерея файлів', + 'gallery_help' => 'Перше зображення галереї використовується в якості превю товара. Ви маєте можливість сортувати зображення шляхом їх переміщення мишкою.', + 'content' => 'Контент', + 'management_product_functionality' => 'Керування функціоналом товару', + 'views_on_help' => 'Ввімкнути функціонал підрахунку переглядів товару.', + 'rating_on_help' => 'Ввімкнути функціонал підрахунку рейтингу товара.', + 'quantity_on_help' => 'Ввімкнути функціонал залишку товарів.', + 'orders_on' => 'Замовлення', + 'orders_on_help' => 'Ввімкнути функціонал замовлень на сайті.', + 'product_link' => 'Посилання на товар', + 'product_link_rule_help' => 'Оберіть правило для формування посилання на товар.', + 'product_link_rule_root' => 'від корня сайту', + 'product_link_rule_catalog' => 'від корня каталогу', + 'product_link_rule_category' => 'від категорії товару', ]; \ No newline at end of file diff --git a/module/sCommerceModule.php b/module/sCommerceModule.php index bb74a9e..cbf6e66 100644 --- a/module/sCommerceModule.php +++ b/module/sCommerceModule.php @@ -3,8 +3,13 @@ * E-commerce management module */ +use Illuminate\Pagination\Paginator; +use Illuminate\Support\Facades\Cookie; use Seiger\sCommerce\Controllers\sCommerceController; use Seiger\sCommerce\Facades\sCommerce; +use Seiger\sCommerce\Models\sProduct; +use Seiger\sCommerce\Models\sProductTranslate; +use Seiger\sGallery\Facades\sGallery; if (!defined('IN_MANAGER_MODE') || IN_MANAGER_MODE != 'true') die("No access"); if (!file_exists(EVO_CORE_PATH . 'custom/config/seiger/settings/sCommerce.php')) { @@ -12,21 +17,114 @@ } $sCommerceController = new sCommerceController(); -$get = request()->get ?? "orders"; +Paginator::defaultView('sCommerce::partials.pagination'); +$get = request()->get ?? (sCommerce::config('basic.orders_on', 1) == 1 ? "orders" : "products"); $editor = ''; + $tabs = ['products']; if (evo()->hasPermission('settings')) { $tabs[] = 'settings'; } switch ($get) { + /* + |-------------------------------------------------------------------------- + | Orders + |-------------------------------------------------------------------------- + */ default: case "orders": break; + /* + |-------------------------------------------------------------------------- + | Products + |-------------------------------------------------------------------------- + */ + case "products": + $perpage = Cookie::get('scom_products_page_items', 50); + $order = request()->input('order', 'id'); + $direc = request()->input('direc', 'desc'); + + $data['items'] = sProduct::orderBy($order, $direc)->paginate($perpage); + break; + /* + |-------------------------------------------------------------------------- + | Product + |-------------------------------------------------------------------------- + */ case "product": - $tabs = ['product']; + $tabs = ['product', 'content']; + $product = sCommerce::getProduct((int)request()->input('i', 0)); + //dd($product); $data['categories'] = []; + $data['product'] = $product; + break; + case "productSave": + $requestId = (int)request()->input('i', 0); + $alias = request()->input('alias', 'new-product'); + $product = sCommerce::getProduct($requestId); + + $votes = data_is_json($product->votes ?? '', true); + $type = $product->type ?: 'simple'; + $cover = sGallery::first('product', $requestId); + + if (empty($alias)) { + $translate = sProductTranslate::whereProduct($requestId) + ->whereIn('lang', ['en', $sCommerceController->langDefault()])->orderByRaw('FIELD(lang, "en", "' . $sCommerceController->langDefault() . '")') + ->first(); + if ($translate) { + $alias = $translate->pagetitle; + } else { + $alias = 'new-product'; + } + } + + if (!$votes) { + $votes = []; + $votes['total'] = 1; + $votes['1'] = 0; + $votes['2'] = 0; + $votes['3'] = 0; + $votes['3'] = 0; + $votes['4'] = 0; + $votes['5'] = 1; + } + + $product->published = (int)request()->input('published', 0); + $product->availability = (int)request()->input('availability', 0); + $product->category = (int)request()->input('parent', sCommerce::config('basic.catalog_root', evo()->getConfig('site_start', 1))); + $product->sku = request()->input('sku', ''); + $product->alias = $sCommerceController->validateAlias($alias, (int)$product->id); + $product->position = (int)request()->input('position', 0); + $product->quantity = (int)request()->input('quantity', 0); + $product->price_regular = $sCommerceController->validatePrice(request()->input('price_regular', 0)); + $product->price_special = $sCommerceController->validatePrice(request()->input('price_special', 0)); + $product->price_opt_regular = $sCommerceController->validatePrice(request()->input('price_opt_regular', 0)); + $product->price_opt_special = $sCommerceController->validatePrice(request()->input('price_opt_special', 0)); + $product->weight = (float)request()->input('weight', 0); + $product->cover = $cover->src ?? '/assets/site/noimage.png'; + $product->relevants = json_encode(request()->input('relevants', [])); + $product->similar = json_encode(request()->input('similar', [])); + $product->tmplvars = json_encode(request()->input('tmplvars', [])); + $product->votes = json_encode($votes); + $product->type = $type; + $product->save(); + + $product->categories()->sync((array)request()->input('categories', [])); + + if (!$product->texts->count()) { + $product->texts()->create(['lang' => $sCommerceController->langDefault()]); + } + + $sCommerceController->setProductsListing(); + $back = str_replace('&i=0', '&i=' . $product->id, (request()->back ?? '&get=product')); + return header('Location: ' . sCommerce::moduleUrl() . $back); break; + /* + |-------------------------------------------------------------------------- + | Settings + |-------------------------------------------------------------------------- + */ case "settings": if (!evo()->hasPermission('settings')) { $back = request()->back ?? '&get=orders'; @@ -34,10 +132,9 @@ } break; case "settingsSave": - $sCommerceController->saveBasicConfigs(); - + $sCommerceController->updateDBConfigs(); + $sCommerceController->updateFileConfigs(); evo()->clearCache('full'); - sleep(5); session()->flash('success', __('sCommerce::global.settings_save_success')); $back = request()->back ?? '&get=settings'; diff --git a/plugins/sCommercePlugin.php b/plugins/sCommercePlugin.php index 8890081..d643eeb 100644 --- a/plugins/sCommercePlugin.php +++ b/plugins/sCommercePlugin.php @@ -11,7 +11,7 @@ * Add Menu item */ Event::listen('evolution.OnManagerMenuPrerender', function($params) { - if (evo()->getConfig('scom_in_main_menu', 0) == 1) { + if (sCommerce::config('basic.in_main_menu', 0) == 1) { $menu['scommerce'] = [ 'scommerce', 'main', @@ -22,7 +22,7 @@ "", "main", 0, - evo()->getConfig('scom_main_menu_order', 11), + sCommerce::config('basic.main_menu_order', 11), ]; return serialize(array_merge($params['menu'], $menu)); @@ -33,9 +33,9 @@ * Add icon to tree */ Event::listen('evolution.OnManagerNodePrerender', function($params) { - if (evo()->getConfig('scom_catalog_root', 0) > 1) { + if (sCommerce::config('basic.catalog_root', 0) > 1) { switch ($params['ph']['id']) { - case evo()->getConfig('scom_catalog_root') : + case sCommerce::config('basic.catalog_root') : $params['ph']['icon'] = ''; $params['ph']['icon_folder_open'] = ""; $params['ph']['icon_folder_close'] = ""; diff --git a/src/Controllers/sCommerceController.php b/src/Controllers/sCommerceController.php index a7c56ab..609fc72 100644 --- a/src/Controllers/sCommerceController.php +++ b/src/Controllers/sCommerceController.php @@ -1,118 +1,100 @@ view('index'); + $productsListing = []; + $products = sProduct::select('id', 'alias')->wherePublished(1)->get(); + if ($products) { + foreach ($products as $product) { + $link = str_replace(MODX_SITE_URL, '', $product->link); + $productsListing[trim($link, '/')] = $product->id; + } + } + evo()->clearCache('full'); + Cache::forever('productsListing', $productsListing); } /** - * Save management of basic functionality section + * Update database configurations * - * @return bool + * This method updates various database configurations based on the values provided in the request data. + * + * @return bool Returns true */ - public function saveBasicConfigs(): bool + public function updateDBConfigs(): bool { $prf = 'scom_'; $tbl = evo()->getDatabase()->getFullTableName('system_settings'); - /* - |-------------------------------------------------------------------------- - | Management of basic functionality - |-------------------------------------------------------------------------- - */ - if (request()->has('in_main_menu') && request()->in_main_menu != evo()->getConfig($prf . 'in_main_menu')) { - $in_main_menu = request()->in_main_menu; - evo()->getDatabase()->query("REPLACE INTO {$tbl} (`setting_name`, `setting_value`) VALUES ('{$prf}in_main_menu', '{$in_main_menu}')"); - evo()->setConfig($prf . 'in_main_menu', $in_main_menu); - } - if (request()->has('main_menu_order') && request()->main_menu_order != evo()->getConfig($prf . 'main_menu_order')) { - $main_menu_order = request()->main_menu_order; - evo()->getDatabase()->query("REPLACE INTO {$tbl} (`setting_name`, `setting_value`) VALUES ('{$prf}main_menu_order', '{$main_menu_order}')"); - evo()->setConfig($prf . 'main_menu_order', $main_menu_order); - } - if (request()->has('catalog_root') && request()->catalog_root != evo()->getConfig($prf . 'catalog_root')) { - $catalog_root = request()->catalog_root; + + if (request()->has('basic__catalog_root') && request()->input('basic__catalog_root') != evo()->getConfig($prf . 'catalog_root')) { + $catalog_root = request()->input('basic__catalog_root'); evo()->getDatabase()->query("REPLACE INTO {$tbl} (`setting_name`, `setting_value`) VALUES ('{$prf}catalog_root', '{$catalog_root}')"); evo()->setConfig($prf . 'catalog_root', $catalog_root); } - /* - |-------------------------------------------------------------------------- - | Presentation of the list of products - |-------------------------------------------------------------------------- - */ - if (request()->has('show_field_products_id') && request()->show_field_products_id != evo()->getConfig($prf . 'show_field_products_id')) { - $show_field_products_id = request()->show_field_products_id; - evo()->getDatabase()->query("REPLACE INTO {$tbl} (`setting_name`, `setting_value`) VALUES ('{$prf}show_field_products_id', '{$show_field_products_id}')"); - evo()->setConfig($prf . 'show_field_products_id', $show_field_products_id); - } - if (request()->has('show_field_products_sku') && request()->show_field_products_sku != evo()->getConfig($prf . 'show_field_products_sku')) { - $show_field_products_sku = request()->show_field_products_sku; - evo()->getDatabase()->query("REPLACE INTO {$tbl} (`setting_name`, `setting_value`) VALUES ('{$prf}show_field_products_sku', '{$show_field_products_sku}')"); - evo()->setConfig($prf . 'show_field_products_sku', $show_field_products_sku); - } - if (request()->has('show_field_products_price') && request()->show_field_products_price != evo()->getConfig($prf . 'show_field_products_price')) { - $show_field_products_price = request()->show_field_products_price; - evo()->getDatabase()->query("REPLACE INTO {$tbl} (`setting_name`, `setting_value`) VALUES ('{$prf}show_field_products_price', '{$show_field_products_price}')"); - evo()->setConfig($prf . 'show_field_products_price', $show_field_products_price); - } - if (request()->has('show_field_products_price_special') && request()->show_field_products_price_special != evo()->getConfig($prf . 'show_field_products_price_special')) { - $show_field_products_price_special = request()->show_field_products_price_special; - evo()->getDatabase()->query("REPLACE INTO {$tbl} (`setting_name`, `setting_value`) VALUES ('{$prf}show_field_products_price_special', '{$show_field_products_price_special}')"); - evo()->setConfig($prf . 'show_field_products_price_special', $show_field_products_price_special); - } - if (request()->has('show_field_products_price_opt') && request()->show_field_products_price_opt != evo()->getConfig($prf . 'show_field_products_price_opt')) { - $show_field_products_price_opt = request()->show_field_products_price_opt; - evo()->getDatabase()->query("REPLACE INTO {$tbl} (`setting_name`, `setting_value`) VALUES ('{$prf}show_field_products_price_opt', '{$show_field_products_price_opt}')"); - evo()->setConfig($prf . 'show_field_products_price_opt', $show_field_products_price_opt); - } - if (request()->has('show_field_products_price_opt_special') && request()->show_field_products_price_opt_special != evo()->getConfig($prf . 'show_field_products_price_opt_special')) { - $show_field_products_price_opt_special = request()->show_field_products_price_opt_special; - evo()->getDatabase()->query("REPLACE INTO {$tbl} (`setting_name`, `setting_value`) VALUES ('{$prf}show_field_products_price_opt_special', '{$show_field_products_price_opt_special}')"); - evo()->setConfig($prf . 'show_field_products_price_opt_special', $show_field_products_price_opt_special); - } - if (request()->has('show_field_products_quantity') && request()->show_field_products_quantity != evo()->getConfig($prf . 'show_field_products_quantity')) { - $show_field_products_quantity = request()->show_field_products_quantity; - evo()->getDatabase()->query("REPLACE INTO {$tbl} (`setting_name`, `setting_value`) VALUES ('{$prf}show_field_products_quantity', '{$show_field_products_quantity}')"); - evo()->setConfig($prf . 'show_field_products_quantity', $show_field_products_quantity); - } - if (request()->has('show_field_products_availability') && request()->show_field_products_availability != evo()->getConfig($prf . 'show_field_products_availability')) { - $show_field_products_availability = request()->show_field_products_availability; - evo()->getDatabase()->query("REPLACE INTO {$tbl} (`setting_name`, `setting_value`) VALUES ('{$prf}show_field_products_availability', '{$show_field_products_availability}')"); - evo()->setConfig($prf . 'show_field_products_availability', $show_field_products_availability); - } - if (request()->has('show_field_products_category') && request()->show_field_products_category != evo()->getConfig($prf . 'show_field_products_category')) { - $show_field_products_category = request()->show_field_products_category; - evo()->getDatabase()->query("REPLACE INTO {$tbl} (`setting_name`, `setting_value`) VALUES ('{$prf}show_field_products_category', '{$show_field_products_category}')"); - evo()->setConfig($prf . 'show_field_products_category', $show_field_products_category); - } - if (evo()->getConfig('check_sMultisite', false) && request()->has('show_field_products_websites') && request()->show_field_products_websites != evo()->getConfig($prf . 'show_field_products_websites')) { - $show_field_products_websites = request()->show_field_products_websites; - evo()->getDatabase()->query("REPLACE INTO {$tbl} (`setting_name`, `setting_value`) VALUES ('{$prf}show_field_products_websites', '{$show_field_products_websites}')"); - evo()->setConfig($prf . 'show_field_products_websites', $show_field_products_websites); - } - if (request()->has('show_field_products_visibility') && request()->show_field_products_visibility != evo()->getConfig($prf . 'show_field_products_visibility')) { - $show_field_products_visibility = request()->show_field_products_visibility; - evo()->getDatabase()->query("REPLACE INTO {$tbl} (`setting_name`, `setting_value`) VALUES ('{$prf}show_field_products_visibility', '{$show_field_products_visibility}')"); - evo()->setConfig($prf . 'show_field_products_visibility', $show_field_products_visibility); + return true; + } + + /** + * Update file configurations + * + * This method updates the file configurations based on the provided tabs array. + * It generates a PHP file with the updated settings and saves it in a specific location. + * + * @return bool + */ + public function updateFileConfigs(): bool + { + $filters = ['basic', 'product', 'products']; + $all = request()->all(); + ksort($all); + $config = []; + + // Data array formation + foreach ($filters as $filter) { + foreach ($all as $key => $value) { + if (str_starts_with($key, $filter . '__')) { + $key = str_replace($filter . '__', '', $key); + if ($this->isInteger($value)) { + $value = intval($value); + } + $config[$filter][$key] = $value; + } + } } + + // Preparation of deadlines with data + $string = 'dataToString($config) . ';'; + + // Save the config + $handle = fopen(EVO_CORE_PATH . 'custom/config/seiger/settings/sCommerce.php', "w"); + fwrite($handle, $string); + fclose($handle); + return true; } /** - * Default language + * Retrieve the default language from the configuration. * - * @return string + * @return string The default language. */ public function langDefault(): string { @@ -120,9 +102,9 @@ public function langDefault(): string } /** - * Languages list + * Retrieve the list of languages configured in the system. * - * @return array + * @return array The list of languages. */ public function langList(): array { @@ -136,13 +118,13 @@ public function langList(): array } /** - * List of categories and subcategories + * Retrieve the list of categories and their respective IDs. * - * @return array + * @return array An associative array where the keys are the category IDs and the values are the category titles. */ public function listCategories(): array { - $root = SiteContent::find(evo()->getConfig('scom_catalog_root', evo()->getConfig('site_start', 1))); + $root = SiteContent::find(sCommerce::config('basic.catalog_root', evo()->getConfig('site_start', 1))); $this->categories[$root->id] = $root->pagetitle; if ($root->hasChildren()) { foreach ($root->children as $item) { @@ -153,10 +135,10 @@ public function listCategories(): array } /** - * Price validation + * Validate and sanitize a price value. * - * @param mixed $price - * @return float + * @param mixed $price The price value to be validated. + * @return float The validated and sanitized price value. */ public function validatePrice(mixed $price): float { @@ -174,13 +156,14 @@ public function validatePrice(mixed $price): float } /** - * Alias validation + * Validate an alias and ensure its uniqueness. * - * @param $data - * @param string $table - * @return string + * @param string $string The string to be used for generating the alias. + * @param int $id The ID of the item for which the alias is being generated. + * @param string $key The key representing the entity type for which the alias is being generated. (Default: 'product') + * @return string The valid and unique alias. */ - public function validateAlias($string = '', $id = 0, $key = 'article'): string + public function validateAlias(string $string, int $id, string $key = 'product'): string { if (trim($string)) { $alias = Str::slug(trim($string), '-'); @@ -190,16 +173,7 @@ public function validateAlias($string = '', $id = 0, $key = 'article'): string switch ($key) { default : - $aliases = sArticle::where('s_articles.id', '<>', $id)->get('alias')->pluck('alias')->toArray(); - break; - case "feature" : - $aliases = sArticlesFeature::where('s_articles_features.fid', '<>', $id)->get('alias')->pluck('alias')->toArray(); - break; - case "tag" : - $aliases = sArticlesTag::where('s_articles_tags.tagid', '<>', $id)->get('alias')->pluck('alias')->toArray(); - break; - case "author" : - $aliases = sArticlesAuthor::where('s_articles_authors.autid', '<>', $id)->get('alias')->pluck('alias')->toArray(); + $aliases = sProduct::whereNot('id', $id)->get('alias')->pluck('alias')->toArray(); break; } @@ -212,28 +186,16 @@ public function validateAlias($string = '', $id = 0, $key = 'article'): string } $alias = $tempAlias; } - return $alias; - } - /** - * Get the error messages for the defined validation rules. - * - * @return array - */ - public function messages() - { - return [ - 'title.required' => 'A title is required', - 'body.required' => 'A message is required', - ]; + return $alias; } /** - * Display render + * Render a view using a template and data. * - * @param string $tpl - * @param array $data - * @return bool + * @param string $tpl The template to render. + * @param array $data The data to pass to the view (optional). + * @return \View The rendered view. */ public function view(string $tpl, array $data = []) { @@ -241,10 +203,11 @@ public function view(string $tpl, array $data = []) } /** - * Categories name as crumb + * Generates the breadcrumb for a given category and its children recursively. + * + * @param mixed $resource The category resource object. + * @param string $crumb The existing breadcrumb to append to. * - * @param $resource - * @param $crumb * @return void */ protected function categoryCrumb($resource, $crumb = ''): void @@ -257,4 +220,47 @@ protected function categoryCrumb($resource, $crumb = ''): void } } } + + /** + * Check if the given input is an integer. + * + * @param mixed $input The input to be checked. + * @return bool Returns true if the input is an integer, otherwise false. + */ + protected function isInteger(mixed $input): bool + { + return (ctype_digit(strval($input))); + } + + /** + * Convert data to a string representation. + * + * @param mixed $data The data to convert. + * @return string The string representation of the data. + */ + protected function dataToString(mixed $data): string + { + ob_start(); + var_dump($data); + $data = ob_get_contents(); + ob_end_clean(); + + $data = Str::of($data)->replaceMatches('/string\(\d+\) .*/', function ($match) { + return substr($match[0], (strpos($match[0], ') ') + 2)) . ','; + })->replaceMatches('/bool\(\w+\)/', function ($match) { + return str_replace(['bool(', ')'], ['', ','], $match[0]); + })->replaceMatches('/int\(\d+\)/', function ($match) { + return str_replace(['int(', ')'], ['', ','], $match[0]); + })->replaceMatches('/float\(\d+\)/', function ($match) { + return str_replace(['float(', ')'], ['', ','], $match[0]); + })->replaceMatches('/array\(\d+\) /', function ($match) { + return str_replace($match[0], '', $match[0]); + })->replaceMatches('/=>\n[ \t]{1,}/', function () { + return ' => '; + })->replaceMatches('/ /', function () { + return ' '; + })->remove('[')->remove(']')->replace('{', '[')->replace('}', '],')->rtrim(",\n"); + + return $data; + } } diff --git a/src/Models/sCategory.php b/src/Models/sCategory.php new file mode 100644 index 0000000..d3d55ba --- /dev/null +++ b/src/Models/sCategory.php @@ -0,0 +1,20 @@ +belongsToMany(sProduct::class, 's_product_category', 'category', 'product'); + } +} \ No newline at end of file diff --git a/src/Models/sProduct.php b/src/Models/sProduct.php index fb123ef..b7cedef 100644 --- a/src/Models/sProduct.php +++ b/src/Models/sProduct.php @@ -1,10 +1,20 @@ leftJoin('s_product_translates', function ($leftJoin) use ($locale) { + $leftJoin->on('s_products.id', '=', 's_product_translates.product') + ->where('lang', function ($leftJoin) use ($locale) { + $leftJoin->select('lang') + ->from('s_product_translates') + ->whereRaw(DB::getTablePrefix() . 's_product_translates.product = ' . DB::getTablePrefix() . 's_products.id') + ->whereIn('lang', [$locale, 'base']) + ->orderByRaw('FIELD(lang, "' . $locale . '", "base")') + ->limit(1); + }); + }); + } + + /** + * Get the categories associated with the product. + * + * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany The relation representing the product's categories. + */ + public function categories() + { + return $this->belongsToMany(sCategory::class, 's_product_category', 'product', 'category'); + } + + /** + * Get all related product translations + * + * @return Illuminate\Database\Eloquent\Relations\HasMany The relation object for the product translations. + */ + public function texts() + { + return $this->hasMany(sProductTranslate::class, 'product', 'id'); + } + + /** + * Get the link attribute for the current object + * + * Returns the URL of the object based on the configured link rule in the sCommerce module. + * If the link rule is set to "catalog", the URL is based on the catalog root URL. + * If the link rule is set to "category", the URL is based on the current category or the catalog root URL. + * Otherwise, the URL is based on the site start URL. + * + * @return string The URL of the object. + */ + public function getLinkAttribute() + { + switch (sCommerce::config('product.link_rule', 'root')) { + case "catalog" : + $base_url = UrlProcessor::makeUrl(sCommerce::config('basic.catalog_root', evo()->getConfig('site_start', 1))); + break; + case "category" : + $category = (int)$this->category ?: sCommerce::config('basic.catalog_root', evo()->getConfig('site_start', 1)); + $base_url = UrlProcessor::makeUrl($category); + break; + default : + $base_url = UrlProcessor::makeUrl(evo()->getConfig('site_start', 1)); + break; + } + + return $base_url . $this->alias . evo()->getConfig('friendly_url_suffix', ''); + } } \ No newline at end of file diff --git a/src/Models/sProductTranslate.php b/src/Models/sProductTranslate.php new file mode 100644 index 0000000..4a50d5c --- /dev/null +++ b/src/Models/sProductTranslate.php @@ -0,0 +1,14 @@ +belongsTo(sProduct::class, 'product'); + } +} \ No newline at end of file diff --git a/src/sCommerce.php b/src/sCommerce.php index 0eb0cd9..dd70603 100644 --- a/src/sCommerce.php +++ b/src/sCommerce.php @@ -2,16 +2,47 @@ use Illuminate\Support\Facades\Cache; use Illuminate\Support\Str; +use Seiger\sCommerce\Controllers\sCommerceController; +use Seiger\sCommerce\Models\sProduct; class sCommerce { /** - * Module url + * Retrieves the product based on the given ID and language. * - * @return string + * @param int $productId The ID of the product to retrieve. + * @param string $lang (optional) The language to retrieve the product in. Default is an empty string. + * @return object The product object matching the given ID and language, or a new empty product object if no match found. + */ + public function getProduct(int $productId, string $lang = ''): object + { + if (!trim($lang)) { + $sCommerceController = new sCommerceController(); + $lang = $sCommerceController->langDefault(); + } + + return sProduct::lang($lang)->whereProduct($productId)->first() ?? new sProduct(); + } + + /** + * Retrieves the module URL. + * + * @return string The module URL. */ public function moduleUrl(): string { return 'index.php?a=112&id=' . md5(__('sCommerce::global.title')); } + + /** + * Retrieves the value from the config file based on the given key. + * + * @param string $key The key to retrieve the value from the config file. + * @param mixed $default (optional) The default value to return if the key does not exist. Default is null. + * @return mixed The value retrieved from the config file or the default value if the key does not exist. + */ + public function config(string $key, mixed $default = null): mixed + { + return config('seiger.settings.sCommerce.' . $key, $default); + } } \ No newline at end of file diff --git a/views/index.blade.php b/views/index.blade.php index 0ebea06..8ab7349 100644 --- a/views/index.blade.php +++ b/views/index.blade.php @@ -7,10 +7,10 @@ @foreach($tabs as $tab) @if($tab == 'content') - @foreach($sArticlesController->langList() as $idx => $lang) + @foreach($sCommerceController->langList() as $idx => $lang)