<?php

namespace loyalsoft\Util;

/**
 * 将对象在Redis中进行扁平化存储（即将对象的一级属性拆分到hash中存储，属性值仍然采用json编码）
 * @author gwang
 */
trait RedisFlat {

    /**
     * 魔术方法的运用，增加类似于 $obj->name()这样的调用方法，能够直接将属性当做方法用（内部是取数据方法）
     * @param type $name
     * @param type $arguments
     * @return type
     */
    public function __call($name, $arguments) {
        if (array_key_exists("$name", $this)) {
            if (!isset($this->dicSaveflags) or ! is_array($this->dicSaveflags)) {
                $this->dicSaveflags = array();
            }
            if (isset($arguments[0])and $arguments[0]) {
                $this->dicSaveflags[] = $name;
            }
            if (!isset($this->$name)) {
                $this->$name = $this->readPropertyFromMem($name);
            }
        }
        return $this->$name;
    }

    /**
     * 对象实例必须有获取/指定自己在Mem中的key的方法
     */
    abstract function getMemKey();

    /**
     * @return $this 从Mem中初始化对象
     */
    function ReadAllPropertyFromMem() {
        foreach ($this as $name => $value) {
            if ($name == self::$_ext) {
                continue;
            }
            $v = $this->readPropertyFromMem($name);
            if (!empty($v)) {
                $this->$name = $v;
            }
        }
        return $this;
    }

    /**
     * 将对象数据写会mem
     */
    function updateData() {
        $key = $this->getMemKey();
        \loyalsoft\gMem()->hmset($key, $this->getDict());
    }

    /**
     * @return array 将$this转成ASSOC_Array(string propertyName,json proptertyValue)
     */
    private function getDict() {
        $arr = array();
        foreach ($this as $key => $value) {
            if ($key == self::$_ext) {
                continue;
            }
            if (isset($this->dicSaveflags) and in_array($key, $this->dicSaveflags)) { # 只关注做了保存标记的
                $arr[$key] = JsonUtil::encode($value);
            } else {                                                            # 数组未初始化的情况下全部提取
                $arr[$key] = JsonUtil::encode($value);
            }
        }
        return $arr;
    }

    /**
     * 读取单独的key的方法
     * @param type $name
     * @return type
     */
    private function readPropertyFromMem($name) {
        $key = $this->getMemKey();
        return \loyalsoft\gMem()->hget($key, $name);
    }

    /**
     * @var string 特定字段名称，将被排除在序列化之外
     */
    private static $_ext = "dicSaveflags";

    /**
     * @var array[string] 保存标记数组
     */
    protected $dicSaveflags;

}
