【问题标题】:Yii model: Dynamic table relationsYii 模型:动态表关系
【发布时间】:2013-07-30 13:24:52
【问题描述】:

Table.linkedIndexLinkedIndex.ID 相关。 LinkedIndex.TableName 字段的值是 Linked1Linked2 并定义这些表中的哪些与 Table 中的行相关

现在我想与 Yii 模型建立动态链接,以便我可以轻松地从 Table 行获取到相应的 Linked1Linked2 行:

Table.linkedID = [LinkedIndex.TableName].ID


示例

表格值:

LinkedIndex 值:

现在我应该从 Linked2 获取 ID=2 的行:

$model = Table::model()->findByPk(0);
$row = $model->linked;

型号

在模型 Table 中,我尝试使用 linkedIndex.TableName 的值的名称与表建立关系:

public function relations()
{
    return array(
        'linkedIndex' => array(self::HAS_ONE, 'LinkedIndex', array('ID' => 'linkedIndex')),
        'linked' => array(
            self::HAS_ONE,
            'linkedIndex.TableName',
            array('ID' => 'linkedID'),
        )
    )
}

然后我得到错误:

include(linkedIndex.TableName.php) [function.include]:打开流失败:没有这样的文件或目录


有什么方法可以与 Yii 模型建立 动态 关系 Table.linkedID -> [LinkedIndex.TableName].ID

【问题讨论】:

    标签: relational-database yii


    【解决方案1】:

    这里的 Yii 文档:

    http://www.yiiframework.com/doc/api/1.1/CActiveRecord#relations-detail

    我建议使用 self::HAS_ONE 代替(除非 LinkedIndex 中可以有多个具有相同 ID 的行 - 尽管从上面的外观来看,我怀疑是这种情况)。

    您可以通过遵循架构将具有不同键的表链接在一起:

    foreign_key => 主键

    如果您需要指定自定义 PK->FK 关联,您可以将其定义为 array('fk'=>'pk')。对于复合键,它将是数组('fk_c1'=>'pk_с1','fk_c2'=>'pk_c2')。

    所以在你的情况下:

    public function relations(){
        return array(
            'linkedIndex' => array(self::HAS_ONE, 'LinkedIndex', array('ID' => 'linkedIndex')),
        );
    }
    

    LinkedIndex 是 LinkedIndex 模型的类名(相对于您的 Table 模型 - 即同一个文件夹。当然,您可以更改它),array('ID' => 'linkedIndex') 将关系指定为 LinkedIndex.ID = Table.linkedIndex

    编辑

    查看您更新的示例,我认为您误解了关系函数的工作原理。你得到了错误

    include(linkedIndex.TableName.php) [function.include]:打开流失败:没有这样的文件或目录

    因为您正试图在此处创建另一个关系:

    'linked' => array(
        self::BELONGS_TO,
        'linkedIndex.TableName',
        array('ID' => 'linkedID'),
    )
    

    这部分:linkedIndex.TableName 引用了一个新的模型类 linkedIndex.TableName,因此 Yii 尝试加载该类的文件 linkedIndex.TableName.php 并抛出错误,因为它不存在。

    我认为您正在寻找的是能够访问表 LinkedIndex 中的值 TableName,对吗?如果是这样,则可以通过以下方式从 Table 模型中访问:

    $this->linkedIndex->TableName
    

    我们在上面建立的关系使这成为可能。 $this 指的是Table 模型,linkedIndex 指的是我们上面建立的LinkedIndex 关系,TableName 是那个LinkedIndex 模型的属性。

    编辑 2

    根据您的 cmets,您似乎正在尝试建立更复杂的关系。老实说,这不是你应该使用链接表的方式(理想情况下,你应该在两个表之间有一个链接表,而不是一个链接表,说明要链接到哪个第三个表),但我会尝试和在 Yii 中尽可能地回答你的问题。

    理想情况下,这种关系应该在LinkedIndex 模型中建立,因为这就是关系所在。

    由于您使用表名作为链接因素,因此您需要创建一种在找到记录后动态传递要使用的表的方法。

    在 Yii 中创建模型后,您可以使用 LinkedIndex 模型的 afterFind 函数创建二级链接,并在此处实例化新的链接模型。

    你的 LinkedIndex 模型是这样的:

    class LinkedIndex extends CActiveRecord{
        public $linked;
    
        public static function model($className = __CLASS__){
            return parent::model($className);
        }
    
        public function tableName(){
            return 'LinkedIndex';
        }
    
        public function afterFind(){
            $this->linked = new Linked($this->TableName);
    
            parent::afterFind();
        }
    
        //...etc.
    }
    

    afterFind 实例化一个新的Linked 模型,并传入要使用的表名。这允许我们在 Linked 模型中做这样的事情:

    class Linked extends CActiveRecord{
        private $table_name;
    
        public function __construct($table_name){
            $this->table_name = $table_name;
        }
    
        public static function model($className = __CLASS__){
            return parent::model($className);
        }
    
        public function tableName(){
            return $this->table_name;
        }
    
        //...etc.
    }
    

    这就是我们动态创建具有可互换表名的类的方式。当然,失败的类需要对每个方法进行单独的操作,但是您可以检查 table_name 是什么并采取相应的行动(这很麻烦,但会起作用)。

    所有这些都将导致通过(从Table 模型中)访问linked 表的属性:

    $this->linkedIndex->linked->foo;
    

    【讨论】:

    • 关系 Table -> LinkedIndex 不是真正的问题,而是 dynamic 关系 Table -> “LinkedIndex.TableName”
    • 我不确定我是否看到了问题(也许我误解了这个问题)。链接后,您可以通过Table 模型访问linkedIndex 的属性:$this->linkedIndex->tableName
    • 刚刚用您的输入更正了我的示例。目标是像这样从 Linked1Linked2 获取值:$this->linked->ANYVALUES where Table 通过 LinkedIndex.TableName 链接到相应的表
    • 对,我需要 TableName 根据 $this-> 建立从 TableLinked1Linked2 的关系链接索引-> 表名。因此,通过调用 $this->linked,我将从 Linked1Linked2 中获取行。像这样:Table.linkedID -> [LinkedIndex.TableName].ID.
    【解决方案2】:

    因为需要Linkedex.TableName和Table.linkedID的值来获取值,所以我将M Sost建议的afterFind直接移到Table-Class 并相应地更改其内容。不再需要虚拟模型。

    class Table extends CActiveRecord {
        public $linked; // Needs to be public, to be accessible
        // ...etc.
        public function afterFind() {
            $model = new $this->linkedIndex->TableName;
            $this->linked = $model::model()->findByPk( $this->linkedID );
            parent::afterFind();
        }
        // ...
    }
    

    现在我从 Linked2 获得 ID=2 的行:

    $model = Table::model()->findByPk(0);
    $row = $model->linked;
    

    【讨论】:

    • 最终这也会起作用,但是由于链接表名称包含在LinkedIndex 中,它应该真正属于该模型的类(因为它在技术上是该类的属性)。不过,这个解决方案肯定会奏效。也感谢您的提醒,$linked 需要公开才能访问。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多