1
0
mirror of https://github.com/robonen/metr.git synced 2026-03-20 02:44:42 +00:00

Offer filters and user feedback

This commit is contained in:
2022-05-29 04:21:56 +07:00
parent ff7fe27698
commit fe2e5d316c
13 changed files with 272 additions and 10 deletions

View File

@@ -0,0 +1,18 @@
<?php
namespace App\Filters;
use Illuminate\Database\Eloquent\Builder;
trait Filterable
{
/**
* @param \Illuminate\Database\Eloquent\Builder $builder
* @param \App\Filters\QueryFilter $filters
* @return \Illuminate\Database\Eloquent\Builder
*/
public function scopeFilter(Builder $builder, QueryFilter $filters): Builder
{
return $filters->apply($builder);
}
}

View File

@@ -0,0 +1,57 @@
<?php
namespace App\Filters;
use App\Enums\OrderTypesEnum;
use Illuminate\Database\Eloquent\Builder;
class OfferFilter extends QueryFilter
{
/**
* @param string $type
* @return \Illuminate\Database\Eloquent\Builder
*/
protected function type(string $type): Builder
{
if (OrderTypesEnum::tryFrom($type) !== null)
return $this->builder->where('type', $type);
return $this->builder;
}
/**
* @param int $rooms
* @return \Illuminate\Database\Eloquent\Builder
*/
protected function rooms(int $rooms): Builder
{
if ($rooms >= 1)
return $this->builder->where('rooms', '>=', $rooms);
return $this->builder;
}
/**
* @param int $price
* @return \Illuminate\Database\Eloquent\Builder
*/
protected function startPrice(int $price): Builder
{
if ($price >= 0)
return $this->builder->where('price', '>=', $price);
return $this->builder;
}
/**
* @param int $price
* @return \Illuminate\Database\Eloquent\Builder
*/
protected function endPrice(int $price): Builder
{
if ($price >= 0)
return $this->builder->where('price', '<=', $price);
return $this->builder;
}
}

View File

@@ -0,0 +1,46 @@
<?php
namespace App\Filters;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Http\Request;
abstract class QueryFilter
{
protected Request $request;
protected Builder $builder;
/**
* @param \Illuminate\Http\Request $request
*/
public function __construct(Request $request)
{
$this->request = $request;
}
/**
* @param \Illuminate\Database\Eloquent\Builder $builder
* @return \Illuminate\Database\Eloquent\Builder
*/
public function apply(Builder $builder): Builder
{
$this->builder = $builder;
foreach ($this->filters() as $name => $value) {
if (method_exists($this, $name)) {
call_user_func_array([$this, $name], array_filter([$value]));
}
}
return $this->builder;
}
/**
* @return array|string|null
*/
private function filters(): array|string|null
{
return $this->request->query();
}
}

View File

@@ -0,0 +1,69 @@
<?php
namespace App\Http\Controllers;
use App\Http\Requests\StoreFeedbackRequest;
use App\Http\Requests\UpdateFeedbackRequest;
use App\Http\Resources\FeedbackResource;
use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
class FeedbackController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection
*/
public function index(): AnonymousResourceCollection
{
return FeedbackResource::collection(auth()->user()->feedback()->get());
}
/**
* Display the specified resource.
*
* @param int $id
* @return \App\Http\Resources\FeedbackResource
*/
public function show(int $id): FeedbackResource
{
$feedback = auth()->user()->feedback()->findOrFail($id);
return new FeedbackResource($feedback);
}
/**
* Store a newly created resource in storage.
*
* @param \App\Http\Requests\StoreFeedbackRequest $request
* @return \App\Http\Resources\FeedbackResource
*/
public function store(StoreFeedbackRequest $request): FeedbackResource
{
$feedback = auth()->user()->feedback()->create($request->validated());
return new FeedbackResource($feedback);
}
/**
* Update the specified resource in storage.
*
* @param \App\Http\Requests\UpdateFeedbackRequest $request
* @param int $id
* @return void
*/
public function update(UpdateFeedbackRequest $request, int $id): void
{
$feedback = auth()->user()->feedback()->findOrFail($id);
$feedback->update($request->validated());
}
/**
* Remove the specified resource from storage.
*
* @param int $id
* @return void
*/
public function destroy(int $id): void
{
auth()->user()->feedback()->findOrFail($id)->delete();
}
}

