BaseModel.php 12.6 KB
<?php
/**
 * Created by Qingger Corp.
 * User: jsspf
 * Date: 2017/5/5
 * Time: 15:37
 */
namespace App\Models;

use App\Exceptions\ECException;
use App\Exceptions\ModelException;
use App\Library\AppUtils\UtilToolMethods;
use App\Library\VariDefines\Common\GlobalSysEnum;
use App\Library\VariDefines\ErrorCodes\GlobalErrCode;
use App\Services\Cache\AppCacheManager;
use Illuminate\Database\Query\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Query\Expression;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\App;
use Windwalker\String\SimpleTemplate;
use Log;
use DB;

/**
 * Class BaseModel
 * @package App\Models
 *
 * @method Builder where(string|array|\Closure $column, string $operator = null, mixed $value = null, string $boolean = 'and')
 * @method Builder orWhere(string $column, string $operator = null, mixed $value = null)
 * @method Builder whereRaw(string $sql, array $bindings = array(), string $boolean = 'and')
 * @method Builder orWhereRaw(string $sql, array $bindings = array())
 * @method Builder whereBetween(string $column, array $values, string $boolean = 'and', bool $not = false)
 * @method Builder orWhereBetween(string $column, array $values)
 * @method Builder whereNotBetween(string $column, array $values, string $boolean = 'and')
 * @method Builder orWhereNotBetween(string $column, array $values)
 * @method Builder whereNested(\Closure $callback, string $boolean = 'and')
 * @method addNestedWhereQuery(Builder|Builder $query, string $boolean = 'and')
 * @method Builder whereExists(\Closure $callback, string $boolean = 'and', bool $not = false)
 * @method Builder orWhereExists(\Closure $callback, bool $not = false)
 * @method Builder whereNotExists(\Closure $callback, string $boolean = 'and')
 * @method Builder orWhereNotExists(\Closure $callback)
 * @method Builder whereIn(string $column, mixed $values, string $boolean = 'and', bool $not = false)
 * @method Builder orWhereIn(string $column, mixed $values)
 * @method Builder whereNotIn(string $column, mixed $values, string $boolean = 'and')
 * @method Builder orWhereNotIn(string $column, mixed $values)
 * @method Builder whereNull(string $column, string $boolean = 'and', bool $not = false)
 * @method Builder whereNotNull(string $column, string $boolean = 'and')
 * @method Builder orWhereNotNull(string $column)
 * @method Builder whereDate(string $column, string $operator, int $value, string $boolean = 'and')
 * @method Builder whereDay(string $column, string $operator, int $value, string $boolean = 'and')
 * @method Builder whereMonth(string $column, string $operator, int $value, string $boolean = 'and')
 * @method Builder whereYear(string $column, string $operator, int $value, string $boolean = 'and')
 * @method $this dynamicWhere(string $method, string $parameters)
 * @method Builder groupBy()
 * @method Builder having(string $column, string $operator = null, string $value = null, string $boolean = 'and')
 * @method Builder orHaving(string $column, string $operator = null, string $value = null)
 * @method $this havingRaw(string $sql, array $bindings = array(), string $boolean = 'and')
 * @method Builder orHavingRaw(string $sql, array $bindings = array())
 * @method Builder orderBy(string $column, string $direction = 'asc')
 * @method Builder latest(string $column = 'created_at')
 * @method Builder oldest(string $column = 'created_at')
 * @method Builder orderByRaw(string $sql, array $bindings = array())
 * @method $this offset(int $value)
 * @method Builder skip(int $value)
 * @method Builder limit(int $value)
 * @method Builder take(int $value)
 * @method Builder forPage(int $page, int $perPage = 15)
 * @method Builder union(Builder|\Closure $query, bool $all = false)
 * @method Builder unionAll(Builder|\Closure $query)
 * @method $this lock(bool $value = true)
 * @method Builder lockForUpdate()
 * @method Builder sharedLock()
 * @method string toSql()
 * @method mixed find(int $id, array $columns = array('*'))
 * @method mixed first(array $columns = array('*'))
 * @method mixed value(string $column)
 * @method $this select(array|mixed $columns = array('*'))
 * @method $this distinct()
 * @method $this join(string $table, string $one, string $operator = null, string $two = null, string $type = 'inner', bool $where = false)
 * @method Builder joinWhere(string $table, string $one, string $operator, string $two, string $type = 'inner')
 * @method Builder leftJoin(string $table, string $first, string $operator = null, string $second = null)
 * @method Builder leftJoinWhere(string $table, string $one, string $operator, string $two)
 * @method Builder rightJoin(string $table, string $first, string $operator = null, string $second = null)
 * @method Builder rightJoinWhere(string $table, string $one, string $operator, string $two)
 * @method Collection get(array $columns = array('*'))
 * @method array lists(string $column, string|null $key = null)
 * @method string implode(string $column, string $glue = '')
 * @method bool exists()
 * @method int count(string $columns = '*')
 * @method mixed min(string $column)
 * @method mixed max(string $column)
 * @method mixed sum(string $column)
 * @method mixed avg(string $column)
 * @method mixed average(string $column)
 * @method mixed aggregate(string $function, array $columns = array('*'))
 * @method float|int numericAggregate(string $function, array $columns = array('*'))
 * @method bool insert(array $values)
 * @method int insertGetId(array $values, string $sequence = null)
 * @method void truncate()
 * @method Builder newQuery()
 * @method void mergeWheres(array $wheres, array $bindings)
 * @method Expression raw(mixed $value)
 *
 */
