IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    Laravel专供:实现Schemaless

    老王发表于 2017-01-14 09:11:03
    love 0

    之所以要实现 Schemaless,主要是因为在线 DDL 有很多痛点,关于这一点,我在以前已经写过文章,没看过的不妨看看「史上最LOW的在线DDL解决方案」,不过那篇文章主要以介绍为主,并没有涉及具体的实现,所以我写了一个 Laravel 的例子。

    首先创建测试用的 users 表,并且添加虚拟字段 name、address、level:

    mysql> CREATE TABLE users (
               id INT UNSIGNED NOT NULL AUTO_INCREMENT,
               created_at timestamp null,
               updated_at timestamp null,
               data JSON NOT NULL,
               PRIMARY KEY(id)
           );
    
    mysql> ALTER TABLE users add name VARCHAR(100) AS
           (JSON_UNQUOTE(JSON_EXTRACT(data, '$.name'))) AFTER id;
    
    mysql> ALTER TABLE users add address VARCHAR(100) AS
           (JSON_UNQUOTE(JSON_EXTRACT(data, '$.address'))) AFTER name;
    
    mysql> ALTER TABLE users add level INT UNSIGNED AS
           (JSON_EXTRACT(data, '$.level')) AFTER name;

    然后是核心代码 Schemaless.php,以 trait 的方式实现:

    <?php
    
    namespace App;
    
    trait Schemaless
    {
        public function getDirty()
        {
            $dirty = collect(parent::getDirty());
    
            $keys = $dirty->keys()->map(function($key) {
                if (in_array($key, $this->virtual)) {
                    $key = $this->getDataColumn() . '->' . $key;
                }
    
                return $key;
            });
    
            return $keys->combine($dirty)->all();
        }
    
        public function save(array $options = [])
        {
            if (!$this->exists) {
                $this->reviseRawAttributes();
            }
    
            return parent::save($options);
        }
    
        public function getDataColumn()
        {
            static $column;
    
            if ($column === null) {
                $column = defined('static::DATA') ? static::DATA : 'data';
            }
    
            return $column;
        }
    
        private function reviseRawAttributes()
        {
            $attributes = collect($this->getAttributes());
    
            $virtual = $attributes->only($this->virtual);
    
            $attributes = $attributes->diffKeys($virtual)->merge([
                $this->getDataColumn() => json_encode($virtual->all()),
            ]);
    
            $this->setRawAttributes($attributes->all());
        }
    }

    接着是 Model 实现 User.php,里面激活了 schemaless,并设置了虚拟字段:

    <?php
    
    namespace App;
    
    use Illuminate\Database\Eloquent\Model;
    
    class User extends Model
    {
        use Schemaless;
    
        protected $virtual = ['name', 'address', 'level'];
    }

    最后是 Controller 实现 UsersController.php,里面演示了如何创建和修改:

    <?php
    
    namespace App\Http\Controllers;
    
    use Illuminate\Http\Request;
    use App\User;
    
    class UsersController extends Controller
    {
        public function __construct(User $user)
        {
            $this->user = $user;
        }
    
        public function store()
        {
            $user = $this->user;
    
            $user->name = '老王';
            $user->address = '东北';
            $user->level = 1;
            $user->save();
        }
    
        public function update()
        {
            $user = $this->user->find(1);
    
            $user->address = '北京';
            $user->save();
        }
    }
    

    从代码演示中,我们可以看到,为了实现 Schemaless,虽然我们引入了虚拟字段的概念,但并没有对使用者造成困扰,基本用法没有任何变化,完全透明实现!



沪ICP备19023445号-2号
友情链接