phpcakephpcallbacksaveafter-save

Cakephp Callback function called multiple times


first some background information:

A user can fill out some input text boxes and upload multiple images (in one upload field). After the form is submitted, the text from the text fields is saved in the DB with $this->XXX->save(). Additionally the data (in particular the images from the file upload) is processed in the callback function afterSave(). So far so good.

Now to the problem:

It seems that the callback function is called multiple times (1 time for each uploaded image). So the problem is, the first time is everything fine, but after that the $this->data array is basically empty (all text fields are = '') so the callback function throws some exceptions because there is no data. I solved the problem by just checking with isset() and so on but I think that is not solving the problem.

So my question is, why is the callback function called multiple times and how can I prevent that?

Edit: Following some relevant code snippets:

Controller:

      if ($this->request->is('post') || $this->request->is('put')) {

        if($aid==null) $this->Article->create();
        if ($this->Article->save($this->data)) {
            $this->Session->setFlash(__('The article has been saved'), 'flash_custom');
            return $this->redirect(array('controller' => 'articles', 'action' => 'view', $this->id));
        } ...

Model:

I think most of that is not relevant here.. In general I send data to other Models where this data is saved in other db tables like this for pictures

 if ($this->data['Article']['picture']) {
   foreach ($this->data['Article']['picture'] as $picture) {
       if (is_uploaded_file($picture['tmp_name']) && (substr($picture['type'], 0, 5) == "image") && $numberOfPictures < $pictures_allowed) {
           $this->Picture->addPicture($picture, $this->id);
       }
       $numberOfPictures++;
   }

Error Dump:

I think a Dump of the $this->data array is quite interesting here (explanation below)

array(
'Article' => array(
    'pictures' => '0',
    'title' => 'Error Test',
    'abstract' => 'Test abstract',
    'body' => 'Testtext',
    'picture' => array(
        (int) 0 => array(
            [maximum depth reached]
        ),
        (int) 1 => array(
            [maximum depth reached]
        ),
        (int) 2 => array(
            [maximum depth reached]
        )
    ),
    'modified' => '2015-04-13 22:00:09',
    'created' => '2015-04-13 22:00:09',
    'id' => '294'
))


Notice (8): Undefined index: title [APP/Model/Article.php, line 723]
Notice (8): Undefined index: body [APP/Model/Article.php, line 724]
Notice (8): Undefined index: abstract [APP/Model/Article.php, line 725]

array(
    'Article' => array(
        'id' => '294',
        'pictures' => (int) 1,
        'modified' => '2015-04-13 22:00:09',
        'title' => '',
        'body' => '',
        'abstract' => '',
    )
)

Notice (8): Undefined index: picture [APP/Model/Article.php, line 777]

Notice (8): Undefined index: title [APP/Model/Article.php, line 723]

Notice (8): Undefined index: body [APP/Model/Article.php, line 724]

Notice (8): Undefined index: abstract [APP/Model/Article.php, line 725]

array(
    'Article' => array(
        'id' => '294',
        'pictures' => (int) 2,
        'modified' => '2015-04-13 22:00:10',
        'title' => '',
        'body' => '',
        'abstract' => '',
    )
)

Notice (8): Undefined index: picture [APP/Model/Article.php, line 777]

Notice (8): Undefined index: title [APP/Model/Article.php, line 723]

Notice (8): Undefined index: body [APP/Model/Article.php, line 724]

Notice (8): Undefined index: abstract [APP/Model/Article.php, line 725]

array(
    'Article' => array(
        'id' => '294',
        'pictures' => (int) 3,
        'modified' => '2015-04-13 22:00:10',
        'title' => '',
        'body' => '',
        'abstract' => '',
    )
)

Notice (8): Undefined index: picture [APP/Model/Article.php, line 777]

Explanation:

I just dumped $this->data once but like you see I've uploaded 3 pictures and I got 3 afterSave calls and so 3 $this->data dumps. The first time everything is fine, but after that some warnings are thrown because the array is not filled anymore.

I hope this additional information may help you


Solution

  • If you're calling Model::save via the aftersave callback for the same model, then it will be a recursively saving, as the aftersave will call the save, which will trigger the aftersave again..

    Disable callbacks in save method you're using in the aftersave

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

    Documentation