class BaseModel extends Model
{
    use UtilToolMethods;
    protected $table='';
    protected $defautCacheTime = 60;

    /**
     * 缓存管理器
     * @var AppCacheManager
     */
    protected $appCacheManager = null;

    /**
     * 对Model的操作行为
     * @var string
     */
    private $modelAction = GlobalSysEnum::STS_CREATED;


    public function __construct(array $attributes = [])
    {
        parent::__construct($attributes);
        $this->appCacheManager = App::make(AppCacheManager::class);
    }

    public function getPrimaryKey() {
        return $this->primaryKey;
    }

    public function getMyId() {
        return $this->{$this->primaryKey};
    }

    public function getTable() {
        return $this->table;
    }

    public function getColItem($item) {
        return $this->table.".".$item;
    }

    public function formatArray($queryResult)
    {
        return json_decode(json_encode($queryResult), true);
    }

    /**
     * 基础的条件查询,支持以下几种方式
     *      $this->getQueryByConditions(array(
     *          'id'    => '1',                             // id==1
     *          'col1'  => [1,2,3],                         // col1 in (1,2,3)
     *          'col2'  => [ 'sign' => '!=' , value=>3 ]    // col2 != 3
     *          'col3'  => [ 'operator=>'whereNotIn', value=[1,2,3] ]  // col3 not in (1,2,3)
     *      ));
     * @param array $conditions
     *
     * @param array $selectItems
     * @param bool $isDistinct
     * @return Builder
     */
    public function getQueryByConditions(Array $conditions,Array $selectItems=[],$isDistinct=false) {
        $query = $this;
        foreach ($conditions as $key=>$val) {
            if(is_array($val) && isset($val['operator'])) {
                $query = $query->{$val['operator']}($val['value']);
            }elseif(is_array($val) && isset($val['sign'])) {
                $query = $query->where($key,$val['sign'],$val['value']);
            }elseif(is_array($val)){
                $query = $query->whereIn($key,$val);
            }else{
                $query = $query->where($key,$val);
            }
        }
        if(!empty($selectItems)) {
            $query = $query->select($selectItems);
        }
        if($isDistinct) {
            $query = $query->distinct();
        }

        return $query;
    }



    /* override */
    public function checkValidItem(Array $conditions) {
        return $this->where($conditions)->count();
    }

    /**
     * 根据primaryId更新数据字段
     * @param array $updateItems
     * @param $idVal
     * @return int
     */
    public function updateItemsByPrimaryId(Array $updateItems,$idVal) {
        return DB::table($this->table)->where($this->primaryKey,$idVal)->update($updateItems);
    }

    /**
     * 根据条件更新数据字段
     * @param array $updateItems
     * @param array $conditions
     * @return int
     */
    public function updateItemsByConditions(Array $updateItems,Array $conditions) {
        return DB::table($this->table)->where($conditions)->update($updateItems);
    }

