How to use raw sql Pagination in Laravel5? - php

This is my Controller code:
$sql = "SELECT *,earth_distance(ll_to_earth(team.lat, team.lng), ll_to_earth(23.1215939329,113.3096030895)) AS distance FROM team where earth_box(ll_to_earth(23.1215939329,113.3096030895),1000) #> ll_to_earth(team.lat, team.lng); ";
$result = DB::select( \DB::raw( $sql ) );
How can I add pagination to this code to build my restful api?
iOS or android will send the "next page" parameter, how to use it and find the next section data?

As far as I know you can't paginate raw query, here's why:
$result = DB::select($sql);
$result here will have the array type and paginate() is the method from the Illuminate\Database\Query\Builder class.
Your case can be performed this way:
$items = DB::table('team')
->selectRaw('SELECT *,earth_distance(ll_to_earth(team.lat, team.lng), ll_to_earth(23.1215939329,113.3096030895)) AS distance')
->whereRaw('earth_box(ll_to_earth(23.1215939329,113.3096030895),1000) #> ll_to_earth(team.lat, team.lng)')
->paginate(10);
foreach($items as $item) {
echo $item->distance;
}
As you can see minimal effort is needed here to separate raw query to selectRaw() and whereRaw() methods.

Another option if you are trying to paginate dynamic columns that maybe you were processing calculations on for reporting is to create a sort method and pass in your array and params:
public function sort($array_of_objects, $sort_by=null, $order, $page)
{
$collection = collect($array_of_objects);
if ($sort_by)
{
if ($order=='desc') {
$sorted = $collection->sortBy(function($role) use ($sort_by)
{
return $role->{$sort_by};
})->reverse();
} else if ($order=='asc') {
$sorted = $collection->sortBy(function($role) use ($sort_by)
{
return $role->{$sort_by};
});
}
} else {
$sorted = $collection;
}
$num_per_page = 20;
if (!$page) {
$page = 1;
}
$offset = ( $page - 1) * $num_per_page;
$sorted = $sorted->splice($offset, $num_per_page);
return new Paginator($sorted, count($array_of_objects), $num_per_page, $page);
}

Related

OctoberCMS Pagination

I use octobercms and User Extended plugin(Clacke). I try to render a pagination because for now i have a lot of registered users and they display on one page.
I use random users function from \classes\UserManager.php
public static function getRandomUserSet($limit = 7)
{
$returner = new Collection;
$userCount = User::all()->count();
if(!isset($userCount) || empty($userCount) || $userCount == 0)
return [];
if($userCount < $limit)
$limit = $userCount;
$users = User::all(); //paginate(5)
if(empty($users))
return $returner;
$users->random($limit);
$friends = FriendsManager::getAllFriends();
foreach($users as $user)
{
$userAdd = true;
if(!$friends->isEmpty())
{
foreach($friends as $friend)
{
if($user->id == $friend->id)
{
$userAdd = false;
break;
}
}
}
if($user->id == UserUtil::getLoggedInUser()->id)
$userAdd = false;
if($userAdd)
{
$returner->push($user);
}
}
return $returner->shuffle();
}
try to do this with changing return $returner->paginate(25); and $users = User::paginate(25); but throws me an error
An exception has been thrown during the rendering of a template
("Method paginate does not exist.").
After that i try to change directly in \components\User.php
public function randomUsers()
{
return UserManager::getRandomUserSet($this->property('maxItems'))->paginate(12);
}
But again the same error.
Tryed and with this code and render in default.htm {{ tests.render|raw }}
public function randomUsers()
{
$test = UserManager::getRandomUserSet($this->property('maxItems'));
return $test->paginate(10);
}
Again with no success. Could anyoune give me some navigation and help to fix this?
If you are using random users function from \classes\UserManager.php
I checked the code and found that its using Illuminate\Support\Collection Object. So, for that Collection Object pagination works differently
You need to use forPage method.
On the other hands paginate is method of Illuminate\Database\Eloquent\Collection <- so both collection are not same
Use forpage
// OLD return UserManager::getRandomUserSet($this->property('maxItems'))
// ->paginate(12);
TO
return UserManager::getRandomUserSet($this->property('maxItems'))
->forPage(1, 12);
forPage method works like forPage(<<PAGE_NO>>, <<NO_OF_ITEM_PER_PAGE>>);
so if you use forPage it will work fine.
if any doubt please comment.

