Order by specific field values in CakePHP - php

I have array $productsTop
(int) 0 => '6
(int) 1 => '4',
(int) 2 => '1',
(int) 3 => '2',
(int) 4 => '3',
(int) 5 => '5'
where 6 4 1 2 3 5 are id's of product table.
I want to display only 5 products from my products table but not order by ID ASC or DSC,
I want to order them by ID exactly like they are ordered in arrar so it can first show product ID 6, then ID 4... to ID 5.
Can anybody help please.
$productTop = [6,4,1,2,3,5];
$product = $this->Product->find('all', array(
'conditions'=>array('Product.id'=>$productTop),
'limit'=>5
));
In this way it shows me all products but ordered by their ID so instead of showing me:
6,4,1,2,3,5
it shows:
1,2,3,4,5,6

You can order by specified values like this:
'order' => "FIELD(id, '6', '4', '1', '3', '2', '5')"

You can add like this. :)
->order(["FIELD(Product.id, '228')"=>'DESC', "Product.id"=>'DESC'])

Related

Laravel 5.2 - Delete duplicates from my query

i have a query like this:
$players = PostBalance::where('post_id', $post->id)->orderBy('id','desc')->get();
It work well and return array with all values, Post balances have fields:
ID
score
post_id
user_id
I would like Delete user_id duplicated AND get the max score value. for example if i have:
[0] = 'id' => 1 , 'score'=> 10, 'user_id'=> 1, 'post_id' => 1
[1] = 'id' => 2 , 'score'=> 20, 'user_id'=> 1, 'post_id' => 1
[2] = 'id' => 3 , 'score'=> 30, 'user_id'=> 1, 'post_id' => 1
[3] = 'id' => 4 , 'score'=> 40, 'user_id'=> 2, 'post_id' => 1
[4] = 'id' => 5 , 'score'=> 50, 'user_id'=> 2, 'post_id' => 1
[5] = 'id' => 6 , 'score'=> 60, 'user_id'=> 2, 'post_id' => 1
I would like delete duplicates user_id and get only the user_id with max score:
RESULT:
[0] = 'id' => 3 , 'score'=> 30, 'user_id'=> 1, 'post_id' => 1
[1] = 'id' => 6 , 'score'=> 60, 'user_id'=> 2, 'post_id' => 1
You can use groupBy() and max() method like this (note: this will not actually delete the duplicates from DB, but work for your query):
$result = PostBalance::groupBy('user_id')
->max('score');
For further reference, see Laravel Docs
Or if you want to order the results by score, you can do it like this:
$result = PostBalance::orderBy('score', 'desc')
->groupBy('user_id')
->get();
Note: To get max of group by, try to first run orderBy(), then run groupBy() on the query instead.
Hope this helps!

Yii: can't use LIMIT in a mysql query

I'm using Yii, and I want to select 5 rows from mysql starting from the third row.
For Example, I have these rows:
ID - NAME
1 - abc
2 - bcd
3 - hdf
4 - fgr
5 - gdf
...
and I want to select 5 rows, starting from the third row.
My code:
$rows = Users::model()->findAll(array(
'order' => 'id DESC',
'limit' => '3, 5'
));
The problem this selects nothing.
There is an offset parameter.
$rows = Users::model()->findAll(array(
'order' => 'id DESC',
'limit' => '5',
'offset' => '3'
));

CakePHP MySQL Values

echo $this->Form->input('quantity', array('options' => array('1','2','3','4')));
I have this code to input the values 1,2,3 or 4 into the quantity field in my database.
If a user selects 1 it inputs 0, 2 inputs 1 etc.
If the code is
echo $this->Form->input('quantity');
The user can input what they like and guess what...
It works. What am I doing wrong?
I think you're trying to implement a drop-down box. I think you can try this:
$options = array('1' => '1', '2' => '2', '3' => '3', '4' => '4');
echo $this->Form->input('quantity', array('options' => $options, 'default' => '1'));
this will create a select drop down box.
For detail please see here.

Preventing associated queries on a hasMany model with find

