4
votes

I have a form with a file upload field in it and I have created a model behaviour file to handle file processing.

I have two functions, beforeSave and afterSave:

In beforeSave I do some stuff and then set the file value in data to null so it can be saved. Else it will try to save an array, and the database expects just a string (the file name)

In afterSave I generate a new file name based on some text fields on the form, and add the lastInsertId infront of it. I also move the file from temp to desired location. This all works fine, but when I try to save the new filename to the Model it just doesnt work.

I have done a lot of test and debugging, and also spent hours searching online. The conclusion is that you can not save in afterSave, it triggers itself and will run beforeSave again.

So my question is, how can I update the newly inserted model? The filename inserted need to have the primary key in its name, and its unknown at time of beforeSave.

grateful for any help! jason

4

4 Answers

16
votes

If you want to bypass all callbacks (afterSave/beforeSave) in the afterSave() itself, I found this syntax working for me :

$this->save($data, array('callbacks'=>false));

To disable the triggers, the manual states indeed that :

The save method also has an alternate syntax:

save(array $data = null, array $params = array()) $params array can have any of the following available options as keys:

array(
     'validate' => true,
     'fieldList' => array(),
     'callbacks' => true //other possible values are false, 'before', 'after' )
6
votes

It can be done this way

// Its your model Image.php
function afterSave($created) {
    if($created) {
         // its new record
         // do your work here
    }
}

Little Tweak (not recommended)

If you want to bypass beforeSave on db operations in afterSave() use $this->Model->query() , instead of $this->Model->save();

// little hack to bypass beforeSave
$this->Model->query('UPDATE listings SET name="xx" WHERE id="1"');
0
votes

Ideally, if your filename is dependent on other columns in the database, then you don't need to resave your model data again. In fact, it would introduce columns in your table's schema that depend on each other, which goes against normalization.

Eg. If your filename is of the form "textfield1-textfield2-yourid.ext", you should store the values of textfield1, textfield2 and ext in the database. Then, in the afterFind() method of your model, you can loop through your results creating the generated filename as a new field in your data array.

Sample Table Schema:

id | textfield1 | textfield2 | extension | created | modified

Sample View Code:

echo $this->Html->image("{$data['Picture']['textfield1']}-{$data['Picture']['textfield2']}-{$data['Picture']['id']}.{$data['Picture']['extension']}");

Of course, like I mentioned earlier, this can be simplified if you override the afterFind() in your model and create a new field called "filename". More on that over here.

This would shorten your code to:

echo $this->Html->image($data['Picture']['filename']);

And would also make it easier to modify universally at any point.

0
votes

Personally, all the file processing should be done in the controller (or component) after you saved your model. I don't think a model should manage file according to MVC design.

In your Controller

// Save model
if ($model->save()) {
    // Save your file
    ...
    // Update the model
    $model->updateField();
} 

$model->save();

Hope this help.