SilverStripe random order for ArrayList()

I know that we can randomly sort a DataList with the following:
$example = Example::get()->sort('RAND()');
But when I try to randomly sort an ArrayList it doesn't work. I can sort an ArrayList by ID DESC, but not with RAND().
Is there a way to make an ArrayList randomly sort its items?
Example:
public function AllTheKits() {
$kits = Versioned::get_by_stage('KitsPage', 'Live');
$kitsArrayList = ArrayList::create();
foreach ($kits as $kit) {
if ($kit->MemberID == Member::currentUserID()) {
$kitsArrayList->push($kit);
}
}
return $kitsArrayList;
}
In a page:
public function getKitsRandom() {
return $this->AllTheKits()->sort('RAND()');
}
This does not work in a template with <% loop KitsRandom %>
Not really. This is the best workaround I can come up with:
foreach($myArrayList as $item) {
$item->__Sort = mt_rand();
}
$myArrayList = $myArrayList->sort('__Sort');
You could randomly sort the DataList before you loop over it, instead of trying to randomly sort the ArrayList:
public function AllTheKits($sort = '') {
$kits = Versioned::get_by_stage('KitsPage', 'Live', '', $sort);
$kitsArrayList = ArrayList::create();
foreach ($kits as $kit) {
if ($kit->MemberID == Member::currentUserID()) {
$kitsArrayList->push($kit);
}
}
return $kitsArrayList;
}
public function getKitsRandom() {
return $this->AllTheKits('RAND()'));
}
As a side note, you can filter the original DataList to fetch KitsPages that relate to this MemberID in the Versioned::get_by_stage call:
public function AllTheKits($sort = '') {
$kits = Versioned::get_by_stage(
'KitsPage',
'Live',
'MemberID = ' . Member::currentUserID(),
$sort
);
$kitsArrayList = ArrayList::create($kits);
return $kitsArrayList;
}
You could also just do this:
return KitsPage::get()->filter('MemberID', Member::currentUserID())->sort('RAND()');
When you are viewing the live site this will only get the live KitPages.

Fetch data from database in codeigniter

