Skip to content

Commit

Permalink
[ADD] Filters.
Browse files Browse the repository at this point in the history
  • Loading branch information
Seiger committed Dec 23, 2024
1 parent 1779b8e commit ed26205
Show file tree
Hide file tree
Showing 12 changed files with 448 additions and 49 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ of Evolution CMS for seamless and efficient **online commerce**.
- [ ] Geolocation Attribute.
- [ ] Constructor Attribute.
- [x] Custom Attribute.
- [ ] Dynamic Filters for Product Search.
- [x] Dynamic Filters for Product Search.
- [x] Duplicate Product.
- [ ] AI-Powered Product Search.
- [ ] Flexible Product Bundles.
Expand All @@ -64,6 +64,7 @@ of Evolution CMS for seamless and efficient **online commerce**.
- [x] sCommerceAfterProductDuplicate.
- [x] Javascript events.
- [x] sCommerceAddedToCart.
- [x] sCommerceRemovedFromCart.
- [x] Multi-currency Support (ISO 4217).
- [ ] Integration with Payment Systems.
- [ ] Integration with Warehouses.
Expand Down
3 changes: 2 additions & 1 deletion docs/pages/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ of Evolution CMS for seamless and efficient **online commerce**.
- [ ] Geolocation Attribute.
- [ ] Constructor Attribute.
- [x] Custom Attribute.
- [ ] Dynamic Filters for Product Search.
- [x] Dynamic Filters for Product Search.
- [x] Duplicate Product.
- [ ] AI-Powered Product Search.
- [ ] Flexible Product Bundles.
Expand All @@ -70,6 +70,7 @@ of Evolution CMS for seamless and efficient **online commerce**.
- [x] sCommerceAfterProductDuplicate.
- [x] Javascript events.
- [x] sCommerceAddedToCart.
- [x] sCommerceRemovedFromCart.
- [x] Multi-currency Support (ISO 4217).
- [ ] Integration with Payment Systems.
- [ ] Integration with Warehouses.
Expand Down
4 changes: 2 additions & 2 deletions module/sCommerceModule.php
Original file line number Diff line number Diff line change
Expand Up @@ -766,8 +766,8 @@
*/
case "attributes":
$perpage = Cookie::get('scom_attributes_page_items', 50);
$order = request()->input('order', 'id');
$direc = request()->input('direc', 'desc');
$order = request()->input('order', 'position');
$direc = request()->input('direc', 'asc');
$query = sAttribute::lang($sCommerceController->langDefault())->search();

