Laravel 5 Pagination with Query Builder - php

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

Related

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

Laravel 5.4: slow loading

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

pagination totoal does not return 0 if there is no record in laravel 5

I have error in pagination total.
Actually I'm getting the results but the problem is when there is no records then it throws the following error:
Undefined index: inactive_users (View: /home/vagrant/Code/krankontroll/resources/views/customer/inactive.blade.php)
If I don't have any records for inactive_users array I'm getting the above error where actually it should give "No of records 0".
My controller page code is:
$customers = Customer::getCustomerPaginated(Session::get('search'), $data['sortorder'], $data['sortby']);
$data['customers'] = Customer::getCustomerByStatus($customers, (Input::get('page'))?Input::get('page'):1);
And my model page code is:
public static function getCustomerByStatus($customers, $pageStart=1)
{
$customer_status = array();
$customer_result = array();
$newcustomers=array();
foreach($customers as $customer){
$customer_status[$customer->status][] = $customer;
if($customer->status<>2)
$customer_status[3][] = $customer;
$newcustomers[] = $customer;
}
$customer_result = $customer_status;
$perPage = 10;
// Start displaying items from this number;
$offSet = ($pageStart * $perPage) - $perPage;
//Slice the collection to get the items to display in current page
$currentPageSearchResults = $customers->slice($offSet, $perPage, true)->all();
$collection = new Collection($currentPageSearchResults);
// Get only the items you need using array_slice
$pagination['all'] = new LengthAwarePaginator($collection, count($newcustomers), $perPage, Paginator::resolveCurrentPage(), array('path' => Paginator::resolveCurrentPath()));
foreach($customer_status as $status=>$customer_state)
{
$itemsForCurrentPage = new Collection(array_slice($customer_state, $offSet, $perPage, true));
if($status==0)
$label='active_users';
else if($status==1)
$label='inactive_users';
else if($status==3)
$label='nonyearly_users';
else
$label='yearly_users';
$pagination[$label] = new LengthAwarePaginator($itemsForCurrentPage, count($customer_state), $perPage, Paginator::resolveCurrentPage(), array('path' => Paginator::resolveCurrentPath()));
}
var_dump($pagination);
exit;
return $pagination;
}
Can anyone help me???

How to create pagination links when combining data from two different queries

I have a controller with a method that looks something like this:
public function browsecategory($category_id)
{
//find any subcategories for this category
$this->load->model('category/category_model');
$this->load->model('category/product_category_model');
$records['categories'] = $this->category_model->find_all_by('parent_id', $category_id);
//add some product data too.
$records['products'] = $this->product_category_model->find_all_by('category_id', $category_id);
Template::set('records', $records);
Template::render();
}//end browsecategory
All the examples I've seen for the codeigniter pagination "stuff" is using one query.
I need to combine two data sets and serve on one view.
Any suggestions?
EDIT 1
I've tried to follow MDeSilva's suggestion below. And although the pagination object is correctly calculating the number of links to create, all items appear on all pages.
Here's the code in the model that gets the data:
public function get_categories_and_products($limit=12, $offset=0, $category_id=null)
{
print '<BR>the function got the following offeset:'.$offset;
$query = "(SELECT cat.category_id, cat.title, cat.image_thumb, cat.deleted, cat.display_weight ";
$query = $query."FROM bf_categories cat ";
$query = $query."WHERE cat.parent_id=".$category_id;
$query = $query." AND cat.category_id <>".$category_id;
$query = $query.") UNION (";
$query = $query."SELECT p.product_id, p.name, p.image_thumb, p.deleted , p.display_weight";
$query = $query." FROM bf_product p ";
$query = $query."Inner join bf_product_category cp ";
$query = $query."on p.product_id=cp.product_id ";
$query = $query."Where cp.category_id=".$category_id.")";
$this->db->limit($limit, $offset);
$catsandprods= $this->db->query($query);
return $catsandprods->result() ;
}
And here's the code in the controller:
public function browsecategory($category_id, $offset=0)
{
$this->load->library('pagination');
$total = $this->product_model->get_cats_prods_count($category_id);
$config['base_url'] = site_url('/product/browsecategory/'.$category_id);
$config['uri_segment'] = 4;
$config['total_rows'] = $total;
$config['per_page'] = 5;
$config['num_links'] = 10;
$this->pagination->initialize($config);
$offset = ($this->uri->segment($config['uri_segment'])) ? $this->uri->segment($config['uri_segment']) : 0;
print $offset;
//Call the model function here to get the result,
$records= $this->product_model->get_categories_and_products(5,$offset,$category_id);
//add to breadcrumb trail
$this->build_bread_crumb_trail($category_id);
$breadcrumbs = $this->breadcrumbs->expand_to_hyperlinks();
Template::set('currentcategory',$category_id);
Template::set('breadcrumbs', $breadcrumbs);
Template::set('records', $records);
Template::render();
}
I've debugged and I can see that the line of code "$this->db->limit($limit, $offset);" in the model is not working. It always returns the full record set...
Can you tell me what I'm missing?
Thanks.
This is the way to generate pagination links in CI, for your requirement have a query with a join,
public function index($offset = 0) {
$language_id = 1;
$artwork_id = null;
if ($_SERVER['REQUEST_METHOD'] == 'POST')
{
$artwork_id = $this->input->post('serach_artwork_id', TRUE) ? $this->input->post('serach_artwork_id', TRUE) : null;
$data['artwork_id'] = $artwork_id;
}
$this->load->library('pagination');
$limit = 10;
$total = $this->Artwork_model->get_artwork_count($language_id, $artwork_id);
$config['base_url'] = base_url().'artwork/index/';
$config['total_rows'] = $total;
$config['per_page'] = $limit;
$config['uri_segment'] = 3;
$config['first_link'] = '<< First';
$config['last_link'] = 'Last >>';
$config['next_link'] = 'Next ' . '>';
$config['prev_link'] = '<' . ' Previous';
$config['num_tag_open'] = '<span class="number">';
$config['num_tag_close'] = '</span>';
$config['cur_tag_open'] = '<span class="current"><a href="#">';
$config['cur_tag_close'] = '</a></span>';
$this->pagination->initialize($config);
//Call the model function here to get the result,
$data['artworks'] = $this->Artwork_model->get_artworks($language_id, $limit, $offset, $artwork_id);
$this->template->write('title', 'Artwork : Manage Artwork');
$this->template->write_view('content', 'artwork/index', $data);
$this->template->render();
}
Here is an example for query with multiple joins in the model
public function get_artworks($language_id = 1, $limit = 10, $offset = 0, $arwork_id = null)
{
$this->db->select('a.id, a.price, a.is_shop, at.title,at.status,at.date_added,ats.name as artist_name');
$this->db->from('artworks a');
$this->db->join('artwork_translations at', 'a.id = at.artwork_id');
$this->db->join('artists ats', 'a.artist_id = ats.id');
$this->db->where('at.language_id', $language_id);
if(!is_null($arwork_id) && !empty($arwork_id) && $arwork_id != 'all')
{
$this->db->where('a.id =', $arwork_id);
}
$this->db->order_by('a.id DESC');
$this->db->limit($limit, $offset);
$artworks = $this->db->get();
return $artworks->result();
}
In the View
<?= $this->pagination->create_links(); ?>
The pagination class doesn't care about the how the data source is constructed, just so you hand it the data result object it wants. So you would just pass limits & offsets into your data queries, or else pull all your data and slice it up afterwards.
However, I don't really understand how you are thinking to combine these different bits of data into a single result to display - are you trying to display all categories, then paginate the products? If so, you are set up incorrectly
Simply use PHP function array_merge
<?php $beginning = 'foo'; $end = array(1 => 'bar');
$result = array_merge((array)$beginning, (array)$end);
$this->load->view('view.php', $result);
?>
and extract according to keys for array used.
It is really simple & working