I have 2 cases where i am fetching the entire data and total number of rows of a same table in codeigniter, I wish to know that is there a way through which i can fetch total number of rows, entire data and 3 latest inserted records from the same table through one code
Controller code for both cases is as given below (although i am applying it for each case seperately with different parameters)
public function dashboard()
{
$data['instant_req'] = $this->admin_model->getreq();
$this->load->view('admin/dashboard',$data);
}
1) to fetch the entire data from a table in codeigniter
Model Code
public function getreq()
{
$this->db->where('status','pending');
$query=$this->db->get('instanthire');
return $query->result();
}
View Code
foreach ($instant_req as $perreq)
{
echo $perreq->fullname;
echo "<br>";
}
2) to fetch number of rows from a table in codeigniter
public function getreq()
{
$this->db->where('status','pending');
$query=$this->db->get('instanthire');
return $query->num_rows();
}
View Code
echo $instant_req;
You can make only one function that gives you the all data at once total number of rows, entire data and 3 latest inserted records
for example in the model
public function getreq()
{
$this->db->where('status','pending');
$query=$this->db->get('instanthire');
$result=$query->result();
$num_rows=$query->num_rows();
$last_three_record=array_slice($result,-3,3,true);
return array("all_data"=>$result,"num_rows"=>$num_rows,"last_three"=>$last_three_record);
}
in controller dashboard function
public function dashboard()
{
$result = $this->admin_model->getreq();
$this->load->view('admin/dashboard',$result);
}
in view
foreach ($all_data as $perreq)
{
echo $perreq->fullname;
echo "<br>";
}
//latest three record
foreach ($last_three as $perreq)
{
echo $perreq->fullname;
echo "<br>";
}
//total count
echo $num_rows;
Raw query may work here.
$resultSet = $this->db->query("select * from table_name");
$queryCount = count($resultSet );
Try this logic :
Model code :
public function getreq()
{
$this->db->where('status','pending');
$this->db->order_by('id', 'DESC'); //actual field name of id
$query=$this->db->get('instanthire');
return $query->result();
}
Controller Code :
public function dashboard()
{
$data['instant_req'] = $this->admin_model->getreq();
$data['total_record'] = count($data['instant_req']);
$this->load->view('admin/dashboard',$data);
}
View Code:
$i=0;
foreach ($instant_req as $perreq)
{
if($i<3){
echo $perreq->fullname;
echo "<br>";
}
$i++;
}
Echo 'Total record : '.$total_record;
Function
function getData($limit = 0){
//Create empty array
$data = [];
//Where clause
$this->db->where('status','pending');
//Order Data based on latest ID
$this->db->order_by('id', 'DESC');
if($limit != 0){
$this->db->limit($limit);
}
//Get the Data
$query = $this->db->get('instanthire');
$data['count'] = $query->num_rows();
$data['result'] = $query->result();
return $data;
}
Calls
//Last 3 Inserted
$data = getData(3);
//All Data
$data = getData();
CodeIgniter Database Documentation
Here is a simple solution that I can first think of but if you want me to maybe improve I can.
Just stick with your first code(Model) and in the view count how many items are iterated through.
$count = 0;
foreach ($instant_req as $perreq)
{
echo $perreq->fullname;
echo "<br>";
$count++;
}
echo $count;
Am I still missing something? just let me know
EDIT:
This is another solution, return an array
public function getreq()
{
$this->db->where('status','pending');
$query=$this->db->get('instanthire');
$data['results'] = $query->result();
$data['count'] = $query->num_rows();
return $data
}
I'm not very confident and haven't really tried this but on top of my head I think it can work.
Model:
public function getreq()
{
$res = $this->db->order_by("<place column primary id>","desc")->get_where('instanthire',['status'=> 'pending']);
$latest_3 = [];
if(count($res)){
$i=1;
foreach($res as $r){
$latest_3[]=$r;
if($i == 3)
break;
$i++;
}
}
$arr = [
'latest_3' => $latest_3,
'count' => count($res),
'total_result' => $res,
];
return $arr;
}

Laravel - Multi fields search form

