This commit is contained in:
2025-09-25 03:03:31 +05:00
commit ae480cf2f6
2768 changed files with 1485826 additions and 0 deletions

View File

@@ -0,0 +1,98 @@
<?php
namespace App\Helpers\Ecommerce\Product\Filter;
use App\Rules\CommaSeparatedIntegers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
class ProductFilterer
{
/*
* Query builder
*/
protected $queryBuilder;
/**
* Request
*/
protected Request $request;
/**
* Product filterer
*/
public function __construct($queryBuilder, $request)
{
$this->queryBuilder = $queryBuilder;
$this->request = $request;
}
/**
* Create "new" class via static method
*/
public static function make($queryBuilder, $request): self
{
return new self($queryBuilder, $request);
}
/**
* Validate the request
*/
public function validateRequest(): \Illuminate\Contracts\Validation\Validator
{
return Validator::make($this->request->all(), [
'ids' => ['nullable', 'string', new CommaSeparatedIntegers()],
'brands' => ['nullable', 'string', new CommaSeparatedIntegers()],
'categories' => ['nullable', 'string', new CommaSeparatedIntegers()],
'name' => ['nullable', 'string', 'max:255'],
'min_price' => ['nullable', 'numeric'],
'max_price' => ['nullable', 'numeric'],
'backorder' => ['nullable', 'in:0,1'],
]);
}
/**
* Sort
*/
public function filter()
{
if ($this->validateRequest()->fails()) {
return $this->queryBuilder;
}
if ($this->request->filled('brands')) {
$this->queryBuilder->whereIntegerInRaw('products.brand_id', explode(',', $this->request->brands));
}
if ($this->request->filled('categories')) {
$this->queryBuilder->whereIn(
column: 'id',
values: (
fn ($query) => $query->from('product_has_relations')
->select('product_id')
->distinct('product_id')
->where('productable_type', '=', 'category')
->whereIn('productable_id', explode(',', $this->request->categories))
)
);
}
if ($this->request->filled('name')) {
$this->queryBuilder->where('products.name', 'ilike', $this->request->name.'%');
}
if ($this->request->filled('min_price')) {
$this->queryBuilder->whereRaw('products.price_amount::NUMERIC >= ?', [$this->request->float('min_price')]);
}
if ($this->request->filled('max_price')) {
$this->queryBuilder->whereRaw('products.price_amount::NUMERIC <= ?', [$this->request->float('max_price')]);
}
if ($this->request->filled('backorder')) {
$this->queryBuilder->where('products.backorder', $this->request->backorder);
}
return $this->queryBuilder;
}
}

View File

@@ -0,0 +1,96 @@
<?php
namespace App\Helpers\Ecommerce\Product\Sort;
use App\Rules\SortableColumnRule;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
class ProductSorter
{
/*
* Query builder
*/
protected mixed $queryBuilder;
/**
* Request
*/
protected Request $request;
/**
* Allowed columns for sorting
*
* @var array<string>
*/
protected array $allowedColumns = [
'price_amount',
'created_at',
'name',
];
/**
* Constructor
*/
public function __construct($queryBuilder, $request)
{
$this->queryBuilder = $queryBuilder;
$this->request = $request;
}
/**
* Construct statically
*/
public static function make($queryBuilder, $request): self
{
return new self($queryBuilder, $request);
}
/**
* Validate the request
*/
public function validateRequest(): \Illuminate\Contracts\Validation\Validator
{
return Validator::make($this->request->all(), [
'sorting' => ['nullable', 'string', new SortableColumnRule($this->allowedColumns)],
]);
}
/**
* Sort from request
*/
public function sort()
{
if ($this->request->isNotFilled('sorting') || $this->validateRequest()->fails()) {
return $this->orderByLatest();
}
return $this->queryBuilder->orderBy($this->getColumn(), $this->getSortType());
}
/**
* Get sort column
*/
public function getColumn(): string
{
return explode('-', $this->request->sorting)[0];
}
/**
* Get sort type
*/
public function getSortType(): string
{
$sortType = explode('-', $this->request->sorting)[1];
return $sortType === 'descending' ? 'DESC' : 'ASC';
}
/**
* Order by latest (created_at)
*/
public function orderByLatest(): mixed
{
return $this->queryBuilder->latest();
}
}