at the moment Iam really struggeling with filtering and the pagination of Laravel. On http://snkrgllry.herokuapp.com/ you can try to sort the images with the Filter Modal for example likes ascending, if you go now to the second page it says that view[2] is not found.
I send the parameters for filtering through a form to a controller which makes a query and will send all those data back to the view. Everything fine so far, but the second page is not working at all.
Here is my code on the Blade
<div class="container">
<div class="col-xs-12 row-centered">
{{ $images->appends(request()->input())->links()}}
</div>
</div>
This is the controller function, please excuse my bad programming its my first web-/laravel project.
public function filter(Request $request)
{
$brand = $request->brand;
$color = $request->color;
$style = $request->style;
$material = $request->material;
$year = $request->year;
$shape = $request->shape;
$sorting = $request->sort;
$page = $request->page;
$user_id = $request->user_id;
$sortingMethod = 'desc';
$sortingParameter = 'created_At';
//Abfrage wie sortiert werden soll
if ($sorting == 'uploadDesc') {
$sortingMethod = 'desc';
$sortingParameter = 'created_At';
} else if ($sorting == 'uploadAsc') {
$sortingMethod = 'asc';
$sortingParameter = 'created_At';
} else if ($sorting == 'leer') {
$sortingMethod = 'desc';
$sortingParameter = 'created_At';
} else if ($sorting == 'likesAsc') {
$sortingParameter = 'count';
$sortingMethod = 'asc';
} else if ($sorting == 'likesDesc') {
$sortingParameter = 'count';
$sortingMethod = 'desc';
}
//$imagesQuery = DB::table('images')->select('brand', 'color', 'style', 'material', 'shape', 'year', 'id', 'path', 'created_at')->where('contest', 'true');
$imagesQuery = DB::table('images')
->leftJoin('likes', 'images.id', '=', 'likes.image_id')
->select('images.*', DB::raw("count(likes.image_id) as count"))
->groupBy('images.id', 'images.brand', 'images.user_id', 'images.color', 'images.style', 'images.material', 'images.shape', 'images.year', 'images.desc', 'images.path', 'images.name', 'images.model', 'images.contest', 'images.remember_token', 'images.created_at', 'images.updated_at')
->orderBy($sortingParameter, $sortingMethod);
$brands = DB::table('images')->select('brand')->groupBy('brand')->get();
$colors = DB::table('images')->select('color')->groupBy('color')->get();
$styles = DB::table('images')->select('style')->groupBy('style')->get();
$materials = DB::table('images')->select('material')->groupBy('material')->get();
$years = DB::table('images')->select('year')->groupBy('year')->get();
$shapes = DB::table('images')->select('shape')->groupBy('shape')->get();
if ($brand !== 'leer') {
$imagesQuery->where('brand', '=', $brand);
}
if ($year !== 'leer') {
$imagesQuery->where('year', '=', $year);
}
if ($color !== 'leer') {
$imagesQuery->where('color', '=', $color);
}
if ($style !== 'leer') {
$imagesQuery->where('style', '=', $style);
}
if ($material !== 'leer') {
$imagesQuery->where('material', '=', $material);
}
if ($shape !== 'leer') {
$imagesQuery->where('shape', '=', $shape);
}
if ($year !== 'leer') {
$imagesQuery->where('year', '=', $year);
}
if ($page == 'contest') {
$imagesQuery->where('images.contest', '=', 'true');
$brands->where('contest', 'true');
$colors->where('contest', 'true');
$styles->where('contest', 'true');
$materials->where('contest', 'true');
$years->where('contest', 'true');
$shapes->where('contest', 'true');
}
if ($page == 'profile') {
$imagesQuery->where('images.user_id', '=', $user_id);
$user = User::find($user_id);
}
$images = $imagesQuery->paginate(12);
return view($page)->with(compact('images', 'brands', 'colors', 'styles', 'materials', 'years', 'shapes', 'user'));
}
And this is my route which will called, if I submit the filter form.
Route::get('/indexFilter', 'ImagesController#filter');
Are there any suggestions from your side how to fix this problem. I read a lot about it but I still didnt get it done.
I would really appreciate you help!
Best regards Lars
You pass page as a parameter:
return view($page)
So it is '2' for the second page. Just pass template name, not page number. Use another name for passed page variable, it is used for pagination.
Nice shoes! :)
The problem is in your frontend code. When you click the next page, the request param of page is 2 instead of index
Here's the HTML code: 2
Thanks a lot I will not managed it to solve it until tomorrow (contribution of the project to our Prof. at University) but now I know my mistake and I "fixed" it so it will work out for me. I'll try my best to fix the issue with your solution!!
Related
I have this type of modal for search data from the database.
Image
I want to search the data if the user only types company name and CIN or *company name only or
company state and company district user can choose any field. So I want to fetch the data only on selected fields.
Is there any simplest way to do this
I have coded multiple if-else statements.
My Code
else if ($req->state && $req->district) {
$data = tbl_company::query()
->where(
"state",
"LIKE",
"%{$req->state}%"
)->where(
"district",
"LIKE",
"%{$req->district}%"
)
->paginate(100);
}
// Filter using only state and city
else if ($req->city && $req->district && $req->state == null) {
$data = tbl_company::query()
->where(
"city",
"LIKE",
"%{$req->city}%"
)->where(
"district",
"LIKE",
"%{$req->district}%"
)
->paginate(100);
}
// company status only
else if ($req->company_status && $req->city == null && $req->district == null && $req->state == null) {
$data = tbl_company::query()
->where(
"company_status",
$req->company_status
)
->paginate(100);
}
use Conditional Clauses
$data = tbl_company::query()->when($req->state && $req->district, function ($query, $req) {
$query->where("state", "LIKE", "%{$req->state}%")
->where("district", "LIKE", "%{$req->district}%");
})->when($req->city && $req->district && $req->state == null, function ($query, $req) {
$query->where("city", "LIKE", "%{$req->city}%")
->where("district", "LIKE", "%{$req->district}%");
})->paginate(100);
Updates
use loop
$data = tbl_company::query()->where(function ($query)use($req){
foreach ($req->only('state','district','city','company_status') as $filterField=>$filterFieldValue){
if(!empty($filterFieldValue)&&is_array($filterFieldValue)){
$query->wherein($filterField,$filterFieldValue);
}elseif (!empty($filterFieldValue)){
$query->where($filterField, "LIKE", "%{$filterFieldValue}%");
}
}
})->paginate(100);
I found the answer. I solved this problem using Pipeline Design Pattern
$query = tbl_company::query();
if ($req->has('state')) {
$query->whereIn('state', $req->input('state'));
}
if ($req->has('district')) {
$query->whereIn('district', $req->input('district'));
}
if ($req['date_of_registration']['start'] && $req['date_of_registration']['end']) {
$from = Carbon::parse($req['date_of_registration']['start']);
$to = Carbon::parse($req['date_of_registration']['end']);
$query->whereBetween(
DB::Raw("STR_TO_DATE(date_of_registration,'%d-%m-%Y')"),
[$from, $to]
);
}
if ($req['authorized_capital']['start'] && $req['authorized_capital']['end']) {
$query->whereBetween(
"authorized_capital",
[$req['authorized_capital']['start'], $req['authorized_capital']['end']]
);
}
//finally
$data = $query->paginate(100);
enter image description here
I have several inputs in order to filter products in the online shop. My question is, how can I filter products if some inputs are left without being filled/chosen. How should I query?
public function find()
{
$categories = Category::all();
if (isset($_GET['submit'])) {
if (!empty($_GET['brand'])) {
$selectedBrand = $_GET['brand'];
echo 'You have chosen: ' . $selectedBrand;
} else {
echo 'Please select the value.';
}
$date = Request::get('date');
$name = Request::get('name');
$selected = $_GET['type'];
$data = DB::table('product')->where('product.type', $_GET['type'])
->where('product.name', $name)
->join('shop', 'product.id', '=', 'shop.product_id')
->where('shop.releasedate', $date)
->get();
return view('pages/catalog')->with(['product' => $data, 'categories' => $categories]);
}
}
You can first check if your fields are filled and continue to query your model with when method
Logic
$date = null;
if($request->filled('date)){
$date = $request->date;
}
// your other values can go here like above
$data = DB::table('product')->where('product.type', $_GET['type'])
->where('product.name', $name)
->join('shop', 'product.id', '=', 'shop.product_id')
->when($date, function ($query, $transmission) {
// this query runs only if $date is `true` (has a value and not empty)
return return $query->where('shop.releasedate','=', $date);
->orderBy('shop.created_at','desc);
}, function ($query) {
// something you want to return if the $date is `false` (empty)
})
->get();
In a Laravel app, I'm trying to implement a structure where posts are fetched that have one or more of the tags that the user has access to. I wrote the code below to do that:
$query = new Posts();
if (count(Auth::user()->tags) > 0) {
$query = $query->whereHas('tags', function ($q) {
$i = 0;
foreach (Auth::user()->tags as $tag) {
if ($i == 0) {
$q->where('title', '=', $tag->title);
} else {
$q->orWhere('title', '=', $tag->title);
}
$i++;
}
});
}
$posts = $query->where('isTemplate', true)->orderBy($key, $order)->paginate(15);
This works, but feels off. So I'm wondering if there's a better way to do this?
#user4992124, Will this help you.
$query = Posts::query()
->where('isTemplate', true)
->orderBy($key, $order);
if (Auth::user()->tags->isNotEmpty()) {
$tags = Auth::user()
->tags
->pluck('title')
->toArray();
$query = $query->whereIn('tags', $tags);
}
$posts = $query->paginate(15);
I have problem with slow load: almost 10 seconds. I guess I have to optimize the code in some way, but I don't know how. Any help? Thanks.
This is the controller. I use the trait ListNoticias (below the controller).
class NoticiaController extends Controller
{
use ListNoticias;
public function actualidad(Request $request)
{
$data['section_id'] = explode(',', '1,2,3');
$data['ruta'] = 'actualidad';
$data['title'] = __('header.actualidad');
$data['num'] = $request->num;
$url = $request->url();
$data = $this->listNoticias($data, $url);
return view('web.actualidad.listado', compact('data'));
}
}
And this is the trait. Here, I collect a list of all the news in three different arrays for each of the languages and then I manually paginate them.
trait ListNoticias
{
public function listNoticias($data, $url)
{
$now = date('Y-m-d');
$time = date('H:i:s');
(isset($data['num']))? $num = $data['num'] : $num = '15';
$data['images'] = Image::where('imageable_type', 'App\Models\Noticia')->get();
$data['sections'] = Section::all();
$data['noticias'] = Noticia::where('date', '<', $now)
->where('active', '1')
->whereIn('section_id', $data['section_id'])
->orWhere('date', '=', $now)
->where('time', '<=', $time)
->where('active', '1')
->whereIn('section_id', $data['section_id'])
->orderBy('date', 'desc')
->orderBy('time', 'desc')
->get();
$data['noticias-es'] = [];
$data['noticias-en'] = [];
$data['noticias-pt'] = [];
foreach($data['noticias'] as $row){
foreach($row->langs as $row_lang) {
if ($row_lang->lang_id == '1') {
$data['noticias-es'][] = $row;
} elseif ($row_lang->lang_id == '2') {
$data['noticias-en'][] = $row;
} elseif ($row_lang->lang_id == '3') {
$data['noticias-pt'][] = $row;
} else null;
}
}
// Manual paginate
/* Get current page form url e.x. &page=1
Create a new Laravel collection from the array data
Slice the collection to get the items to display in current page
Create our paginator and pass it to the view
set url path for generated links
*/
$currentPage = LengthAwarePaginator::resolveCurrentPage();
// ES
$itemCollection = collect($data['noticias-es']);
$currentPageItems = $itemCollection->slice(($currentPage * $num) - $num, $num)->all();
$data['noticias-es'] = new LengthAwarePaginator($currentPageItems , count($itemCollection), $num);
$data['noticias-es']->setPath($url);
// EN
$itemCollection = collect($data['noticias-en']);
$currentPageItems = $itemCollection->slice(($currentPage * $num) - $num, $num)->all();
$data['noticias-en'] = new LengthAwarePaginator($currentPageItems , count($itemCollection), $num);
$data['noticias-en']->setPath($url);
// PT
$itemCollection = collect($data['noticias-pt']);
$currentPageItems = $itemCollection->slice(($currentPage * $num) - $num, $num)->all();
$data['noticias-pt'] = new LengthAwarePaginator($currentPageItems , count($itemCollection), $num);
$data['noticias-pt']->setPath($url);
return $data;
}
}
EDITED WITH MORE INFO
Following the advice of the comments, I found one of the main problems in the following view, where I call the images of each news item to show it in the list along with the url and the slug. This I have done creating a foreach inside another. Is there any way to do it without nesting foreachs? Thank you.
The partial view with the image and url and slug:
#foreach($new->langs as $new_lang)
#if($new_lang->lang_id == $lang_id)
#foreach($data['images'] as $image)
#if($image->imageable_id == $new->id && $image->main == '1')
#php
$mini = substr($image->path, 0, strrpos( $image->path, "/"));
$name = substr($image->path, strrpos($image->path, '/') + 1);
$image_mini = $mini.'/mini-'.$name;
#endphp
<div class="crop">
<a href="{{ route('noticia', [$new->id, $new_lang->slug]) }}">
{{ HTML::image(file_exists($image_mini)? $image_mini : $image->path, '', array('class' => 'img-responsive ancho_100')) }}
</a>
</div>
#endif
#endforeach
#endif
#endforeach
How to insert strings as query in Laravel? I have to handle a dynamic value for "book formats" (such as "pdf", "epub", "physical", "") and this formats are separated by comma. Here is my code:
$formats_sql = '';
$format_filter_count = 0;
$format_filter = explode(',', $format_filter);
foreach ($format_filter as $format_filter_tmp) {
if ($format_filter_count == 0) {
$formats_sql .= "where('format', '=', '{$format_filter_tmp}')";
} else {
$formats_sql .= "->orWhere('format', '=', '{$format_filter_tmp}')";
}
$format_filter_count += 1;
}
if ($price_filter == 'paid') {
$books = Book::where('book_id', '=', $category_book->book_id)->$formats_sql->where('sell_price', '>', '0')->where('status', '=', '1')->get();
}
But makes this problem:
Undefined property: Illuminate\Database\Eloquent\Builder::$where('format', '=', 'pdf')->orWhere('format', '=', 'epub')
Your over complicating this. You should be using whereIn where you need to search for an array of values.
You whole code above can be condensed to:
if ($price_filter == 'paid') {
$formats = explode(',', $format_filter);
Book::where('book_id', $category_book->book_id)->whereIn('format', $formats)->where('sell_price', '>', '0')->where('status', '1')->get();
}