switch ($order) {
Expand Down
15 changes: 12 additions & 3 deletions plugins/sCommercePlugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,32 @@
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Event;
use Seiger\sCommerce\Facades\sCommerce;
use Seiger\sCommerce\Facades\sFilter;

/**
* Catch the Product by alias
*/
Event::listen('evolution.OnPageNotFound', function($params) {
$goTo = false;
$aliasArr = request()->segments();
if ($aliasArr[0] == evo()->getConfig('lang', 'base')) {
if ($aliasArr[0] === evo()->getConfig('lang', 'base')) {
unset($aliasArr[0]);
}
$alias = implode('/', $aliasArr);
$goTo = Arr::exists(sCommerce::documentListing(), $alias);
if (!$goTo && evo()->getLoginUserID('mgr')) {
if (!$goTo) {
$alias = Arr::last($aliasArr);
$product = sCommerce::getProductByAlias($alias ?? '');
if ($product && isset($product->id) && (int)$product->id > 0) {
$goTo = true;
if (evo()->getLoginUserID('mgr')) {
$goTo = true;
}
} else {
$doc = sFilter::validateFilters();
if ($doc) {
evo()->sendForward($doc);
exit();
};
}
}
if ($goTo) {
Expand Down
44 changes: 44 additions & 0 deletions src/Controllers/sCommerceController.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
use Seiger\sCommerce\Facades\sCommerce;
use Seiger\sCommerce\Facades\sFilter;
use Seiger\sCommerce\Models\sAttribute;
use Seiger\sCommerce\Models\sAttributeValue;
use Seiger\sCommerce\Models\sCategory;
Expand All @@ -17,6 +18,7 @@ class sCommerceController
{
protected $data = [];
protected $categories = [];
protected $productIds = [];

/**
* Set the products listing in the cache.
Expand Down Expand Up @@ -323,6 +325,48 @@ public function listSubCategories(object &$category, int $dept): object
return $category;
}

/**
* Retrieves product IDs associated with a specified category and its active subcategories.
*
* This method identifies all products linked to a given category and its subcategories
* up to the specified depth level. If the category is not provided,
* the current document identifier is used as the default category.
*
* @param int|null $category The ID of the category to fetch products for.
* Defaults to the current document identifier if not specified.
* @param int $dept The depth level for traversing subcategories.
* Determines how deep into the category hierarchy the search extends.
* Defaults to 10.
*
* @return array An array of product IDs related to the specified category and its subcategories.
*/
public function productIds(int $category = null, int $dept = 10)
{
$category = $category ? $category : evo()->documentIdentifier;

if (!isset($this->productIds[$category]) || !is_array($this->productIds[$category])) {
$categories = array_merge([$category], $this->listAllActiveSubCategories($category, $dept));
$filters = sFilter::getValidatedFiltersIds();

$query = DB::table('s_product_category')->select(['product'])->whereIn('category', $categories);

if (is_array($filters) && count($filters)) {
foreach ($filters as $filter => $values) {
$query->whereIn('product', function ($q) use ($filter, $values) {
$q->select(['product'])
->from('s_product_attribute_values')
->where('attribute', $filter)
->whereIn('value', $values);
});
}
}

$this->productIds[$category] = $query->get()->pluck('product')->toArray();
}

return $this->productIds[$category];
}

/**
* Initializes and returns a rich text editor for the specified elements.
*
Expand Down
19 changes: 19 additions & 0 deletions src/Facades/sFilter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php namespace Seiger\sCommerce\Facades;

use Illuminate\Support\Facades\Facade;

/**
* @mixin \Seiger\sCommerce\sFilter
*/
class sFilter extends Facade
{
/**
* Get the registered name of the component.
*
* @return string
*/
protected static function getFacadeAccessor()
{
return 'sFilter';
}
}
72 changes: 37 additions & 35 deletions src/sCommerce.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
use Seiger\sCommerce\Controllers\sCommerceController;
use Seiger\sCommerce\Facades\sFilter;
use Seiger\sCommerce\Models\sAttribute;
use Seiger\sCommerce\Models\sAttributeValue;
use Seiger\sCommerce\Models\sCategory;
use Seiger\sCommerce\Models\sProduct;
use Seiger\sCommerce\Models\sProductTranslate;
Expand All @@ -28,6 +30,12 @@ class sCommerce
* @var Collection
*/
protected $currencies;
protected $controller;

public function __construct()
{
$this->controller = new sCommerceController();
}

/**
* The current currency for the session.
Expand All @@ -51,10 +59,7 @@ class sCommerce

public function getProducts(array $productIds, string $lang = null, int $perPage = 1000): object
{
if (!$lang) {
$lang = evo()->getLocale();
}

$lang = !$lang ? evo()->getLocale() : $lang;
return sProduct::lang($lang)->whereIn('id', $productIds)->active()->paginate($perPage);
}

Expand All @@ -65,13 +70,9 @@ public function getProducts(array $productIds, string $lang = null, int $perPage
* @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
public function getProduct(int $productId, string $lang = null): object
{
if (!trim($lang)) {
$sCommerceController = new sCommerceController();
$lang = $sCommerceController->langDefault();
}

$lang = !$lang ? $this->controller->langDefault() : $lang;
$product = sProduct::lang($lang)->whereId($productId)->extractConstructor()->first();

if (!$product) {
Expand Down Expand Up @@ -104,9 +105,8 @@ public function getProductByAlias(string $alias): object
*/
public function getTreeActiveCategories(int $category, int $dept = 10): object
{
$sCommerceController = new sCommerceController();
$object = sCategory::find($category);
return $sCommerceController->listSubCategories($object, $dept);
return $this->controller->listSubCategories($object, $dept);
}

/**
Expand All @@ -120,36 +120,42 @@ public function getTreeActiveCategories(int $category, int $dept = 10): object
*/
public function getCategoryProducts(int $category = null, string $lang = null, int $perPage = 1000, int $dept = 10): object
{
$sCommerceController = new sCommerceController();

if (!$lang) {
$lang = evo()->getLocale();
}

if (!$category) {
$category = evo()->documentIdentifier;
}

$categories = array_merge([$category], $sCommerceController->listAllActiveSubCategories($category, $dept));
$productIds = DB::table('s_product_category')->select(['product'])->whereIn('category', $categories)->get()->pluck('product')->toArray();

$productIds = $this->controller->productIds($category, $dept);
return $this->getProducts($productIds, $lang, $perPage);
}

/**
* Retrieves filters associated with a specific category.
*
* This method generates a collection of filters based on attributes
* and their corresponding values for the products within the specified category.
*
* @param int|null $category The ID of the category for which filters are retrieved.
* If null, all categories are considered.
* @param string|null $lang The language locale for the filters.
* Defaults to the application's current locale.
* @param int $dept The depth level for category traversal.
* Determines how deep the category hierarchy should be explored.
* Defaults to 10.
*
* @return object|Collection A collection of filters for the specified category.
* Each filter includes attribute details and value counts.
*/
public function getCategoryFilters(int $category = null, string $lang = null, int $dept = 10): object
{
return sFilter::byCategory($category, $lang, $dept);
}

/**
* Retrieves the attribute object by its ID and language.
*
* @param int $attributeId The ID of the attribute to retrieve.
* @param string $lang The language code to use. Defaults to an empty string.
* @return object The attribute object if found, otherwise a new sAttribute object.
*/
public function getAttribute(int $attributeId, string $lang = ''): object
public function getAttribute(int $attributeId, string $lang = null): object
{
if (!trim($lang)) {
$sCommerceController = new sCommerceController();
$lang = $sCommerceController->langDefault();
}

$lang = !$lang ? $this->controller->langDefault() : $lang;
return sAttribute::lang($lang)->whereAttribute($attributeId)->first() ?? new sAttribute();
}

Expand Down Expand Up @@ -305,20 +311,16 @@ public static function config(string $key, mixed $default = null): mixed
*/
protected static function loadCurrentCurrency(): string
{
// Try to retrieve currency from session
$currency = $_SESSION['currency'];

// Check cookies if currency is still not set
if (!$currency && Cookie::has('currency')) {
$currency = Cookie::get('currency');
}

// Fallback to default currency from configuration
if (!$currency) {
$currency = static::config('basic.main_currency', 'USD');
}

// Store currency in session if it is not already set
if (!$_SESSION['currency'] || $_SESSION['currency'] !== $currency) {
$_SESSION['currency'] = $currency;
}
Expand Down
4 changes: 4 additions & 0 deletions src/sCommerceServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ public function boot()
// Register the sCart class as a singleton
$this->app->singleton(sCart::class);
$this->app->alias(sCart::class, 'sCart');

// Register the sFilter class as a singleton
$this->app->singleton(sFilter::class);
$this->app->alias(sFilter::class, 'sFilter');
}

/**
Expand Down
Loading

0 comments on commit ed26205

Please sign in to comment.