I'm builind a form with laravel to search users, this form has multiple fields like
Age (which is mandatory)
Hobbies (optional)
What the user likes (optional)
And some others to come
For the age, the user can select in the list (18+, 18-23,23-30, 30+ etc...) and my problem is that i would like to know how i can do to combine these fields into one single query that i return to the view.
For now, i have something like this :
if(Input::get('like')){
$users = User::where('gender', $user->interested_by)->has('interestedBy', Input::get('like'))->get();
if(strlen(Input::get('age')) == 3){
$input = substr(Input::get('age'),0, -1);
if(Input::get('age') == '18+' || Input::get('age') == '30+' )
{
foreach ($users as $user)
{
if($user->age($user->id) >= $input){
$result[] = $user;
// On enregistre les users étant supérieur au if plus haut
}
else
$result = [];
}
return view('search.result', ['users' => $result]);
}
elseif (strlen(Input::get('age')) == 5) {
$min = substr(Input::get('age'), 0, -3);
$max = substr(Input::get('age'), -2);
$result = array();
foreach($users as $user)
{
if($user->age($user->id) >= $min && $user->age($user->id) <= $max)
$result[] = $user;
}
return view('search.result', ['users' => $result]);
}
}
else
$users = User::all();
And so the problem is that there is gonna be 2 or 3 more optional fields coming and i would like to query for each input if empty but i don't know how to do it, i kept the age at the end because it's mandatory but i don't know if it's the good thing to do.
Actually this code works for now, but if i had an other field i don't know how i can do to query for each input, i know that i have to remove the get in my where and do it at the end but i wanna add the get for the last query..
Edit: my models :
User.php
public function interestedBy()
{
return $this->belongsToMany('App\InterestedBy');
}
And the same in InterestedBy.php
class InterestedBy extends Model{
/**
* The database table used by the model.
*
* #var string
*/
protected $table = 'interested_by';
public function users()
{
return $this->belongsToMany('App\User');
}
}
you can use query builer to do this as follow
$userBuilder = User::where(DB::raw('1')); //this will return builder object to continue with the optional things
// if User model object injected using ioc container $user->newQuery() will return blank builder object
$hobbies = Request::input('hobbies') // for laravel 5
if( !empty($hobbies) )
{
$userBuilder = $userBuilder->whereIn('hobbies',$hobbies) //$hobbies is array
}
//other fields so on
$users = $userBuilder->get();
//filter by age
$age = Request::input('age');
$finalRows = $users->filter(function($q) use($age){
return $q->age >= $age; //$q will be object of User
});
//$finalRows will hold the final collection which will have only ages test passed in the filter
A way you could possible do this is using query scopes (more about that here) and then check if the optional fields have inputs.
Here is an example
Inside your User Model
//Just a few simple examples to get the hang of it.
public function scopeSearchAge($query, $age)
{
return $query->where('age', '=', $age);
});
}
public function scopeSearchHobby($query, $hobby)
{
return $query->hobby()->where('hobby', '=', $hobby);
});
}
Inside your Controller
public function search()
{
$queryBuilder = User::query();
if (Input::has('age'))
{
$queryBuilder ->searchAge(Input::get('age'));
}
if (Input::has('hobby'))
{
$queryBuilder->searchHobby(Input::get('hobby'));
}
$users= $queryBuilder->get();
}

Getting distinct rows from paginated result set in Laravel

I have created the following for a product catelog/lister:
public function index($type_id = null) {
$filters = $sort = array();
if (isset($type_id)) {
$filters['type'] = $type_id;
} else {
$filters['type'] = Input::get('type');
}
$filters['search'] = Input::get('search');
$filters['brand'] = Input::get('brand');
$sort['sort'] = Input::get('sort');
$sort['sortdir'] = Input::get('dir');
$productsPaginated = $this->fetchProducts($filters, $sort);
return View::make('products.products', array(
'productsList' => $productsPaginated
)
);
}
public function fetchProducts($filters, $sorts, $perpage = 2) {
print_r($filters);
$Product = Product::query();
if (!empty($filters['search']))
$Product->where('name', 'LIKE', '%' . $filters['search'] . '%');
if (isset($filters['type']))
$Product->where('type_id', $filters['type']);
if (isset($filters['brand']))
$Product->where('brand_id', $filters['brand']);
if (isset($sorts['sort']))
$Product->orderBy($sorts['sort'], $sorts['sortdir']);
$Product = $Product->paginate($perpage);
return $Product;
}
Which works well so far.
I am now trying to create some filters so a user can further filter the results.
How can I access and determine distinct rows based on a column in:
$productsPaginated = $this->fetchProducts($filters, $sort);
?
The groupBy method not only exists on the query builder but also on the collection class. (which will be returned when calling paginate)
Take a look at the source on github
So add an argument to your function and use groupBy
public function fetchProducts($filters, $sorts, $perpage = 2, $groupBy = null) {
// code omitted for brevity
$Product = $Product->paginate($perpage);
if($groupBy){
$Product = $Product->groupBy($groupBy);
}
return $Product;
}
Update
Then there's the lists function that works on collections as well as on query builders...
$Product->lists('column-name');
Update 2
I was curious so I did some testing and a found something very weird and I have no idea if its a bug or a feature I don't understand
When calling groupBy the collection returned has actually only one item (index "") and this item contains an array of the "original" items. So to make lists work. I found this workaround
$Product = $Product->groupBy($groupBy);
$Product = new Collection($Product[""]); // \Illuminate\Support\Collection
$Product = $Product->lists('column-name');

Categories