diff --git a/cake/basics.php b/cake/basics.php index 54537b03b..cad5b1565 100644 --- a/cake/basics.php +++ b/cake/basics.php @@ -449,6 +449,48 @@ } } } +/** + * Normalizes a string or array list + * + * @param mixed $list + * @param boolean $assoc If true, $list will be converted to an associative array + * @param string $sep If $list is a string, it will be split into an array with $sep + * @param boolean $trim If true, separated strings will be trimmed + * @return array + */ + function normalizeList($list, $assoc = true, $sep = ',', $trim = true) { + if (is_string($list)) { + $list = explode($sep, $list); + if ($trim) { + $list = array_map('trim', $list); + } + return normalizeList($list); + } elseif (is_array($list)) { + $keys = array_keys($list); + $count = count($keys); + $numeric = true; + + if (!$assoc) { + for ($i = 0; $i < $count; $i++) { + if (!is_int($keys[$i])) { + $numeric = false; + break; + } + } + } + if (!$numeric || $assoc) { + for ($i = 0; $i < $count; $i++) { + if (is_int($keys[$i])) { + $newList[$list[$keys[$i]]] = null; + } else { + $newList[$keys[$i]] = $list[$keys[$i]]; + } + } + $list = $newList; + } + } + return $list; + } /** * Prints out debug information about given variable. * @@ -798,6 +840,11 @@ * @return mixed The contents of the temporary file. */ function cache($path, $data = null, $expires = '+1 day', $target = 'cache') { + + if (defined('DISABLE_CACHE')) { + return null; + } + if (!is_numeric($expires)) { $expires = strtotime($expires); } diff --git a/cake/libs/model/datasources/dbo_source.php b/cake/libs/model/datasources/dbo_source.php index 2a2e137ba..9609fd36b 100644 --- a/cake/libs/model/datasources/dbo_source.php +++ b/cake/libs/model/datasources/dbo_source.php @@ -167,46 +167,66 @@ class DboSource extends DataSource { $limit = null; $page = null; $recursive = null; + if (count($args) == 1) { return $this->fetchAll($args[0]); } elseif (count($args) > 1 && (strpos(low($args[0]), 'findby') === 0 || strpos(low($args[0]), 'findallby') === 0)) { - if (isset($args[1][1])) { - $fields = $args[1][1]; - } - - if (isset($args[1][2])) { - $order = $args[1][2]; - } + $params = $args[1]; if (strpos(strtolower($args[0]), 'findby') === 0) { $all = false; $field = Inflector::underscore(preg_replace('/findBy/i', '', $args[0])); - - if (isset($args[1][3])) { - $recursive = $args[1][3]; - } } else { $all = true; $field = Inflector::underscore(preg_replace('/findAllBy/i', '', $args[0])); - if (isset($args[1][3])) { - $limit = $args[1][3]; - } - - if (isset($args[1][4])) { - $page = $args[1][4]; - } - - if (isset($args[1][5])) { - $recursive = $args[1][5]; - } } - $query = array($args[2]->name . '.' . $field => $args[1][0]); + + $or = (strpos($field, '_or_') !== false); + if ($or) { + $field = explode('_or_', $field); + } else { + $field = explode('_and_', $field); + } + $off = count($field) - 1; + + if (isset($params[1 + $off])) { + $fields = $params[1 + $off]; + } + + if (isset($params[2 + $off])) { + $order = $params[2 + $off]; + } + + $c = 0; + $query = array(); + foreach ($field as $f) { + $query[$args[2]->name . '.' . $f] = $params[$c++]; + } + + if ($or) { + $query = array('OR' => $query); + } if ($all) { + + if (isset($params[3 + $off])) { + $limit = $params[3 + $off]; + } + + if (isset($params[4 + $off])) { + $page = $params[4 + $off]; + } + + if (isset($params[5 + $off])) { + $recursive = $params[5 + $off]; + } return $args[2]->findAll($query, $fields, $order, $limit, $page, $recursive); } else { + if (isset($params[3 + $off])) { + $recursive = $params[3 + $off]; + } return $args[2]->find($query, $fields, $order, $recursive); } } else { @@ -1012,11 +1032,31 @@ class DboSource extends DataSource { $sql .= $limit; } - $sql .= ' ' . join(', ', $this->fields($linkModel, $alias, $assocData['fields'])); + $joinFields = array(); + if (isset($assocData['with'])) { + $joinName = array_keys($assocData['with']); + $joinFields = $assocData['with'][$joinName[0]]; + + if (is_array($joinFields) && !empty($joinFields)) { + $joinFields = $this->fields($linkModel, $joinName[0], $joinFields); + } else { + $joinFields = array($this->name($joinName[0]) . '.*'); + } + } + + $sql .= ' ' . join(', ', am($this->fields($linkModel, $alias, $assocData['fields']), $joinFields)); $sql .= ' FROM ' . $this->fullTableName($linkModel) . ' ' . $this->alias . $this->name($alias); - $sql .= ' JOIN ' . $joinTbl . ' ON ' . $joinTbl; + $sql .= ' JOIN ' . $joinTbl; + + $joinAssoc = $joinTbl; + if (isset($assocData['with'])) { + $joinAssoc = $joinName[0]; + $sql .= $this->alias . $this->name($joinAssoc); + } + + $sql .= ' ON ' . $this->name($joinAssoc); $sql .= '.' . $this->name($assocData['foreignKey']) . ' = {$__cakeID__$}'; - $sql .= ' AND ' . $joinTbl . '.' . $this->name($assocData['associationForeignKey']); + $sql .= ' AND ' . $this->name($joinAssoc) . '.' . $this->name($assocData['associationForeignKey']); $sql .= ' = ' . $this->name($alias) . '.' . $this->name($linkModel->primaryKey); $sql .= $this->conditions($assocData['conditions']); diff --git a/cake/libs/model/model_php4.php b/cake/libs/model/model_php4.php index 191d7ae0e..daf96baa2 100644 --- a/cake/libs/model/model_php4.php +++ b/cake/libs/model/model_php4.php @@ -458,13 +458,13 @@ class Model extends Object{ * @param string $type Type of assocation * @access private */ - function __constructLinkedModel($assoc, $className) { + function __constructLinkedModel($assoc, $className, $id = false, $table = null, $ds = null) { $colKey = Inflector::underscore($className); if (ClassRegistry::isKeySet($colKey)) { $this->{$className} =& ClassRegistry::getObject($colKey); } else { - $this->{$className} =& new $className(); + $this->{$className} =& new $className($id, $table, $ds); } $this->alias[$assoc] = $this->{$className}->table; @@ -478,7 +478,7 @@ class Model extends Object{ * @access private */ function __generateAssociation($type) { - foreach($this->{$type}as $assocKey => $assocData) { + foreach($this->{$type} as $assocKey => $assocData) { $class = $assocKey; if (isset($this->{$type}[$assocKey]['className']) && $this->{$type}[$assocKey]['className'] !== null) { @@ -515,6 +515,8 @@ class Model extends Object{ case 'className': $data = $class; break; + } elseif ($key == 'with') { + $this->{$type}[$assocKey][$key] = normalizeList($this->{$type}[$assocKey][$key]); } $this->{$type}[$assocKey][$key] = $data; diff --git a/cake/libs/model/model_php5.php b/cake/libs/model/model_php5.php index 07a5508af..e5ecbe217 100644 --- a/cake/libs/model/model_php5.php +++ b/cake/libs/model/model_php5.php @@ -45,7 +45,7 @@ uses('class_registry', 'validators'); * @package cake * @subpackage cake.cake.libs.model */ -class Model extends Object{ +class Model extends Object { /** * The name of the DataSource connection that this Model uses @@ -253,11 +253,11 @@ class Model extends Object{ * @var array */ var $__associationKeys = array( - 'belongsTo' => array('className', 'conditions', 'order', 'foreignKey', 'counterCache'), - 'hasOne' => array('className', 'conditions', 'order', 'foreignKey', 'dependent'), - 'hasMany' => array('className', 'conditions', 'order', 'foreignKey', 'fields', 'dependent', 'exclusive', 'finderQuery', 'counterQuery'), - 'hasAndBelongsToMany' => array('className', 'joinTable', 'fields', 'foreignKey', 'associationForeignKey', 'conditions', 'order', 'uniq', 'finderQuery', 'deleteQuery', 'insertQuery') - ); + 'belongsTo' => array('className', 'conditions', 'order', 'foreignKey', 'counterCache'), + 'hasOne' => array('className', 'conditions', 'order', 'foreignKey', 'dependent'), + 'hasMany' => array('className', 'conditions', 'order', 'foreignKey', 'fields', 'dependent', 'exclusive', 'finderQuery', 'counterQuery'), + 'hasAndBelongsToMany' => array('className', 'joinTable', 'fields', 'foreignKey', 'associationForeignKey', 'conditions', 'order', 'uniq', 'finderQuery', 'deleteQuery', 'insertQuery', 'with') + ); /** * Holds provided/generated association key names and other data for all associations @@ -301,11 +301,11 @@ class Model extends Object{ parent::__construct(); if ($this->name === null) { - $this->name = get_class($this); + $this->name = get_class($this); } if ($this->primaryKey === null) { - $this->primaryKey = 'id'; + $this->primaryKey = 'id'; } $this->currentModel = Inflector::underscore($this->name); @@ -450,15 +450,18 @@ class Model extends Object{ * @param string $assoc * @param string $className Class name * @param string $type Type of assocation + * @param mixed $id Primary key ID of linked model + * @param string $table Database table associated with linked model + * @param string $ds Name of DataSource the model should be bound to * @access private */ - function __constructLinkedModel($assoc, $className) { + function __constructLinkedModel($assoc, $className, $id = false, $table = null, $ds = null) { $colKey = Inflector::underscore($className); if (ClassRegistry::isKeySet($colKey)) { $this->{$className} = ClassRegistry::getObject($colKey); } else { - $this->{$className} = new $className(); + $this->{$className} = new $className($id, $table, $ds); } $this->alias[$assoc] = $this->{$className}->table; @@ -472,7 +475,7 @@ class Model extends Object{ * @access private */ function __generateAssociation($type) { - foreach($this->{$type}as $assocKey => $assocData) { + foreach($this->{$type} as $assocKey => $assocData) { $class = $assocKey; if (isset($this->{$type}[$assocKey]['className']) && $this->{$type}[$assocKey]['className'] !== null) { @@ -512,6 +515,8 @@ class Model extends Object{ } $this->{$type}[$assocKey][$key] = $data; + } elseif ($key == 'with') { + $this->{$type}[$assocKey][$key] = normalizeList($this->{$type}[$assocKey][$key]); } if ($key == 'foreignKey' && !isset($this->keyToTable[$this->{$type}[$assocKey][$key]])) { diff --git a/cake/libs/view/helpers/ajax.php b/cake/libs/view/helpers/ajax.php index 803017e84..4da48e131 100644 --- a/cake/libs/view/helpers/ajax.php +++ b/cake/libs/view/helpers/ajax.php @@ -813,7 +813,7 @@ class AjaxHelper extends Helper { $data[] = $key . ':"' . rawurlencode($val) . '"'; } } - $out = 'var __ajaxUpdater__ = {' . join(', ', $data) . '};' . "\n"; + $out = 'var __ajaxUpdater__ = {' . join(", \n", $data) . '};' . "\n"; $out .= 'for (n in __ajaxUpdater__) { if (typeof __ajaxUpdater__[n] == "string" && $(n)) Element.update($(n), unescape(__ajaxUpdater__[n])); }'; @ob_end_clean();