sort on array read - cakephp

In my controller I have
var $uses = array('User','Customer');
then I am using read to call the users
$loggedOutCustomer = $this->User->read(null, $this->Auth->user('id'));
this gives me users and cutsomers that I can use but I want to do a sort on customers name. How can i do that in cake?

You can set the default order in your User model.
If Customer belongsTo User, User hasMany Customer.
In your User model, under the hasMany variable, find the Customer record and add Customer.name to the order array key.
Also, please remove the cakephp version tag that you are not using.
You can also add your sorting options when you're using the find() method of your model.
This can also be defined in the pagination array
Another option would be to use the Containable behavior

Give this a try
$loggedOutCustomer = $this->User->find('first', array('conditions' => array('User.id' => $this->Auth->user('id')), 'order' => 'Customer.name ASC'));

Related

CakePHP conditions clause on associations when using Model::find()

I just confused because of a find() result. This is my configurations:
First, users can have different User.role values: student, admin, and some others.
// Book
public $belongsTo = array(
'Student' => array(
'className' => 'User',
'foreignKey' => 'student_id'
'conditions' => array('User.role' => 'student')
);
);
When I chain Models like $this->Book->Student->find('list'); I was expecting to get only users whose role are 'student', but instead, it gets all users. What is going on here, what is conditions for on association definition, where can it and cannot be used. Any lead would help, thanks.
PS: I am aware that I could put conditions on find(), that's not the issue
There is a difference between associated data and accessing an associated model object. If you access $this->Book->Student you're accessing the Student model and work in it's scope. The conditions in the defined associations work only in the context of the accessed object.
So if you do a find on the Book and list the students for that book:
$this->Book->find('first', array('contain' => array('Student'));
Your code will work correctly. It will find the book plus the first user who has the role stundent. BUT your association is wrong then: It should be hasMany. because why would you filter a book by role if the book just belongsTo one student?
If you want to filter users by their role you can implement a query param that is checked in beforeFind(), pseudocode: if isset roleFilter then add contention to filter by that role from roleFilter.
Or, if you don't need to paginate just create a getStudents() method in the user model that will return a find('list') that has the conditions.
Or Student extends User and put the filter in the beforeFind() and use that model instead of the User model in your Book association.
If you want to filter on model level or per model I think the last one is a good option. Don't forget to set $useTable and $name or the inherited model will cause problems.
you have miss , inside your model.
try this:
public $belongsTo = array(
'Student' => array(
'className' => 'User',
'foreignKey' => 'student_id', //<------ miss
'conditions' => array('User.role' => 'student')
);
);
Yoi can debug your query to check what is the real query that you make.
Personally I have never use this approach, I prefer to use foreign key with another table for examples Rolesand User.role_id.
Is better for me to use this approach to have more flexibility inside your app.
After I prefer to use a conditions where inside controller to check well the query, because in your way every query you search always for student role not for the other and can be a problem for the rest of role, because inside controller you see a find without conditions but it doesn't take right value because in your model there is a particular conditions.
For me the good way is to create a new table, use foreign key and where conditions inside action of the controller to view well what are you doing.
For default all relations are "left join", you must set the parameter "type" with "inner" value
// Book
public $belongsTo = array(
'Student' => array(
'className' => 'User',
'foreignKey' => 'student_id'
'conditions' => array('Student.role' => 'student'), // <-- Fix That (field name)
'type' => 'inner', // <-- add that
);
);

What is the wrong here on associaction cake php

I am working on cake php and I have an association with users and user_details table, When I sign up then its working fine. Its post data on both the tables but when I redirect to profile page then it throws an error of userDetail array. When I printed that info array I got only one array instead of two arrays one is User and another one is UserDetail. Its working fine on my local machine but not working on server, But when I used recursive=>1 than its works. Please let me know what wrong here.
Query
$userInfo = $this->User->find('first',array('conditions'=>array('User.id'=>$userId)));
when I pass recursive than it works
$userInfo = $this->User->find('first',array('recursive'=>1,'conditions'=>array('User.id'=>$userId)));
Thanks
Shiv
Please use Containable behavior. It's more intuitive and clean then recursive variable. You can do this adding in your AppModel (or specific models if you don't want this behavior in all of them):
public $actsAs = array('Containable');
Then, in your find:
$userInfo = $this->User->find('first',array(
'conditions'=>array(
'User.id'=> $userId
),
'contain' => array('UserDetail')
));
If you have declared your association, you will retrieve your User along any UserDetail for that User
If you always want UserDetail to be fetched when you do a find on User, add the $recursive property to your User model:
public $recursive = 1;
However, the above is not recommended as usually, $recursive should be set to -1 in your AppModel. This is because Model::find() should normally only fetch data from a single model and not ALL related models. E.g. if your User model is related to say UserDetail and UserRole model, data from all of them will be fetched if $recursive is not equal to -1. This slows down your app.
When you do require related model data like in your question, use the containable behavior like this:
$userInfo = $this->User->find('first', array(
'conditions' => array('User.id'=>$userId),
'contain' => array('UserDetail')
));

CakePHP hasMany checkbox

