cakePHP - can i save ONLY the associated models data using save()? - cakephp

Can I use the $this->ModelName->AssociatedModel->save($this->data) to save only the related data?
If not - what are my options?
The data structure is:
$this->data['AssociatedModel']['field_a'] = 'some value';
$this->data['AssociatedModel']['field_b'] = 'some other value';

well, I landed here with a User HABTM ROLE usecase where the User table is a read-only db view.
The accepted solution didn't worked for me on cake2.x
In the end I settled on the following AppModel method:
public function saveHabtmOnly($data, $parent_id) {
$this->_saveMulti($data, $parent_id, $db=$this->getDataSource());
// _saveMulti has no failure signaling
// probably just throws Exception
return true;
}
where
$data = array('Role'=>array(...));
and $parent_id is the id of the User

Yes, you can save associated data like that.

Related

Symfony2 mapping between 3 entities

I have three entities : Event, Photo and User.
Three main relations :
An Event has 0 or more photos (blue relation, OneToMany)
An Event has been created by one photo, which I call the firstPhoto (red relation,
OneToOne)
A user can create 0 or more photos (violet relation,
OneToMany)
What I want is to map the relation between an Event and the User who created it, without adding or changing my database. It means the user that created the firstPhoto of the Event.
I'm not looking for a SQL query which I succed to do but really a mapping in my User.php Entity.
$user->getEvents() would give the events the user created.
I can't success to do so... any idea ? Am I obliged to add or change something in my database ?
I see 2 ways of doing that:
1) make a named native query http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/native-sql.html#named-native-query
2) write something like
public function getEvents()
{
$res = array();
$photos = $this->getPhotos();
foreach($photos as $photo) {
$res[] = $photo->getEvent();
}
return $res;
}

Receive model data inside a CakePHP model callback function