I have a model that has several hasMany associations to other models. One thing I have noticed is that when I make a query against the parent table, all of the associated tables are queried as well. For performances sake, I would like to prevent this, as I do not need this data on every call to the parent model.
This is my current parent model:
class UserEntity extends UserAgentAppModel {
var $name = 'UserEntity';
var $primaryKey = 'entity_id';
var $actsAs = array('EavEntity');
var $validate = array(
'user_name'=>array(
'rule'=>'isUnique',
'message'=>'This username has already been taken. Please try again'
),
'user_pass' => array(
'rule' => array('between', 8, 16),
'message' => 'Passwords must be between 8 and 16 characters long.')
);
var $hasMany = array(
'UserEntityVarchar' => array(
'className' => 'UserEntityVarchar',
'foreignKey' => 'entity_id',
'isEav' => 'true'
),
'UserEntityDatetime' => array(
'className' => 'UserEntityDatetime',
'foreignKey' => 'entity_id',
'isEav' => 'true'
),
'UserEntityInteger' => array(
'className' => 'UserEntityInteger',
'foreignKey' => 'entity_id',
'isEav' => 'true'
),
'UserEntityBoolean' => array(
'className' => 'UserEntityBoolean',
'foreignKey' => 'entity_id',
'isEav' => 'true'
),
'UserEntityArray' => array(
'className' => 'UserEntityArray',
'foreignKey' => 'entity_id',
'isEav' => 'true'
)
);
);?>
This is what I am seeing in the query log. The issue I am seeing is that queries 12-17 always occur when using find. However, I am using a behavior to pull this data from my eav model.
1 SHOW FULL COLUMNS FROM `user_entities` 8 8 1
2 SELECT CHARACTER_SET_NAME FROM INFORMATION_SCHEMA.COLLATIONS WHERE COLLATION_NAME= 'latin1_swedish_ci'; 1 1 1
3 SHOW FULL COLUMNS FROM `user_entity_varchars` 4 4 1
4 SHOW FULL COLUMNS FROM `user_entity_datetimes` 4 4 1
5 SHOW FULL COLUMNS FROM `user_entity_integers` 4 4 1
6 SHOW FULL COLUMNS FROM `user_entity_booleans` 4 4 1
7 SHOW FULL COLUMNS FROM `user_entity_arrays` 4 4 1
12 SELECT `UserEntity`.`entity_id`, `UserEntity`.`user_name`, `UserEntity`.`user_pass`, `UserEntity`.`user_status`, `UserEntity`.`user_group`, `UserEntity`.`instance_id`, `UserEntity`.`is_logged_in`, `UserEntity`.`is_visible` FROM `user_entities` AS `UserEntity` WHERE 1 = 1 2 2 0
13 SELECT `UserEntityVarchar`.`value_id`, `UserEntityVarchar`.`attribute_id`, `UserEntityVarchar`.`entity_id`, `UserEntityVarchar`.`value` FROM `user_entity_varchars` AS `UserEntityVarchar` WHERE `UserEntityVarchar`.`entity_id` IN (1, 2) 3 3 0
14 SELECT `UserEntityDatetime`.`value_id`, `UserEntityDatetime`.`attribute_id`, `UserEntityDatetime`.`entity_id`, `UserEntityDatetime`.`value` FROM `user_entity_datetimes` AS `UserEntityDatetime` WHERE `UserEntityDatetime`.`entity_id` IN (1, 2) 0 0 0
15 SELECT `UserEntityInteger`.`value_id`, `UserEntityInteger`.`attribute_id`, `UserEntityInteger`.`entity_id`, `UserEntityInteger`.`value` FROM `user_entity_integers` AS `UserEntityInteger` WHERE `UserEntityInteger`.`entity_id` IN (1, 2) 0 0 0
16 SELECT `UserEntityBoolean`.`value_id`, `UserEntityBoolean`.`attribute_id`, `UserEntityBoolean`.`entity_id`, `UserEntityBoolean`.`value` FROM `user_entity_booleans` AS `UserEntityBoolean` WHERE `UserEntityBoolean`.`entity_id` IN (1, 2) 0 0 0
17 SELECT `UserEntityArray`.`value_id`, `UserEntityArray`.`attribute_id`, `UserEntityArray`.`entity_id`, `UserEntityArray`.`value` FROM `user_entity_arrays` AS `UserEntityArray` WHERE `UserEntityArray`.`entity_id` IN (1, 2) 0 0 0
22 SHOW FULL COLUMNS FROM `eav_attributes` 8 8 1
23 SELECT `EavAttribute`.`attribute_id`, `EavAttribute`.`attribute_code`, `EavAttribute`.`backend_model`, `EavAttribute`.`frontend_input`, `EavAttribute`.`frontend_label`, `EavAttribute`.`is_required`, `EavAttribute`.`is_user_defined`, `EavAttribute`.`is_unique` FROM `eav_attributes` AS `EavAttribute` WHERE `attribute_id` = 5 1 1 0
24 SELECT `EavAttribute`.`attribute_id`, `EavAttribute`.`attribute_code`, `EavAttribute`.`backend_model`, `EavAttribute`.`frontend_input`, `EavAttribute`.`frontend_label`, `EavAttribute`.`is_required`, `EavAttribute`.`is_user_defined`, `EavAttribute`.`is_unique` FROM `eav_attributes` AS `EavAttribute` WHERE `attribute_id` = 6 1 1 0
25 SELECT `EavAttribute`.`attribute_id`, `EavAttribute`.`attribute_code`, `EavAttribute`.`backend_model`, `EavAttribute`.`frontend_input`, `EavAttribute`.`frontend_label`, `EavAttribute`.`is_required`, `EavAttribute`.`is_user_defined`, `EavAttribute`.`is_unique` FROM `eav_attributes` AS `EavAttribute` WHERE `attribute_id` = 7
If you don't want to pull all the hasMany data in your find query set the value of recursive to -1 like in your controller
$results = $this->Model->find('all', 'recursive' => -1));
A better option is to use Containable behavior, this way you can specify which Models to fetch and which not. http://book.cakephp.org/view/1323/Containable
Do proper use of 'recursive' and 'unbind model' very good functionality of cake to restrict your query upto your useful data.
Check here how both works's you will get a better idea.