I have two tables: Ingredients and Customers. The relationship between them is that Customers hasMany Ingredients. By default when doing the cakebake using the console, the only way to change them is by assigning an ingredient to the customer in the Ingredients page. However, I want to have in Customers page a checkbox list of Ingredients that can be assigned. Is it possible to do this? If yes, how?
edit:
What I have done until now is that I add this code to my add.ctp:
echo $this->Form->input('Ingredient',
array('label'=>'',
'type'=>'select',
'multiple'=>'checkbox',
'options'=>$ingredients));
However, it gives me "Undefined variable: ingredients" error when I tried to open the add view.
You want and need a HABTM relationship. Different customers can access and use the same ingredients. Look at the docs here yours would be very similar to different Posts using same Tags.
If you are getting this error:
"Undefined variable: ingredients"
It sounds like you haven't declared this variable in your controller, and set it so that the view can use it. Without knowing your code, you would probably need do do something like this (please note I am guessing what your application structure looks like and have not tested this code).
CustomersController.php
// The controller action for your view
public function view() {
// Get the ID and name of all your ingredients
$ingredients = $this->Ingredient->find('all', array(
'fields' => array('id', 'name'),
'order' => 'name',
'recursive' => -1
));
// We will use this array to store all the HTML select options
$ingredientOptions = array();
// Loop through all the ingredients and add them to the select
// options in a format that is suitable for CakePHP to use in
// the view to build your HTML select menu.
foreach ($ingredients as $i) {
$ingredient = $i['Ingredient'];
$ingredientOptions[$ingredient['id']] = $ingredient['name'];
}
// Make the variable available to the view
$this->set('ingredients', $ingredientOptions);
}

How to sort data of bind table in cakephp 2.0

I need the data from various table. I bind them by using cakephp's $hasMany variable. The data is fetched successfully. But I need to sort the result coming from $hasMany table.
for eg. I have two tables
Survey
Questions
Now Survey table contains the data related to Survey like title, id, purpose and Questions table contains question for related survey. I bind questions table with survey in survey model. Now I have a field in Questions table with name ordering. I need to fetch data in that order.
How can I fetch it in that way?
Please help me.
If you want to sort the data directly when it is fetched from db
You can define default order when adding relations between tables in your models. In your Survey model:
var $hasMany = array(
'Question' => array(
'order' => 'ordering DESC'
)
);
See http://book.cakephp.org/2.0/en/models/associations-linking-models-together.html#hasmany.
You can also define custom ordering when retrieving data from your controller in your conditional array, http://book.cakephp.org/2.0/en/models/retrieving-your-data.html#find:
$conditions = array(
'order' => array('Question.ordering DESC')
);
If you are paginating your result with the paginator component, you can setup it like in following example book.cakephp.org/2.0/en/core-libraries/components/pagination.html#query-setup:
public $paginate = array(
'order' => array(
'Question.ordering' => 'desc'
)
);
If you want to sort the data presented in the view
Here you can use the pagination helper (together with the pagination component in the controller) as:
echo $this->Paginator->sort('Question.ordering');
see book.cakephp.org/2.0/en/core-libraries/helpers/paginator.html#creating-sort-links
Sorry for removing 'http://' on the two last links, but I am not allowed to post more than two links (<10 rep).
In CakePHP you can sort by associated tables. but you need to sort by column, you should use something like this in your view:
<?php echo $this->Paginator->sort('Question.ordering'); ?>

Specifying order parameter through a belongsTo table in CakePHP

Let's say I've got two tables: cities and countries. The City model belongsTo a Country. Now, when I display lists of cities, I want them to be ordered by country name and then city name.
I tried this in my City model class:
var $order = array('Country.name' => 'asc', 'City.name' => 'asc');
The sort order works correctly for my index page, but I get errors in several places where the model has been asked not to load associated models. Do I have to change the order parameters when I change which tables are loaded, or is there a smarter way to do this?
For now, I think I'll make the default order definition be City.name and then just change it to Country.name and City.name on the index page. That way it's safe by default, and I shouldn't get unexpected errors.
Update: As Rob suggested you can specify order parameters in the model associations. The query builder applies them like this:
If there is an order field on the main model, apply it first.
Walk through all the associated models in the order they appear. If the association includes an order parameter, add it to the end of the list.
To implement my example, I would do it like this:
class City extends AppModel {
var $belongsTo = array(
'Country' => array(
'order' => array('Country.name' => 'asc', 'City.name' => 'asc')));
}
One caution: if you turn off City.recursive, then the cities will be unsorted. However, I'm usually retrieving only one record when I've turned off recursion.
Have you tried defining the order directly in your association? I've never needed to do this, so I can't swear it will do what you're after, but:
class City extends AppModel {
$belongsTo = array(
'Country' => array(
'Order' => 'Country.name'
)
);
}
You could do something similar for your Country model, of course.
this is untested, but the idea is
in the country model you can do
hasMany = array('City');
function beforeFind()
{
foreach($this->hasMany as $model)
{
$this->order[] = $model['className'].'.'.'ASC';
}
}
not worth doing IMO. ur way is fine.

Resources