Scenario
I have Provider and Package.
A provider can have a number of featured packages.
So we need a HABTM between Provider and Package
I want to save all the providers featured packages in one shot using the Provider::edit() method
Setup
I have three models.
Provider
FeaturedPackage
Package
Models
These are setup using the 'HABTM Through', which should not be confused with HABTM. So the relationships are as follows.
Provider hasMany FeaturedPackage
FeaturedPackage belongsTo Provider
Package hasMany FeaturedPackage
FeaturedPackage belongsTo Package
Controller
public function admin_edit($id) {
if ($this->request->is('post') || $this->request->is('put')) {
if ($this->Provider->saveAll($this->request->data)) {
// snip
View
echo $this->Form->input('FeaturedPackages', array('type' => 'select', 'multiple' => true, 'options' => $packages));
The issue
I'm not sure how to save multiple variable numbers of hasMany records from one side of the relationship. I know from reading the book that the expected data array should be numerically indexed beneath the model.
However I'm not sure what to name my field to get the data formatted correctly.
I am unable to bake the view as it seems to ignore the hasMany and not even add a field for it.
Field names I've tried
FeaturedPackage
FeaturedPackage.FeaturedPackage
FeaturedPackage.package_id
FeaturedPackage..package_id
FeaturedPackage.[].package_id
FeaturedPackage.package_id][
I've solved this using a data massage method in my model, which is called from the controller.
This goes through and updates the array submitted from the form to match what is expected by the save.
I blogged my solution, http://jedistirfry.co.uk/blog/2013-08/how-to-create-hasmanythrough-multi-selects/
Related
Cakephp 2.10 ?
$text = $this->PrivacyPolicy->find('all', array(
'fields' => array('id', 'title', 'description')
));
How PrivacyPolicy is becoming a model role as there is no Model class in the files or relation with the database ?
Magic and unicorn dust... otherwise known as naming conventions and auto-models.
If no concrete model class can be found, CakePHP will create an instance of the AppModel base class instead, which will lookup the database table based on the the model name that you've used. So in your case the AppModel instance will look up the data in privacy_policies (lowercased, underscored, plural variant of the model name).
Quote from the docs:
CakePHP will dynamically create a model object for you if it cannot find a corresponding file in /app/Model. This also means that if your model file isn’t named correctly (for instance, if it is named ingredient.php or Ingredients.php rather than Ingredient.php), CakePHP will use an instance of AppModel rather than your model file (which CakePHP assumes is missing). If you’re trying to use a method you’ve defined in your model, or a behavior attached to your model, and you’re getting SQL errors that are the name of the method you’re calling, it’s a sure sign that CakePHP can’t find your model and you need to check the file names, your application cache, or both.
https://book.cakephp.org/2/en/models.html#understanding-models
We are using the new cakePHP ORM and I have some issues understanding the way the new ORM works when dealing with hasMany associations.
E.g. We have a Table called "Users" which has a hasMany relation to another Table "UsersAbsences". The definition and handling itself works fine. We have defined the Table-Objects and the Entities.
$this->addAssociations([
'hasMany' => [
'UsersAbsences' => [
'className' => 'UsersAbsences',
'propertyName' => 'absences',
'foreignKey' => 'user_id'
]
]);
Within our UsersTable we've created a custom method which retrieves details to one User, using the QueryBuilders ->contain Method to fetch the hasMany-associated "UsersAbsences" defined by property "absence". We're setting the view-variable $user to work with the Entity in the template: Works fine.
...
$users->contain(['UsersAbsences',...]);
...
Now the part that puzzles me:
The Object-type of $user is "UserEntity". When I now iterate through the $user->absences... i always get CakeEntity objects, not (as I would expect) AbsenceEntity-objects.
Problem: I would like to implement a custom method in the UserAbsence-Entity which I would like to call in the template when iterating through each Absence of the user.
When using the ->contain Method for associations attached with "belongsTo", I get the correct Entity-Class.
Someone an idea how to deal with that?
Mind your terminology, entity classes do not have a Entity suffix, this makes your question a little confusing, as one might think that you've named all your classes incorrectly! Please use actual, ideally fully qualified classnames in your questions!
That being said, by default the name of the corresponding entity is figured from the table class name, that is, the singular name without Table suffix. So, for UsersTable it's User, and for UsersAbsencesTable it would be UsersAbsence, not just Absence.
So, renaming your Absence entity file/class to UsersAbsence should fix the problem. Alternatively you can manually define the entity class a table should use by specifying it via Table::entityClass().
See also
Cookbook > ... CakePHP Conventions > File and Class Name Conventions
Cookbook > ... ORM > Table Objects > Customizing the Entity Class a Table Uses
I have 3 models.
Webcast and Tag are associated witha HABTMA association.
Webcast and Host are associated with a hasMany relationship (Webcast has many Host).
When I do a Tag->find I get Tag and Webcast models, however I want to get all 3. How can I go about that?
If your query is using $this->webcast->find then you'll get everything your looking for, except you can't search 'TAG' without joining the tables before the query. If you want to search 'TAG' which I recommend in this situation then your need to go into your Tag model and create relationships there too.
Tag HABTM Webcast
should do it. If you're not getting host then try 'recursive' => 2 in your query.
$this->Tag->find('all');
OR
$this->Tag->find('all', array('recursive' => 2));
From docs
The recursive property defines how deep CakePHP should go to fetch associated model data via find(), and read() methods.
http://book.cakephp.org/2.0/en/models/model-attributes.html#recursive
I have an admin page that pulls data from my ExpenseClaim model. I want to have 3 different paginated tables, each table displaying data based on a different condition (a status). This is what I have (which doesn't work - nothing is paginated in the view) in my controller:
// Pending
$this->set('claims', $this->paginate('ExpenseClaim', array('ExpenseClaim.claim_status_id' => '2')));
// Get approved
$this->set('approvedClaims', $this->paginate('ExpenseClaim', array('ExpenseClaim.claim_status_id' => '3')));
// Get Declined
$this->set('declinedClaims', $this->paginate('ExpenseClaim', array('ExpenseClaim.claim_status_id' => '4')));
Does anyone know how I can achieve this, I've do a fair amount of searching but only found things relating to different models or hacks using jquery plugins. Surely this can be done in cake alone?
Thanks in advance
Did you wrote the above code inside ExpenseClaimsController? But in case if you in another controller, make sure you have a paginate variable as the following
public $paginate = array(
'ExpenseClaim' => array(
.......
)
);
I'm sure there is a very simple solution to this, but the explanation is complex, so please do bear with me.
I have a registration form Registration::add() and it comprises of three sections.
The first is the Registration data, a number of fields.
The second is checkboxes from three related HABTM models, Role, Category and CategoryChild
Third is creating a record in User
My Registration model has a user_id and I need to save the generated User.id into that field.
I'm sure that I should be able to do this using the model relationships, as the User model saves the User.registration_id fine, but it doesn't seem to be writing into the Registration model.
Do I need to create another field in my add.ctp view so that the field is present in the $this->data->request array? I would much rather do this, than get embroiled in faffing with beforeSave() and afterSave().
So do I just need to create
$this->Form->input('Registration.user_id', array('type'=>'hidden'));
My relationships, for reference,
Registration hasOne User
Registration hasAndBelongsToMany Category
Registration hasAndBelongsToMany CategoryChild
Registration hasAndBelongsToMany Role
User hasOne Registration
I'm currently using saveAll($this->request->data) to save all my data, and it's managing to save everything except Registration.user_id
Your Relationships have
Registration hasOne User
However you have both a Registration.user_id and a User.registration_id implying that you need hasAndBelongsToMany relationship.
Just in case you're not using the Cake Baker to generate the models it is very useful.
Yes, something like this should work as per your question:
<?php echo $form->input('Registration.user_id',array('type'=>'hidden', 'value' => $user_id)); ?>
Hope it helps