Laravel 5.4: slow loading - php

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

Related

Laravel array index variable won't pass to redirected view

My $data['orders'] won't pass to my redirected view and i get the error "Undefined index: orders (View: /.../pages/userhome.blade.php)". For some reason the $data['user'] variable will pass and show its value but the 'orders' one will not. Ive changed the name and why way i create the data array but its still won't work.
pagescontroller.php
$this->validate($request, []);
$data = array();
$orderdate = date('Y-m-d H:i:s');
$data['user'] = Auth::user();
$ordernum = Str::uuid()->toString();
$sum = 0;
$cart = DB::table('cart')->where('buyerid', '=', auth()->user()->id)->paginate(10);
foreach ($cart as $item) {
$product = Product::find($item->itemid);
$orderitem = new Orderitem;
$orderitem->buyerid = $item->buyerid;
$orderitem->productid = $product->id;
$orderitem->quantity = $item->quantity;
$orderitem->ordernumber = $ordernum;
$orderitem->dateordered = $orderdate;
$sum = $sum + (number_format($product->price * $item->quantity, 2));
$product->sold = $product->sold + $item->quantity;
$orderitem->save();
}
$order = new Order;
$order->buyerid = Auth::user()->id;
$order->customeremail = Auth::user()->email;
$order->customeraddress = ''; //$request->input('address');
$order->total = number_format($product->price * $item->quantity, 2);
$order->dateordered = $orderdate;
$order->city = ''; //$request->input('city');
$order->zipcode = ''; //$request->input('zipcode');
$order->ordernumber = $ordernum;
$order->total = $sum;
$order->save();
$orders = DB::table('orders')->where('buyerid', '=', auth()->user()->id)->get();
$data['orders'] = $orders;
return redirect("/userhome/{$data['user']->name}")->with('success', 'Your order has been sent. A confirmation will be sent to your email shortly.')->with(compact($data));
userhome.blade.php
the code fails right at the '#if(count($data['orders']) > 0)' line
<h1>{{ $data['user']->name }}</h1>
<section class="topsellers">
<h2>Orders</h2>
<div class="container flex">
#if (count($data['orders']) > 0)
#foreach ($data['orders'] as $order)
<div class="productcard" }>
<p>test</p>
</div>
#endforeach
#else
<p>Looks like you have no current orders.</p>
#endif
</div>
{{-- {{$data['products']->links()}} --}}
</section>
Use your controller method to get the orders
First: change your redirect like below:
return redirect("/userhome/{$data['user']->name}")
->with('success', 'Your order has been sent. A confirmation will be sent to your email shortly.');
Second : Query from your orders table in controller method then pass to the view like below code;
public function someMethod()
{
$data['orders'] = DB::table('orders')->where('buyerid', '=', auth()->user()->id)->get();
return view('userhome', $data);
}

How can i deploy pagination after foreach loop in laravel

I'm trying to create a pagination in my search result. I have one queries in my repository like:
public function getFilteredVehicles($id,$pax,$categories,$search_type,$from_date,$to_date)
{
$vehicles = Vehicle::whereHas('destinations', function($q) use($id){
$q->where('destination_id',$id)
->where('active',1);
})
->paginate(1);
if($search_type == 'disposal' || $search_type == 'pnd')
{
$vehicles = $vehicles->where('registered_location',$id);
}
if($categories)
{
$vehicles = $vehicles->where('vehicle_categoryid',$categories);
}
return $vehicles;
}
The returned result again needs to be processed via loop like:
public function calculateLocationAmount($vehicles,$fdate,$tdate,$destination_id)
{
$datetime1 = new DateTime($fdate);
$datetime2 = new DateTime($tdate);
$interval = $datetime1->diff($datetime2);
$days = $interval->format('%a');
$days = $days+1;
$nights = $days-1;
foreach ($vehicles as $key => $vehicle) {
# code...
$perday_rate = $vehicle->destinations->where('id',$destination_id)->first()->pivot->day_rate;
$pernight_rate = $vehicle->destinations->where('id',$destination_id)->first()->pivot->night_rate;
$day_rate = $perday_rate * $days;
$night_rate = $pernight_rate * $nights;
$total_amount = $day_rate + $night_rate;
$vehicle['total_amount'] = $total_amount;
$vehicle['availability'] = 'true';
if($vehicle->whereHas('unavailability', function($q) use($fdate,$tdate){
$q->whereRaw("? BETWEEN `from_date` AND `to_date`", [$fdate])
->orwhereRaw("? BETWEEN `from_date` AND `to_date`", [$tdate]);
})->count()>0){
$vehicle['availability'] = 'false';
}
}
return $vehicles;
}
This final result needs to be paginated. How can i do it?
Using foreach is changing the value to collection due to which links is not working. If i don't do paginate() or get(), for loop is not executed.
Kindly help.
You can paginate your initial query just as you have, then loop over the pagination object as if it was your regular collection or use $pagination->items()
You should also use nested with('relation') in your initial query to stop N+1 queries https://laravel.com/docs/8.x/eloquent-relationships#constraining-eager-loads

Fetch posts that have a tag that the user has as well

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);

Laravel Pagination after sending parameters through form (GET)

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!!

Laravel 5 Pagination with Query Builder