    /**
     * 检查模型的ID数据是否存在,即是否真正的实体
     * @return bool
     * @throws ModelException
     */
    protected function checkObjectIdExist() {
        if(!isset($this->primaryKey) || !isset($this->{$this->primaryKey})) {
            throw new ModelException('Object Not Found Error',GlobalErrCode::ERR_MODEL_OBJECT_NOT_FOUND);
        }
        return true;
    }


    /**
     * 根据主键获得实例
     * @param $keyId
     * @return BaseModel
     */
    public function getInstanceByKeyId($keyId) {
        return $this->find($keyId);
    }

    /**
     * @return mixed|null
     */
    public function getMyUpdatedAt() {
        return isset($this->updated_at) ? $this->updated_at : null;
    }

    /**
     * @return mixed|null
     */
    public function getMyCreatedAt() {
        return isset($this->created_at) ? $this->created_at : null;
    }


    /**
     * 检查ID对应的数据实例是否存在
     * @param $id
     * @return true
     * @throws ECException
     */
    public function checkIdExists($id) {
        $instance = $this->find($id);
        if(!$instance) {
            throw new ECException('数据对应的ID不存在:'.$id,GlobalErrCode::ERR_DATA_NOT_FOUND);
        }
        return true;
    }

    /**
     * @override
     * @param array $options
     * @return bool
     */
    public function save(array $options = [])
    {
        if(isset($this->{$this->primaryKey})) {
            $this->modelAction = GlobalSysEnum::STS_UPDATED;
        } else {
            $this->modelAction = GlobalSysEnum::STS_CREATED;
        }
        Log::debug(SimpleTemplate::render('Model Save for {{table}} - {{action}}',[
            'table'  => $this->table,
            'action' => $this->modelAction
        ]),['data'=>toArray($this)]);


        return parent::save($options);
    }

    /**
     * @override
     * @return bool|null
     */
    public function delete()
    {
        $this->modelAction = GlobalSysEnum::STS_DELETED;
        Log::debug(SimpleTemplate::render('Model Delete for {{table}}',[
            'table' => $this->table
        ]),['id'=>$this->getMyId()]);

        return parent::delete();
    }


    /**
     * 基础方法,获得数据所归属的企业
     * @return mixed|null
     */
    public function getMyGroupId() {
        return isset($this->group_id) ? $this->group_id : null;
    }


    /**
     * 获得对象的Hash值
     * @param $objectId
     * @return string | null
     */
    protected function getObjectHashValue($objectId) {
        $fullClassName = $this->getFullClassName();
        $groupId = $this->getMyGroupId();

        if(!isset($fullClassName) || !isset($groupId)) {
            return null;
        }

        return (new ODAObjectKeyHash())->getObjectKeyHash($groupId,$fullClassName,$objectId);
    }

    /**
     * 设置对象的Hash值
     * @param $objectId
     * @param array $val
     * @return ODAObjectKeyHash|null
     */
    protected function setObjectHash($objectId,array $val) {
        $fullClassName = $this->getFullClassName();
        $groupId = $this->getMyGroupId();

        if(!isset($fullClassName) || !isset($groupId) || empty($val)) {
            return null;
        }

        $valEncoding = $this->arrayEncode($val,GlobalSysEnum::SIGN_SHA1);

        return (new ODAObjectKeyHash())->setObjectKeyHash($groupId,$fullClassName,$objectId,$valEncoding);
    }


    /**
     * 检查对象的Hash是否存在,如不存在则存储Hash
     * @param BaseModel $baseModel
     * @param $keyId
     * @param array $value
     * @return bool
     */
    protected function checkObjectExistAndStoreHash(BaseModel $baseModel, $keyId ,array $value) {
        if($baseModel) {
            $valEncodingHash = $this->arrayEncode($value,GlobalSysEnum::SIGN_SHA1);

            $storeValHash    = $baseModel->getObjectHashValue($keyId);

            if(isset($storeValHash) && $storeValHash==$valEncodingHash) {
                return true;
            } else {
                $baseModel->setObjectHash($keyId,$value);
            }
        }
        return false;
    }

}