cant get pagination by when i use other method than count_all codeigniter

I have used join query to fetch the data, when some data is deleted from the table which is joined then it creating problem with pagination
controller code
function index($msg='',$offset = 0)
{
$data = array('title'=>'Towns','message'=>'', 'link_add'=>site_url('manage/town/add'), 'edit_link'=>site_url('manage/town/edit'), 'tbl'=>'towns' );
$uri_segment = 4;
$offset = $this->uri->segment($uri_segment);
// load data
$value=('towns.Id,towns.Name as TownName,city.Name as CityName,city.Status,towns.Status,towns.TaxAmount');
$data['list_records'] = $this->admin_model->get_joinlist($data['tbl'],$value,'city','city.Id = towns.cityId','left outer','towns.Id','asc',array('towns.Status !='=>'Delete','city.Status'=>'Enable'),$this->limit, $offset)->result();
if($msg=='m')$data['message'] = 'New Town has been added successfully!';
// generate pagination
$this->load->library('pagination');
$config['base_url'] = site_url('manage/town/index/');
$this->total = $this->admin_model->**count_all**($data['tbl'],array('Status !='=>'Delete'));
$config['total_rows'] = $this->total;
$config['per_page'] = $this->limit;
$config['uri_segment'] = $uri_segment;
$this->pagination->initialize($config);
$data['pagination'] = $this->pagination->create_links();
$data['j'] = 0 + $offset;
$data['total_rows']= $this->total;
// load view
$this->load->view('manage/includes/header', $data);
$this->load->view('manage/town', $data);
$this->load->view('manage/includes/footer');
}
<?php
class Admin_model extends CI_Model {
//listing with join
public function get_joinlist($table,$value,$table2,$condi,$join_type,$order_by,$order,$where,$limit, $offset)
{
$this->db->select($value);
$this->db->join($table2,$condi,$join_type);
$this->db->order_by($order_by,$order);
$this->db->where($where);
return $query= $this->db->get($table, $limit, $offset);
}
//For pagination
function count_all($table,$where)
{
return $this->db->where($where)
->count_all_results($table);
}
function num_rows($table)
{
return $this->db->affected_rows($table);
}
Do something like this:
public function get_joinlist($table,$value,$table2,$condi,$join_type,$order_by,$order,$where,$limit, $offset)
{
$this->db->start_cache();
$this->db->select($value);
$this->db->join($table2,$condi,$join_type);
$this->db->order_by($order_by,$order);
$this->db->where($where);
$this->db->stop_cache();
$query['num_rows']=$this->db->get($table)->num_rows();
$query['results']=$this->db->get($table, $limit, $offset);
$this->db->flush_cache();
return $query;
}
This way, your model will return an array with the the total rows of the join and the results limited by offset and limit rows

Categories