0

What I'm trying to do:

I want to install the LogableBehavior by Alkemann in Cakephp.

The error I get:

When I want to make an edit, an error is returned:

Error:

Notice (8): Undefined variable: logData [APP\Model\Behavior\LogableBehavior.php, line 431]

Context given in standard cakephp error:

LogableBehavior::afterSave() - APP\Model\Behavior\LogableBehavior.php, line 431 ObjectCollection::trigger() - CORE\Cake\Utility\ObjectCollection.php, line 130 call_user_func - [internal], line ?? CakeEventManager::dispatch() - CORE\Cake\Event\CakeEventManager.php, line 246 Model::save() - CORE\Cake\Model\Model.php, line 1755 Model::saveField() - CORE\Cake\Model\Model.php, line 1582 ChantiersController::inPlaceDateUpdate() - APP\Controller\ChantiersController.php, line 370 ReflectionMethod::invokeArgs() - [internal], line ?? Controller::invokeAction() - CORE\Cake\Controller\Controller.php, line 485 Dispatcher::_invoke() - CORE\Cake\Routing\Dispatcher.php, line 186 Dispatcher::dispatch() - CORE\Cake\Routing\Dispatcher.php, line 161 [main] - APP\webroot\index.php, line 92

Code given in standard cakephp error:

$Model = object(Chantier) {}
$created = false
  $keys = array(
      (int) 0 => 'id',
      (int) 1 => 'Date_de_debut_MOA',
      (int) 2 => 'modified'
)
$diff = array(
    (int) 1 => 'Date_de_debut_MOA',
    (int) 2 => 'modified'
)
$id = '126'

What I tried to do:

