Yii框架“元数据库模型”创作+ postgres继承 [英] Yii framework "meta db model" creation + postgres inheritance

查看:146
本文介绍了Yii框架“元数据库模型”创作+ postgres继承的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有几个数据库表,女巫是使用继承从一个表女巫是一种用于创建新表的模板,现在我有一组业务逻辑方法女巫工作在列继承自模板,附加列仅用作演示模型的参数,它们对逻辑没有意义。



目标是在所有表中共享业务逻辑方法,我知道,现在可以通过添加另一个类来增加CActiveRecord,并从每个模型扩展,或者将逻辑包作为一个行为,并将其附加到模型。
但是,这将需要至少为每个表/模型写入转储类文件,但是这些表在系统中存活,并将被系统生命周期删除/创建。



有没有办法写一些元模型女巫将作为参数,表名称,或者可能有些方法来创建即时表的模型并附加对于企业逻辑?



我已经在Yii用户板上问了这个问题,但没有找到任何回应:/
我正在考虑这一点一些代码挑战,所以欢迎任何帮助/线索:)





一些样本:不同客户端设备的




  • hfc.cable_modem

  • lan.switch_port

  • lan.voip_gateway

  • (不久的将来,系统会添加更多的技术,所以新的表格客户端设备,并且有可能删除其中的一些支持)



每个表从模板表继承,client_device有这个字段:




  • client_id

  • service_id

  • core_device_id

  • (加上一些元数据列,用于创建,更新,更新等等的时间戳行为。)



您会看到业务逻辑仅在ID上运行,并且对于每个表都是相同的,其余的列用作设备参数存储/演示信息。



我的目标是拥有元模型客户端设备,将将业务逻辑应用于所有这些表,并且仍然为每个表提供每个表单,访问特定字段,而无需编写模型类,对于每个表(我必须做,每一个单一时间,当新技术将被添加,或者对于给定技术的支持在将来会被删除)

解决方案

我明白你是对的,我有一个基于我所做的事情的建议:



我有一个基本的功能模型。但该功能可以是文本功能,或图像功能等。但是,它们都共享共同的功能ID和其他几列。所以我采取了一种 EAV 方法。我有一个单独的功能表,然后我有一个表为每个子类型(文本,图像等)。 功能表中的其中一列包含子类型信息。然后在我的afterFind()方法的基础上,功能模型我看看子类型列。如果子类型是文本,我附加了一个文本类型的行为。此行为从子类型表中获取变量,并将其设置为与基本模型的属性一样被访问。



这样的一个例子:



client_device_table :(基表)

-client_id(主键)

-service_id

-core_device_id

-device_type(行为名称,如CableModemBehavior或VoipGatewayBehavior)



cable_modem_table

-core_device_id

-modem_info_1

-modem_into_2



voip_gateway_table

-core_device_id

-gateway_info_1

-gateway_into_2



在ClientDevice CActiveRecord模型(基本模型) :

  protectedFile(){
parent :: afterFind();
//记住$ this-> device_type保存相关行为,即CableModemBehavior
$ this-> attachBehavior($ this-> device_type,call_user_func(array($ this-> device_type,'model ')));
}

行为看起来像这样:

  class CableModemBehavior extends CActiveRecordBehavior {
public modem_info_1;
public modem_info_2;
public function attach($ owner)
{
parent :: attach($ owner);
$ connection = Yii :: app() - > getDb();
$ command = $ connection-> createCommand(SELECT *
FROM cable_modem_table
WHERE core_device_id =:device_id);
$ command-> bindParam(':device_id',$ this-> owner-> core_device_id);
$ data = $ command-> queryRow();
$ this-> modem_info_1 = $ data-> modem_info_1;
$ this-> modem_info_2 = $ data-> modem_info_2;
}
}

这是未经测试的,但现在应该发生的是您可以使用CableModemBehavior获取ClientDevice模型,因为它是子类型列条目,您将能够像常规ClientDevice属性(client_id)一样访问调制解调器属性(modem_info_1):



ClientDevice-> modem_info_1



当然会比这更多。这只是为了找到的情况。您将需要做更多的工作来获取大量属性分配的东西适用于$ _POSTs,或转移关系,或添加afterDelete,验证和afterSave方法来支持保存和删除等,但我希望这是一个有用的开始。



您还可以通过在行为中覆盖基本模型的__get和__set方法来使其更好,以便如果子类型表中的列被请求,它从文本表中透明地获取它,做一个模式查找来获取列名称等等。比在这个例子中像我这样做的硬编码更好。在 yiiext 信息库中查看EavBehavior是有帮助的, AdvancedArBehavior (或类似的),以获得如何使其更加轻松的句柄。而不是每个子类型的行为,您可以有通用的行为,只传递子类型表名称。 (哦,我真的很喜欢)



