Necessary Core Hacks – Cake1.3

As of now there are some litte adjustments that are either necessary or at least very useful to apply

I keep this list here up to date and will remove or add hacks if something changes (usually the cake team is quite fast in applying appropriate patches).

For me, the very first and most important one for cake1.3 was this:

Disabling the old $helper syntax

Otherwise you gain nothing from the new one ($this->Helper), because the old ones are refererred to them overriding any local variable and totally messing everything up

Example:
$this->Vote->check()
$vote->check()
both work on 1.3 (downwards comp.)
BUT:
If you try to use $vote in any other way (locale variable), it will screw up $this->Vote too (which is our helper).
Lets say we have a controller and model called "votes" and "Vote:

// retrieve all model records
foreach ($votes as $vote) {
    // BAM - big problem! helper $vote AND helper $this->Vote are not usable anymore, neither is $vote as variable
}

The solution: getting rid of the old one altogether

Thats how it’s done – put this into your configs:

$config['Core'] = array(
'disableOldHelperSyntax' => 1
);

And change line 710 of /cake/libs/view/view.php (in the cake core!) from

    ${$name} =& $helper;

to

if (!Configure::read('Core.disableOldHelperSyntax')) {
    ${$name} =& $helper;
}

Any project that does have the above 1 in the "disableOldHelperSyntax" setting will not use the old syntax anymore. The core itself is not modified by it!

// inside a view
foreach ($votes as $vote) {
    echo $this->Vote->calc($vote); // everything is fine now
}

Some could argue: "just use variables that will never be used as helper". But thats crap – maybe some day there is such a helper and your code gets screwed up. So until this backwards comp. is removed this is my answer for that problem. You are now free to use any local variable you want (well, almost anyway).
Ticket: Link

Proper logging feature for debug = 0

Although this is probably the most useful debugging feature ever it didnt quite make it into the core.
We all know that even for debug = 0 there are now log files of errors/warnings etc.
Thats already very helpful if there are any errors occuring in live mode.
But usually it just tells you THAT something went wrong, not WHERE.
This little patch logs the stracktrace of this error to /app/tmp/logs/trace – very adjustable per configs settings

The new "write" function in /cake/libs/log/file_log.php looks like this:

/**
* Implements writing to log files.
*
* @param string $type The type of log you are making.
* @param string $message The message you want to log.
* @return boolean success of write.
*/
function write($type, $message) {
    $debugTypes = array('notice', 'info', 'debug');

    if ($type == 'error' || $type == 'warning') {
        $filename = $this->_path  . 'error.log';
    } elseif (in_array($type, $debugTypes)) {
        $filename = $this->_path . 'debug.log';
    } else {
        $filename = $this->_path . $type . '.log';
    }
    $output = date('Y-m-d H:i:s') . ' ' . ucfirst($type) . ': ' . $message . "\n";
    $log = new File($filename, true);

    /** CORE-MOD for ability to trace logged events - 2010-07-16 ms **/
    $debug = (int)Configure::read('debug');
    if (($debug == 0 && (Configure::read('System.trace') === true || Configure::read('System.trace.prod')) || $debug > 0 && (Configure::read('System.trace') === true || Configure::read('System.trace.dev'))) && ($stackTracing = Configure::read('System.stackTracing'))) {
        $continueTracing = true;
        $path = $this->_path . 'traces' . DS;
        if (!file_exists($path)) {
            if (!mkdir($path, 0777)) {
                // abort; raise notice?
                $continueTracing = false;
            }
        }
        if ($stackTracing !== true) { // log all events otherwise
            $stackTracing = (array)$stackTracing;
            if (!in_array($type, $stackTracing)) {
                // event to log not in list; abort
                $continueTracing = false;
            }
        }
        if ($continueTracing) {
            $trace = new File($path . $type . '_' . time() . '.log', true);

        if (!class_exists('CustomDebugger')) {
                require (LIBS . 'log' . DS . 'custom_debugger.php');
            }
            $CustomDebugger = new CustomDebugger();

            $traceOutput = '';
            $traceOutput = $CustomDebugger->trace();
            $trace->append("Message: '" . $message . "'\n" .
                "Referer: '". env('HTTP_REFERER'). "'\n" .
                "Location: '". env('REDIRECT_URL'). "'\n" .
                "Router::url(): '". Router::url(array(), true). "'\n" .
                "UID: '". (defined('UID')?UID:'---') ."'\n" . // I even log the user who caused this
                $traceOutput . "\n\n"
            , true);
            $trace->close();
        }
    }
    /** CORE-MOD end **/

    if ($log->writable()) {
        return $log->append($output);
    }
}

I did put the cake debugger into the same folder – slightly modified (using "txt" output). You could do the same.

Anyway, the configs could look like this:

$config['System'] = array(
    'stackTracing' => array('debug', 'warning', 'error', 'notice', 'info', '301', 'cacheprob'),
    'trace' => array('dev'=>true, 'prod'=>true),
);

It does only trace the above error types. and you can chose between development and productive environment.
Still place for improvment of course, but I already discovered hundreds of small bugs that I would have never found without it. I would have known that those errors happenened, but actually finding them is usually impossible if the error message is something like "Notice (8): unserialize() [function.unserialize]: Error at offset 11676 of 11722 bytes in [H:…\cake\libs\cache\file.php, line 176]". It is that simple: The core files trigger the error but there is no way to tell which app file actually is responsable if no trace is logged.

Ticket-status on this matter:
cakephp.lighthouseapp.com/projects/42648/tickets/267

Changing default value of Configure::read() to NULL

There is no way to get all the set configure values. So this little tweak makes it possible. It doesnt make sense to use "debug" as default, anyway.

In /cake/libs/configure.php at line 154:

function read($var = null) { // changed default to NULL
    $_this =& Configure::getInstance();

    # fix for retrieving all configure vars (debugging purposes etc) - 2010-09-12 ms
    if ($var === null) {
        return (array)$_this;
    }
    # end fix
    ...

Without passing any parameter it will now return all set config arrays.

Misc

Some pending tickets or things i considered changing (but didn’t do it yet) are located here.

In the model.php, I don’t like "last"=>false as default value (should be true – logically):

$default = array(
    'allowEmpty' => null,
    'required' => null,
    'rule' => 'blank',
    'last' => false,
    'on' => null
);

Ticket: cakephp.lighthouseapp.com/projects/42648-cakephp/tickets/924

Form validation "required" in form helper is not exactly that what you would expect – or want.
Details coming

2 Comments

  1. they would never approve of something like that 🙂
    mainly because the feature-freeze and because they don’t want to add new customization options

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.