I am having custom array like:
[business] => Array
(
[55] => Array
(
[id] => 1
[name] => abc
[contact] => 1325467897
),
[96] => Array
(
[id] => 5
[name] => xyz
[contact] => 9876543210
)
)
This array is derived from conditional (if-else) multiple queries. So, I just want to add pagination on array. Can somebody suggest me how to add custom pagination on this type of array using standard paginator of CakePHP 3.
The PaginatorComponent can take a Cake\ORM\Query as it's thing to paginate, so I would suggest passing your compiled query object to the paginator.
So in your controller you could do something like the following.
public function example()
{
$this->paginate = ['limit' => 5];
$query = $this->Examples->find();
if ($something === 'foo') {
$query->where(['foo' => $something]);
}
if ($wtfbbq) {
$query->contain(['Wtfs', 'Barbeques']);
}
$results = $this->paginate($query);
}
This will produce a Cake\ORM\Query with the pagination built in. Then you can adjust the pagination parameters as you see fit, by checking the book page on the Paginator.
Related
In my CodeIgniter controller called Leads
I am having a code which retrieve data from model (database):
$data['leads'] = $this->model_leads->get_leads_by_person($person_id);
Now I can get some fileds like:
Array ( [0] => Array ( [lead_id] => 79 [lead_date] => 2014-07-15 12:34:41 [lead_priv] => 0 [1] => Array ( [lead_id] => 395 [lead_date] => 2014-07-15 12:34:41 [[lead_priv] => 0))
Now I want to add to every lead in $data['leads'] additional value, in my example lead_chance.
So let's say that I have a variable $lead_chance='100';
How to add this as an element to an array $data['leads']?
foreach($data['leads'] as $id => $lead) {
$data['leads'][$id]['lead_chance'] = '100';
}
Something like this?
foreach ($data['leads'] as $x) {
$x['lead_chance']=$lead_chance;
}
This would give you one lead_chance per item. If you want only one lead_chance for the whole array, it is much easier:
$data['leads']['lead_chance']=$lead_chance;
I am using the pagination using zend framework2 and i am getting the array as below
Zend\Paginator\Paginator Object
(
[cacheEnabled:protected] => 1
[adapter:protected] => Zend\Paginator\Adapter\ArrayAdapter Object
(
[array:protected] => Array
(
[Id] => 123
[AccountId] => 1
[Name] => abc abc
[AccountName] => a1
)
[count:protected] => 4
)
[currentItemCount:protected] =>
[currentItems:protected] =>
[currentPageNumber:protected] => 1
[filter:protected] =>
[itemCountPerPage:protected] => 25
[pageCount:protected] => 1
[pageRange:protected] => 10
[pages:protected] =>
[view:protected] =>
)
But my question is how can i access the Id,AccountId,Name,AccountName individual without using the foreach loop ?
As mentioned in documentation, there is public function getItem
public function getItem($itemNumber, $pageNumber = null)
Using it is not that simple as accessing by index of array, but keep in mind that internal data in adapter is usually lazy loaded.
So you'd better to write some wrapper class with ArrayAcccess implemented which relies on getItem in case you want to access elements by index.
I have model for
user(id,name)
section(id,name)
section_users(id,user_id,section_id)
The admin adds all the users and sections separately. Once theses are added I want the admin to selects the section and add all the users in it in section_users
I have a select input with multiple set to true. How do i save this data the cakephp way along with validation.
<?php echo $this->Form->input("section_id"); ?>
<?php echo $this->Form->input("user_id", array('multiple'=>'checkbox')); ?>
This generates
Array
(
[section_id] => 1
[user_id] => Array
(
[0] => 3
[1] => 4
)
)
I know i can loop and convert to this and use saveAll or saveMany but what is the cakephp way/right way to do it.
Array
(
[0] => Array
(
[section_id] => 1
[user_id] => 3
)
[1] => Array
(
[section_id] => 1
[user_id] => 4
)
)
As already mentioned, this is exaplained in the docs, please read them, and in case you don't understand them (which would be understandable as the HABTM section is a little confusing and requires some trial & error), tell us what exactly you are having problems with.
http://book.cakephp.org/2.0/en/models/saving-your-data.html#saving-related-model-data-habtm
Based on the examples shown, the format for saving multiple X to Y should be
Array
(
[Section] => Array
(
[id] => 1
)
[User] => Array
(
[User] => Array(3, 4)
)
)
The corresponding form could look like this:
<?php echo $this->Form->create('User'); ?>
<?php echo $this->Form->input('Section.id'); ?>
<?php echo $this->Form->input('User', array('multiple' => 'checkbox')); ?>
<?php echo $this->Form->end('Add Users'); ?>
And the data would be saved via the Section model, that way its modified column is being updated properly.
public function addUsersToSection($id) {
// ...
if($this->request->is('post')) {
if($this->Section->save($this->request->data)) {
// ...
} else {
// ...
}
} else {
$options = array(
'conditions' => array(
'Section.' . $this->Section->primaryKey => $id
)
);
$this->request->data = $this->Section->find('first', $options);
}
$users = $this->Section->User->find('list');
$this->set(compact('users'));
}
Another way would be to restructure the array as shown by Vinay Aggarwal, that works fine, the only difference is that it requires saving through the join model, and consequently it doesn't update the Section models modified column.
CakePHP has the saveMany function, as mentioned in the documentation:
Model::saveMany(array $data = null, array $options = array())¶
This is HABTM relation, first of all you need have relation setup in SectionUser model. Then you can use saveAll() method to save all records at once.
Array
(
[0] => Array
(
[user_id] => 33
[section_id] => 9
)
[1] => Array
(
[user_id] => 33
[section_id] => 10
)
)
Make sure your data array is in above given format.
$this->SectionUser->saveAll($data);
I'm trying to figure out the best way to do something. I have a table "groups" with a has_many relationship to another table "vehicles" (groups of vehicles). I want to query the groups table and get back an array of groups, with each group containing an array of related vehicle IDs (if any). The end result should be an JSON array of objects:
[{"id":4534,"group_name":"Annual",vehicles:[2311,3357]},{"id":4752,"group_name":"Summer",vehicles:[5,3348,4316]},{"id":4533,"group_name":"Winter",vehicles:[3116]}];
So far, with these methods:
public function vehicle()
{
return $this->has_many('Vehicle');
}
public static function many()
{
return self::with (array('vehicle'))
->where('account_id', '=', Session::get('account_id_selected'))
->order_by('group_name')
->select(array('id', 'group_name'))
->get();
}
I get this result:
[0] => Array
(
[id] => 4534
[group_name] => Annual
[vehicle] => Array
(
[0] => Array
(
[id] => 2311
[created] => 2007-06-01
)
[1] => Array
(
[id] => 3357
[created] => 2008-08-25
)
)
)
[1] => Array
(
[id] => 4752
[group_name] => Summer
[vehicle] => Array
(
[0] => Array
(
[id] => 5
[created] => 0000-00-00
[1] => Array
(
[id] => 3348
[created] => 2008-08-18
[2] => Array
(
[id] => 4316
[created] => 2011-02-24
)
)
[2] => Array
(
[id] => 4533
[group_name] => Winter
[vehicle] => Array
(
[0] => Array
(
[id] => 3116
[created] => 2008-05-15
)
)
At the moment, after the query, I use the following to melt it all down to JSON:
foreach (Group::many() as $group) {
$groups[] = $group->to_array();
}
var Groups = {{ json_encode($groups); }};
There are two problems with the above approach (for me): (1) It returns all the fields of the vehicles table (I only want the ID). (2) I want the vehicles property to simply contain an array of IDs — not bunch of nested objects.
Now, I know can parse the vehicle property while iterating through the Eloquent object and format the query result:
$groups = array();
foreach (Group::many() as $group) {
$v = array();
foreach ($group->vehicle as $vehicle) {
$v[] = $vehicle->id;
}
$groups[] = array('id' => $group->id, 'group_name' => $group->group_name, 'vehicles' => $v);
}
var Groups = {{ json_encode($groups); }};
But I really think this should be accomplished in the Model instead. I guess what I'm asking is, what is the best way in your opinion to go from this sort of model relationship to the resulting JSON? It is possible to eliminate the foreach loop and extra parsing code to produce the simpler JSON object described above?
Just use a join instead - more flexibility.
public static function many()
{
return self::join('vehicles', 'vehicles.account_id', '=, 'accounts.id')
->where('account_id', '=', Session::get('account_id_selected'))
->order_by('group_name')
->select(array('id', 'group_name', 'vehicles.id as vehicle_id'))
->get();
}
Note: Im not sure of the table structure of your database so have had to assume the table names are plural and have assumed key relationships, but you should be able to work it out.
You'll then get a row, or array element for every vechicle_id that matches (i.e. id will repeat). Just run it through some sort of foreach loop to get it the way you want.
You can use a closure to limit what gets selected.
public static function getManyByAccountId( $account_id )
{
return self::with (
array(
'vehicle' => function($query) use ($account_id ) {
$query->select('id as vehicle_id');
}
)
)->select(array('id', 'group_name'))
->order_by('group_name')
->where('account_id', '=', $account_id);
}
And the do something around:
$vehicles = json_encode( Vehicles::getManyByAccountId($account_id)->to_array() );
I am playing around with a quotes database relating to a ski trip I run. I am trying to list the quotes, but sort by the person who said the quote, and am struggling to get the paginate helper to let me do this.
I have four relevant tables.
quotes, trips, people and attendances. Attendances is essentially a join table for people and trips.
Relationships are as follows;
Attendance belongsTo Person hasMany Attendance
Attendance belongsTo Trip hasMany Attendance
Attendance hasMany Quote belongs to Attendance
In the QuotesController I use containable to retrieve the fields from Quote, along with the associated Attendance, and the fields from the Trip and Person associated with that Attendance.
function index() {
$this->Quote->recursive = 0;
$this->paginate['Quote'] = array(
'contain' => array('Attendance.Person', 'Attendance.Trip'));
$this->set('quotes', $this->paginate());
}
This seems to work fine, and in the view, I can echo out
foreach ($quotes as $quote) {
echo $quote['Attendance']['Person']['first_name'];
}
without any problem.
What I cannot get to work is accessing/using the same variable as a sort field in paginate
echo $this->Paginator->sort('Name', 'Attendance.Person.first_name');
or
echo $this->Paginator->sort('Location', 'Attendance.Trip.location');
Does not work. It appears to sort by something, but I'm not sure what.
The $quotes array I am passing looks like this;
Array
(
[0] => Array
(
[Quote] => Array
(
[id] => 1
[attendance_id] => 15
[quote_text] => Hello
)
[Attendance] => Array
(
[id] => 15
[person_id] => 2
[trip_id] => 7
[Person] => Array
(
[id] => 2
[first_name] => John
[last_name] => Smith
)
[Trip] => Array
(
[id] => 7
[location] => La Plagne
[year] => 2000
[modified] =>
)
)
)
I would be immensely grateful if someone could suggest how I might be able to sort by the the first_name of the Person associated with the Quote. I suspect my syntax is wrong, but I have not been able to find the answer. Is it not possible to sort by a second level association in this way?
I am pretty much brand new with cakephp so please be gentle.
Thanks very much in advance.
I've had the similar problem awhile back. Not with sort though. Try putting the associated table in another array.
echo $this->Paginator->sort('Name', 'Attendance.Person.first_name');
change to:
echo $this->Paginator->sort('Name', array('Attendance' => 'Person.first_name'));
Hope this helps
i'm also looking for help with this.
so far i've found that you can sort multi level associations in controller's pagination options after using the linkable plugin https://github.com/Terr/linkable.
but it breaks down when you try to sort form the paginator in the view. i'm using a controller for magazine clippings. each clipping belongs to an issue and each issue belongs to a publication.
$this->paginate = array(
"recursive"=>0,
"link"=>array("Issue"=>array("Publication")),
"order"=>array("Publication.name"=>"ASC",
"limit"=>10);
after debugging $this->Paginator->params->paging->Clipping in the view, you can see that the sort is described in two separate places, "defaults" and "options". the sort info needs to be present in both for it to work in the view.
here is after setting order in controller:
[Clipping] => Array
(
[page] => 1
[current] => 10
[count] => 6685
[prevPage] =>
[nextPage] => 1
[pageCount] => 669
[defaults] => Array
(
[limit] => 10
[step] => 1
[recursive] => 0
[link] => Array
(
[Issue] => Array
(
[0] => Publication
)
)
[order] => Array
(
[Publication.name] => ASC
)
[conditions] => Array
(
)
)
[options] => Array
(
[page] => 1
[limit] => 10
[recursive] => 0
[link] => Array
(
[Issue] => Array
(
[0] => Publication
)
)
[order] => Array
(
[Publication.name] => ASC
)
[conditions] => Array
(
)
)
)
and here is after using $this->Paginator->sort("Publication","Publication.name");.
notice the options array is empty.
[Clipping] => Array
(
[page] => 1
[current] => 10
[count] => 6685
[prevPage] =>
[nextPage] => 1
[pageCount] => 669
[defaults] => Array
(
[limit] => 10
[step] => 1
[recursive] => 0
[link] => Array
(
[Issue] => Array
(
[0] => Publication
)
)
[order] => Array
(
[Publication.name] => DESC
)
[conditions] => Array
(
)
)
[options] => Array
(
[page] => 1
[limit] => 10
[recursive] => 0
[link] => Array
(
[Issue] => Array
(
[0] => Publication
)
)
[order] => Array
(
)
[conditions] => Array
(
)
)
does one really need to modify the paginator class to make this work?
UPDATE:
i found out the problem:
in the core cake controller paginator merges default and options to create the find query.
but the options array is empty when using linkable to sort. because options is listed after default it overrides default and the empty array replaces the default array of options.
solution to this is extending the paginate function inside of app_controller.php and unsetting the options array order value if it is empty:
(line 1172 in cake/libs/controller/controller.php)
if(empty($options["order"])){
unset($options["order"]);
}
then the options will not be overwritten by thte blank array.
of course this should not be changed inside of controller.php, but put it in app_controller.php and move it to your app folder.
On CakePHP 3 this problem can be solved by adding 'sortWhitelist' params to $this->paginate on your controller.
$this->paginate = [
// ...
'sortWhitelist' => ['id', 'status', 'Attendance.Person.first_name']
];
And then in your view:
echo $this->Paginator->sort('Name', 'Attendance.Person.first_name');
This is noted in the docs:
This option is required when you want to sort on any associated data, or computed fields that may be part of your pagination query:
However that could be easily missed by tired eyes, so hope this helps someone out there!