I try to use existing model data inside a models callback function in CakePHP 2.1 but can't get it working.
What I do is I try to get a users role in the beforeValidate() callback and check if it's empty. If yes, I'll set it. Normally I do it like this, and for the first creation of the record it works pretty well.
if (empty($this->data[$this->alias]['role']))
$this->data[$this->alias]['role'] = 'user';
The problem is, every time an existing record (user) gets updated, the role will be set again.
Question: So, how do I check if the field role is already set in the record data, not the post data (seems like $this->data[$this->alias] only contains POST data)?
There are three solutions to this problem as I can see it.
Set a default value in the database column (easiest, best?)
Add role to your inputs everytime.
Lookup the user and add a role if it's missing
The first two options seem obvious, so I'll just illustrate the last.
public function beforeValidate() {
if (!empty($this->id) {
$this->data[$this->alias][$this->primaryKey] = $this->id;
}
if (!empty($this->data[$this->alias][$this->primaryKey])) {
// user exists, check their data
$id = $this->data[$this->alias][$this->primaryKey];
$user = $this->find('first', array(
'conditions' => array($this->primaryKey => $id)
));
$this->data[$this->alias]['role'] = $user[$this->alias]['role'];
}
if (empty($this->data[$this->alias]['role'])) {
// new user but missing a role
$this->data[$this->alias]['role'] = 'user';
}
return true;
}
This callback will check if an ID was passed, and if so it will look up the user and populate the role field. Then, it checks for an empty role and fills it with the default if necessary. Obviously he more code you have, the more possibilities for bugs, so I suggest the first option for default column values.
try:
if (empty($this->data[$this->alias]['role']) && empty($this->role)) {
$this->data[$this->alias]['role'] = 'user';
}

backbone.js not updating id of model object after save, why not?

I have been trying out backbone.js and have been stymied when I create a new model object then call model.save(). I am expecting the backbone.js default behavior to update the model object with the id from the database but it is not. Is this not supposed to happen? I have verified that I am getting a post with the attributes in json format. My server saves the json to a table and then returns the json with a new id field to backbone.js. Is this correct? Should my server return the entire new object or just the id or what?
//contents of the POST from backbone.js
{ "text":"this is a test" }
//reply from my server
{ id:"15", text:"this is a test" }
My sample code is below
var SQLRow = Backbone.Model.extend({
table:"",
urlRoot:'db',
url:function () {
return "/" + this.urlRoot + "?table=" + this.table +
"&id=" + this.attributes.id;
}
});
var Xtra = SQLRow.extend ({
table:'Xtra'
});
var row = new Xtra({
text: "this is a test"
});
alert(row.url());
row.save()
alert("row:" + row.get("id"));
Tough to tell from your post. Two ideas :
1) the response from the server isn't successful What does your save call return ?
2) Your "id" attribute is named something other than ID. To account for the different name add the following to your model :
idAttribute : "MyModelsID",
EDIT
You're likely facing a timing issue, where the alert fires before the ID has returned. Instead of your last two lines try this :
row.save( null,
{
success : function(model, response) { alert(model.get('id'); }
}
);
ALTERNATIVE
As #mu_is_too_short mentioned, another way is to listen for the change even on the model and respond to the event. (i was just trying to keep the answer as close to your code as possible). But something like the following pseudo code should get you started...
var myView = Backbone.View.extend({
....
initialize : function () {
this.collection.bind('change', this.SOME_LISTENING_FUNC );
}
});
OR, if you're in a collection/view-less world something like this creates a listenr ...
row.on('change', function() { /* do stuff */ }, this);
This answer is based on one comment of Cjolly in the answer above.
It is essential for making the Backbone.Model.save([attributes],[options]) successful in assiging the model with the newly generated model's id from the server, that the server returns the model's id in a JSON string like this { "id" : <the id> }. (note it is "id" and not id).
In essence backbone rightly expects a JSON string and in contrast to how objects may be defined in Javascript without quoted keys, JSON requires the object keys to be quoted (see JSON Spec - does the key have to be surrounded with quotes?)
Since according to Cjolly's comment this has been the essential problem, I want to hightlight this solution in an second answer. Partially because I was hit by the very same problem and only by reading througth the comments I was able to receive the insight.
I've faced the same issue and what I've found is that my validate function of the saved model actually invalidates the model returned from the back end. That's why my fields were not updated properly.
Maybe its a little outtimed, but today I had the same missing id.
It turns out, that the server just sends a Header 'Location' with a redirect containing the new id, but dosen't return the persisted object.
Adding the object to the response was the solution.
It seems, that not returning the object is standard behavier with Roo(Spring) generated Json-Controllers.

Is it safe to do query with Model while in Behavior's BeforeSave callback?

I don't see this documented anywhere, so I ask you, my dear Cake-eaters.
Inside a CakePHP's Behavior::BeforeSave(&$Model) method, I read and write changes to $Model->data array. Before I am finished, I need to read some other records from the database. I am worried that, if I use $Model->find(), it will overwrite the current data within the model, which is about to be saved.
Viewing the source code, the Model::find() function clearly resets the Model::$id variable. This is the same variable I later use to check if a field is being updated.
Here's an example:
<?php
class UniqueBehavior extends ModelBehavior {
function beforeSave(&$Model){
$value = $Model->data[$Model->alias]['unique_field'];
$query = array('conditions' => array('unique_field' => $value));
if ($Model->find('first', $query){
// Does $Model::find() reset the internal $Model->data array?
$Model->data[$Model->alias]['unique_field'] = "..."
//... some other code here
}
//ALSO...
if ($Model->exists()) // Returns true if a record with the currently set ID exists.
$slug = $Model->field('slug');
// this should fetch the slug of the currently updated Model::id from the database
// if I do find()'s, can I trust that the record I'm getting is the right one?
}
}
?>
you can always store the current id in $tmp and assign this stored id back to the model after you are finished
$tmp = $Model->id;
// ...
$Model->id = $tmp;
This way you don't run into problems using the Model-id.
If it is save or not depends on how you work in your model.
I - for example - never rely on this id. I always assign the id to the model manually prior to any update or delete call etc. But this is not necessary, of course. You have to be more careful then, though.

how to display the data returned by get_by_user_id() in DataMapper Code Igniter?

I am new to code igniter data mapper. I have a table called user, and I am trying to retrieve data from the database table and show them to the user.
Here is what I have in the model:
$u=new User();
$results=$u->get_by_user_id($id);
//$results here will be set to huge bunch of none sense data( which also includes the row that I am looking for as well)
if ($u->exists())
{
foreach ($results->all as $row){
$data['user']['first_name']=($row->user_first); //this where I am stuck ..
$data['user']['last_name']=($row->user_last);//this is also where I am stuck..
}
I don't know how to treat results to get a required fields I am looking for and store them in the $data I am passing to the user to view.
Thanks!
When you call get_by_x() on the model, the fields will be populated with data and you can access them like this:
$u = new User();
$u->get_by_user_id($id);
if($u->exists())
{
// you can access the table columns as object fields
$data['user']['first'] = $u->first;
$data['user']['last'] = $u->last;
}
else
{
$data['error'] = 'No such user!';
}
Have a look at the documentation which is really helpful: see Get and Get By.
Also, DataMapper expects all tables to have an id column: see Table Naming Rules. If your column is named id you should then call $u->get_by_id($id) instead of $u->get_by_user_id($id).

Resources