Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/3.0' into 3.0-entity-save
Browse files Browse the repository at this point in the history
Conflicts:
	Cake/Test/TestCase/ORM/TableTest.php
  • Loading branch information
lorenzo committed Oct 25, 2013
2 parents 604d1da + fcbf52e commit b324bd5
Show file tree
Hide file tree
Showing 25 changed files with 937 additions and 564 deletions.
56 changes: 54 additions & 2 deletions Cake/Database/ConnectionManager.php
Expand Up @@ -45,6 +45,13 @@ class ConnectionManager {
*/
protected static $_config = [];

/**
* A map of connection aliases.
*
* @var array
*/
protected static $_aliasMap = [];

/**
* The ConnectionRegistry used by the manager.
*
Expand All @@ -71,17 +78,62 @@ public static function config($key, $config = null) {
return static::_config($key, $config);
}

/**
* Set one or more connection aliases.
*
* Connection aliases allow you to rename active connections without overwriting
* the aliased connection. This is most useful in the testsuite for replacing
* connections with their test variant.
*
* Defined aliases will take precedence over normal connection names. For example,
* if you alias 'default' to 'test', fetching 'default' will always return the 'test'
* connection as long as the alias is defined.
*
* You can remove aliases with ConnectionManager::dropAlias().
*
* @param string $from The connection to add an alias to.
* @param string $to The alias to create. $from should return when loaded with get().
* @return void
* @throws Cake\Error\MissingDataSourceConfigException When aliasing a connection that does not exist.
*/
public static function alias($from, $to) {
if (empty(static::$_config[$to]) && empty(static::$_config[$from])) {
throw new Error\MissingDatasourceConfigException(
__d('cake_dev', 'Cannot create alias of "%s" as it does not exist.', $from)
);
}
static::$_aliasMap[$to] = $from;
}

/**
* Drop an alias.
*
* Removes an alias from ConnectionManager. Fetching the aliased
* connection may fail if there is no other connection with that name.
*
* @param string $name The connection name to remove aliases for.
* @return void
*/
public static function dropAlias($name) {
unset(static::$_aliasMap[$name]);
}

/**
* Get a connection.
*
* If the connection has not been constructed an instance will be added
* to the registry.
* to the registry. This method will use any aliases that have been
* defined. If you want the original unaliased connections use getOriginal()
*
* @param string $name The connection name.
* @param boolean $useAliases Set to false to not use aliased connections.
* @return Connection A connection object.
* @throws Cake\Error\MissingDatasourceConfigException When config data is missing.
*/
public static function get($name) {
public static function get($name, $useAliases = true) {
if ($useAliases && isset(static::$_aliasMap[$name])) {
$name = static::$_aliasMap[$name];
}
if (empty(static::$_config[$name])) {
throw new Error\MissingDatasourceConfigException(['name' => $name]);
}
Expand Down
8 changes: 6 additions & 2 deletions Cake/ORM/Association.php
Expand Up @@ -16,6 +16,9 @@
*/
namespace Cake\ORM;

use Cake\ORM\Table;
use Cake\ORM\TableRegistry;

/**
* An Association is a relationship established between two tables and is used
* to configure and customize the way interconnected records are retrieved.
Expand Down Expand Up @@ -209,8 +212,9 @@ public function target(Table $table = null) {
}

if ($table === null) {
$className = $this->_className;
$this->_targetTable = Table::build($this->_name, compact('className'));
$this->_targetTable = TableRegistry::get($this->_name, [
'className' => $this->_className,
]);
}
return $this->_targetTable;
}
Expand Down
6 changes: 3 additions & 3 deletions Cake/ORM/Association/BelongsToMany.php
Expand Up @@ -19,6 +19,7 @@
use Cake\ORM\Association;
use Cake\ORM\Query;
use Cake\ORM\Table;
use Cake\ORM\TableRegistry;
use Cake\Utility\Inflector;

/**
Expand Down Expand Up @@ -93,8 +94,7 @@ public function pivot($table = null) {
if (empty($this->_pivotTable)) {
$tableName = $this->_joinTableName();
$tableAlias = Inflector::classify(Inflector::singularize($tableName));
$table = Table::instance($tableAlias);
$table = $table ?: Table::build($tableAlias, [
$table = TableRegistry::get($tableAlias, [
'table' => $tableName
]);
} else {
Expand All @@ -103,7 +103,7 @@ public function pivot($table = null) {
}

if (is_string($table)) {
$table = Table::build($table);
$table = TableRegistry::get($table);
}

if (!$table->association($sAlias)) {
Expand Down
161 changes: 35 additions & 126 deletions Cake/ORM/Table.php
Expand Up @@ -28,40 +28,36 @@
use Cake\Utility\Inflector;

/**
* Represents a single database table. Exposes methods for retrieving data out
* of it and manages the associations it has to other tables. Multiple
* instances of this class can be created for the same database table with
* different aliases, this allows you to address your database structure in a
* richer and more expressive way.
* Represents a single database table.
*
* Exposes methods for retrieving data out of it, and manages the associations
* this table has to other tables. Multiple instances of this class can be created
* for the same database table with different aliases, this allows you to address
* your database structure in a richer and more expressive way.
*
* ### Retrieving data
*
* The primary way to retreive data is using Table::find(). See that method
* for more information.
*
* ### Bulk updates/deletes
*
* You can use Table::updateAll() and Table::deleteAll() to do bulk updates/deletes.
* You should be aware that events will *not* be fired for bulk updates/deletes.
*
* ### Callbacks/events
*
* Table objects provide a few callbacks/events you can hook into to augment/replace
* find operations. Each event uses the standard Event subsystem in CakePHP
* find operations. Each event uses the standard event subsystem in CakePHP
*
* - beforeFind($event, $query, $options) - Fired before each find operation. By stopping
* the event and supplying a return value you can bypass the find operation entirely. Any
* changes done to the $query instance will be retained for the rest of the find.
*
* @see Cake\Event\EventManager for reference on the events system.
*/
class Table {

/**
* A list of all table instances that has been built using the factory
* method. Instances are indexed by alias
*
* @var array
*/
protected static $_instances = [];

/**
* A collection of default options to apply to each table built with the
* factory method. Indexed by table name
*
* @var array
*/
protected static $_tablesMap = [];

/**
* Name of the table as it can be found in the database
*
Expand Down Expand Up @@ -150,16 +146,9 @@ public function __construct(array $config = []) {
if (!empty($config['table'])) {
$this->table($config['table']);
}

if (!empty($config['alias'])) {
$this->alias($config['alias']);
}

$table = $this->table();
if (isset(static::$_tablesMap[$table])) {
$config = array_merge(static::$_tablesMap[$table], $config);
}

if (!empty($config['connection'])) {
$this->connection($config['connection']);
}
Expand All @@ -178,10 +167,23 @@ public function __construct(array $config = []) {
}

/**
* This method is meant to be overridden by subclasses so that any initial setting
* up for associations, validation rules or any custom logic can be done.
* Get the default connection name.
*
* This method is used to get the fallback connection name if an
* instance is created through the TableRegistry without a connection.
*
* @return string
* @see Cake\ORM\TableRegistry::get()
*/
public static function defaultConnectionName() {
return 'default';
}

/**
* Initialize a table instance. Called after the constructor.
*
* ### Example:
* You can use this method to define associations, attach behaviors
* define validation and do any other initialization logic you need.
*
* {{{
* public function initialize(array $config) {
Expand All @@ -197,99 +199,6 @@ public function __construct(array $config = []) {
public function initialize(array $config) {
}

/**
* A factory method to build a new Table instance. Once created, the instance
* will be registered so it can be re-used if tried to build again for the same
* alias.
*
* The options that can be passed are the same as in `__construct()`, but the
* key `className` is also recognized.
*
* When $options contains `className` this method will try to instantiate an
* object of that class instead of this default Table class.
*
* If no `table` option is passed, the table name will be the tableized version
* of the provided $alias.
*
* @param string $alias the alias for the table
* @param array $options a list of options as accepted by `__construct()`
* @return Table
*/
public static function build($alias, array $options = []) {
if (isset(static::$_instances[$alias])) {
return static::$_instances[$alias];
}

list($plugin, $baseClass) = pluginSplit($alias);
$options = ['alias' => $baseClass] + $options;

if (empty($options['className'])) {
$options['className'] = get_called_class();
}

if ($options['className'] === __CLASS__ || $plugin) {
$class = $options['className'];
$classified = Inflector::classify($alias);
$class = App::classname($classified, 'Model\Repository', 'Table') ?: $class;
$options['className'] = $class;
}

return static::$_instances[$alias] = new $options['className']($options);
}

/**
* Returns the Table object associated to the provided alias, if any.
* If a Table is passed as second parameter it will be associated to the
* passed $alias even if another object was associated before.
*
* @param string $alias
* @param Table $object
* @return Table
*/
public static function instance($alias, self $object = null) {
if ($object === null) {
return isset(static::$_instances[$alias]) ? static::$_instances[$alias] : null;
}
return static::$_instances[$alias] = $object;
}

/**
* Stores a list of options to be used when instantiating an object for the table
* with the same name as $table. The options that can be stored are those that
* are recognized by `build()`
*
* If second argument is omitted, it will return the current settings for $table
*
* If no arguments are passed it will return the full configuration array for
* all tables
*
* @param string $table name of the table
* @param array $options list of options for the table
* @return array
*/
public static function config($table = null, array $options = null) {
if ($table === null) {
return static::$_tablesMap;
}
if (!is_string($table)) {
return static::$_tablesMap = $table;
}
if ($options === null) {
return isset(static::$_tablesMap[$table]) ? static::$_tablesMap[$table] : [];
}
return static::$_tablesMap[$table] = $options;
}

/**
* Clears the registry of instantiated tables and default configurations
*
* @return void
*/
public static function clearRegistry() {
static::$_instances = [];
static::$_tablesMap = [];
}

/**
* Returns the database table name or sets a new one
*
Expand Down Expand Up @@ -368,7 +277,7 @@ public function schema($schema = null) {
if ($this->_schema === null) {
$this->_schema = $this->connection()
->schemaCollection()
->describe($this->_table);
->describe($this->table());
}
return $this->_schema;
}
Expand Down

0 comments on commit b324bd5

Please sign in to comment.