动态创建的数据源未传递给 CakePHP 中的关联模型
Dynamically created datasource not being passed to associated models in CakePHP
我有一个模型 - 汽车 - 汽车有几个关联模型,让我们考虑其中一个与 hasMany
关系相关联的模型 - 车轮
在我的 CarsController 中,我使用以下代码动态生成数据源 -
$schemaName = $this->Session->read('User.schema');
$config = ConnectionManager::getDataSource('default')->config;
$config['database'] = $schemaName;
ConnectionManager::create($schemaName, $config);
然后我使用以下代码行在我的汽车模型中设置此数据源
$this->Car->setDataSource($schemaName);
在此之后我可以查询和操作 Car,但是,如果我尝试使用以下语句操作 Wheel - 我会收到错误消息
$this->Car->Wheel->create();
$this->Car->Wheel->save($wheelData);
我得到的错误是 -
错误:[MissingTableException] Table 在数据源默认值中找不到模型 Wheel 的轮子。
出于某种原因,数据源未从父模型传递到关联的子模型。如果我使用以下行在 Wheel 中明确设置数据源,那么一切正常。
$this->Car->Wheel->setDataSource($schemaName);
任何人都可以帮助阐明这种行为以及如何解决这个问题吗?我觉得这不方便的原因是我的父模型有几个关联模型(还有关联模型)并且在每个模型上单独设置数据源听起来不正确。
附带问题 - 有没有办法在尝试动态创建数据源之前检查数据源是否已经存在?我有一个包装整个代码的 for 循环,每次循环迭代最终都会创建一个新的数据源
我正在使用 CakePHP 2.5.4
这里有一些代码可以将 setDatasource() 调用传递给关联的模型,如果您只希望 Car 模型通过其数据源,请将此代码放入 Car 模型中,如果您希望所有模型都通过,放在 AppModel.php
public function setDatasource($datasource = null) {
foreach (array_keys($this->getAssociated()) as $modelName) {
$this->{$modelName}->setDatasource($datasource);
}
parent::setDatasource($datasource);
}
为了回答您的评论,我会在 AppModel.php
中添加 public $dynamicDb = false
,这意味着 false 将是此变量的默认值,然后在您的模型中通过添加 public $dynamicDb = true
来覆盖它,然后把上面的函数改成:
public function setDatasource($datasource = null) {
foreach (array_keys($this->getAssociated()) as $modelName) {
if ($this->{$modelName}->dynamicDb === true) {
$this->{$modelName}->setDatasource($datasource);
}
}
parent::setDatasource($datasource);
}
(我还没有测试这个修改后的功能,因为我现在不在我的开发电脑上,但这是一个相当简单的改变,它应该可以工作)
要在创建数据源之前检查数据源是否已经存在,我可以看到两种可能的方法,一种是调用 ConnectionManager::getDatasource($schemaName)
并在数据源不存在时捕获异常,或者调用 ConnectionManager::sourceList()
并检查您的 $schemaName
是否在返回的数组中,这是第一个选项的实现:
$schemaName = $this->Session->read('User.schema');
try {
ConnectionManager::getDatasource($schemaName)
} catch (MissingDatasourceException $e) {
$config = ConnectionManager::getDataSource('default')->config;
$config['database'] = $schemaName;
ConnectionManager::create($schemaName, $config);
}
和第二个选项:
$datasources = ConnectionManager::sourceList();
$schemaName = $this->Session->read('User.schema');
if (!in_array($schemaName, $datasources)) {
$config = ConnectionManager::getDataSource('default')->config;
$config['database'] = $schemaName;
ConnectionManager::create($schemaName, $config);
}
希望对您有所帮助
我有一个模型 - 汽车 - 汽车有几个关联模型,让我们考虑其中一个与 hasMany
关系相关联的模型 - 车轮
在我的 CarsController 中,我使用以下代码动态生成数据源 -
$schemaName = $this->Session->read('User.schema');
$config = ConnectionManager::getDataSource('default')->config;
$config['database'] = $schemaName;
ConnectionManager::create($schemaName, $config);
然后我使用以下代码行在我的汽车模型中设置此数据源
$this->Car->setDataSource($schemaName);
在此之后我可以查询和操作 Car,但是,如果我尝试使用以下语句操作 Wheel - 我会收到错误消息
$this->Car->Wheel->create();
$this->Car->Wheel->save($wheelData);
我得到的错误是 - 错误:[MissingTableException] Table 在数据源默认值中找不到模型 Wheel 的轮子。
出于某种原因,数据源未从父模型传递到关联的子模型。如果我使用以下行在 Wheel 中明确设置数据源,那么一切正常。
$this->Car->Wheel->setDataSource($schemaName);
任何人都可以帮助阐明这种行为以及如何解决这个问题吗?我觉得这不方便的原因是我的父模型有几个关联模型(还有关联模型)并且在每个模型上单独设置数据源听起来不正确。
附带问题 - 有没有办法在尝试动态创建数据源之前检查数据源是否已经存在?我有一个包装整个代码的 for 循环,每次循环迭代最终都会创建一个新的数据源
我正在使用 CakePHP 2.5.4
这里有一些代码可以将 setDatasource() 调用传递给关联的模型,如果您只希望 Car 模型通过其数据源,请将此代码放入 Car 模型中,如果您希望所有模型都通过,放在 AppModel.php
public function setDatasource($datasource = null) {
foreach (array_keys($this->getAssociated()) as $modelName) {
$this->{$modelName}->setDatasource($datasource);
}
parent::setDatasource($datasource);
}
为了回答您的评论,我会在 AppModel.php
中添加 public $dynamicDb = false
,这意味着 false 将是此变量的默认值,然后在您的模型中通过添加 public $dynamicDb = true
来覆盖它,然后把上面的函数改成:
public function setDatasource($datasource = null) {
foreach (array_keys($this->getAssociated()) as $modelName) {
if ($this->{$modelName}->dynamicDb === true) {
$this->{$modelName}->setDatasource($datasource);
}
}
parent::setDatasource($datasource);
}
(我还没有测试这个修改后的功能,因为我现在不在我的开发电脑上,但这是一个相当简单的改变,它应该可以工作)
要在创建数据源之前检查数据源是否已经存在,我可以看到两种可能的方法,一种是调用 ConnectionManager::getDatasource($schemaName)
并在数据源不存在时捕获异常,或者调用 ConnectionManager::sourceList()
并检查您的 $schemaName
是否在返回的数组中,这是第一个选项的实现:
$schemaName = $this->Session->read('User.schema');
try {
ConnectionManager::getDatasource($schemaName)
} catch (MissingDatasourceException $e) {
$config = ConnectionManager::getDataSource('default')->config;
$config['database'] = $schemaName;
ConnectionManager::create($schemaName, $config);
}
和第二个选项:
$datasources = ConnectionManager::sourceList();
$schemaName = $this->Session->read('User.schema');
if (!in_array($schemaName, $datasources)) {
$config = ConnectionManager::getDataSource('default')->config;
$config['database'] = $schemaName;
ConnectionManager::create($schemaName, $config);
}
希望对您有所帮助