Retrieve Child Objects

I want a table of comments like so
id | comment | parent_id
--------------------------
1 text1 0
2 text2 1
3 text3 2
4 text4 3
5 text5 3
6 text6 5
I want to construct an array displaying the hierarchy of the parents and children. The tree should go back a undetermined number of generations. I don't want to use nesting foreach loops as I'm not sure how deep it goes. That is why I'm here, I'm not sure of the best practice for a problem like this. I also want to display the depth in the array. Below is an example. It doesn't really relate to table above, but hopefully gives you an idea of what I need.
array(
"depth"=> 4
"parent" => array(
"id"=> 1,
"comment" => "sometext1"
"child_count" => 2,
"children" => array(
0 => array(
"id" => 2
"comment" => "sometext2",
"child_count" => 0,
"children" => null
),
1 => array(
"id" => 3
"comment" => "sometext3"
"child_count" => 1,
"children" => array(
0 => array(
"id" => 2
"comment" => "sometext2",
"child_count" => 2,
"children" => array(
0 => array(
"id" => 2
"comment" => "sometext2",
"child_count" => 0,
"children" => null
),
1 => array(
"id" => 2
"comment" => "sometext2",
"child_count" => 1,
"children" => array(
"id" => 2
"comment" => "sometext2",
"child_count" => 0,
"children" => null
)
)
)
)
)
)
)
)
I was going to use foreach and do a SQL statement to retrive that parent/childs children. ie
$sql = "SELECT * FROM comments WHERE parent = $parent_id";
Im not really looking for the code for all this, just a pseudo code solution.
This can be easily done in PHP... For this you need two arrays and a two while loops.
This code will make a tree the way you wanted and for an undetermined depth and number of children.
Pastebin to the working code.
Using references, lets imagine everything is saved in an array $data with this structure: (id, comment, parent_id) where parent_id points to an id.
Code to build the tree.
$tree = array();
reset($data);
while (list($k, $v) = each($data))
if (0 == ($pid = $v['parent_id']))
$tree[$k] =& $data[$k]; else
$data[$pid]['children'][$k] =& $data[$k];
And to generate the depth and child count.
reset($data);
while (list($k, $v) = each($data))
if (0 != $v['parent_id'])
{
$ref =& $data[$k];
$depth = 0;
do
{
if ($depth) $ref =& $data[$ref['parent_id']];
$dre =& $ref['depth'];
if (!isset($dre) || $dre <= $depth) $dre = $depth++;
if (isset($ref['children']))
$ref['child_count'] = count($ref['children']);
else
{
$ref['child_count'] = 0;
$ref['children'] = null;
}
}
while ($ref['parent_id']);
}
All my code has been written on the fly and not even tested, so if there are any errors please forgive meeeeeeeee!!!!!!!!!!! ← Forget that, I tried it, fixed a couple of issues and now works perfectly.
Note
For this code to work, the index of every item has to be equal to its ID.
The array I used to try the code.
$data = array(
'1' => array('id' => '1', 'comment' => 'a', 'parent_id' => 0),
'2' => array('id' => '2', 'comment' => 'b', 'parent_id' => 0),
'3' => array('id' => '3', 'comment' => 'c', 'parent_id' => 1),
'4' => array('id' => '4', 'comment' => 'd', 'parent_id' => 1),
'5' => array('id' => '5', 'comment' => 'e', 'parent_id' => 2),
'6' => array('id' => '6', 'comment' => 'f', 'parent_id' => 2),
'7' => array('id' => '7', 'comment' => 'g', 'parent_id' => 5),
'8' => array('id' => '8', 'comment' => 'h', 'parent_id' => 7)
);
This is the problem when you use Adjacency list for trying to retrieve all child nodes in the hierarchy. It just doesn'y handle recursion very well if you are using mysql. (Oracle is another matter).
Creating the structure is simple, you should not really concern yourself with how to create the array structure just yet, first you want to try and create an efficient query and effiecient models that play perfectly to the type of queries that you will be making.
For example, you say that you want to retrieve all child nodes. Well then you should probably be using nested set models instead or in addition to adjacency list.
Take a look at some of these resources...
Is there a simple way to query the children of a node?
The idea of a nested set, is that you store the lft and right edge values of a node, meaning that retrieving any child nodes, is incredibly simple, beause you just select nodes which have a lft value greater than the target nodes lft value, and smaller than the rgt value.
Once you retrieve your result set, creating your array structure will be effortless.
See here : http://en.wikipedia.org/wiki/Nested_set_model
Once you have your results, then take a look at this question, which I asked a year or so ago, which is exactly what you want. PHP > Form a multi-dimensional array from a nested set model flat array
Example
id | comment | parent_id | lft | rgt |
-------------------------------------------------
1 World null 1 12
2 Europe 1 2 11
3 England 2 3 10
4 Kent 3 4 5
5 Devon 3 6 9
6 Plymouth 5 7 8

Categories