doufu8127 2010-08-25 09:44 采纳率: 100%
浏览 61
已采纳

Yii框架“元数据库模型”创建+ postgres继承

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)

  • 写回答

1条回答 默认 最新

  • duanniwu7730 2010-08-26 18:28
    关注

    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!

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 素材场景中光线烘焙后灯光失效
  • ¥15 请教一下各位,为什么我这个没有实现模拟点击
  • ¥15 执行 virtuoso 命令后,界面没有,cadence 启动不起来
  • ¥50 comfyui下连接animatediff节点生成视频质量非常差的原因
  • ¥20 有关区间dp的问题求解
  • ¥15 多电路系统共用电源的串扰问题
  • ¥15 slam rangenet++配置
  • ¥15 有没有研究水声通信方面的帮我改俩matlab代码
  • ¥15 ubuntu子系统密码忘记
  • ¥15 保护模式-系统加载-段寄存器