干杯!


I have few DB tables, witch are build using inheritance from one table witch is an sort of "template" for creation of new tables, and now i have set of businesses logic methods witch work on columns inherit from template, additional columns are used only as params for presentation of models, they're have no meaning for logic.

The goal is to share businesses logic methods along all of that tables, i know, now it can be done by adding another class witch extends CActiveRecord, and extend from it every model, or pack logic as a behavior and append it to models. But this will require to write at least "dump" class file for every table/model, but those tables "live" in system, and will be deleted/created with system life cycle.

Is there a way to write some sort of "meta-model" witch will take as a param, table name, or maybe some way to create models for tables "on-the-fly" and append to it businesses logic?

I've asked this question on Yii users board, but did not find any response :/ I'm considering this as some sort of code challenge, so any help / clues are welcome :)

[EDIT]

Some samples: tables for different client devices

  • hfc.cable_modem
  • lan.switch_port
  • lan.voip_gateway
  • (in near future, there will be more "technologies" added to system, so new tables for client devices, and there is a possibility to drop support for some of them)

every table inherits from template table client_device witch has that fields:

  • client_id
  • service_id
  • core_device_id
  • (plus some meta columns for timestampable behavior like created, updated, updater etc.)

like You see business logic operates only on ID's, and its identical for every table, rest of columns are used as device params storage/presentation information.

My goal is to have "meta-model" client device, witch will apply business logic to all this tables, and still provide for every of them, access to specific fields, without having to write model class, for every table (witch i'll have to do, every single time, when new technology will be added, or support for given technology will be dropped in a future)

解决方案

Well, if I understand you right, I have a suggestion based on something similar I am doing:

I have a base "feature" model. But the feature can be a "text" feature, or an "image" feature, etc. But they all share the common "feature id" and a couple other columns as well. So I took sort of an EAV approach. I have a single "feature" table, and then I have a table for each sub-type (text, image, etc). One of the columns in the "feature" table contains the sub-type info. Then in my "afterFind()" method on the base "feature" model I look at the sub-type column. If the sub-type is "text" I attach a "text" type behavior I made. This behavior gets the variables from the sub-type table and sets them up to be accessed just like attributes of the base model.

Something like this:

client_device_table: (base table)
-client_id (primary key)
-service_id
-core_device_id
-device_type (name of the behavior, like CableModemBehavior, or VoipGatewayBehavior)

cable_modem_table
-core_device_id
-modem_info_1
-modem_into_2

voip_gateway_table
-core_device_id
-gateway_info_1
-gateway_into_2

In the ClientDevice CActiveRecord model (the base model):

protected function afterFind() {
  parent::afterFind();
  // remember $this->device_type holds the relevant behavior i.e. CableModemBehavior
  $this->attachBehavior($this->device_type,call_user_func(array($this->device_type, 'model')));
}

And the behavior looks something like this:

class CableModemBehavior extends CActiveRecordBehavior {
  public modem_info_1;
  public modem_info_2;
  public function attach($owner)
  {
    parent::attach($owner);
    $connection = Yii::app()->getDb();
    $command=$connection->createCommand("SELECT * 
      FROM cable_modem_table 
      WHERE core_device_id=:device_id");
    $command->bindParam(':device_id',$this->owner->core_device_id);
    $data=$command->queryRow();
    $this->modem_info_1 = $data->modem_info_1;
    $this->modem_info_2 = $data->modem_info_2;
  }
}

This is untested, but what SHOULD happen now is if you get a ClientDevice model with CableModemBehavior as it's sub-type column entry, you will be able to access the modem attributes (modem_info_1) just like the regular ClientDevice attributes (client_id):

ClientDevice->modem_info_1

There is going to be more to it than this, of course. This is just for the "find" case. You will need to do some more work to get the mass attribute assignment thing to work for $_POSTs, or to transfer Relations, or to add afterDelete, validate and afterSave methods to support saving and deleting, etc, but I hope this is a helpful start.

You could also make this a lot nicer by overriding the __get and __set methods of the base model in the behaviors so that if a column from the sub-type table is requested, it goes and get's it from the text table transparently, doing a schema lookup to get the column names, etc. Better than hard coding it like I did in this example. It would be helpful to look at the EavBehavior in the yiiext repository and the AdvancedArBehavior (or similar ones) to get a handle on how to make it slicker. Instead of a behavior for each sub-type, you could have a generic behavior and just pass in the sub-types table name. (ooo I like that actually)

Cheers!

这篇关于Yii框架“元数据库模型”创作+ postgres继承的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