【问题标题】:Dynamically created datasource not being passed to associated models in CakePHP动态创建的数据源未传递给 CakePHP 中的关联模型
【发布时间】:2015-01-11 21:26:28
【问题描述】:

我有一个模型 - 汽车 - 汽车有几个关联的模型,让我们考虑其中一个与 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] 模型 Wheel 的表轮在数据源默认值中找不到。

由于某种原因,数据源没有从父模型传递到关联的子模型。如果我使用以下行在 Wheel 中明确设置数据源,那么一切正常。

$this->Car->Wheel->setDataSource($schemaName);

谁能帮助阐明这种行为以及如何解决这个问题?我觉得这不方便的原因是我的父模型有几个关联模型(它们还有关联模型)并且在每个模型上单独设置数据源听起来不正确。

附带问题 - 有没有办法在尝试动态创建数据源之前检查数据源是否已经存在?我有一个包装整个代码的 for 循环,每次循环迭代最终都会创建一个新的数据源

我使用的是 CakePHP 2.5.4

【问题讨论】:

    标签: php cakephp cakephp-2.0


    【解决方案1】:

    这里有一些代码会将 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);
    }
    

    (我没有测试这个修改后的功能,因为我现在不在我的开发 PC 上,但它是一个相当简单的更改,它应该可以工作)

    要在创建数据源之前检查数据源是否已经存在,我可以看到两种可能的方法,一种是调用ConnectionManager::getDatasource($schemaName) 并在数据源不存在时捕获异常,或者调用ConnectionManager::sourceList() 并检查您的@ 987654329@ 在返回的数组中,这是第一个选项的实现:

    $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);
    }
    

    希望对你有帮助

    【讨论】:

    • 一个问题 - 我想在某些模型中设置数据源,其中有一个名为 dynamicDB 的变量设置为 true。在设置数据源之前,我将如何修改上面的代码以检查它?
    • 我在回答中添加了一个函数来执行此操作
    • 谢谢 - 非常感谢 - 你对我在原始帖子中提到的附带问题有任何意见/建议 - 附带问题 - 有没有办法在尝试之前检查数据源是否已经存在动态创建一个?我有一个包装整个代码的 for 循环,每次循环迭代最终都会创建一个新的数据源
    • 我添加了几种方法来检查我的答案中是否存在来源,很高兴我能提供帮助
    • 我在新场景中遇到了错误。一些型号belongTo 其他型号反过来hasMany 的原始型号。在这种情况下,setDataSource 会导致递归并且不再起作用。有什么建议吗?
    猜你喜欢
    • 2018-08-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多