Merge pull request #45 from CyberAli1989/master

feat: Implement product listing API with caching and sorting
pull/49/head
A1Gard 5 months ago committed by GitHub
commit bc60ae2498
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,38 @@
<?php
namespace App\Http\Controllers\Api\Web;
use App\Http\Controllers\Controller;
use App\Http\Resources\AdvResource;
use App\Http\Resources\CategoryResource;
use App\Http\Resources\PostResource;
use App\Http\Resources\ProductResource;
use App\Http\Resources\SliderResource;
use App\Models\Adv;
use App\Models\Category;
use App\Models\Menu;
use App\Models\Post;
use App\Models\Product;
use App\Models\Slider;
use Illuminate\Http\Request;
class HomeController extends Controller
{
public function index()
{
$data = [];
$data['menu'] = Menu::with(['items' => function ($query) {
$query->select(['id', 'title', 'menuable_id', 'menuable_type', 'kind', 'meta', 'parent', 'sort', 'user_id', 'menu_id']);
}])->first(['id', 'name']);
$data['slider'] = SliderResource::collection(Slider::take(6)->get());
$data['categories'] = CategoryResource::collection(Category::with('products')->whereNull('parent_id')->orderBy('sort')->take(8)->get());
$data['adv'] = AdvResource::collection(
Adv::query()
->where('status', true)
->whereColumn('click', '<', 'max_click')
->get()
);
$data['post'] = PostResource::collection(Post::orderByDesc('created_at')->take(8)->get());
return success($data);
}
}

@ -0,0 +1,63 @@
<?php
namespace App\Http\Controllers\Api\Web;
use App\Http\Controllers\Controller;
use App\Http\Resources\ProductResource;
use App\Models\Category;
use App\Models\Product;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;
class ProductController extends Controller
{
public function index(Request $request)
{
$cacheKey = 'products_' . md5($request->getUri());
$data = Cache::remember($cacheKey, now()->addMinutes(env('CACHE_LIFE_TIME', 10)), function () use ($request) {
$product = Product::query();
/**
* Product Sort by keys
*/
if (isset($request['sort']) && !is_null($request['sort'])) {
if ($request['sort'] === 'new')
$product = $product->orderByDesc('created_at');
if ($request['sort'] === 'old')
$product = $product->orderBy('created_at');
if ($request['sort'] === 'most_view')
$product = $product->orderByDesc('view');
if ($request['sort'] === 'less_view')
$product = $product->orderBy('view');
if ($request['sort'] === 'most_buy')
$product = $product->orderByDesc('sell');
if ($request['sort'] === 'less_buy')
$product = $product->orderBy('sell');
}
if (isset($request['category']) && !is_null($request['category']))
$product = $product->where('category_id', Category::firstWhere('slug', $request['category'])->id);
if (isset($request['search']) && !is_null($request['search']))
$product = $product->where('name', 'LIKE', "%$request->search%");
if (isset($request['min_price']) &&
isset($request['max_price']) &&
!is_null($request['min_price']) &&
!is_null($request['max_price'])
) {
$product = $product->whereBetween('buy_price', [
intval($request->min_price),
intval($request->max_price)
]);
}
$request->merge([
'loadCategory' => true
]);
return [
'products' => ProductResource::collection($product->paginate($request->input('per_page', 20)))->resource->toArray(),
];
});
return success($data);
}
}

@ -0,0 +1,28 @@
<?php
namespace App\Http\Resources;
use App\Models\Adv;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;
class AdvResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @return array<string, mixed>
*/
public function toArray(Request $request): array
{
/**
* @var $this Adv
*/
return [
'id' => $this->id,
'image' => $this->imgUrl,
'title' => $this->title,
'link' => $this->link,
];
}
}

@ -0,0 +1,41 @@
<?php
namespace App\Http\Resources;
use App\Models\Category;
use App\Models\Product;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;
//use Illuminate\Http\Resources\Json\ResourceCollection;
class CategoryResource extends JsonResource
{
/**
* Transform the resource collection into an array.
*
* @return array<int|string, mixed>
*/
public function toArray(Request $request, $data = null): array
{
/**
* @var $this Category
*/
if (!$request['loadCategory'])
$request->merge([
'loadCategory' => false
]);
return [
'id' => $this->id,
'name' => $this->name,
'slug' => $this->slug,
'subtitle' => $this->subtitle,
'description' => $this->description,
'sort' => $this->sort,
'image' => $this->image,
'bg' => $this->bg,
'products' => $this->when($request->input('loadProduct', true), ProductResource::collection($this->products)->additional(['request' => $request['loadCategory']]))
];
}
}

