git-svn-id: file:///svn-source/pmgr/branches/surplus_account_20090815@590 97e9348a-65ac-dc4b-aefc-98561f571b83
492 lines
16 KiB
PHP
492 lines
16 KiB
PHP
<?php
|
|
/* SVN FILE: $Id: app_model.php 7945 2008-12-19 02:16:01Z gwoo $ */
|
|
|
|
/**
|
|
* Application model for Cake.
|
|
*
|
|
* This file is application-wide model file. You can put all
|
|
* application-wide model-related methods here.
|
|
*
|
|
* PHP versions 4 and 5
|
|
*
|
|
* CakePHP(tm) : Rapid Development Framework (http://www.cakephp.org)
|
|
* Copyright 2005-2008, Cake Software Foundation, Inc. (http://www.cakefoundation.org)
|
|
*
|
|
* Licensed under The MIT License
|
|
* Redistributions of files must retain the above copyright notice.
|
|
*
|
|
* @filesource
|
|
* @copyright Copyright 2005-2008, Cake Software Foundation, Inc. (http://www.cakefoundation.org)
|
|
* @link http://www.cakefoundation.org/projects/info/cakephp CakePHP(tm) Project
|
|
* @package cake
|
|
* @subpackage cake.app
|
|
* @since CakePHP(tm) v 0.2.9
|
|
* @version $Revision: 7945 $
|
|
* @modifiedby $LastChangedBy: gwoo $
|
|
* @lastmodified $Date: 2008-12-18 18:16:01 -0800 (Thu, 18 Dec 2008) $
|
|
* @license http://www.opensource.org/licenses/mit-license.php The MIT License
|
|
*/
|
|
|
|
/**
|
|
* Application model for Cake.
|
|
*
|
|
* Add your application-wide methods in the class below, your models
|
|
* will inherit them.
|
|
*
|
|
* @package cake
|
|
* @subpackage cake.app
|
|
*/
|
|
class AppModel extends Model {
|
|
|
|
var $actsAs = array('Containable', 'Linkable');
|
|
var $useNullForEmpty = true;
|
|
var $formatDateFields = true;
|
|
|
|
// Default Log Level, if not specified at the function level
|
|
var $default_log_level = 5;
|
|
|
|
// Class specific log levels
|
|
var $class_log_level = array('Model' => 5);
|
|
|
|
// Function specific log levels
|
|
var $function_log_level = array();
|
|
|
|
// Force the module to log at LEAST at this level
|
|
var $min_log_level;
|
|
|
|
// Force logging of nothing higher than this level
|
|
var $max_log_level;
|
|
|
|
|
|
// REVISIT <AP>: 20090730
|
|
// Why is this constructor crashing?
|
|
// Clearly it's in some sort of infinite
|
|
// loop, but it seems the correct way
|
|
// to have a constructor call the parent...
|
|
|
|
/* function __construct() { */
|
|
/* parent::__construct(); */
|
|
/* $this->prClassLevel(5, 'Model'); */
|
|
/* } */
|
|
|
|
/**************************************************************************
|
|
**************************************************************************
|
|
**************************************************************************
|
|
* function: pr
|
|
* - Prints out debug information, if the log level allows
|
|
*/
|
|
|
|
function prClassLevel($level, $class = null) {
|
|
$trace = debug_backtrace(false);
|
|
$caller = array_shift($trace);
|
|
$caller = array_shift($trace);
|
|
if (empty($class))
|
|
$class = $caller['class'];
|
|
$this->class_log_level[$class] = $level;
|
|
}
|
|
|
|
function prFunctionLevel($level, $function = null, $class = null) {
|
|
$trace = debug_backtrace(false);
|
|
$caller = array_shift($trace);
|
|
$caller = array_shift($trace);
|
|
if (empty($class))
|
|
$class = $caller['class'];
|
|
if (empty($function))
|
|
$function = $caller['function'];
|
|
$this->function_log_level["{$class}-{$function}"] = $level;
|
|
}
|
|
|
|
function _pr($level, $mixed, $checkpoint = null) {
|
|
if (Configure::read() <= 0)
|
|
return;
|
|
|
|
$log_level = $this->default_log_level;
|
|
|
|
$trace = debug_backtrace(false);
|
|
|
|
// Get rid of pr/prEnter/prReturn
|
|
$caller = array_shift($trace);
|
|
|
|
// The next entry shows where pr was called from, but it
|
|
// shows _what_ was called, which is pr/prEntry/prReturn.
|
|
$caller = array_shift($trace);
|
|
$file = $caller['file'];
|
|
$line = $caller['line'];
|
|
|
|
// So, this caller holds the calling function name
|
|
$caller = $trace[0];
|
|
$function = $caller['function'];
|
|
$class = $caller['class'];
|
|
//$class = $this->name;
|
|
|
|
// Use class or function specific log level if available
|
|
if (isset($this->class_log_level[$class]))
|
|
$log_level = $this->class_log_level[$class];
|
|
if (isset($this->function_log_level["{$class}-{$function}"]))
|
|
$log_level = $this->function_log_level["{$class}-{$function}"];
|
|
|
|
// Establish log level minimums
|
|
$min_log_level = $this->min_log_level;
|
|
if (is_array($this->min_log_level)) {
|
|
$min_show_level = $min_log_level['show'];
|
|
$min_log_level = $min_log_level['log'];
|
|
}
|
|
|
|
// Establish log level maximums
|
|
$max_log_level = $this->max_log_level;
|
|
if (is_array($this->max_log_level)) {
|
|
$max_show_level = $max_log_level['show'];
|
|
$max_log_level = $max_log_level['log'];
|
|
}
|
|
|
|
// Determine the applicable log and show levels
|
|
if (is_array($log_level)) {
|
|
$show_level = $log_level['show'];
|
|
$log_level = $log_level['log'];
|
|
}
|
|
|
|
// Adjust log level up/down to min/max
|
|
if (isset($min_log_level))
|
|
$log_level = max($log_level, $min_log_level);
|
|
if (isset($max_log_level))
|
|
$log_level = min($log_level, $max_log_level);
|
|
|
|
// Adjust show level up/down to min/max
|
|
if (isset($min_show_level))
|
|
$show_level = max($show_level, $min_show_level);
|
|
if (isset($max_show_level))
|
|
$show_level = min($show_level, $max_show_level);
|
|
|
|
// If the level is insufficient, bail out
|
|
if ($level > $log_level)
|
|
return;
|
|
|
|
if (!empty($checkpoint)) {
|
|
$chk = array("checkpoint" => $checkpoint);
|
|
if (is_array($mixed))
|
|
$mixed = $chk + $mixed;
|
|
else
|
|
$mixed = $chk + array($mixed);
|
|
}
|
|
|
|
static $pr_unique_number = 0;
|
|
$pr_id = 'pr-section-class-' . $class . '-print-' . (++$pr_unique_number);
|
|
$pr_trace_id = $pr_id . '-trace';
|
|
$pr_output_id = $pr_id . '-output';
|
|
|
|
$pr_entire_base_class = "pr-section";
|
|
$pr_entire_class_class = $pr_entire_base_class . '-class-' . $class;
|
|
$pr_entire_function_class = $pr_entire_class_class . '-function-' . $function;
|
|
$pr_entire_class = "$pr_entire_base_class $pr_entire_class_class $pr_entire_function_class";
|
|
$pr_header_class = "pr-caller";
|
|
$pr_trace_class = "pr-trace";
|
|
$pr_output_base_class = 'pr-output';
|
|
$pr_output_class_class = $pr_output_base_class . '-class-' . $class;
|
|
$pr_output_function_class = $pr_output_class_class . '-function-' . $function;
|
|
$pr_output_class = "$pr_output_base_class $pr_output_class_class $pr_output_function_class";
|
|
|
|
echo '<DIV class="'.$pr_entire_class.'" id="'.$pr_id.'">'."\n";
|
|
echo '<DIV class="'.$pr_header_class.'">'."\n";
|
|
echo '<DIV class="'.$pr_trace_class.'" id="'.$pr_trace_id.'" style="display:none;">'."\n";
|
|
echo '<HR />' . "\n";
|
|
|
|
// Flip trace around so the sequence flows from top to bottom
|
|
// Then print out the entire stack trace (in hidden div)
|
|
$trace = array_reverse($trace);
|
|
for ($i = 0; $i < count($trace); ++$i) {
|
|
$bline = $trace[$i]['line'];
|
|
$bfile = $trace[$i]['file'];
|
|
$bfile = str_replace(ROOT.DS, '', $bfile);
|
|
$bfile = str_replace(CAKE_CORE_INCLUDE_PATH.DS, '', $bfile);
|
|
|
|
if ($i > 0) {
|
|
$bfunc = $trace[$i-1]['function'];
|
|
$bclas = $trace[$i-1]['class'];
|
|
} else {
|
|
$bfunc = null;
|
|
$bclas = null;
|
|
}
|
|
|
|
echo("$bfile:$bline (" . ($bclas ? "$bclas::$bfunc" : "entry point") . ")<BR>\n");
|
|
//echo(($bclas ? "$bclas::$bfunc" : "entry point") . "; $bfile : $bline<BR>\n");
|
|
}
|
|
echo '</DIV>' . "\n"; // End pr_trace_class
|
|
$file = str_replace(ROOT.DS, '', $file);
|
|
$file = str_replace(CAKE_CORE_INCLUDE_PATH.DS, '', $file);
|
|
|
|
echo "<strong>$file:$line ($class::$function)</strong>" . ";\n";
|
|
/* $log_show_level = isset($show_level) ? $show_level : '?'; */
|
|
/* echo ' L' . $level . "({$log_level}/{$log_show_level})" . ";\n"; */
|
|
echo ' L' . $level . ";\n";
|
|
echo ' <A HREF="#" onclick="$' . "('#{$pr_trace_id}').slideToggle(); return false;" . '">stack</A>'.";\n";
|
|
|
|
echo " this ";
|
|
echo '<A HREF="#" onclick="$' . "('#{$pr_output_id}').slideToggle(); return false;" . '">t</A>'."/";
|
|
echo '<A HREF="#" onclick="$' . "('#{$pr_id}').hide(); return false;" . '">n</A>'.";\n";
|
|
|
|
echo " $class ";
|
|
echo '<A HREF="#" onclick="$' . "('.{$pr_output_class_class}').slideDown(); return false;" . '">s</A>'."/";
|
|
echo '<A HREF="#" onclick="$' . "('.{$pr_output_class_class}').slideUp(); return false;" . '">h</A>'."/";
|
|
echo '<A HREF="#" onclick="$' . "('.{$pr_entire_class_class}').hide(); return false;" . '">n</A>'.";\n";
|
|
|
|
echo " $function ";
|
|
echo '<A HREF="#" onclick="$' . "('.{$pr_output_function_class}').slideDown(); return false;" . '">s</A>'."/";
|
|
echo '<A HREF="#" onclick="$' . "('.{$pr_output_function_class}').slideUp(); return false;" . '">h</A>'."/";
|
|
echo '<A HREF="#" onclick="$' . "('.{$pr_entire_function_class}').hide(); return false;" . '">n</A>'.";\n";
|
|
|
|
echo " all ";
|
|
echo '<A HREF="#" onclick="$' . "('.{$pr_output_base_class}').show(); return false;" . '">s</A>'."/";
|
|
echo '<A HREF="#" onclick="$' . "('.{$pr_output_base_class}').hide(); return false;" . '">h</A>'."/";
|
|
echo '<A HREF="#" onclick="$' . "('.{$pr_entire_base_class}').hide(); return false;" . '">n</A>'."\n";
|
|
|
|
echo '</DIV>' . "\n"; // End pr_header_class
|
|
|
|
if (isset($show_level) && $level > $show_level)
|
|
$display = 'none';
|
|
else
|
|
$display = 'block';
|
|
|
|
echo '<DIV class="'.$pr_output_class.'" id="'.$pr_output_id.'" style="display:'.$display.';">'."\n";
|
|
pr($mixed, false, false);
|
|
echo '</DIV>' . "\n"; // End pr_output_class
|
|
echo '</DIV>' . "\n"; // End pr_entire_class
|
|
}
|
|
|
|
function pr($level, $mixed, $checkpoint = null) {
|
|
$this->_pr($level, $mixed, $checkpoint);
|
|
}
|
|
|
|
function prEnter($args, $level = 15) {
|
|
$this->_pr($level, $args, 'Function Entry');
|
|
}
|
|
|
|
function prReturn($retval, $level = 16) {
|
|
$this->_pr($level, $retval, 'Function Return');
|
|
return $retval;
|
|
}
|
|
|
|
|
|
/**************************************************************************
|
|
**************************************************************************
|
|
**************************************************************************
|
|
* function: queryInit
|
|
* - Initializes the query fields
|
|
*/
|
|
function prDump($all = false) {
|
|
$vars = get_object_vars($this);
|
|
foreach (array_keys($vars) AS $name) {
|
|
if (preg_match("/^[A-Z]/", $name))
|
|
unset($vars[$name]);
|
|
if (preg_match("/^_/", $name) && !$all)
|
|
unset($vars[$name]);
|
|
}
|
|
pr($vars);
|
|
}
|
|
|
|
|
|
/**
|
|
* Get Enum Values
|
|
* Snippet v0.1.3
|
|
* http://cakeforge.org/snippet/detail.php?type=snippet&id=112
|
|
*
|
|
* Gets the enum values for MySQL 4 and 5 to use in selectTag()
|
|
*/
|
|
function getEnumValues($columnName=null, $tableName=null)
|
|
{
|
|
if ($columnName==null) { return array(); } //no field specified
|
|
|
|
if (!isset($tableName)) {
|
|
//Get the name of the table
|
|
$db =& ConnectionManager::getDataSource($this->useDbConfig);
|
|
$tableName = $db->fullTableName($this, false);
|
|
}
|
|
|
|
//Get the values for the specified column (database and version specific, needs testing)
|
|
$result = $this->query("SHOW COLUMNS FROM {$tableName} LIKE '{$columnName}'");
|
|
|
|
//figure out where in the result our Types are (this varies between mysql versions)
|
|
$types = null;
|
|
if ( isset( $result[0]['COLUMNS']['Type'] ) ) { //MySQL 5
|
|
$types = $result[0]['COLUMNS']['Type']; $default = $result[0]['COLUMNS']['Default'];
|
|
}
|
|
elseif ( isset( $result[0][0]['Type'] ) ) { //MySQL 4
|
|
$types = $result[0][0]['Type']; $default = $result[0][0]['Default'];
|
|
}
|
|
else { //types return not accounted for
|
|
return array();
|
|
}
|
|
|
|
//Get the values
|
|
return array_flip(array_merge(array(''), // MySQL sets 0 to be the empty string
|
|
explode("','", strtoupper(preg_replace("/(enum)\('(.+?)'\)/","\\2", $types)))
|
|
));
|
|
} //end getEnumValues
|
|
|
|
|
|
/**************************************************************************
|
|
**************************************************************************
|
|
**************************************************************************
|
|
* function: queryInit
|
|
* - Initializes the query fields
|
|
*/
|
|
function queryInit(&$query, $link = true) {
|
|
if (!isset($query))
|
|
$query = array();
|
|
if (!isset($query['conditions']))
|
|
$query['conditions'] = array();
|
|
if (!isset($query['group']))
|
|
$query['group'] = null;
|
|
if (!isset($query['fields']))
|
|
$query['fields'] = null;
|
|
if ($link && !isset($query['link']))
|
|
$query['link'] = array();
|
|
if (!$link && !isset($query['contain']))
|
|
$query['contain'] = array();
|
|
|
|
// In case caller expects query to come back
|
|
return $query;
|
|
}
|
|
|
|
|
|
/**************************************************************************
|
|
**************************************************************************
|
|
**************************************************************************
|
|
* function: nameToID
|
|
* - Returns the ID of the named item
|
|
*/
|
|
function nameToID($name) {
|
|
$this->cacheQueries = true;
|
|
$item = $this->find('first', array
|
|
('recursive' => -1,
|
|
'conditions' => compact('name'),
|
|
));
|
|
$this->cacheQueries = false;
|
|
if ($item) {
|
|
$item = current($item);
|
|
return $item['id'];
|
|
}
|
|
return null;
|
|
}
|
|
|
|
|
|
/**************************************************************************
|
|
**************************************************************************
|
|
**************************************************************************
|
|
* function: statMerge
|
|
* - Merges summary data from $b into $a
|
|
*/
|
|
|
|
function statsMerge (&$a, $b) {
|
|
if (!isset($b))
|
|
return;
|
|
|
|
if (!isset($a)) {
|
|
$a = $b;
|
|
}
|
|
elseif (!is_array($a) && !is_array($b)) {
|
|
$a += $b;
|
|
}
|
|
elseif (is_array($a) && is_array($b)) {
|
|
foreach (array_intersect_key($a, $b) AS $k => $v)
|
|
{
|
|
if (preg_match("/^sp\./", $k))
|
|
$a[$k] .= '; ' . $b[$k];
|
|
else
|
|
$this->statsMerge($a[$k], $b[$k]);
|
|
}
|
|
$a = array_merge($a, array_diff_key($b, $a));
|
|
}
|
|
else {
|
|
die ("Can't yet merge array and non-array stats");
|
|
}
|
|
}
|
|
|
|
|
|
function filter_null($array) {
|
|
return array_diff_key($array, array_filter($array, 'is_null'));
|
|
}
|
|
|
|
function recursive_array_replace($find, $replace, &$data) {
|
|
if (!isset($data))
|
|
return;
|
|
|
|
if (is_array($data)) {
|
|
foreach ($data as $key => &$value) {
|
|
$this->recursive_array_replace($find, $replace, $value);
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (isset($replace))
|
|
$data = preg_replace($find, $replace, $data);
|
|
elseif (preg_match($find, $data))
|
|
$data = null;
|
|
}
|
|
|
|
function beforeSave() {
|
|
/* pr(array('class' => $this->name, */
|
|
/* 'alias' => $this->alias, */
|
|
/* 'function' => 'AppModel::beforeSave')); */
|
|
|
|
// Replace all empty strings with NULL.
|
|
// If a particular model doesn't like this, they'll have to
|
|
// override the behavior, or set useNullForEmpty to false.
|
|
if ($this->useNullForEmpty)
|
|
$this->recursive_array_replace("/^\s*$/", null, $this->data);
|
|
|
|
if ($this->formatDateFields) {
|
|
$alias = $this->alias;
|
|
|
|
foreach ($this->_schema AS $field => $info) {
|
|
if ($info['type'] == 'date' || $info['type'] == 'timestamp') {
|
|
if (isset($this->data[$alias][$field])) {
|
|
/* pr("Fix Date for '$alias'.'$field'; current value = " . */
|
|
/* "'{$this->data[$alias][$field]}'"); */
|
|
if ($this->data[$alias][$field] === 'CURRENT_TIMESTAMP')
|
|
// Seems CakePHP is broken for the default timestamp.
|
|
// It tries to automagically set the value to CURRENT_TIMESTAMP
|
|
// which is wholly rejected by MySQL. Just put it back to NULL
|
|
// and let the SQL engine deal with the defaults... it's not
|
|
// Cake's place to do this anyway :-/
|
|
$this->data[$alias][$field] = null;
|
|
else
|
|
$this->data[$alias][$field] =
|
|
$this->dateFormatBeforeSave($this->data[$alias][$field]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**************************************************************************
|
|
**************************************************************************
|
|
**************************************************************************
|
|
* function: dateFormatBeforeSave
|
|
* - convert dates to database format
|
|
*/
|
|
|
|
function dateFormatBeforeSave($dateString) {
|
|
/* $time = ''; */
|
|
/* if (preg_match('/(\d+(:\d+))/', $dateString, $match)) */
|
|
/* $time = ' '.$match[1]; */
|
|
/* $dateString = preg_replace('/(\d+(:\d+))/', '', $dateString); */
|
|
/* return date('Y-m-d', strtotime($dateString)) . $time; */
|
|
|
|
if (preg_match('/:/', $dateString))
|
|
return date('Y-m-d H:i:s', strtotime($dateString));
|
|
else
|
|
return date('Y-m-d', strtotime($dateString));
|
|
}
|
|
|
|
function INTERNAL_ERROR($msg, $depth = 0) {
|
|
INTERNAL_ERROR($msg, false, $depth+1);
|
|
echo $this->requestAction(array('controller' => 'accounts',
|
|
'action' => 'render_empty'),
|
|
array('return', 'bare' => false)
|
|
);
|
|
$this->_stop();
|
|
}
|
|
}
|