I got a few lines of codes in a Model in cakePHP 1.26:
function beforeSave() {
$this->data['User']['pswd'] = md5($raw['User']['pswd']);
return true;
} // this beforeSave() works
The code above has been tested and it is working in my database.
Yet, I am not sure if I can understand it well,
so, I re-wrote the code in other way, and it just failed to work then.
function beforeSave() {
$raw=$this->data;
$raw['User']['pswd'] = md5($raw['User']['pswd']);
return true;
} // this beforeSave() failed to work
Why the second method can not work?
In this line:
$raw=$this->data
You're just assigning $this->data by value to $raw. So when you change $raw's array data, $this->data isn't affected by the change.
Besides, you're totally changing the meaning of your code. What you end up doing is replacing $raw's data with $this->data from your model. I've not worked with CakePHP before, but I assume $raw already contains all the raw data you've received through some kind input, while $this->data in your model contains the older version of your model data (for example, an older password that the user was going to change). Your changed code will just erase all the new data in $raw, which I don't think is what you intend to do judging from your first code example.
To give you a little explanation of this line:
$this->data['User']['pswd'] = md5($raw['User']['pswd']);
It's pretty simple: the pswd item in the User array of $this->data is set as the MD5 checksum of the pswd in the User array of $raw.
if($this->data['Register']['password'] == $this->data['Register']['confirm_password'])
{
return true;
}
else
{
return false;
}
Use this in your model's beforeSave function()
Related
In my AppModel, I have a beforeSave function:
public function beforeSave($options = array()) {
if (!empty($this->data[$this->alias]['created'])) {
$this->data[$this->alias]['created'] = date('Y-m-d G:i:s');
$this->data[$this->alias]['modified'] = $this->data[$this->alias]['created'];
} else {
$this->data[$this->alias]['modified'] = date('Y-m-d G:i:s');
}
$this->data[$this->alias]['modified_by'] = AuthComponent::user('id');
return true;
}
It's a simple function that just records the created and modified dates, and sets a field modified_by to the id of the currently logged in user. Or at least that's what it's supposed to do, everything works except getting the id of the currently logged in user, and I can't figure out why, because as far as I can tell in the documentation, that's exactly how it should be called.
I figured out my issue, and I feel a little dumb because of it, but thought I would add it here in case anyone else runs into the same problem.
In my News model, I was also calling the beforeSave function as well, but I forgot a line in it, namely parent::beforeSave();. How the date stuff in the beforeSave function was working, I don't know, but this fixed my problem of part of the beforeSave function not working.
Thanks for everyone's help in this matter, it's appreciated.
why not grab your user id from
CakeSession::read( 'Auth.User.Id ) ?
I think you should set user id in AppControlle::beforeFiler() method instead of AppModel
$this->data[$this->modelClass]['modified_by'] = $this->Auth->User('id');
I thought this would be a relatively common thing to do, but I can't find examples anywhere, and the Cookbook's section on find() was not clear in the slightest on the subject. Maybe it's just something that's so simple Cake assumes you can just do it on your own.
All I'm looking to do here is retrieve a User's name (not the currently logged-in user…a different one) in Cake based on their ID passed to my by an array in the view.
Here's what I've got in the controller:
public function user_lookup($userID){
$this->User->flatten = false;
$this->User->recursive = 1;
$user = $this->User->find('first', array('conditions' => $userID));
//what now?
}
At this point, I don't even know if I'm on the right track…I assume this will return an array with the User's data, but how do I handle those results? How do I know what the array's gonna look like? Do I just return($cakeArray['first'].' '.$cakeArray['last'])? I dunno…
Help?
You need to use set to take the returned data, and make it accessible as a variable in your views. set is the main way you send data from your controller to your view.
public function user_lookup($userID){
$this->User->flatten = false;
$this->User->recursive = 1;
// added - minor improvement
if(!$this->User->exists($userID)) {
$this->redirect(array('action'=>'some_place'));
// the requested user doesn't exist; redirect or throw a 404 etc.
}
// we use $this->set() to store the data returned.
// It will be accessible in your view in a variable called `user`
// (or what ever you pass as the first parameter)
$this->set('user', $this->User->find('first', array('conditions' => $userID)));
}
// user_lookup.ctp - output the `user`
<?php echo $user['User']['username']; // eg ?>
<?php debug($user); // see what's acutally been returned ?>
more in the manual (this is fundamental cake stuff so might be worth having a good read)
I'm running with cakephp version 2.0.2 and was scratching my head as to why a form submission that submits data to an association of models was not revealing error messages for the associations.
I've been digging into the Model class to diagnose further. I found that if the primary model for the form had its own validation errors, then no validation errors for any associations would ever be revealed in the returned:
$this->validationErrors
But I think I found the smoking gun. In the Model.php's validateAssociated method, you'll see this:
$this->validationErrors = $validationErrors;
if (isset($validationErrors[$this->alias])) {
$this->validationErrors = $validationErrors[$this->alias];
}
The first line sets $this->validationErrors to contain all built up errors across all associations. But if $validationErrors contains errors for the key of $this->alias which is the primary model name, then as you can see, $this->validationErrors gets overwritten to just those errors.
So this begs the question.... why? I'm so certain this is a bug I want to modify my Model.php and I think it'll work. But I wanted to get this in front of others in case I'm doing something really stupid here.
I had the same issue today. Its like that for BC. I know, it sucks. It should be a bug. The way I work around it is by re-formatting validation errors.
// AppModel.php
public function formatValidationErrors($models) {
foreach($models as $model => $assoc) {
if (is_numeric($model)) {
$model = $assoc;
$assoc = null;
}
$this->validationErrors[$model] = $this->{$model}->validationErrors;
if ($assoc) {
$this->{$model}->formatValidationErrors($assoc);
}
}
}
I call that if validation fails, and pass an array like you would do to contain. You can use that if you don't want to modify the core.
I follow in book.cake and I don't know I should send something to the parameters.
function beforeSave() {
if (!empty($this->data['Article']['create_dt']) && !empty($this->data['Article']['modified_dt'])) {
$this->data['Article']['create_dt'] = $this->dateFormatBeforeSave($this->data['Article']['create_dt']);
$this->data['Article']['modified_dt'] = $this->dateFormatBeforeSave($this->data['Article']['modified_dt']);
}
return true;
}
I try to search example but don't found.
I need many example
somebody can help me to find big resource
thank for suggest
beforeSave is called automatically by Cake before it saves data. In it, you can do whatever you want to do before each save. Typically this means altering $this->data, which is the data that is about to be saved.
The method is passed one parameter: an array of the form array('validate' => true/false, ('fieldList' => array(...)). This corresponds to the two extra parameters you can supply to save():
$this->Model->save($this->data, false, array('foo', 'bar'));
In this case the array would look like
array('validate' => false, 'fieldList' => array('foo', 'bar')).
You can accept this array by specifying an argument:
public function beforeSave($options) { ... }
$options will look like described above. You can use this information any way you want.
If you don't return true from beforeSave, the save operation will be canceled altogether.
That's all.
try using created and modified magic fields with datetime type in table cake would automatically handle them
i want to mention, that beforeSave() should be used carefully, because it is used on every time when data is saved with this model.
if you forget that it is used, you will get unexpected results.
Happens to me several times... ;)
If I have a person model with first_name and last_name, how do I create and display a full_name? I would like to display it at the top of my Edit and View views (i.e. "Edit Frank Luke") and other places. Simply dropping echoes to first_name and last_name isn't DRY.
I'm sorry if this is a very simple question, but nothing has yet worked.
Thank you,
Frank Luke
Edit for clarity: Okay, I have a function on the person model.
function full_name() {
return $this->Person->first_name . ' ' . $this->Person->last_name;
}
In the view, I call
echo $person['Person']['full_name']
This gives me a notice that I have an undefined index. What is the proper way to call the function from the view? Do I have to do it in the controller or elsewhere?
If what you are wanting is just to display a full name, and never need to do any database actions (comparisons, lookups), I think you should just concatenate your fields in the view.
This would be more aligned with the MVC design pattern. In your example you just want to view information in your database in a different way.
Since the action of concatenating is simple you probably don't save much code by placing it in a separate function. I think its easiest to do just in the view file.
If you want to do more fancy things ( ie Change the caps, return a link to the user ) I would recommend creating an element which you call with the Users data.
The arrays set by the save() method only return fields in the datbase, they do not call model functions. To properly use the function above (located in your model), you will need to add the following:
to the controller, in the $action method:
$this->set( 'fullname', $this->Person->full_name();
// must have $this-Person->id set, or redefine the method to include $person_id
in the view,
echo $fullname;
Basically, you need to use the controller to gather the data from the model, and assign it to the controller. It's the same process as you have before, where you assign the returned data from the find() call to the variable in the view, except youre getting the data from a different source.
There are multiple ways of doing this. One way is to use the afterFind-function in a model-class.
See: http://book.cakephp.org/view/681/afterFind.
BUT, this function does not handle nested data very well, instead, it doesn't handles it al all!
Therefore I use the afterfind-function in the app_model that walks through the resultset
function afterFind($results, $primary=false){
$name = isset($this->alias) ? $this->alias : $this->name;
// see if the model wants to attach attributes
if (method_exists($this, '_attachAttributes')){
// check if array is not multidimensional by checking the key 'id'
if (isset($results['id'])) {
$results = $this->_attachAttributes($results);
} else {
// we want each row to have an array of required attributes
for ($i = 0; $i < sizeof($results); $i++) {
// check if this is a model, or if it is an array of models
if (isset($results[$i][$name]) ){
// this is the model we want, see if it's a single or array
if (isset($results[$i][$name][0]) ){
// run on every model
for ($j = 0; $j < sizeof($results[$i][$name]); $j++) {
$results[$i][$name][$j] = $this->_attachAttributes($results[$i][$name][$j]);
}
} else {
$results[$i][$name] = $this->_attachAttributes($results[$i][$name]);
}
} else {
if (isset($results[$i]['id'])) {
$results[$i] = $this->_attachAttributes($results[$i]);
}
}
}
}
}
return $results;
}
And then I add a _attachAttributes-function in the model-class, for e.g. in your Person.php
function _attachAttributes($data) {
if (isset($data['first_name']) && isset($data['last_name'])) {
$data['full_name'] = sprintf("%s %s %s", $data['first_name'], $data['last_name']);
}
return $data;
}
This method can handle nested modelData, for e.g. Person hasMany Posts then this method can also attachAttributes inside the Post-model.
This method also keeps in mind that the linked models with other names than the className are fixed, because of the use of the alias and not only the name (which is the className).
You must use afterFind callback for it.
You would probably need to take the two fields that are returned from your database and concatenate them into one string variable that can then be displayed.
http://old.nabble.com/Problems-with-CONCAT-function-td22640199.html
http://teknoid.wordpress.com/2008/09/29/dealing-with-calculated-fields-in-cakephps-find/
Read the first one to find out how to use the 'fields' key i.e. find( 'all', array( 'fields' => array( )) to pass a CONCAT to the CakePHP query builder.
The second link shows you how to merge the numeric indexes that get returned when you use custom fields back into the appropriate location in the returned results.
This should of course be placed in a model function and called from there.