I have two models, donors hasMany donations.
Upon creation of donor record, I want to update some donor fields. I tried using saveAssociated() as follows
$this->Donation->create();
$this->request->data['Donation']['donor_id'] = $id;
$this->request->data['Donor']['last_donated'] = date('Ymd H:i:s', strtotime('now'));
if($this->Donation->saveAssociated($this->request->data , array('deep' => true))){
}
Everything works except that the donor is not updated but a new donor record is created altogether.
Do I need to set the donor id manually somehow?
"Do I need to set the donor id manually somehow ?"
Yes.
More explanation:
In cake, if you want to update something, you need to pass the id, otherwise you'll create a new record. You can also "load" the model instance like
$this->Model->id = $id;
and then the save will update the row with that id. But I always find it more mentally-safe to add the id to the saved array, specially when using saveAll, saveMany and saveAssociated.
In your case, you must have the donor's id somewhere, cake is not that magical and it won't know what donor you are refering to.
Something like this
$this->request->data['Donor']['id'] = $the_id;
will do the trick.
... or you can save the donor's last_donated time with a different query, if it's giving you too much trouble.
Related
Normally in CakePHP, when you add a record with a form to a database table, CakePHP will automatically fill in the "created" field in de database with the current date & time. It works for my table called "attractions" (model "Attraction").
But now, strange things are happening. When I add a record for:
model "AttractionProperty", table "attraction_properties"
model "AttractionTypes", table "attraction_types"
model "AttractionPropertyLink", table "attraction_properties_links"
...
... both the fields "created" and "modified" are filled in. I checked if the id of my model is set in the add action ($this->request->id), but it says "false". Is this a common problem or what could be the reason of this behavior?
Do you have modified field in your Attraction model as well?
It is a feature to always set the created and modified field, if present. If you want to prevent it, add 'modified' => false into your $data array, that you pass to Model::create($data) or Model::save($data).
Read more here
Is there a way to write a CakePHP query to return all fields (columns) except one via find()? Or do I need to use the fields parameter and actually list all the fields, except the excluded field?
For example, if I have a database table (model), Company, with these fields:
id
name
street
city
state
zip
phone
Normally, $this->Company->find('all') would return all the fields. I want to exclude the phone field from the resultset.
$fields = array_keys($this->Company->getColumnTypes());
$key = array_search('phone', $fields);
unset($fields[$key]);
$this->Company->find('all', array('fields' => $fields));
For more info, please have a look at http://book.cakephp.org/2.0/en/models/additional-methods-and-properties.html#model-getcolumntypes
I can think of a couple ways to do this
Write out all the fields you want to include in the fields parameter. As mentioned in the comment, you can use $this->Company->schema to get all the fields programmatically rather than writing them out.
Unset the field you don't want after you get the data. You can do this in the model's afterFind function too.
I am new to CakePHP and have a fairly basic question.
I have two tables : books and users. books and users have a habtm relationship. I have created the MVC for the above.
Now when a user logs into the system, I want the user to be able to reserve a book (ie an entry in books_users), by looking at the results of the 'index' action. What is the API to be used?
$this->Book->save() does not seem appropriate as we aren't creating a book. We only want an association between an existing book and the logged-in user.
I am trying to avoid, retrieving $this->Book, iterating manually through the sub-array User, creating a new sub-array and saving the whole thing back. I am sure there must be a simpler way.
Adapted from Chuck's answer, unsure why edit was pushed back.
In app/Model/Book.php
class Book extends AppModel {
/************************************************************************
* If you want your multiple assoc. to work you must set unique to *
* false, otherwise when you save an entry it will enforce unique *
* on book ID and subsequently your associations will delete previously *
* saved associations, acting more like "User HasMany Books". *
************************************************************************/
var $hasAndBelongsToMany = array(
'User' => array(
'className' => 'User',
'unique' => false
));
public function addUser($bid, $uid) {
$this->data['User']['id'] = $uid;
$this->data['Book']['id'] = $bid;
$this->save($this->data);
}
}
In app/Controller/BooksController.php (or UsersController)
$this->Book->addUser($bid, $uid);
Fat Models / Skinny Controllers. Allows duplicate entries (you need to constrain limits and check for duplicates, otherwise default behaviour makes HMBTM difficult). Does exactly what you want it to, you just need to supply book and user id.
CakePHP doesn't tend to encourage complex associations, and the reason this is because HMBTM is just a convenience and care should be taken when mixing it with other associations, as per the link provided below, self defined associations are more predictable than HMBTM in CakePHP
http://book.cakephp.org/2.0/en/models/saving-your-data.html#what-to-do-when-habtm-becomes-complicated
You simply need to save a record to Book or User that contains the ids of both and it will insert it into the HABTM table.
$this->data['User']['id'] = {USER_ID};
$this->data['Book']['id'] = {BOOK_ID};
$this->Book->save($this->data);
Look at the HABTM table and you will find the record.
did you bake your application? This (basic) functionality will be provided to you for you to adapt.
In short - take the id of the book and the id of the user. Save it to your books_users table.
id | book_id | user_id
1 1 1
2 2 2
3 2 3
If you have set your associations up correctly, when you request a user, all their books will be returned from the join table.
Your logic will need to deal with - number of books available,if a person can reserve more than one book at once...
http://book.cakephp.org/2.0/en/models/saving-your-data.html#saving-related-model-data-habtm
Has an example.
I have a "production" table with field employee_id as a belongsTo relation to employees table.
The problem is my employees table uses field emp_appserial as primary key -as opposed to id field- (not every entry on employees table gets an id value, everyone gets auto increment emp_appserial)
I wonder if there is a way to use saveField using a field other than id to get to my record: (I mentioned I have records with no "id" value, only emp_appserial, which is pk)
$this->loadModel('Employees');
$this->Employees->id = $id;
$this->Employees->saveField('emp_hrnote', 'text to be saved');
I'd like to use:
$this->Employees->emp_appserial = $id;
instead of
$this->Employees->id = $id;
I that doable?
Aside from that, it may not be too late to re-design my tables, but I already have a lot of production data :-(
Thank you for any pointers.
The following should do the trick (btw, models should be singular):
class Employees extends Model {
public $primaryKey = 'emp_appserial';
}
If you don't set the $primaryKey attribute, it gets set to id: Source
Once you set that saveField() will use that field for the condition: Source
Edit: Just to make it clear, you would still use Model::$id to set the primary key value. Model::$id holds the primary key value, Model::$primaryKey holds the primary key field
Used
$this->Employee->updateAll(
array('Employee.emp_hrnote' => "$thetxt"),
array('Employee.emp_appserial' => $id)
);
As a workaround is just fine, however I wish I could solve my empty id issue... will post another issue with this on another post.
This is my code:
$charities = explode(',',$this->data['Charity']['charities']);
foreach ($charities as $key=>$charity){
$data['Charity'][$key] = $charity;
}
$this->Grouping->id = $this->data['Charity']['grouping_id'];
if ($this->Grouping->save($data)){
//Great!
}else{
//Oh dear
}
The code is from an action that gets called by AJAX. $this->data['Charity']['charities'] is a comma separated list of ids for the Charity model, which HABTM Grouping.
The code works fine, except that Cake doesn't seem to check whether that charity is already associated with that grouping, so I end up with lots of duplicate entries in the join table. I can see that this will be a pain later on so I'd like to get it right now.
What am I doing wrong?
Thanks
A few things I spotted:
A. Is $this->data['Charity']['charities'] an array with named keys corresponding to the table columns? Because inside the foreach() loop, you are taking the key and putting it in the $data['Charity'] array. The result could be a wrong format. The $data array for Model saves is commonly formatted as $data['Charity']['NAME_OF_COLUMN1], $data['Charity']['NAME_OF_COLUM2], and so on for each column that wants to be saved. So, if the keys are numbers, then you could be having something like: $data['Charity'][0], $data['Charity'][1], which is wrong.
B. HABTM Associations are saved differently. What I do recommend, is that you take a look at the book's section on saving HABTM. I save a HABTM relation like this (supposing a relation between users and coupons):
$this->data['Coupon'] = array('id' => 1, 'code' = 'BlaBla');
$this->data['User'] = array('id' => 33);
$this->Coupon->save($this->data, false);
So, as you can see, the $data array has a subarray named after the foreign model ('User') with the columns+values that I want to save. Then I save this array to the Coupon model.
C. Be aware that CakePHP will always delete old records and insert new ones within the join table when it is 'updating' HABTM relations. To avoid this, you set the 'unique' field to false in the Model's $HABTM configuration.