I am trying to filter data using when query in Laravel, where it should filter data using the filter $sortBy or $categoryId. Please note the all 3 fields like $id $sortBy $categoryId are optional and will not be presented in all queries
public function Products(Request $request)
{
$page = $request->has('page') ? $request->get('page') : 1;
$limit = $request->has('itemsPerPage') ? $request->get('itemsPerPage') : 10;
$sortBy = (($request->sortBy == "popularity") ? "viewCount" : "created_at");
$categoryId= $request->get('categoryId');
$sellerId = $request->header('id')?SellersBranding::findOrFail($request->header('id')):"Null";
$productLive = ProductsLive::select('productTitle', 'product_id', 'brand_id', 'category_id')
->when($sellerId=="Null", function($query) use ($page, $limit){
return $query->where('status', 'active')
->limit($limit)->offset(($page - 1) * $limit);
})
->when($sortBy, function ($query) use ($sortBy, $sellerId, $page, $limit){
return $query->orderBy($sortBy, 'DESC')
->where('Sid', $sellerId->id)
->where('status','active')
->limit($limit)->offset(($page - 1) * $limit);
})
->when($categoryId, function ($query) use ($categoryId, $sellerId, $page, $limit) {
->where('Sid', $sellerId->id)
->where(['category_id' => $categoryId, 'status' => 'active'])
->limit($limit)->offset(($page - 1) * $limit)
->inRandomOrder();
})->get();
}
i am new in php and also in laravel please help how to get filtered data
i cleanup your code you can check this
public function Products(Request $request)
{
$page = $request->has('page') ? $request->get('page') : 1;
$limit = $request->has('itemsPerPage') ? $request->get('itemsPerPage') : 10;
$sortBy = (($request->sortBy == "popularity") ? "viewCount" : "created_at");
$categoryId= $request->filled('categoryId');
$seller = $request->header('id') ? SellersBranding::findOrFail($request->header('id')): null;
$productLive = ProductsLive::select('productTitle', 'product_id', 'brand_id', 'category_id')
->when($seller ,function ($query) use ($seller){
$query->where('Sid', $seller->id);
})
->when($categoryId ,function ($query)){
$query->where('category_id', request('categoryId'))
->inRandomOrder();
})
->where('status','active')
->orderBy($sortBy, 'DESC')
->limit($limit)->offset(($page - 1) * $limit);
return $productLive;
}
here when() something filter is coming we are only applying condition.
Not returning each filter as you did
Related
Hi I am trying to do this query
public function execute() {
return $this->applyModelFilter(Document::with('contact', 'sales_person','document_detail','contact_profile')->invoices())->chunkMap(function ($invoice) {
return $this->mapColumns($invoice);
}, $this->chunkSize)->groupBy($this->groupByFormatted)
->map(function ($group) {
return [
'summary' => $this->getSummary($group),
'transactions' => $this->paginateCollection($group->all()),
'group_name' => $group->first()->get($this->groupByFormatted),
'group_count' => $group->count(),
];
})->values();
}
////
public function paginateCollection($items, $perPage = 5, $page = null, $options = [])
{
$page = $page ?: (\Illuminate\Pagination\Paginator::resolveCurrentPage() ?: 1);
$items = $items instanceof \Illuminate\Support\Collection ? $items : \Illuminate\Support\Collection::make($items);
return new \Illuminate\Pagination\LengthAwarePaginator(array_values($items->forPage($page, $perPage)->toArray()), $items->count(), $perPage, $page, $options);
}
But it displays pagination only in transaction, i want pagination for whole data.
So I wonder how can I do that without to lose the paginate function ? Thanks.
How can I cache custom query into redis. I am trying the following
public function __construct()
{
$this->orders_sql = Cache::remember('orders', 10, function () {
return $query = DB::connection('db1')->table('orders as o')
->leftJoin('addresses as pa', 'o.id', '=', 'pa.order_id')
->leftJoin('users as u', 'o.user_id', '=', 'u.id')
->leftJoin('clients', 'clients.user_id', '=', 'u.id')
->select(
'o.id as id', 'o.type as type', 'o.extra_info as extra_info', 'o.status as order_status', 'o.created_at as created_at', 'o.type as order_type', 'o.inspection_date as inspection_date', 'o.assignee as assignee', 'o.user_id as user_id', 'o.inspector_name as inspector_name',
'pa.address as address', 'pa.city as city', 'pa.state as state',
'clients.first_name as first_name', 'clients.middle_name as middle_name', 'clients.last_name as last_name'
)
->whereIn('o.status', OrderHelper::$ALLOWED_STATUS)
->where('o.type', '<>', OrderHelper::$CONSTRUCTION_EXISTING)
->where('o.deleted_at', null);
});
}
public function orders($sort_by, $sort_order, $limit, $filters)
{
if ($filters) {
$query = $this->applyFilters($filters);
}
$orders = $query->orderBy($sort_by ?? OrderHelper::$DEFAULT_SORT_COLUMN, $sort_order ?? OrderHelper::$DEFAULT_SORT_ORDER);
if ($limit === 'all') {
$orders = $orders->get();
} else {
$orders = $orders->get();
// $orders = $orders->paginate($limit ?? CommonHelper::$DEFAULT_PAGINATION_LIMIT);
}
//adding more information with orders such as Bank and address info
foreach ($orders as $order) {
$order->created_at = OrderHelper::getFormattedDate($order->id);
$order->draw = OrderHelper::draw($order->id);
$order->inspection_date = OrderHelper::getFormattedInspectionDate($order->inspection_date);
$order->client_name = $order->first_name . ' ' . $order->middle_name . ' ' . $order->last_name;
$order->type = OrderHelper::getFormattedOrderType($order);
if (empty($order->assignee)) {
$order->inspector_name = '-';
}
}
return $orders ? $orders : false;
}
And I am getting the error as
"message": "Serialization of 'Closure' is not allowed",
"exception": "Exception",
"file": "/var/www/api.local/vendor/laravel/framework/src/Illuminate/Cache/RedisStore.php",
"line": 295,
I'm guessing that you are using one of the laravel services like queue or something if yes in your case laravel tries uses serialize() function to serialize the class properties but one problem with serialize() function is that it cannot serialize closure that you are passing
anonymous functions cannot be serialized thats php behavior
What you can do is to try to assign the result to the property or pass the result to the constructor...
I try to add some new values to each user from foreach, but because I use get, now I can't use paginate on response, but I also need to add that values to each user. Any ideas?
public function statistics()
{
$users = User::select(['id', 'name'])->get();
foreach ($users as $key => $user) {
$history = AnswerHistory::where('user_id', '=', $user->id)->get();
$user->total_votes = count($history);
$user->total_time = gmdate("H:i:s", ($history->sum('answer_time')));
}
return response()->json($users);
}
what you want is not possible in laravel by default, however there are a few things you can do.
Solution one you can return paginator first and then modify the collection.
$users = User::select(['id', 'name'])->paginate(4)->toArray();
$users['data'] = array_map(function ($user) {
$history = AnswerHistory::where('user_id', '=', $user->id)->get();
$user->total_votes = count($history);
$user->total_time = gmdate("H:i:s", ($history->sum('answer_time')));
return $user;
}, $users['data']);
return $users;
Solution two The macro way. If you prefer, add the Collection macro to a Service Provider. That way you can call paginate() on any collection:
See AppServiceProvider.php for a sample implementation.
public function boot()
{
Collection::macro('paginate', function ($perPage, $total = null, $page = null, $pageName = 'page') {
$page = $page ?: LengthAwarePaginator::resolveCurrentPage($pageName);
return new LengthAwarePaginator(
$this->forPage($page, $perPage),
$total ?: $this->count(),
$perPage,
$page,
[
'path' => LengthAwarePaginator::resolveCurrentPath(),
'pageName' => $pageName,
]
);
});
}
and then your code will be like this
$users = User::select(['id', 'name'])->get();
foreach ($users as $key => $user) {
$history = AnswerHistory::where('user_id', '=', $user->id)->get();
$user->total_votes = count($history);
$user->total_time = gmdate("H:i:s", ($history->sum('answer_time')));
}
return response()->json($users->paginate(4));
Solution three The subclass way. Where you want a "pageable" collection that is distinct from the standard Illuminate\Support\Collection, implement a copy of Collection.php in your application and simply replace your use Illuminate\Support\Collection statements at the top of your dependent files with use App\Support\Collection:
<?php
namespace App\Support;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Collection as BaseCollection;
class Collection extends BaseCollection
{
public function paginate($perPage, $total = null, $page = null, $pageName = 'page')
{
$page = $page ?: LengthAwarePaginator::resolveCurrentPage($pageName);
return new LengthAwarePaginator(
$this->forPage($page, $perPage),
$total ?: $this->count(),
$perPage,
$page,
[
'path' => LengthAwarePaginator::resolveCurrentPath(),
'pageName' => $pageName,
]
);
}
}
and your code will be like this
// use Illuminate\Support\Collection
use App\Support\Collection;
$users = User::select(['id', 'name'])->get();
foreach ($users as $key => $user) {
$history = AnswerHistory::where('user_id', '=', $user->id)->get();
$user->total_votes = count($history);
$user->total_time = gmdate("H:i:s", ($history->sum('answer_time')));
}
return response()->json((new Collection($users))->paginate(4);
According to your post, User has many AnswerHistory. You can build relationship between them.
So getting the total_votes and total_time by withCount:
$users = User::withCount('answerHistories AS total_votes')
->withCount(['answerHistories AS total_time' => function($query) {
$query->select(DB::raw("SUM(answer_time)"));
}])->paginate(10);
And you can get the pagination datas by getCollection, and change the datas inside:
$users->getCollection()->transform(function ($data) {
$data->total_time = gmdate('H:i:s', $data->total_time);
return $data;
});
You can create pagination by yourself look to this Laravel doc https://laravel.com/docs/7.x/pagination#manually-creating-a-paginator.
I will suggest to use LengthAwarePaginator
Here is some code example with array
// creating pagination
$offset = max(0, ($page - 1) * $perPage);
$resultArray = array_slice($result, $offset, $perPage);
$paginator = new LengthAwarePaginator($resultArray, count($result), $perPage, $page);
$paginator->setPath(url()->current());
$paginator->appends(['per_page' => $perPage]);
return response()->json([
'message' => 'Success',
'data' => $paginator
]);
But I think your case have better "good" solution, you can load AnswerHistory with hasMany Laravel relation and with function.
How to create api for search in lumen/laravel .. I tried using keyword but not working.
public function index(){
$Employees = Employees::all();
$page = Input::get('page', 1);
$keyword = Input::get('keyword', '');
if ($keyword!='') {
$keyword = Employees::
where("firstname", "LIKE","%$keyword%")
->orWhere("lastname", "LIKE", "%$keyword%");
}
$itemPerPage=5;
$count = Employees::count();
$offSet = ($page * $itemPerPage) - $itemPerPage;
$itemsForCurrentPage = array_slice($Employees->toArray(), $offSet, $itemPerPage);
return new LengthAwarePaginator($itemsForCurrentPage, count($Employees), $itemPerPage, $page,$keyword);
}
You should change this line :
if ($keyword!='') {
$Employees = Employees::
where("firstname", "LIKE","%$keyword%")
->orWhere("lastname", "LIKE", "%$keyword%")
->get();
}
Also i think You should the pagination within the model query, not on the returned result.
you can also do this
define your logic in a scope created in you model and consume it in your controller.here is what i mean
This should be in your model
public function scopeFilter($query, $params)
{
if ( isset($params['name']) && trim($params['name'] !== '') )
{
$query->where('name', 'LIKE', trim($params['name']) . '%');
}
if ( isset($params['state']) && trim($params['state'] !== '') )
{
$query->where('state', 'LIKE', trim($params['state']) . '%');
}
return $query;
}
and in your controller have something like
public function filter_property(Request $request)
{
$params = $request->except('_token');
$product = Product::filter($params)->get();
return response($product);
}
you can get more by reading scope on laravel doc and this blog post here
I'm building a filter function in a project.
I have a filter option "Show newest", "Show oldest" and a bunch of other options. I found a way how to implement conditional where clauses, but there doesn't seems to be a conditional orderBy class.
My conditional where clause looks like this:
$query->where(function($query) use ($request){
if( ! empty($request->input('prices')) ){
$opts = $request->prices;
$query->where('price_id', $opts[0]);
}
})
Is there a way to do this with a ->orderBy too?
UPDATE
return Auction::where('end_date', '>', Carbon::now() )
->where('locale', $locale)
->where('sold', 0)
->where(function($query) use ($request){
if( ! empty($request->input('prices')) ){
$opts = $request->prices;
$query->where('price_id', $opts[0]);
}
})->paginate(8);
How can I do it in the eloquent-way?
Of course, you can do it this way:
if ($request->input('id_desc')) {
$query = $query->orderBy('id', 'DESC');
}
or you can do it this way:
$columns = ['id','name',]; // here define columns you allow for sorting
$orderBy = ['ASC', DESC'];
$column = $request->input('order_by_column');
$type = $request->input('order_by_type');
if (!in_array($column, $columns)) {
$column = 'id';
}
if (!in_array($type , $orderBy )) {
$type = 'ASC';
}
$query = $query->orderBy($column, $type);
EDIT
Using your code:
$query = Auction::where('end_date', '>', Carbon::now() )
->where('locale', $locale)
->where('sold', 0)
->where(function($query) use ($request){
if( ! empty($request->input('prices')) ){
$opts = $request->prices;
$query->where('price_id', $opts[0]);
}
});
if ($request->input('id_desc')) {
$query = $query->orderBy('id', 'DESC');
}
return $query->paginate(8);