@ -0,0 +1,38 @@
<?php
namespace App\Http\Resources;
use App\Models\Post;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;
class PostResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @return array<string, mixed>
*/
public function toArray(Request $request): array
{
/**
* @var $this Post
*/
return [
'id' => $this->id,
'slug' => $this->slug,
'subtitle' => $this->subtitle,
'body' => $this->body,
'group' => $this->load('groups'),
'author' => $this->load('author'),
'view' => $this->view,
'is_pinned' => $this->is_pinned,
'hash' => $this->hash,
'like' => $this->like,
'dislike' => $this->dislike,
'icon' => $this->icon,
'created_at' => $this->created_at,
];
}
}

@ -0,0 +1,43 @@
<?php
namespace App\Http\Resources;
use App\Models\Product;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;
class ProductResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @return array<string, mixed>
*/
public function toArray(Request $request): array
{
/**
* @var $this Product
*/
if (!$request['loadProduct'])
$request->merge([
'loadProduct' => false
]);
return [
'id' => $this->id,
'name' => $this->name,
'slug' => $this->slug,
'description' => $this->description,
'table' => $this->table,
'sku' => $this->sku,
'virtual' => $this->virtual,
'downloadable' => $this->downloadable,
'price' => intval($this->price),
'buy_price' => $this->buy_price,
'average_rating' => floatval($this->average_rating),
'view' => $this->view,
'category' => $this->when($request->input('loadCategory', true), new CategoryResource($this->category)),
'image' => $this->imgUrl()
];
}
}

@ -0,0 +1,32 @@
<?php
namespace App\Http\Resources;
use App\Models\Slider;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;
class SliderResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @return array<string, mixed>
*/
public function toArray(Request $request): array
{
/**
* @var $this Slider
*/
return [
'id' => $this->id,
'body' => $this->body,
'image' => $this->imgUrl(),
'tag' => $this->tag,
'user_id' => $this->user_id,
'status' => $this->status,
'data' => $this->data,
'user' => $this->load('author')
];
}
}

@ -9,12 +9,12 @@ Route::get('/user', function (Request $request) {
Route::get('', function () {
return 'xshop api:'.config('app.name');
return 'xshop api:' . config('app.name');
});
Route::get('/clear', function () {
if (!auth()->check()){
if (!auth()->check()) {
return abort(403);
}
Artisan::call('cache:clear');
@ -33,9 +33,12 @@ Route::prefix('v1')->name('v1.')->group(
return 'xShop api v1';
});
Route::get('states', [\App\Http\Controllers\Api\StateController::class,'index'])->name('state.index');
Route::get('state/{state}', [\App\Http\Controllers\Api\StateController::class,'show'])->name('state.show');
Route::get('category/props/{category}', [\App\Http\Controllers\Api\CategoryController::class,'props'])->name('category.prop');
Route::post('morph/search', [\App\Http\Controllers\Api\MorphController::class,'search'])->name('morph.search');
Route::post('visitor/display', [\App\Http\Controllers\Api\VisitorController::class,'display'])->name('visitor.display');
Route::get('states', [\App\Http\Controllers\Api\StateController::class, 'index'])->name('state.index');
Route::get('state/{state}', [\App\Http\Controllers\Api\StateController::class, 'show'])->name('state.show');
Route::get('category/props/{category}', [\App\Http\Controllers\Api\CategoryController::class, 'props'])->name('category.prop');
Route::post('morph/search', [\App\Http\Controllers\Api\MorphController::class, 'search'])->name('morph.search');
Route::post('visitor/display', [\App\Http\Controllers\Api\VisitorController::class, 'display'])->name('visitor.display');
Route::apiResource('web', \App\Http\Controllers\Api\Web\HomeController::class)->only('index');
Route::apiResource('products' , \App\Http\Controllers\Api\Web\ProductController::class)->only('index');
});

Loading…
Cancel
Save