Yii模型:动态表关系

时间:2013-07-30 13:24:53

标签: relational-database yii

Table.linkedIndex LinkedIndex.ID 相关。字段 LinkedIndex.TableName 的值为 Linked1 Linked2 ,并定义其中哪些表与表中的行相关即可。

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

Table.linkedID = [LinkedIndex.TableName] .ID

DB diagram


实施例

表格值:

enter image description here

LinkedIndex 值:

enter image description here

现在我应该从 Linked2 获取行ID,其中ID = 2:

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

模型

在模型中,我尝试使用 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]:无法打开流:没有这样的文件或目录


有没有办法建立动态关系 Table.linkedID - >使用Yii Models [LinkedIndex.TableName] .ID

2 个答案:

答案 0 :(得分:1)

根据这里的Yii文档:

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

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

您可以按照架构将具有不同键的表链接在一起:

foreign_key => primary_key

  

如果您需要指定自定义PK-> FK关联,您可以将其定义为数组('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模型的类名(相对于您的表模型 - 即相同的文件夹。当然可以更改它),array('ID' => 'linkedIndex')将关系指定为{{1} }。

修改

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

  

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

因为你试图在这里建立另一种关系:

LinkedIndex.ID = Table.linkedIndex

这一部分:'linked' => array( self::BELONGS_TO, 'linkedIndex.TableName', array('ID' => 'linkedID'), ) 引用了一个新的模型类linkedIndex.TableName,因此Yii尝试加载该类'文件linkedIndex.TableName并抛出错误,因为它不存在。

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

Table

这是通过我们在上面建立的关系实现的。 $this->linkedIndex->TableName 引用$this模型,Table引用我们上面提到的linkedIndex关系,LinkedIndexTableName模型的属性

修改2

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

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

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

您可以使用LinkedIndex模型的afterFind函数在Yii中创建模型后创建辅助链接,并在那里实例化新的链接模型。

你的LinkedIndex模型有这样的东西:

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模型中)来访问linked表的属性:

Table

答案 1 :(得分:0)

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

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,其中ID = 2:

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