Hi i have model logo with the following associations
var $belongsTo = array(
'Attachment' => array(
'className'=>'Attachment',
'foreignKey'=>'attachment_id'
),
'Employee' => array(
'className'=>'Employee',
'foreignKey'=>'employee_id'
)
);
var $hasMany = array(
'Voting' => array(
'className'=>'Voting',
'foreignKey'=>'program_id'
)
);
i wrote a query in the following way it throws error
$PrgCond['contain'] = array(
'Attachment',
'Voting' => array(
'fields' => array(
'logo_program_id',
'COUNT(employee_id) as noOfEmps'
),
'group' => array('LogoVoting.logo_program_id')
),
'Employee' => array(
'fields' => array('id', 'employee_number', 'first_name', 'last_name')
)
);
$logoPrgDatas = $this->Program->find('all',$PrgCond);
Thrown Error is
SQL Error: 1054: Unknown column 'LogoVoting.logo_program_id' in 'field list'
This is an old question but still comes up in Google results..
I had a similar issue and found out that you cannot use group in the Model find options when you have associations or either use containable behavior(which uses associations) in cakephp 1.* or 2.*.
However, this issue is fixed in cakephp 3.* by using query builder! :)
It's a good idea to reference the model in your fields. For example, when you are using a column in a condition or a fields array, you should call it Model.column_name.
Having said that, the problem you are having is most likely related to the group:
'group' => array('LogoVoting.logo_program_id')
There is no LogoVoting in your model. It should be:
'group' => array('Voting.logo_program_id')
So I would update the query to be:
$PrgCond['contain'] = array(
'Attachment',
'Voting' => array(
'fields' => array(
'Voting.logo_program_id',
'COUNT(Voting.employee_id) as noOfEmps',
),
'group' => array('Voting.logo_program_id'),
),
'Employee' => array(
'fields' => array(
'Employee.id',
'Employee.employee_number',
'Employee.first_name',
'Employee.last_name',
),
),
);
Related
In my CakePHP 2 project, I have Projects that have many Articles, an Article can belong to many projects (a many-to-many relation).
Now I would like to find all Projects that have an Article.
My current code for getting the Projects is as follows
$projects = $this->Project->find('list', array(
'fields' => array('Project.slug', 'Project.name')
));
I tried adding contain to the query, without results
$projects = $this->Project->find('list', array(
'contain' => array('PressArticles' => array()),
'fields' => array('Project.slug', 'Project.name')
));
How can I modify this so I receive all projects that have an article?
Containing won't help, non-1:1 relations will be retrieved in a separate query, so that won't have any effect on your main query.
You could for example manually create INNER joins with the association's join and target table, that would automatically filter out all projects that have no associated articles, something along the lines of this (I've more or less guessed the names, it's just a quick and dirty example):
$projects = $this->Project->find('list', array(
'fields' => array('Project.slug', 'Project.name'),
'joins' => array(
array(
'table' => 'press_articles_projects',
'alias' => 'PressArticleProject',
'type' => 'INNER',
'conditions' => array(
'PressArticleProject.project_id = Project.id',
),
),
array(
'table' => 'press_articles',
'alias' => 'PressArticle',
'type' => 'INNER',
'conditions' => array(
'PressArticle.id = PressArticleProject.press_article_id',
),
)
),
'group' => 'Project.id'
));
Or if you are using a counter cache, then filtering by the counter would be an option too:
$projects = $this->Project->find('list', array(
'fields' => array('Project.slug', 'Project.name'),
'conditions' => array(
'Project.press_article_count >' => 0
)
));
See also
Cookbook > Models > Associations: Linking Models Together > Joining tables
Cookbook > Models > Associations: Linking Models Together > counterCache - Cache your count()
In your Project model, you can do
public $hasMany = array(
'PressArticle' => array(
'className' => 'PressArticle',
'foreignKey' => 'project_id'
)
);
For more info, check here
I have a model Ranking which holds a contact_id and belongsTo Model Contact.
Model Contact has a costumer_id and belongsTo Model Costumer.
And hasMany Rankings.
There is also a Model Product which hasMany Ranking.
On a statistics page I select
$this->Product->recursive = 1;
$this->set('products', $this->Paginator->paginate())
;
and I get the array of
array(
'Product' => array(
'id' => '69',
),
'Ranking' => array(
(int) 0 => array(
'id' => '29',
'contact_id' => '9',
'product_id' => '69',
'ranking' => '9',
),
I would like to bind now the Contact and Costumer to the ranking based on the contact_id.
Is this manually possible via bindModel?
If yes, how can I do that?
I tried to set $this->Product->recursive = 1; to 2 and 3, but that select so many other things which I would need to clear with unbindModel... So I hope there is a smarter way of bind those model to get to the data...?
What you basically want to use is containable behavior. With this behavior you are able to filter and limit model find operations. You have the possibility to add this behavior on model level or at the controller to avoid side effects if the application has already grown to a complicated level.
Example from Cake-Book:
// Activate Containable Behavior on the fly in a controller
$this->User->Behaviors->load('Containable');
$this->User->contain();
$this->User->find('all', array(
'contain' => array(
'Profile',
'Account' => array(
'AccountSummary'
),
'Post' => array(
'PostAttachment' => array(
'fields' => array('id', 'name'),
'PostAttachmentHistory' => array(
'HistoryNotes' => array(
'fields' => array('id', 'note')
)
)
),
'Tag' => array(
'conditions' => array('Tag.name LIKE' => '%happy%')
)
)
)
));
Hope this gives you a push into the right direction.
using find it will get me the right data with this:
$this->set('products', $this->Product->find('all', array(
'contain' => array(
'Ranking' => array(
'Contact' => array(
'foreignKey' => 'contact_id',
'Customer' => array(
'foreignKey' => 'customer_id',
)
)
)
)
)));
When using the Paginator it looks like
$this->Paginator->settings['contain'] = array(
'Ranking' => array(
'Contact' => array(
'foreignKey' => 'contact_id',
'Customer' => array(
'foreignKey' => 'customer_id',
)
)
)
);
$this->Product->Behaviors->load('Containable');
$this->set('products', $this->Paginator->paginate());
Thanks so much!!
I have some deep associations using containable and need to filter back the results. For the sake of this question, let's say we are selling cars and want to narrow the results down by features.
Car hasmany make hasmany model HABTM features
$options = array(
'order' => array('Car.price'),
'contain' => array(
'make',
'model' => array(
'order' => 'Model.name ASC'
),
'features'
)
);
$cars = $this->Car->find('all', $options);
How would I go about excluding all cars that don't have power windows (Features.name != power_windows).
Containable is only suitable for you to specify what models you wanted to include when fetching data, but not limiting the parent model from fetching data at all. One obvious symptom is that sometimes your parent data may have some null contained data.
So to achieve it, I think we should use joins here so you can specify condition:
$options = array(
'order' => array('Car.price'),
'contain' => array(
'make',
'model' => array(
'order' => 'Model.name ASC'
),
'features'
),
'joins' => array(
array(
'table' => 'features',
'alias' => 'Feature',
'type' => 'LEFT',
'conditions' => array(
'Car.id = Feature.car_id'
)
)
),
'conditions' => array(
'Features.name !=' => 'power_windows',
)
);
But one drawback of this is that you might have duplicated Car due to joining. That's a separate issue ;)
I have this NPO table which has one template. A template in turn has a theme. I want to retrieve which theme was selected by Npo.
I have following relation setup:
NPO - template on npo.id = template.npoid Template - theme on theme.id
= template.template_theme_id
And I am using:
$this->Npo->bindmodel(array(
'hasOne' => array(
'NpoTemplate' => array(
'className' => 'NpoTemplate'
)
)
), false);
$this->NpoTemplate->bindmodel(array(
'hasOne' => array(
'TemplateTheme' => array(
'className' => 'TemplateTheme',
'fields' => 'TemplateTheme.html'
)
)
), false);
$arrUserSite = $this->Npo->find('first', array(
'conditions'=> array(
'Npo.address' => $user
)
));
But it does not fetch anything from TemplateTheme. Instead it writes a seperate query for this table and does not consider it in the join.
I have set recursive level to 3
Please help. I don't really understand how the cake association works.
Regards
Himanshu Sharma
Try setting up your relationships in a single bindModel() call.
$this->Npo->bindmodel(array(
'hasOne' => array(
'NpoTemplate' => array(
'foreignKey' => false,
'conditions' => array(
'Npo.id = NpoTemplate.npoid'
)
),
'TemplateTheme' => array(
'foreignKey' => false,
'conditions' => array(
'NpoTemplate.template_theme_id = TemplateTheme.id'
)
)
)
));
$arrUserSite = $this->Npo->find('first', array(
'conditions' => array(
'Npo.address' => $user
)
));
You'll probably need to tweak the bindModel setup because I'm not 100% sure of your database structure. Good luck.
This is one of those times when I know I'm doing something wrong, but I'm apparently deaf, dumb and blind with respect to seeing it. I'm hoping that another pair of eyes can open my own.
I have a ZipCode model and an Incentive model. There is a glorified join table (glorified because it has its own key) sitting in the middle. The join table has id, incentive_id and zip fields (legacy database). My ZipCode model HABTM Incentive as shown:
public $hasAndBelongsToMany = array(
'Incentive' => array(
'with' => 'ZipCodeIncentive',
'foreignKey' => 'zip',
'associationForeignKey' => 'incentive_id',
),
);
My Incentive model HABTM ZipCode as follows:
public $hasAndBelongsToMany = array(
'ZipCode' => array(
'with' => 'ZipCodeIncentive',
'foreignKey' => 'incentive_id',
'associationForeignKey' => 'zip',
),
I have a method, ZipCode::incentives( $zip ) that wants to pull all of the incentives relevant to the specified zip code:
$incentives = $this->Incentive->find(
'all',
array(
'contain' => array( 'ZipCode' ),
'fields' => array( 'Incentive.id', 'Incentive.name', 'Incentive.it_name', 'Incentive.amount', 'Incentive.state', 'Incentive.entire_state', 'Incentive.excluded', 'Incentive.is_active' ),
'conditions' => array(
'Incentive.excluded' => 0,
'Incentive.is_active' => 1,
'OR' => array(
'Incentive.state' => 'US', # nationwide incentives
array(
# Incentives that apply to the entire state the zip code belongs to
'Incentive.entire_state' => 1,
'Incentive.state' => $state,
),
'ZipCode.zip' => $zip # specific to the building's zip code
)
),
'order' => array( 'Incentive.amount DESC' ),
)
);
What I get for my trouble is the following error:
SQL Error: 1054: Unknown column 'ZipCode.zip' in 'where clause'
The ZipCode model's table isn't getting joined in the SQL, but I haven't grasped why yet. It's worth mentioning that the Incentive model is tied to a MySql view, not a table, via $useTable. I haven't seen anything to suggest that it should be a problem in this scenario, but it's non-standard.
If you see what I'm missing, please call 911 or at least drop an answer.
Rob
Move the condition
'ZipCode.zip' => $zip
To your contain declaration like this
array(
'contain' => array( 'ZipCode'=>
array('conditions'=>
array('ZipCode.zip' => $zip ))),
Then continue with the rest of your statement as usual