View File

@@ -2,6 +2,7 @@
namespace App\Http\Controllers; namespace App\Http\Controllers;
use App\Filters\OfferFilter;
use App\Http\Requests\StoreOfferRequest; use App\Http\Requests\StoreOfferRequest;
use App\Http\Requests\UpdateOfferRequest; use App\Http\Requests\UpdateOfferRequest;
use App\Http\Resources\OfferResource; use App\Http\Resources\OfferResource;
@@ -15,9 +16,9 @@ class OfferController extends Controller
* *
* @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection * @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection
*/ */
public function index(): AnonymousResourceCollection public function index(OfferFilter $filters): AnonymousResourceCollection
{ {
return OfferResource::collection(Offer::all()); return OfferResource::collection(Offer::filter($filters)->get());
} }
/** /**

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Http\Requests;
class StoreFeedbackRequest extends BaseRequest
{
/**
* Get the validation rules that apply to the request.
*
* @return array<string, mixed>
*/
public function rules()
{
return [
'comment' => ['required', 'string', 'max:2000'],
'rating' => ['required', 'numeric', 'min:1', 'max:5'],
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Http\Requests;
class UpdateFeedbackRequest extends BaseRequest
{
/**
* Get the validation rules that apply to the request.
*
* @return array<string, mixed>
*/
public function rules()
{
return [
'comment' => ['string', 'max:2000'],
'rating' => ['numeric', 'min:1', 'max:5'],
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class FeedbackResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
*/
public function toArray($request)
{
return parent::toArray($request);
}
}

View File

@@ -19,4 +19,13 @@ class Feedback extends Model
'comment', 'comment',
'rating', 'rating',
]; ];
/**
* The attributes that should be cast.
*
* @var array<string, string>
*/
protected $casts = [
'rating' => 'integer',
];
} }

View File

@@ -3,12 +3,13 @@
namespace App\Models; namespace App\Models;
use App\Enums\OrderTypesEnum; use App\Enums\OrderTypesEnum;
use App\Filters\Filterable;
use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
class Offer extends Model class Offer extends Model
{ {
use HasFactory; use HasFactory, Filterable;
/** /**
* The attributes that are mass assignable. * The attributes that are mass assignable.

View File

@@ -34,4 +34,9 @@ class User extends Authenticatable
protected $hidden = [ protected $hidden = [
'password', 'password',
]; ];
public function feedback()
{
return $this->hasMany(Feedback::class);
}
} }

View File

@@ -29,6 +29,6 @@ return [
'max_age' => 0, 'max_age' => 0,
'supports_credentials' => false, 'supports_credentials' => true,
]; ];

View File

@@ -3,6 +3,7 @@
use App\Http\Controllers\Auth\LoginController; use App\Http\Controllers\Auth\LoginController;
use App\Http\Controllers\Auth\LogoutController; use App\Http\Controllers\Auth\LogoutController;
use App\Http\Controllers\Auth\RegistrationController; use App\Http\Controllers\Auth\RegistrationController;
use App\Http\Controllers\FeedbackController;
use App\Http\Controllers\OfferController; use App\Http\Controllers\OfferController;
use App\Http\Controllers\OrderController; use App\Http\Controllers\OrderController;
use App\Http\Controllers\UserController; use App\Http\Controllers\UserController;
@@ -32,16 +33,14 @@ Route::prefix('auth')->group(function() {
Route::middleware('auth:sanctum')->group(function() { Route::middleware('auth:sanctum')->group(function() {
Route::prefix('user')->group(function() { Route::apiResource('orders', OrderController::class);
Route::prefix('users')->group(function() {
Route::get('', [UserController::class, 'index']); Route::get('', [UserController::class, 'index']);
Route::put('', [UserController::class, 'update']); Route::put('', [UserController::class, 'update']);
Route::apiResource('feedback', FeedbackController::class);
}); });
Route::apiResource('orders', OrderController::class);
}); });
Route::apiResource('offers', OfferController::class); Route::apiResource('offers', OfferController::class);
// TODO: На главной странице 6 самых дорогих квартир
// TODO: Последние добавленные квартиры + фильтры