Cakephp collection how can I get array index? - cakephp

This is my collection data
[
0 => object(App\Model\Entity\SummaryCoin) id:0 { 'user_id' => (int) 2
'total_sum_coin' => (float) 3 },
1 => object(App\Model\Entity\SummaryCoin) id:1 { 'user_id' => (int) 1
'total_sum_coin' => (float) 33 },
]
How can I get the index where user_id = 1
Using first match I am able to get user 1 new collection
$sumOfUserCoins = $collection->firstMatch([
'user_id' => 1
]);
How I will get the array index 1 that user have ?

There is no specific method for that, you'll have to be a little creative to obtain that information, for example match all instead so that you get a collection back, take everything away expect for the first entry, and convert it to an array that keeps the keys, from which you can then get that information:
$userCoins = $collection
->match(['user_id' => 1])
->take(1)
->toArray();
$index = key($userCoins);
$coin = current($userCoins);

Related

Get key values from a collection in Laravel

I have this collection
1 => {#27
+"id": 1
+"name": "Zel"
+"age": "43"
}
2 => {#28
+"id": 2
+"name": "Kol"
+"age": "56"
}
3 => {#29
+"id": 3
+"name": "Mil"
+"age": "32"
}
and I would like to return an array with the key values as a string like this:
[
'id',
'name',
'age',
]
Can someone help me with that, please?
use array_keys :
$keys = array_keys($collection->first());
Laravel collection has a keys() method you could simply use it like this:
$keys = $collection->keys();
$get = $keys->all();
It is all clearly written in the Laravel Documentation
EDIT
After looking at your edit, my first consideration would be that if your collection is consistent you could get the first one and subsequently get the keys from there on:
$keys = $collection->first();
$get = $keys->keys()->all();
Or simply put $collection->first()->keys()->all();
EDIT
Here is how i was able to reproduce your problem:
$collection = collect([
[
'id' => 1,
'name' => 'Zel',
'age' => 43
],
[
'id' => 2,
'name' => 'Kol',
'age' => 56
],
[
'id' => 3,
'name' => 'Mil',
'age' => 32
],
]);
$keys = collect($collection->first())->keys()->all();
Here is the Result I got:
array:3 [▼
0 => "id"
1 => "name"
2 => "age"
]
If it still returns a collection or an object based on your last comment, you could try any one of these:
$keys = $keys->toArray();
$keys = collect($keys)->toArray();

CakePHP How to Get Associated Data and COUNT/GROUP BY

