chore: add isFavorite in produtcs response

- refactor code to use query
- add active column in products
This commit is contained in:
kusowl 2026-03-05 13:32:49 +05:30
parent 8ef4383bd9
commit ae008fbc9c
7 changed files with 89 additions and 4 deletions

View File

@ -22,6 +22,7 @@ public function __construct(
public array $productImages, public array $productImages,
public ?string $updatedAt = null, public ?string $updatedAt = null,
public ?string $createdAt = null, public ?string $createdAt = null,
public ?bool $isFavorite = null
) {} ) {}
/** /**
@ -41,6 +42,7 @@ public function toArray(): array
$this->productImages), $this->productImages),
'updatedAt' => $this->updatedAt, 'updatedAt' => $this->updatedAt,
'createdAt' => $this->createdAt, 'createdAt' => $this->createdAt,
'isFavorite' => $this->isFavorite,
]; ];
} }
@ -57,6 +59,8 @@ public static function fromModel(Product $product): self
productImages: $product->images->map(fn (ProductImage $productImage) => ProductImageDTO::fromModel($productImage))->all(), productImages: $product->images->map(fn (ProductImage $productImage) => ProductImageDTO::fromModel($productImage))->all(),
updatedAt: $product->updated_at, updatedAt: $product->updated_at,
createdAt: $product->created_at, createdAt: $product->created_at,
// this column is added by where exists query
isFavorite: $product->favorited_by_exists,
); );
} }
} }

View File

@ -7,6 +7,7 @@
use App\Models\Product; use App\Models\Product;
use App\Models\User; use App\Models\User;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
class FavouriteProductController extends Controller class FavouriteProductController extends Controller
{ {
@ -23,7 +24,7 @@ public function toggle(Request $request, Product $product)
$user = $request->user(); $user = $request->user();
$changes = $user->favoriteProducts()->toggle($product); $changes = $user->favoriteProducts()->toggle($product);
Log::info('hi again');
// If changes has any item, that means a product has been attached. // If changes has any item, that means a product has been attached.
$isFavorite = count($changes['attached']) > 0; $isFavorite = count($changes['attached']) > 0;

View File

@ -6,14 +6,16 @@
use App\Http\Requests\CreateProductRequest; use App\Http\Requests\CreateProductRequest;
use App\Http\Resources\ProductResource; use App\Http\Resources\ProductResource;
use App\Models\Product; use App\Models\Product;
use App\Queries\GetProductsQuery;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class ProductController extends Controller class ProductController extends Controller
{ {
public function index() public function index(GetProductsQuery $getProductsQuery)
{ {
$paginator = Product::query()->with(['category:id,name,slug', 'images:id,path,product_id'])->paginate(); $products = $getProductsQuery->get(Auth::user());
$paginatedDtos = $paginator->through(fn ($product) => ProductDTO::fromModel($product)); $paginatedDtos = $products->through(fn ($product) => ProductDTO::fromModel($product));
return ProductResource::collection($paginatedDtos); return ProductResource::collection($paginatedDtos);
} }

View File

@ -30,6 +30,7 @@ public function toArray(Request $request): array
return Storage::disk('public')->url($productImage->path); return Storage::disk('public')->url($productImage->path);
}, $this->resource->productImages), }, $this->resource->productImages),
'updatedAt' => $this->resource->updatedAt, 'updatedAt' => $this->resource->updatedAt,
'isFavorite' => $this->resource->isFavorite,
]; ];
} }
} }

View File

@ -2,8 +2,11 @@
namespace App\Models; namespace App\Models;
use Illuminate\Database\Eloquent\Attributes\Scope;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Support\Str; use Illuminate\Support\Str;
@ -28,6 +31,17 @@ public function images(): HasMany
return $this->hasMany(ProductImage::class, 'product_id', 'id'); return $this->hasMany(ProductImage::class, 'product_id', 'id');
} }
public function favoritedBy(): BelongsToMany
{
return $this->belongsToMany(User::class, 'favorite_products');
}
#[Scope]
protected function active(Builder $query): Builder
{
return $query->where('is_active', true);
}
protected static function booted(): void protected static function booted(): void
{ {
static::saving(function ($product) { static::saving(function ($product) {
@ -36,4 +50,11 @@ protected static function booted(): void
} }
}); });
} }
protected function casts()
{
return [
'is_active' => 'boolean',
];
}
} }

View File

@ -0,0 +1,27 @@
<?php
namespace App\Queries;
use App\Models\Product;
use App\Models\User;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Pagination\LengthAwarePaginator;
final readonly class GetProductsQuery
{
public function get(?User $user = null): LengthAwarePaginator
{
return Product::query()
->active()
->when($user, function (Builder $query) use ($user) {
$query->withExists(
[
'favoritedBy' => fn (Builder $query) => $query->where('user_id', $user->id),
]
);
})
->with(['category:id,name,slug', 'images:id,path,product_id'])
->paginate();
}
}

View File

@ -0,0 +1,29 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('products', function (Blueprint $table) {
$table->boolean('is_active')->default(true);
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('products', function (Blueprint $table) {
$table->dropColumn('is_active');
});
}
};