Merge in the bug fixes made to Linkable, as well as the better logging mechanism.

git-svn-id: file:///svn-source/pmgr/branches/invoice_receipt_20090629@194 97e9348a-65ac-dc4b-aefc-98561f571b83
This commit is contained in:
abijah
2009-06-30 18:11:40 +00:00
parent 0558c35ebc
commit 707c9a87ef

View File

@@ -85,6 +85,28 @@ class LinkableBehavior extends ModelBehavior {
protected $_defaults = array('type' => 'LEFT'); protected $_defaults = array('type' => 'LEFT');
function pr($lev, $mixed) {
if ($lev >= 5)
return;
pr($mixed);
return;
$trace = debug_backtrace(false);
//array_shift($trace);
$calls = array();
foreach ($trace AS $call) {
$call = array_intersect_key($call,
array('file'=>1,
'line'=>1,
//'class'=>1,
'function'=>1,
));
$calls[] = implode("; ", $call);
}
pr(array('debug' => $mixed, 'stack' => $calls));
}
/* /*
* This is a function for made recursive str_replaces in an array * This is a function for made recursive str_replaces in an array
* NOTE: The palacement of this function is terrible, but I don't * NOTE: The palacement of this function is terrible, but I don't
@@ -108,7 +130,10 @@ class LinkableBehavior extends ModelBehavior {
} }
public function beforeFind(&$Model, $query) { public function beforeFind(&$Model, $query) {
/* pr("Linkable::beforeFind() begin"); pr($query); */ $this->pr(10,
array('function' => 'Linkable::beforeFind',
'args' => array('Model->alias' => '$Model->alias') + compact('query'),
));
if (isset($query[$this->_key])) { if (isset($query[$this->_key])) {
$optionsDefaults = $this->_defaults + array('reference' => $optionsDefaults = $this->_defaults + array('reference' =>
array('class' => $Model->alias, array('class' => $Model->alias,
@@ -132,7 +157,10 @@ class LinkableBehavior extends ModelBehavior {
unset($iterator['defaults']); unset($iterator['defaults']);
} }
$iterations = Set::normalize($iterator); $iterations = Set::normalize($iterator);
/* pr(array('checkpoint' => 'Iterations', compact('iterations'))); */ $this->pr(25,
array('checkpoint' => 'Iterations',
compact('iterations'),
));
foreach ($iterations as $alias => $options) { foreach ($iterations as $alias => $options) {
if (is_null($options)) { if (is_null($options)) {
$options = array(); $options = array();
@@ -145,7 +173,15 @@ class LinkableBehavior extends ModelBehavior {
if (empty($options['class'])) if (empty($options['class']))
$options['class'] = $alias; $options['class'] = $alias;
/* pr(array('checkpoint' => 'Begin Model Work', compact('alias', 'options'))); */ if (!isset($options['conditions']))
$options['conditions'] = array();
elseif (!is_array($options['conditions']))
$options['conditions'] = array($options['conditions']);
$this->pr(20,
array('checkpoint' => 'Begin Model Work',
compact('alias', 'options'),
));
$modelClass = $options['class']; $modelClass = $options['class'];
$modelAlias = $options['alias']; $modelAlias = $options['alias'];
@@ -154,11 +190,13 @@ class LinkableBehavior extends ModelBehavior {
$_Model =& ClassRegistry::init($modelClass); // the incoming model to be linked in query $_Model =& ClassRegistry::init($modelClass); // the incoming model to be linked in query
$Reference =& ClassRegistry::init($referenceClass); // the already in query model that links to $_Model $Reference =& ClassRegistry::init($referenceClass); // the already in query model that links to $_Model
/* pr(array('checkpoint' => 'Aliases Established', */ $this->pr(12,
/* 'Model' => ($modelAlias .' : '. $modelClass . */ array('checkpoint' => 'Aliases Established',
/* ' ('. $_Model->alias .' : '. $_Model->name .')'), */ 'Model' => ($modelAlias .' : '. $modelClass .
/* 'Reference' => ($referenceAlias .' : '. $referenceClass . */ ' ('. $_Model->alias .' : '. $_Model->name .')'),
/* ' ('. $Reference->alias .' : '. $Reference->name .')'))); */ 'Reference' => ($referenceAlias .' : '. $referenceClass .
' ('. $Reference->alias .' : '. $Reference->name .')'),
));
$db =& $_Model->getDataSource(); $db =& $_Model->getDataSource();
@@ -169,20 +207,20 @@ class LinkableBehavior extends ModelBehavior {
// a relationship if one doesn't otherwise already exists. // a relationship if one doesn't otherwise already exists.
if (($associations = $Reference->getAssociated()) && if (($associations = $Reference->getAssociated()) &&
isset($associations[$_Model->alias])) { isset($associations[$_Model->alias])) {
/* pr("Reference defines association to _Model"); */ $this->pr(12, array('checkpoint' => "Reference defines association to _Model"));
$associatedThroughReference = 1; $associatedThroughReference = 1;
$type = $associations[$_Model->alias]; $type = $associations[$_Model->alias];
$association = $Reference->{$type}[$_Model->alias]; $association = $Reference->{$type}[$_Model->alias];
} }
elseif (($associations = $_Model->getAssociated()) && elseif (($associations = $_Model->getAssociated()) &&
isset($associations[$Reference->alias])) { isset($associations[$Reference->alias])) {
/* pr("_Model defines association to Reference"); */ $this->pr(12, array('checkpoint' => "_Model defines association to Reference"));
$type = $associations[$Reference->alias]; $type = $associations[$Reference->alias];
$association = $_Model->{$type}[$Reference->alias]; $association = $_Model->{$type}[$Reference->alias];
} }
else { else {
// No relationship... make our best effort to create one. // No relationship... make our best effort to create one.
/* pr("No assocation between _Model and Reference"); */ $this->pr(12, array('checkpoint' => "No assocation between _Model and Reference"));
$type = 'belongsTo'; $type = 'belongsTo';
$_Model->bind($Reference->alias); $_Model->bind($Reference->alias);
// Grab the association now, since we'll unbind in a moment. // Grab the association now, since we'll unbind in a moment.
@@ -212,93 +250,119 @@ class LinkableBehavior extends ModelBehavior {
$associationAlias, $associationAlias,
$association['conditions']); $association['conditions']);
/* pr(array('checkpoint' => 'Models Established - Check Associations', */ $this->pr(15,
/* 'primaryModel' => $primaryAlias .' : '. $primaryModel->name, */ array('checkpoint' => 'Models Established - Check Associations',
/* 'foreignModel' => $foreignAlias .' : '. $foreignModel->name, */ 'primaryModel' => $primaryAlias .' : '. $primaryModel->name,
/* compact('type', 'association'))); */ 'foreignModel' => $foreignAlias .' : '. $foreignModel->name,
compact('type', 'association'),
));
if (empty($options['conditions'])) { if ($type === 'hasAndBelongsToMany') {
if ($type === 'hasAndBelongsToMany') { if (isset($association['with']))
if (isset($association['with'])) $linkClass = $association['with'];
$linkClass = $association['with']; else
else $linkClass = Inflector::classify($association['joinTable']);
$linkClass = Inflector::classify($association['joinTable']);
$Link =& $_Model->{$linkClass}; $Link =& $_Model->{$linkClass};
if (isset($options['linkalias'])) if (isset($options['linkalias']))
$linkAlias = $options['linkalias']; $linkAlias = $options['linkalias'];
else else
$linkAlias = $Link->alias; $linkAlias = $Link->alias;
// Get the foreign key fields (for the link table) directly from $this->pr(17,
// the defined model associations, if they exists. This is the array('checkpoint' => 'Linking HABTM',
// users direct specification, and therefore definitive if present. compact('linkClass', 'linkAlias'),
$modelLink = $Link->escapeField($association['foreignKey'], $linkAlias); ));
$referenceLink = $Link->escapeField($association['associationForeignKey'], $linkAlias);
// If we haven't figured out the foreign keys, see if there is a // Get the foreign key fields (for the link table) directly from
// model for the link table, and if it has the appropriate // the defined model associations, if they exists. This is the
// associations with the two tables we're trying to join. // users direct specification, and therefore definitive if present.
if (empty($modelLink) && isset($Link->belongsTo[$_Model->alias])) $modelLink = $Link->escapeField($association['foreignKey'], $linkAlias);
$modelLink = $Link->escapeField($Link->belongsTo[$_Model->alias]['foreignKey'], $linkAlias); $referenceLink = $Link->escapeField($association['associationForeignKey'], $linkAlias);
if (empty($referenceLink) && isset($Link->belongsTo[$Reference->alias]))
$referenceLink = $Link->escapeField($Link->belongsTo[$Reference->alias]['foreignKey'], $linkAlias);
// We're running quite thin here. None of the models spell // If we haven't figured out the foreign keys, see if there is a
// out the appropriate linkages. We'll have to SWAG it. // model for the link table, and if it has the appropriate
if (empty($modelLink)) // associations with the two tables we're trying to join.
$modelLink = $Link->escapeField(Inflector::underscore($_Model->alias) . '_id', $linkAlias); if (empty($modelLink) && isset($Link->belongsTo[$_Model->alias]))
if (empty($referenceLink)) $modelLink = $Link->escapeField($Link->belongsTo[$_Model->alias]['foreignKey'], $linkAlias);
$referenceLink = $Link->escapeField(Inflector::underscore($Reference->alias) . '_id', $linkAlias); if (empty($referenceLink) && isset($Link->belongsTo[$Reference->alias]))
$referenceLink = $Link->escapeField($Link->belongsTo[$Reference->alias]['foreignKey'], $linkAlias);
// Get the primary key from the tables we're joining. // We're running quite thin here. None of the models spell
$referenceKey = $Reference->escapeField(null, $referenceAlias); // out the appropriate linkages. We'll have to SWAG it.
$modelKey = $_Model->escapeField(null, $modelAlias); if (empty($modelLink))
$modelLink = $Link->escapeField(Inflector::underscore($_Model->alias) . '_id', $linkAlias);
if (empty($referenceLink))
$referenceLink = $Link->escapeField(Inflector::underscore($Reference->alias) . '_id', $linkAlias);
// Get the primary key from the tables we're joining.
$referenceKey = $Reference->escapeField(null, $referenceAlias);
$modelKey = $_Model->escapeField(null, $modelAlias);
// Join the linkage table to our model. We'll use an inner join, // Join the linkage table to our model. We'll use an inner join,
// as the whole purpose of the linkage table is to make this // as the whole purpose of the linkage table is to make this
// connection. As we are embedding this join, the INNER will not // connection. As we are embedding this join, the INNER will not
// cause any problem with the overall query, should the user not // cause any problem with the overall query, should the user not
// be concerned with whether or not the join has any results. // be concerned with whether or not the join has any results.
// They control that with the 'type' parameter which will be at // They control that with the 'type' parameter which will be at
// the top level join. // the top level join.
$options['joins'][] = array('type' => 'INNER', $options['joins'][] = array('type' => 'INNER',
'alias' => $modelAlias, 'alias' => $modelAlias,
'conditions' => "{$modelKey} = {$modelLink}", 'conditions' => "{$modelKey} = {$modelLink}",
'table' => $db->fullTableName($_Model, true)); 'table' => $db->fullTableName($_Model, true));
// Now for the top level join. This will be added into the list
// of joins down below, outside of the HABTM specific code.
$options['class'] = $linkClass;
$options['alias'] = $linkAlias;
$options['table'] = $Link->getDataSource()->fullTableName($Link);
$options['conditions'][] = "{$referenceLink} = {$referenceKey}";
}
elseif (isset($association['foreignKey']) && $association['foreignKey']) {
$foreignKey = $primaryModel->escapeField($association['foreignKey'], $primaryAlias);
$primaryKey = $foreignModel->escapeField($foreignModel->primaryKey, $foreignAlias);
// Only differentiating to help show the logical flow.
// Either way works and this test can be tossed out
if (($type === 'hasMany' || $type === 'hasOne') ^ $associatedThroughReference)
$options['conditions'][] = "{$primaryKey} = {$foreignKey}";
else
$options['conditions'][] = "{$foreignKey} = {$primaryKey}";
}
else {
// No Foreign Key... nothing we can do.
$options['conditions'] = array();
}
// The user may have specified conditions directly in the model
// for this join. Make sure to adhere to those conditions.
if (isset($association['conditions']) && is_array($association['conditions']))
$options['conditions'] = array_merge($options['conditions'], $association['conditions']);
elseif (!empty($association['conditions']))
$options['conditions'][] = $association['conditions'];
// Now for the top level join. This will be added into the list
// of joins down below, outside of the HABTM specific code.
$options['class'] = $linkClass;
$options['alias'] = $linkAlias;
$options['table'] = $Link->getDataSource()->fullTableName($Link);
$options['conditions'][] = "{$referenceLink} = {$referenceKey}";
} }
elseif (isset($association['foreignKey']) && $association['foreignKey']) {
$foreignKey = $primaryModel->escapeField($association['foreignKey'], $primaryAlias);
$primaryKey = $foreignModel->escapeField($foreignModel->primaryKey, $foreignAlias);
$this->pr(17,
array('checkpoint' => 'Linking due to foreignKey',
compact('foreignKey', 'primaryKey'),
));
// Only differentiating to help show the logical flow.
// Either way works and this test can be tossed out
if (($type === 'hasMany' || $type === 'hasOne') ^ $associatedThroughReference)
$options['conditions'][] = "{$primaryKey} = {$foreignKey}";
else
$options['conditions'][] = "{$foreignKey} = {$primaryKey}";
}
else {
$this->pr(17,
array('checkpoint' => 'Linking with no logic (expecting user defined)',
));
// No Foreign Key... nothing we can do.
}
$this->pr(19,
array('checkpoint' => 'Conditions',
array('options[conditions]' => $options['conditions'],
'association[conditions]' => $association['conditions'],
),
));
// The user may have specified conditions directly in the model
// for this join. Make sure to adhere to those conditions.
if (isset($association['conditions']) && is_array($association['conditions']))
$options['conditions'] = array_merge($options['conditions'], $association['conditions']);
elseif (!empty($association['conditions']))
$options['conditions'][] = $association['conditions'];
$this->pr(19,
array('checkpoint' => 'Conditions2',
array('options[conditions]' => $options['conditions'],
),
));
if (empty($options['table'])) { if (empty($options['table'])) {
$options['table'] = $db->fullTableName($_Model, true); $options['table'] = $db->fullTableName($_Model, true);
} }
@@ -312,26 +376,31 @@ class LinkableBehavior extends ModelBehavior {
(empty($association['fields']) (empty($association['fields'])
? array() : $db->fields($_Model, $modelAlias, $association['fields']))); ? array() : $db->fields($_Model, $modelAlias, $association['fields'])));
/* pr(array('checkpoint' => 'Model Work Complete', compact('options', 'modelClass', 'modelAlias'))); */
$options[$this->_key] = am($options[$this->_key], array_diff_key($options, $optionsKeys)); $options[$this->_key] = am($options[$this->_key], array_diff_key($options, $optionsKeys));
$options = array_intersect_key($options, $optionsKeys); $options = array_intersect_key($options, $optionsKeys);
if (!empty($options[$this->_key])) { if (!empty($options[$this->_key])) {
$iterators[] = $options[$this->_key] + $iterators[] = $options[$this->_key] +
array('defaults' => array('defaults' =>
array_merge($defaults, array_merge($defaults,
array('reference' => array('reference' =>
array('class' => $modelClass, array('class' => $modelClass,
'alias' => $modelAlias)))); 'alias' => $modelAlias))));
} }
$query['joins'][] = array_intersect_key($options, array('type' => true, 'alias' => true, 'table' => true, 'joins' => true, 'conditions' => true)); $query['joins'][] = array_intersect_key($options, array('type' => true, 'alias' => true, 'table' => true, 'joins' => true, 'conditions' => true));
$this->pr(19,
array('checkpoint' => 'Model Join Complete',
compact('options', 'modelClass', 'modelAlias', 'query'),
));
} }
++$cont; ++$cont;
$notDone = isset($iterators[$cont]); $notDone = isset($iterators[$cont]);
} while ($notDone); } while ($notDone);
} }
/* pr(array('checkpoint' => 'Linkable::beforeFind() end', */ $this->pr(20,
/* compact('query'))); */ array('function' => 'Linkable::beforeFind',
'return' => compact('query'),
));
return $query; return $query;
} }
} }