I'm making a Laravel Pagination based from my query result and be rendered in my view. I'm following this guide http://laravel.com/docs/5.1/pagination but I get an error:
Call to a member function paginate() on a non-object
I'm using query builder so I think that should be ok? Here's my code
public function getDeliveries($date_from, $date_to)
{
$query = "Select order_confirmation.oc_number as oc,
order_confirmation.count as cnt,
order_confirmation.status as stat,
order_confirmation.po_number as pon,
order_summary.date_delivered as dd,
order_summary.delivery_quantity as dq,
order_summary.is_invoiced as iin,
order_summary.filename as fn,
order_summary.invoice_number as inum,
order_summary.oc_idfk as ocidfk,
order_summary.date_invoiced as di
FROM
order_confirmation,order_summary
where order_confirmation.id = order_summary.oc_idfk";
if (isset($date_from)) {
if (!empty($date_from))
{
$query .= " and order_summary.date_delivered >= '".$date_from."'";
}
}
if (isset($date_to)) {
if (!empty($date_to))
{
$query .= " and order_summary.date_delivered <= '".$date_to."'";
}
}
$query.="order by order_confirmation.id ASC";
$data = DB::connection('qds106')->select($query)->paginate(15);
return $data;
}
However when I remove the paginate(15); it works fine.
Thanks
in the doc at this page: http://laravel.com/docs/5.1/pagination
we can see that we are not forced to use eloquent.
$users = DB::table('users')->paginate(15);
but, be sure you don't make a groupBy in your query because, the paginate method uses it.
after i'm no sure you can use paginate with query builder ( select($query) )
--- edit
You can create collection an use the paginator class :
$collection = new Collection($put_your_array_here);
// Paginate
$perPage = 10; // Item per page
$currentPage = Input::get('page') - 1; // url.com/test?page=2
$pagedData = $collection->slice($currentPage * $perPage, $perPage)->all();
$collection= Paginator::make($pagedData, count($collection), $perPage);
and in your view just use $collection->render();
public function getDeliveries($date_from, $date_to)
{
$query="your_query_here";
$deliveries = DB::select($query);
$deliveries = collect($deliveries);
$perPage = 10;
$currentPage = \Input::get('page') ?: 1;
$slice_init = ($currentPage == 1) ? 0 : (($currentPage*$perPage)-$perPage);
$pagedData = $users->slice($slice_init, $perPage)->all();
$deliveries = new LengthAwarePaginator($pagedData, count($deliveries), $perPage, $currentPage);
$deliveries ->setPath('set_your_link_page');
return $deliveries;
}
You set it by using the custom pagination..
$query = "Your Query here";
$page = 1;
$perPage = 5;
$query = DB::select($query);
$currentPage = Input::get('page', 1) - 1;
$pagedData = array_slice($query, $currentPage * $perPage, $perPage);
$query = new Paginator($pagedData, count($query), $perPage);
$query->setPath('Your Url');
$this->data['query'] = $query;
return view('Your_view_file', $this->data, compact('query'));
Here you can specify the path by using the setpath().
In your View
#foreach($query as $rev)
//Contents
#endforeach
<?php echo $Reviews->appends($_REQUEST)->render(); ?>
The appends will append the data.
Thank you.
this is the way i did, it use query builder and get the same result with pagination
$paginateNumber = 20;
$key = $this->removeAccents(strip_tags(trim($request->input('search_key', ''))));
$package_id = (int)$request->input('package_id', 0);
$movieHasTrailer = MovieTrailer::select('movie_id')->where('status','!=','-1')->distinct('movie_id')->get();
$movieIds = array();
foreach ($movieHasTrailer as $index => $value) {
$movieIds[] = $value->movie_id;
}
$keyparams = array();
$packages = Package::select('package_name','id')->get();
$whereClause = [
['movie.status', '!=', '-1'],
['movie_trailers.status', '!=', '-1']
];
if(!empty($key)){
$whereClause[] = ['movie.title', 'like', '%'.$key.'%'];
$keyparams['search_key'] = $key;
}
if($package_id !== 0){
$whereClause[] = ['movie.package_id', '=', $package_id];
$keyparams['package_id'] = $package_id;
}
$movies = DB::table('movie')
->leftJoin('movie_package','movie.package_id','=','movie_package.id')
->leftJoin('movie_trailers','movie.id','=','movie_trailers.movie_id')
->where($whereClause)
->whereIn('movie.id',$movieIds)
->select('movie.*','movie_package.package_name','movie_trailers.movie_id as movie_id',
DB::raw('count(*) as total_trailers, movie_id')
)
->groupBy('movie.id')
->paginate($paginateNumber);
If you need to hydrate, you can do this...
$pages = DB::table('stuff')
->distinct()
->paginate(24, ['stuff.id']);
$stuffs = Stuff::hydrate($pages->items());
return view('stuff.index')->with('stuffs', $stuffs)->with('pages', $pages)
$stuffs will contain your model object, $pages will contain your pagination, probably not the most efficient, but it works.
// import those Class into your Laravel Controller
use Illuminate\Pagination\Paginator;
use Illuminate\Support\Facades\Input;
use Illuminate\Database\Eloquent\Collection;
// In your public function
$query = DB::select(DB::raw("SELECT * FROM your_table"));
$collection = new Collection($query);
// Paginate
$perPage = 10; // Item per page
$currentPage = Input::get('page') - 1;
$pagedData = $collection->slice($currentPage * $perPage, $perPage)->all();
$pagination = new Paginator($pagedData, $perPage);
return response()->json([
$pagination
], 200);

Categories