1、在 PHP 7.0.22、CakePHP 2.10.3 下,报错:Error: The datasource configuration tmp was not found in database.php.,如图1
2、打印 $this->useDbConfig,其值为 tmp,如图2
3、确定在 database.php 中不存在 $tmp,如图3
4、但是之前在 CakePHP 2.6.4 确定是正常的,决定对比一下区别,发现区别所在(注:修改了核心库,升级之后,核心库的 _init() 被还原),如图4
/lib/Cake/Model/ConnectionManager.php
<?php protected static function _init() { // @include_once APP . 'Config' . DS . 'database.php'; // if (class_exists('DATABASE_CONFIG')) { // self::$config = new DATABASE_CONFIG(); // } self::$_init = true; } ?>
注:修改了核心库,升级之后,核心库的 _init() 被还原
<?php protected static function _init() { include_once CONFIG . 'database.php'; if (class_exists('DATABASE_CONFIG')) { static::$config = new DATABASE_CONFIG(); } static::$_init = true; } ?>
5、在 /lib/Cake/Model/ConnectionManager.php的getDataSource方法打印static::$config,如图5
6、打印结果,确定不存在 $tmp,如图6
7、现在的需求应该为,在不修改核心库的前提下,确保 static::$config 中存在 $tmp,查看之前的实现,如图7
/app/Model/AppModel.php
<?php public function getDbConfig($tenantid){ if(!$conn = Cache::read($tenantid,'_cake_config_')){ $tenant = new Tenant(); $conn = $tenant->getTenantEnv($tenantid); $this->log($conn); Cache::write($tenantid,$conn,'_cake_config_'); } return $conn; } public function setDataSource($dataSource = null) { if($_GET['tenantid']){ $tenantid = [addslashes($_GET['tenantid'])]; }else{ preg_match('@^(?:http://)?([^/]+)@i', FULL_BASE_URL, $matches); $tenantid = explode('.', $matches[1]); } $conn = $this->getDbConfig($tenantid[0]); if(!$conn) die('系统错误506,无法链接数据库'); $this->useDbConfig = $dataSource = 'tmp'; $oldConfig = $this->useDbConfig; if ($dataSource) { $this->useDbConfig = $dataSource; } $config = new stdClass(); $config->tmp = array( 'datasource' => 'Database/Mysql', 'persistent' => false, 'host' =>$conn['db_info']['host'], 'login' => $conn['db_info']['login'], 'password' => $conn['db_info']['password'], 'database' => $conn['db_info']['database'], 'port' => 3306, 'prefix' => 'operation_', 'encoding' => 'utf8' ); // if(!$conn){ // pr($config->tmp); // $config->tmp = array( // 'datasource' => 'Database/Mysql', // 'persistent' => false, // 'host' => '127.0.0.1', // 'login' =>'root', // 'password' =>'root', // 'database' =>"jifen", // 'port' => 3306, // 'prefix' => 'operation_', // 'encoding' => 'utf8' // ); // } // $this->log($config->tmp); ConnectionManager::$config = $config; $db = ConnectionManager::getDataSource($this->useDbConfig); if (!empty($oldConfig) && isset($db->config['prefix'])) { $oldDb = ConnectionManager::getDataSource($oldConfig); if (!isset($this->tablePrefix) || (!isset($oldDb->config['prefix']) || $this->tablePrefix === $oldDb->config['prefix'])) { $this->tablePrefix = $db->config['prefix']; } } elseif (isset($db->config['prefix'])) { $this->tablePrefix = $db->config['prefix']; } $schema = $db->getSchemaName(); $defaultProperties = get_class_vars(get_class($this)); if (isset($defaultProperties['schemaName'])) { $schema = $defaultProperties['schemaName']; } $this->schemaName = $schema; //pr($config->tmp); } ?>
8、在运行时以给定的名称和设置动态创建一个DataSource对象,便无需修改核心库,如图8
/app/Model/AppModel.php
<?php public function getDbConfig($tenantid){ if(!$conn = Cache::read($tenantid,'_cake_config_')){ $tenant = new Tenant(); $conn = $tenant->getTenantEnv($tenantid); $this->log($conn); Cache::write($tenantid,$conn,'_cake_config_'); } return $conn; } public function setDataSource($dataSource = null) { if($_GET['tenantid']){ $tenantid = [addslashes($_GET['tenantid'])]; }else{ preg_match('@^(?:http://)?([^/]+)@i', FULL_BASE_URL, $matches); $tenantid = explode('.', $matches[1]); } $conn = $this->getDbConfig($tenantid[0]); if(!$conn) die('系统错误506,无法链接数据库'); $dataSource = 'tmp'; $config = array( 'datasource' => 'Database/Mysql', 'persistent' => false, 'host' =>$conn['db_info']['host'], 'login' => $conn['db_info']['login'], 'password' => $conn['db_info']['password'], 'database' => $conn['db_info']['database'], 'port' => 3306, 'prefix' => 'operation_', 'encoding' => 'utf8' ); ConnectionManager::create($dataSource, $config); $this->useDbConfig = $dataSource; $oldConfig = $this->useDbConfig; if ($dataSource) { $this->useDbConfig = $dataSource; } $db = ConnectionManager::getDataSource($this->useDbConfig); if (!empty($oldConfig) && isset($db->config['prefix'])) { $oldDb = ConnectionManager::getDataSource($oldConfig); if (!isset($this->tablePrefix) || (!isset($oldDb->config['prefix']) || $this->tablePrefix === $oldDb->config['prefix'])) { $this->tablePrefix = $db->config['prefix']; } } elseif (isset($db->config['prefix'])) { $this->tablePrefix = $db->config['prefix']; } $schema = $db->getSchemaName(); $defaultProperties = get_class_vars(get_class($this)); if (isset($defaultProperties['schemaName'])) { $schema = $defaultProperties['schemaName']; } $this->schemaName = $schema; } ?>
9、在 /lib/Cake/Model/ConnectionManager.php的getDataSource方法打印static::$config,$tmp已经存在,如图9
10、再次运行,正常,如图10
11、总结:为何需要在 /app/Model/AppModel.php 覆盖 setDataSource(),原因在于数据库是动态从接口获取的,并非源于 /app/Config/database.php,通过 ConnectionManager::create,便可以实现动态创建一个数据源对象。
原创文章,作者:Maggie-Hunter,如若转载,请注明出处:https://blog.ytso.com/tech/webdev/180750.html