I checked that all the installation steps where properly done, according to the docs there are three:

    Requires the following to work as intended :
 * 
 * - "Log" model ( empty but for a order variable [created DESC]
 * - "logs" table with these fields required :
 *     - id         [int]           : 
 *     - title      [string]        : automagically filled with the display field of the model that was modified.
 *     - created    [date/datetime] : filled by cake in normal way
 * 
 * - actsAs = array("Logable"); on models that should be logged

It seems to me I did everything fine:

my logs table

    CREATE TABLE IF NOT EXISTS `logs` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `title` varchar(100) NOT NULL,
  `created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `description` varchar(400) NOT NULL,
  PRIMARY KEY (`id`)
  ) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=45 ;

My Log Model:

   <?php
App::uses('AppModel', 'Model');
class Log extends AppModel {
var $order=array("Log.created"=>"DESC");

}

And in App/Model/Chantier:

var $actsAs = array('Containable','Logable');

Then I search for people having a similar issue:

Found nothing.

Let's dive in the code:

Here is the code.

The error talks of an error line 431:

        $this->_saveLog($Model, $logData); //line 431

It seems that $logData has not been declared.

This line is in a function, afterSave(&$Model,$created):

This function is serie of test, where line 431 is called a the very end. There are numerous declarations of $logData, but always nested in a if statement.

function afterSave(&$Model,$created) {
        
        if (isset($this->settings[$Model->alias]['skip']['add']) && $this->settings[$Model->alias]['skip']['add'] && $created) {
            return true;
        } elseif (isset($this->settings[$Model->alias]['skip']['edit']) && $this->settings[$Model->alias]['skip']['edit'] && !$created) {
            return true;
        }
        $keys = array_keys($Model->data[$Model->alias]);
        $diff = array_diff($keys,$this->settings[$Model->alias]['ignore']);
        if (sizeof($diff) == 0 && empty($Model->logableAction)) {
            return false;
        }
        if ($Model->id) {
            $id = $Model->id;
        } elseif ($Model->insertId) {
            $id = $Model->insertId;
        }       
        if (isset($this->Log->_schema[$this->settings[$Model->alias]['foreignKey']])) {
            $logData['Log'][$this->settings[$Model->alias]['foreignKey']] = $id;
        }
        if (isset($this->Log->_schema['description'])) {        
            $logData['Log']['description'] = $Model->alias.' ';
            if (isset($Model->data[$Model->alias][$Model->displayField]) && $Model->displayField != $Model->primaryKey) {
                $logData['Log']['description'] .= '"'.$Model->data[$Model->alias][$Model->displayField].'" ';
            }

            if ($this->settings[$Model->alias]['description_ids']) {
                $logData['Log']['description'] .= '('.$id.') ';
            }

            if ($created) {
                $logData['Log']['description'] .= __('added',TRUE);
            } else {
                $logData['Log']['description'] .= __('updated',TRUE);   
            }  
        }     
        if (isset($this->Log->_schema['action'])) {                 
            if ($created) {
                $logData['Log']['action'] = 'add';
            } else { 
                $logData['Log']['action'] = 'edit';         
            }  

        }
        if (isset($this->Log->_schema['change'])) {
            $logData['Log']['change'] = '';
            $db_fields = array_keys($Model->_schema);
            $changed_fields = array();
            foreach ($Model->data[$Model->alias] as $key => $value) {
                if (isset($Model->data[$Model->alias][$Model->primaryKey]) && !empty($this->old) && isset($this->old[$Model->alias][$key])) {
                    $old = $this->old[$Model->alias][$key];
                } else {
                    $old = '';
                }
                if ($key != 'modified' 
                    && !in_array($key, $this->settings[$Model->alias]['ignore'])
                    && $value != $old && in_array($key,$db_fields) ) 
                    {
                        if ($this->settings[$Model->alias]['change'] == 'full') {
                            $changed_fields[] = $key . ' ('.$old.') => ('.$value.')';
                        } else if ($this->settings[$Model->alias]['change'] == 'serialize') {
                            $changed_fields[$key] =  array('old'=>$old, 'value'=>$value);
                        } else {
                            $changed_fields[] = $key;   
                        }                   
                    }
            }
            $changes = sizeof($changed_fields);
            if ($changes == 0) {
                return true;
            } 
            if ($this->settings[$Model->alias]['change'] == 'serialize') {
                $logData['Log']['change'] = serialize($changed_fields);
            } else {
                $logData['Log']['change'] = implode(', ',$changed_fields);
            }
            $logData['Log']['changes'] = $changes;      
        }  
        $this->_saveLog($Model, $logData);//line 431
    }

My question:

Ideally I would like some advice from someone knowing this Behabior on how to fix the error, but any general method on how to debug it would be gladly accepted.

Edit: I use Cakephp 2.2.0

Community
  • 1
  • 1
L. Sanna
  • 6,482
  • 7
  • 33
  • 47
  • what cake version are you using? you shouls always(!) specify that in your question. – mark Aug 17 '12 at 09:05

2 Answers2

1

you seem to use a very very old version of it. it has been improved greatly since then. if you are using cake2.x here is a working one that should be up to date (and all test cases pass): https://github.com/dereuromark/tools/blob/2.0/Model/Behavior/LogableBehavior.php

it uses an own log table/model. but other than that it should be pretty straight forward. the sql for the logs table is in Config / sql / log.sql but should probably be the same as yours.

mark
  • 21,691
  • 3
  • 49
  • 71
  • I installed your plugin, but I get: Error: Unsupported operand types File: C:\wamp\www\cakephp\lib\Cake\Core\CakePlugin.php Line: 77 – L. Sanna Aug 17 '12 at 09:33
  • did you load the plugin "Tools" with CakePlugin::load()? and put the file in /Plugin/Tools/Model/Behavior as well as the model in /Plugin/Tools/Model/ ? if you wish to use it without plugin scope you could remove all plugin dependencies and run it stand-alone (if you know what you are doing that is). – mark Aug 17 '12 at 09:36
  • I did. I thought it would be quicker to run it as a plugin, but I'm going to extract the behavior. – L. Sanna Aug 17 '12 at 09:41
  • well, it should be quicker using it as a plugin. not sure what your problem is there. I think your CakePlugin call is wrong! it is supposed to be just CakePlugin::loadAll() or CakePlugin::load('Tools') – mark Aug 17 '12 at 09:54
  • Thanks for your help. I did make it work as a stand-alone, I still don't know why it failed with the plugin. – L. Sanna Aug 17 '12 at 09:59
  • as I said, your CakePlugin call was invalid (but that should have been clear from the error message in combination with a quick look into the source code^^). – mark Aug 17 '12 at 10:02
0

Well this is a minor flaw that you could adress to the makers of the script.

The quick fix, to prevent the notice would be by adding the the following just before line 431 :

<?php     
     $logData = (!isset($logData) ? array() : $logData );
     $this->_saveLog($Model, $logData);
?>

OR add $logData just after function declaration like this :

<?php
    function afterSave(&$Model,$created) {
        $logData = array();

Keep in mind that Notices in general are not visible on live websites, but it is good practice to fix them : Stackoverflow answer

Community
  • 1
  • 1
DonSeba
  • 2,098
  • 2
  • 16
  • 25
  • It would suppress the error. But probably the data too! I will check and come back to you. – L. Sanna Aug 17 '12 at 08:58
  • This will surpress the error : $logData = (!isset($logData) ? array() : $logData ); what it does is the following : check if $logData exists if not then create it. if $logdata already exists then it will be assigned and used again – DonSeba Aug 17 '12 at 09:00
  • Yes. It does suppress the error, but as the object sent is empty, the function does nothing. – L. Sanna Aug 17 '12 at 09:00
  • What do you expect the function to do ? – DonSeba Aug 17 '12 at 09:03
  • The saveLog() function creates a row in the logs table and fill it with the $logData. If I pass an empty object as an argument, it's completely useless. – L. Sanna Aug 17 '12 at 09:05
  • If thats the case, the problem resides somewhere else... logdata was never set, this only surpresses the error. so that is fixed. – DonSeba Aug 17 '12 at 09:10