I have the following relation scheme:
1 portfolio -> Many Users in each Portfolio -> Each User owns many Products
Entities: Portfolio, User, Products
What I would like to display is in one page:
1. The name of the portfolio
2. The title of a user
3. CGridView of all products owned by that user
It seems, if CGridView were not being used, you would populate your model appropriately and then use a foreach loop to loop through each user relation and then loop through the products related to that user. And create a render_partial view for the products and for the user.
However, I am at a complete loss as how to accomplish this with CGridView.
Any advice is much, much appreciated!
You want to render the User's Products in a CGridView?
To render data with a CGridView you need to pass in a CDataProvider to populate the view. So the question is: how do you make a CDataProvider for the HAS_MANY relation?
Surprisingly, the CActiveDataProvider does not support relations in this way. What you need to do get the relation and pass that data into a CArrayDataProvider. Assuming the $user->productsrelation,you can do it like this:
$dataProvider = new CArrayDataProvider($user->products, array());
$this->widget('zii.widgets.grid.CGridView', array(
'dataProvider'=>$dataProvider,
'columns'=>array(
'id', // your columns here
),
));
It's not ideal, but it works. Credit goes here for this specific technique: http://learnyii.blogspot.com/2010/12/yii-how-to-display-related-hasmany-grid.html
Related
This is may be a stupid question, but I am kind of new in yii, and had problem with this simple view..
I have a data like this:
task_type
id name
1 agenda
2 task
3 notes
agenda:
id user due_at created_at task_type_id description
And I would like to display them separately, as agenda and tasks, and notes in different html views like these:
tasks
due_at description
agenda
due_at created_at description
notes
description
I don't want any fancy user filtering as these tables only shows one week max on front page, for current week, and there will be separate page dedicated for this sort of tasks. This is only at front page as quick tasks. I have been trying on CGridView but can't filter it without letting html filter to show up. I need to filter at due_at, and ranged due_at for agenda, and then by user.
Can someone help me to create this?
Thank you in advance
There are a few things that you need to take care of, if you want to use a CGridView for this, and they are the following:
Use a DataProvider : CGridView requires a data provider as its input. A data provider is:
Data providers are components that can feed data for widgets such as data grid, data list. Besides providing data, they also support pagination and sorting.
For your current requirement you can use a CActiveDataProvider. So your gridview code needs this:
$this->widget('zii.widgets.grid.CGridView', array(
'dataProvider'=>$dataProvider,
));
Pass this data provider from the controller action to the view.
Use criteria: You can pass all those conditions in the criteria property of CActiveDataProvider. This criteria is an object of CDbCriteria. So your $dataProvider can be something like:
$dataProvider=new CActiveDataProvider('Agenda',array(
'criteria'=>array(
'condition'=>'task_type_id=1 AND due_at BETWEEN CURDATE() AND DATE_ADD(CURDATE(), INTERVAL 1 WEEK)',
'select'=>'due_at, description' // columns you want to select
)
));
The condition property is the:
query condition. This refers to the WHERE clause in an SQL statement. For example, age>31 AND team=1.
The select property is:
the columns being selected. This refers to the SELECT clause in an SQL statement. The property can be either a string (column names separated by commas) or an array of column names. Defaults to '*', meaning all columns.
Don't specify the filter: To not show a filter, just don't pass any filter property value to the grid:
$this->widget('zii.widgets.grid.CGridView', array(
'dataProvider'=>$dataProvider,
//'filter'=>$model // don't pass any filter
));
Use columns: Use the columns property of CGridView to show only the specific columns you want to show:
$this->widget('zii.widgets.grid.CGridView', array(
'id'=>'agenda-grid',
'dataProvider'=>$dataProvider,
'columns'=>array(
'due_at',
'description'
)
));
Also pass an id which will become the id of this grid's div, incase you don't want the auto-generated id.
That's it, you should get what you want by following the above steps.
I'm using the cakephp framework to develop an application and I'm running into some trouble understanding the associations between these models fully. Below you can see the four models along with their relative database fields.
User
id
Profile
id
user_id
Post (A blog post on the users profile)
id
profile_id
topic_id
Topic (A topic for a blog post)
id
name
Here are the associations as they currently stand:
User
hasOne: Profile
Profile
hasMany: Posts
Post
belongsTo: Topic, Profile
Now my problem. I am unsure if you have to define associations like User hasMany Posts or if it's already assumed because User hasOne Profile and Profile hasMany Posts. My other problem is defining the relationship between a post and its topic.
A profile can have unlimited posts
A post must be associated with a profile
A post can only have one topic
The topic table contains a list of all topics
A post does not NEED a topic
Given these criteria how should my associations look? All the research I've done on associations only shows simple examples.
I'm using CakePHP version 2.1.3
Thanks for any and all help and/or advice in advance
You can recursively find associations of associations, or even better, use Containable.
In the model (I recommend putting it in AppModel, since I find myself using Containable for everything):
class AppModel extends Model {
public $actsAs = array('Containable');
...
}
Then when you call read (or find, or paginate) for User, most likely in your controller, do this:
$this->User->contain(array(
'Profile' => array(
'Post'
)
));
$data = $this->User->read();
$set('user',$data);
If you set that data to your view, you can then access the id of one of the posts from $user['Profile']['Post'][0]['id'].
Now for your next question, you can have conditional associations.
public $hasMany = array(
'Topic' => array(
'className' => 'Topic',
'conditions' => 'Post.topic_id IS NOT NULL'
)
)
I think everything looks fine
Your assumption is correct you dont have to define the User / Post relationship. Users dont have many Posts, Profiles do. You could store the user_id on the Post rather than profile_id to make thing a bit more intuitive but thats up to you.
Topic hasMany Post and you are done. The topic/post conditions you describe can be controlled via the forms and before saves on the model. For example 'A post must be associated with a profile', well at the point you save the post you add in the profile_id based on session info of the logged in user.
My relationships are as follows:
User hasMany Item, Offer, Watcher
Item BelongsTo User
Item hasMany Offer, Watcher
Offer/Watcher BelongTo Item & User
When I try to get the Users Items using this:
$this->loadModel( 'User', $this->Auth->user( 'id' ) );
$this->set( 'user', $this->User->read() );
It gets the users record, the items they're watching and items they've made offers on which is fine.
However on the users items that they're selling it wont get the watchers/offers correctly.
if I use: $this->User->recursive = 2; Then it only gets the user_id but doesn't associate it to the users profile at all!
Example:
http://pastebin.com/9A8k7rDs
I can get this information by including the models individually and getting the data that way, but that's such a hack.
I was wondering if anyone knew any better ways?! or even if my relationships are right :z?
Do you have the relationships set up in all the models? Meaning not only do you have to have the relationship in the User model, but also in the Item, Watcher and Offer models as well.
I got it!
I used $this->User->Item->find( ... ) with $this->Item->recursive = 2;
It returned the data I wanted and a bit extra so I controlled that with the containable behaviour.
Thanks!
I'm quite new to CakePHP so I'm wondering if anyone can help me with how to order my pages.
I have a table of products (with a Product model and products_controller).
I also have a table of categories (with a Category model and categories_controller).
The categories hasMany products.
Firstly, is the name categories incorrect to call it. According to CakePHP convention, what is the correct name to call it?
Secondly I would like the user to click on the products link and then be presented with a list of categories and finally, once he/she chooses a category be presented with the products in that category. How would this be laid out?
You're asking some pretty basic CakePHP stuff, I suggest you read the book, which outlines naming conventions, file structure and data retrieval to name a few things.
That being said, the name categories is correct, unless you want products to have more than one category, the relationship will be Product 'BelongsTo' Category.
To get category info inside the product controller you can just access it's find methods with $this->Product->Category->find();, but again I recommend you read through the CakePHP book as you go to build up our knowledge and learn more about the framework you're using.
You mean that categories is not a plural of category? I think so. Your table has to be named as 'categories'.
Secondly, I think that you need a Categories hasAndBelongsToMany Products (HABTM) in your model, so every Category has many Products, and also a Category belongs to many products.
Use the 'cake bake' command and you will see easily if it is what you want.
Hope it helped, althought I'm quite new in cakePHP as well...
Alf.
If you have categories tables in db, its controller would be categories_controller.php and the Products belongsTo Category will work if products belong to only one category. No need to HABTM relationship. See in cakephp the model files are in singular form and controller file are in plural form with controller attached with them. The tables are named in plural in db.
Regarding ur 2nd question, I think im not getting it exactly.
Currently i'm having a problem. I want to access the data available in the 4th table of my DB.
Db image:
I have the tables in this way: Categories --> Categories_Companies --> Companies --> Affiliates
Like it shows in the image i'm on the categories and in the Categories view (views/categories/view.ctp) i want to show the fields title and url from the affiliates table.
There is another way of doing that without using the this->query?
Regards
You access a table through its model. The Category model is automatically included in the CategoriesController by naming convention. You can include other models by using $uses.
var $uses = array('Category', 'Affiliate');
function view() {
$this->Category->find(…);
$this->Affiliate->find(…);
}
Or, if your models are linked through associations, you can access them through an association:
$this->Category->Company->Affiliate->find(…);
Both examples are equivalent, the first is just more convenient.