tisswb 2015-12-21 22:00:45 16507次浏览 14条评论 43 13 0

业务中有时候有这种情况出现,有些数据表是动态生成的,这时候如果有一个动态AR可以使用,这真是极好的。在网上搜了一圈,只有github上yii2的issue里,有人提供了一些思路,我就沿着这个思路进行了一些完善,代码如下:

<?php

namespace app\models;

use Yii;
use yii\base\InvalidConfigException;
use yii\db\ActiveQuery;
use yii\db\ActiveRecord;
use yii\helpers\ArrayHelper;

class Mar extends ActiveRecord
{
    public static $table = '';

    /**
     * Mar constructor.
     * @param array $table
     * @param array $config
     */
    public function __construct($table, $config = [])
    {
        self::$table = $table;
        parent::__construct($config);
    }

    /**
     * @return array|string
     */
    public static function tableName()
    {
        return self::$table;
    }

//    public function rules()
//    {
//        return [
//        ];
//    }
//
//    public function attributeLabels()
//    {
//        return [
//        ];
//    }

    /**
     * @param $table
     * @return object
     * @throws InvalidConfigException
     */
    public static function findx($table)
    {
        if (self::$table != $table) {
            self::$table = $table;
        }
        return Yii::createObject(ActiveQuery::className(), [get_called_class(), ['from' => [static::tableName()]]]);
    }

    /**
     * @param array $row
     * @return static
     */
    public static function instantiate($row)
    {
        return new static(static::tableName());
    }

    /**
     * @param $table
     * @param $condition
     * @return mixed
     * @throws InvalidConfigException
     */
    public static function findOnex($table, $condition)
    {
        return static::findByConditionx($table, $condition)->one();
    }

    /**
     * @param $table
     * @param $condition
     * @return mixed
     * @throws InvalidConfigException
     */
    public static function findAllx($table, $condition)
    {
        return static::findByConditionx($table, $condition)->all();
    }

    /**
     * @param $table
     * @param $condition
     * @return mixed
     * @throws InvalidConfigException
     */
    protected static function findByConditionx($table, $condition)
    {
        $query = static::findx($table);

        if (!ArrayHelper::isAssociative($condition)) {
            // query by primary key
            $primaryKey = static::primaryKey();
            if (isset($primaryKey[0])) {
                $condition = [$primaryKey[0] => $condition];
            } else {
                throw new InvalidConfigException('"' . get_called_class() . '" must have a primary key.');
            }
        }

        return $query->andWhere($condition);
    }
}

其中,rules()方法、attributeLabels()方法、search()方法我没有去实现,这块可以动态实现,需要看情况而定。

目前这个完成度,可以实现

$user = new Mar('user');
$user->username = 'xxx';
$user->save()

$user = Mar::findx('user')->where(['id' => 1])->one();

$user = Mar::findOnex('user', 1);

这些基本操作已经都实现了,其中'user'就是动态表名。

暂时我是这么实现的,发出来让大家乐呵乐呵。

觉得很赞
  • 评论于 2015-12-22 17:00 举报

    不错,谢谢分享 了

    1 条回复
    评论于 2015-12-22 21:19 回复

    能有用就行

    觉得很赞
  • 评论于 2015-12-28 09:24 举报

    支持支持~~~~

  • 评论于 2015-12-29 16:39 举报

    妙不可言。。

  • 评论于 2015-12-30 09:43 举报

    赞。。。。。。

  • 评论于 2015-12-31 10:31 举报

    为啥不能生成表的时候顺便把模型也生成了。

    1 条回复
    评论于 2016-01-01 20:17 回复

    有时候有些动态生成的表 每一个都重复生成model没有必要,还有些时候 比如集成一些第三方的系统,比如我就做过yii2将phpcms作为一个模块嵌入进来的项目,这时,这个类的作用就体现出来了

  • 评论于 2016-01-12 21:17 举报

    赞一个,有这个是不是就可以跟TP里面的M方法一样了

    2 条回复
    评论于 2016-01-13 00:40 回复

    可以这么认为,不过还是推荐原生态的一个表对应一个model

    评论于 2016-01-26 16:14 回复

    我也是这么觉得

  • 评论于 2016-01-20 15:36 举报

    不错,很好的拓展思路。

  • 评论于 2016-03-07 14:37 举报

    不错!感谢分享!

  • 评论于 2016-04-13 22:50 举报

    动态表思路简单,要是动态字段怎么个思路

    3 条回复
    评论于 2016-04-17 20:01 回复

    你的意思是根据不同的字段动态生成表?还是某个字段是个动态的类型?

    评论于 2016-04-18 20:29 回复

    表单字段由客户自己定义(数量,类型,限制规则)。

    评论于 2016-04-20 20:48 回复

    可以参考phpcms的模型概念来实现一遍。

  • 评论于 2016-10-01 22:43 举报

    楼主你好,我完全按你的代码打的,可是出了这个错误"Missing argument 1 for app\models\Bb::construct(), called in /var/www/html/yii222/basic/controllers/BbController.php on line 73 and defined",那个"construct"函数重载,需要输入3个参数, 可以看这个帖子有类似问题http://www.yiiframework.com/forum/index.php/topic/70587-missing-argument-2-for-yiibasecontroller-construct/ ; 请问怎么解决阿?

    5 条回复
    评论于 2016-10-07 21:23 回复

    我这边测试了一下,没发现这个错误,请问你的用法是按照我帖子里写的方法使用的么?第一个argument应该是动态的表名,你是不是没写这个?

    评论于 2016-10-08 11:32 回复

    我有5个结构相同的表,就名字不同,在tablename里hardcode返回不同表命没问题,但是这里我是写的动态表名,model里的php也是完全按这个方法写的,只是我在control里的index下调用,一调用就出错. index 如下:

    public function actionIndex()
    {
       // $mybb = new Bb('bb');
    
       $dataProvider = new ActiveDataProvider([
              'query' =>Bb::find(),
         //     'query' => $mybb->find(),
          ]);
    
        return $this->render('index', [
            'dataProvider' => $dataProvider,
        ]);
    }
    

    把注释的一取消就会出错,好像是什么ActiveDataProvider里面会调用原来默认的构造函数,但被我们重载了,找不到第一个参数,这种该怎么解决阿,多谢~~~~

    评论于 2016-10-08 12:02 回复

    @hypermoon 试试如下:

    'query' =>Bb::findx('bb')
    
    评论于 2016-10-08 15:22 回复

    谢谢,把那个"instantiate"注释掉,就解决了.

    评论于 2016-10-08 20:56 回复

    @hypermoon 这样啊,我得仔细再看看代码,可能有些冲突,谢谢你的使用

  • 评论于 2016-11-07 21:21 举报

    得到启发,非常感谢分享!

  • 评论于 2016-12-17 17:49 举报

    我错了 哈哈哈哈

  • 评论于 2017-05-31 17:49 举报

    请问 为什么这个方法instantiate() 要传一个$row呢?

  • 评论于 2018-09-27 17:32 举报

    我在作者代码的基础上添加了rules()方法、attributeLabels()方法,希望大家指正哈。
    地址:https://xiejindou.com/2018/09/27/Yii2动态AR模型/

    1 条回复
    评论于 2018-09-28 15:30 回复

    你这个操作 真是棒棒哒

您需要登录后才可以评论。登录 | 立即注册