I'm having some trouble with Cakephp Query builder and try to get results I'm looking for. I have three tables 'Users', 'Items', 'Owns', where Owns belongs to both 'Users' and 'Items'.... A user can own many items (and many of the same items).
So I'm wanting to return the "owned" items by a user along with the count... However whenever I add count into my query I lose the associated Items data.
example - this returns the user data along with associated owns data and associated items data as shown below the query
$owns = $this->Users->get($id, [
'contain' => [
'Owns' => function($q) { return $q->find('all')->group(['Owns.item_id']); },
'Owns.Items'
],
]);
SQL Generated from this is
SELECT
Owns.id AS Owns__id,
Owns.item_id AS Owns__item_id,
Owns.user_id AS Owns__user_id,
Items.id AS Items__id,
Items.name AS Items__name,
Items.description AS Items__description,
Items.created AS Items__created,
Items.modified AS Items__modified
FROM
owns Owns
INNER JOIN items Items ON Items.id = (Owns.item_id)
WHERE
Owns.user_id in (1)
GROUP BY
Owns.item_id
Data results look like this:
'owns' => [
'id' => (int) 1,
'username' => 'myusername',
'owns' => [
(int) 0 => object(App\Model\Entity\Own) id:0 {
'id' => (int) 2
'item_id' => (int) 1
'user_id' => (int) 1
'item' => object(App\Model\Entity\Item) id:1 {
'id' => (int) 1
'name' => 'Item Name'
'description' => 'Item Description'
However in the 'owns' query I want to add in the count (i.e. the number owned). I can get the count by using this query but then I lose the associated item object from my results. I've tried this many different ways but always seems that if I want to use SQL count I can't get the associated data.
$owns2 = $this->Users->get($id, [
'contain' => [
'Owns' => function($q) { return $q->select(['count' => $q->func()->count('Owns.id'),'Owns.id', 'Owns.user_id', 'Owns.item_id'])->group(['Owns.item_id']); },
'Owns.Items'
],
]);
SQL Generated from this is
SELECT
(COUNT(Owns.id)) AS count,
Owns.id AS Owns__id,
Owns.user_id AS Owns__user_id,
Owns.item_id AS Owns__item_id
FROM
owns Owns
INNER JOIN items Items ON Items.id = (Owns.item_id)
WHERE
Owns.user_id in (1)
GROUP BY
Owns.item_id
Data results look like this:
'owns2' => [
'id' => (int) 1,
'username' => 'myusername',
'owns' => [
(int) 0 => object(App\Model\Entity\Own) id:36 {
'count' => (int) 4
'id' => (int) 2
'user_id' => (int) 1
'item_id' => (int) 1
Any insight into how I can get "count" into the first $user query or the associated items into the $user2 would be appreciated.
To keep the association table's fields that are returned in the $owns = find('all') query along with the SQL count function I needed to add the associated fields into the select statement
$owns2 = $this->Users->get($id, [
'contain' => [
'Owns' => function($q) { return $q->select(['count' => $q->func()->count('Owns.id'),'Owns.id', 'Owns.item_id','Owns.user_id', 'Items.id', 'Items.collection_id','Items.name', 'Items.description'])->group(['Owns.item_id']); },
'Owns.Items'
],
]);

Using the paginator directly is not recognising the configuration

CakePHP Version: 4.0.1
Introduction
I have 2 methods that both use the index view, index and search. On index the column can be selected from a select list and a value can be inputted via an input form control enabling a search by column and value. This data is sent via GET to the search method where empty values are checked and the query is executed and the index view is rendered.
In the later 3x versions with the below configuration the index view had the sort on the selected column which is what it is meant to do.
IE: Index view has due_date sorted on the initial load and I select task_name then submit the form to the search method. The task_name has the sort when the view is rendered.
TASKS CONTROLLER
Public pagination property:
public $paginate = [
'sortWhitelist' => [
'Tasks.due_date',
'Tasks.task_name',
'Tasks.type',
'Tasks.priority',
'Tasks.related_to_name',
'Contacts.first_name',
'Contacts.last_name',
'Accounts.account_name',
'Tasks.task_desc'
]
];
Search Method
I initialise the data received from the index method and apply the config to the pagination property and send the query object to the view.
$this->setPage('');
$this->setSort($this->request->getQuery('column'));
$this->setDirection('asc');
// Validation of the page, sort, direction and limit is done here.
// IE: The $this->getSort() must be a string and not be numeric and has a strlen check
// and the $this->getDirection() can only be a string with values 'asc' or 'desc' etc.
if (!empty($this->getPage())) {
$this->paginate['page'] = $this->getPage();
}
$this->paginate['sort'] = $this->getSort();
$this->paginate['direction'] = $this->getDirection();
$this->paginate['limit'] = $this->getLimit();
debug($this->paginate);
$tasks = $this->paginate($query);
$this->set(compact('tasks'));
The result of debug is:
[
'sortWhitelist' => [
(int) 0 => 'Tasks.due_date',
(int) 1 => 'Tasks.task_name',
(int) 2 => 'Tasks.type',
(int) 3 => 'Tasks.priority',
(int) 4 => 'Tasks.related_to_name',
(int) 5 => 'Contacts.first_name',
(int) 6 => 'Contacts.last_name',
(int) 7 => 'Accounts.account_name',
(int) 8 => 'Tasks.task_desc'
],
'sort' => 'Tasks.task_name',
'direction' => 'asc',
'limit' => (int) 25
]
Result
The sort is on the task_name.
A couple of months ago I upgraded to 4 and have just revisted this functionality to find the sort is on the column that was present on index and not the column that was selected. I tried the below to fix the problem:
I referenced this information in the cookbook. And this from SO.
$config = $this->paginate = [
'page' => $this->getPage(),
'sort' => $this->getSort(),
'direction' => $this->getDirection(),
'limit' => $this->getLimit()
];
debug($config);
$tasks = $this->Paginator->paginate($query, $config);
debug($this->Paginator);
$this->set(compact('tasks'));
The result of debug $config is:
[
'page' => '',
'sort' => 'Tasks.task_name',
'direction' => 'asc',
'limit' => (int) 25
]
The result of debug $this->Paginator is:
object(Cake\Controller\Component\PaginatorComponent) {
'components' => [],
'implementedEvents' => [],
'_config' => [
'page' => (int) 1,
'limit' => (int) 20,
'maxLimit' => (int) 100,
'whitelist' => [
(int) 0 => 'limit',
(int) 1 => 'sort',
(int) 2 => 'page',
(int) 3 => 'direction'
]
]
}
NOTE: The whitelist contains limit, sort, page and direction? And the limit is 20 and I don't even have a selection of 20?
Result
The sort is on the due_date and I need it on the task_name.
Extra Info
If I then click the sort on task_name the sort is on the task_name. All the sorts work just not on the initial load?
Question
How can I configure the pagination property so the sort is on the task_name from the initial load of the search method.
Thanks Z.
The fix is a bit costly and not ideal but it does work. I do a redirect on the initial load. Basically submit the form to search then redirect back to search. IE:
if ($this->request->getQuery('initial') === 'yes') {
$redirect = $this->request->getQuery('redirect', [
'action' => 'search',
'?' => [
'method' => 'search',
'column' => $this->getColumn(),
'input' => $this->getInput(),
'page' => $this->getPage(),
'sort' => $this->getSort(),
'direction' => $this->getDirection(),
'limit' => $this->getLimit(),
'filter' => $this->getFilter(),
]
]);
return $this->redirect($redirect);
exit(0);
}
$config = $this->paginate = [
'sortWhitelist' => [
'Tasks.due_date',
'Tasks.task_name',
'Tasks.type',
'Tasks.priority',
'Tasks.related_to_name',
'Contacts.first_name',
'Contacts.last_name',
'Accounts.account_name',
'Tasks.task_desc'
],
'page' => $this->getPage(),
'sort' => $this->getSort(),
'direction' => $this->getDirection(),
'limit' => $this->getLimit()
];
$tasks = $this->Paginator->paginate($query, $config);
$this->set(compact('tasks'));
The sort is now on the task_name.
This negates the initial load problem and simulates usage after the page initially loads where I know the sorts work.

Laravel 5 form validation of array on different

from request I get an array like this:
'array' => [
0 => ['id' => 1,'val' => 2],
1 => ['id' => 1,'val' => 2]
]
I need to validate it so all ids of array will be unique.
right now I try this validation rule:
'array.*.id' => 'different:array.*.id'
but it will check current array with current array so result will be like
The array.0.id and array.0.id must be different.
You should use distinct rule:
'array.*.id' => 'distinct'

CakePHP: how to get total number of records retrieved with pagination

When you retrieve records using $this->paginate('Modelname') with some page limit, how do you get the total number of records retrieved?
I'd like to display this total count on the view, but count($recordsRetrieved) returns the number displayed only on the current page. So, if total number of records retrieved is 99 and limit is set to 10, it returns 10, not the 99.
You can debug($this->Paginator->params());
This will give you
/*
Array
(
[page] => 2
[current] => 2
[count] => 43
[prevPage] => 1
[nextPage] => 3
[pageCount] => 3
[order] =>
[limit] => 20
[options] => Array
(
[page] => 2
[conditions] => Array
(
)
)
[paramType] => named
)
*/
The final code for PHP >=5.4:
$this->Paginator->params()['count'];
For PHP versions less than 5.4:
$paginatorInformation = $this->Paginator->params();
$totalPageCount = $paginatorInformation['count'];
To get your answer go to he following link
http://book.cakephp.org/2.0/en/controllers/request-response.html
use pr($this->request->params) you will find all the stuff of pagination
For cake 3.x
you can use method getPagingParams
example:
debug($this->Paginator->getPagingParams());
output:
[
'users' => [
'finder' => 'all',
'page' => (int) 1,
'current' => (int) 5,
'count' => (int) 5,
'perPage' => (int) 1,
'prevPage' => false,
'nextPage' => true,
'pageCount' => (int) 5,
'sort' => null,
'direction' => false,
'limit' => null,
'sortDefault' => false,
'directionDefault' => false,
'scope' => null
]
]
Here's how I got the count from my controller*
This is for CakePHP 2.3. It uses a view helper, which is typically a no-no in the controller as it violates MVC, but in this case I think makes sense to keep the code DRY.
// Top of file
App::uses('PaginatorHelper', 'View/Helper');
// Later in controller method
$paginatorHelper = new PaginatorHelper(new View(null));
$records = $this->paginate();
$count = $paginatorHelper->params()['count'];
* I know the OP asked about from the view, but I figure if Arzon Barua's answer is helping people (though I think it only tells you the requested count, not the actual count as the OP wants), then this might help too.
This way is getting a pagination information over controller.
class YourController extends Controller{
$helpers = array('Paginator');
public fn(){
$view = new View(null);
var_dump($view->paginator->params());
}
}

Resources