|
|
<?php |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace think\model; |
|
|
|
|
|
use think\Db; |
|
|
use think\db\Query; |
|
|
use think\Model; |
|
|
|
|
|
class Merge extends Model |
|
|
{ |
|
|
|
|
|
protected $relationModel = []; |
|
|
protected $fk = ''; |
|
|
protected $mapFields = []; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public function __construct($data = []) |
|
|
{ |
|
|
parent::__construct($data); |
|
|
|
|
|
|
|
|
if (empty($this->fk)) { |
|
|
$this->fk = strtolower($this->name) . '_id'; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static function get($data = null, $with = [], $cache = false) |
|
|
{ |
|
|
$query = self::parseQuery($data, $with, $cache); |
|
|
$query = self::attachQuery($query); |
|
|
return $query->find($data); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
protected static function attachQuery($query) |
|
|
{ |
|
|
$class = new static(); |
|
|
$master = $class->name; |
|
|
$fields = self::getModelField($query, $master, '', $class->mapFields, $class->field); |
|
|
$query->alias($master)->field($fields); |
|
|
|
|
|
foreach ($class->relationModel as $key => $model) { |
|
|
$name = is_int($key) ? $model : $key; |
|
|
$table = is_int($key) ? $query->getTable($name) : $model; |
|
|
$query->join($table . ' ' . $name, $name . '.' . $class->fk . '=' . $master . '.' . $class->getPk()); |
|
|
$fields = self::getModelField($query, $name, $table, $class->mapFields, $class->field); |
|
|
$query->field($fields); |
|
|
} |
|
|
return $query; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
protected static function getModelField($query, $name, $table = '', $map = [], $fields = []) |
|
|
{ |
|
|
|
|
|
$fields = $fields ?: $query->getTableInfo($table, 'fields'); |
|
|
$array = []; |
|
|
foreach ($fields as $field) { |
|
|
if ($key = array_search($name . '.' . $field, $map)) { |
|
|
|
|
|
$array[] = $name . '.' . $field . ' AS ' . $key; |
|
|
} else { |
|
|
$array[] = $field; |
|
|
} |
|
|
} |
|
|
return $array; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static function all($data = null, $with = [], $cache = false) |
|
|
{ |
|
|
$query = self::parseQuery($data, $with, $cache); |
|
|
$query = self::attachQuery($query); |
|
|
return $query->select($data); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
protected function parseData($model, $data) |
|
|
{ |
|
|
$item = []; |
|
|
foreach ($data as $key => $val) { |
|
|
if ($this->fk != $key && array_key_exists($key, $this->mapFields)) { |
|
|
list($name, $key) = explode('.', $this->mapFields[$key]); |
|
|
if ($model == $name) { |
|
|
$item[$key] = $val; |
|
|
} |
|
|
} else { |
|
|
$item[$key] = $val; |
|
|
} |
|
|
} |
|
|
return $item; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public function save($data = [], $where = [], $sequence = null) |
|
|
{ |
|
|
if (!empty($data)) { |
|
|
|
|
|
if (!$this->validateData($data)) { |
|
|
return false; |
|
|
} |
|
|
|
|
|
foreach ($data as $key => $value) { |
|
|
$this->setAttr($key, $value, $data); |
|
|
} |
|
|
if (!empty($where)) { |
|
|
$this->isUpdate = true; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
$this->autoCompleteData($this->auto); |
|
|
|
|
|
|
|
|
if ($this->autoWriteTimestamp && $this->updateTime && !isset($this->data[$this->updateTime])) { |
|
|
$this->setAttr($this->updateTime, null); |
|
|
} |
|
|
|
|
|
|
|
|
if (false === $this->trigger('before_write', $this)) { |
|
|
return false; |
|
|
} |
|
|
|
|
|
$db = $this->db(); |
|
|
$db->startTrans(); |
|
|
$pk = $this->getPk(); |
|
|
try { |
|
|
if ($this->isUpdate) { |
|
|
|
|
|
$this->autoCompleteData($this->update); |
|
|
|
|
|
if (false === $this->trigger('before_update', $this)) { |
|
|
return false; |
|
|
} |
|
|
|
|
|
if (empty($where) && !empty($this->updateWhere)) { |
|
|
$where = $this->updateWhere; |
|
|
} |
|
|
|
|
|
|
|
|
$data = $this->getChangedData(); |
|
|
|
|
|
foreach ($this->data as $key => $val) { |
|
|
if ($this->isPk($key)) { |
|
|
$data[$key] = $val; |
|
|
} |
|
|
} |
|
|
|
|
|
$data = $this->parseData($this->name, $data); |
|
|
if (is_string($pk) && isset($data[$pk])) { |
|
|
if (!isset($where[$pk])) { |
|
|
unset($where); |
|
|
$where[$pk] = $data[$pk]; |
|
|
} |
|
|
unset($data[$pk]); |
|
|
} |
|
|
|
|
|
$result = $db->strict(false)->where($where)->update($data); |
|
|
|
|
|
|
|
|
foreach ($this->relationModel as $key => $model) { |
|
|
$name = is_int($key) ? $model : $key; |
|
|
$table = is_int($key) ? $db->getTable($model) : $model; |
|
|
|
|
|
$data = $this->parseData($name, $data); |
|
|
if (Db::table($table)->strict(false)->where($this->fk, $this->data[$this->getPk()])->update($data)) { |
|
|
$result = 1; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
$this->trigger('after_update', $this); |
|
|
} else { |
|
|
|
|
|
$this->autoCompleteData($this->insert); |
|
|
|
|
|
|
|
|
if ($this->autoWriteTimestamp && $this->createTime && !isset($this->data[$this->createTime])) { |
|
|
$this->setAttr($this->createTime, null); |
|
|
} |
|
|
|
|
|
if (false === $this->trigger('before_insert', $this)) { |
|
|
return false; |
|
|
} |
|
|
|
|
|
|
|
|
$data = $this->parseData($this->name, $this->data); |
|
|
|
|
|
$result = $db->name($this->name)->strict(false)->insert($data); |
|
|
if ($result) { |
|
|
$insertId = $db->getLastInsID($sequence); |
|
|
|
|
|
if ($insertId) { |
|
|
if (is_string($pk)) { |
|
|
$this->data[$pk] = $insertId; |
|
|
} |
|
|
$this->data[$this->fk] = $insertId; |
|
|
} |
|
|
|
|
|
|
|
|
$source = $this->data; |
|
|
if ($insertId && is_string($pk) && isset($source[$pk]) && $this->fk != $pk) { |
|
|
unset($source[$pk]); |
|
|
} |
|
|
foreach ($this->relationModel as $key => $model) { |
|
|
$name = is_int($key) ? $model : $key; |
|
|
$table = is_int($key) ? $db->getTable($model) : $model; |
|
|
|
|
|
$data = $this->parseData($name, $source); |
|
|
Db::table($table)->strict(false)->insert($data); |
|
|
} |
|
|
} |
|
|
|
|
|
$this->isUpdate = true; |
|
|
|
|
|
$this->trigger('after_insert', $this); |
|
|
} |
|
|
$db->commit(); |
|
|
|
|
|
$this->trigger('after_write', $this); |
|
|
|
|
|
$this->origin = $this->data; |
|
|
return $result; |
|
|
} catch (\Exception $e) { |
|
|
$db->rollback(); |
|
|
throw $e; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public function delete() |
|
|
{ |
|
|
if (false === $this->trigger('before_delete', $this)) { |
|
|
return false; |
|
|
} |
|
|
|
|
|
$db = $this->db(); |
|
|
$db->startTrans(); |
|
|
try { |
|
|
$result = $db->delete($this->data); |
|
|
if ($result) { |
|
|
|
|
|
$pk = $this->data[$this->getPk()]; |
|
|
|
|
|
|
|
|
foreach ($this->relationModel as $key => $model) { |
|
|
$table = is_int($key) ? $db->getTable($model) : $model; |
|
|
$query = new Query; |
|
|
$query->table($table)->where($this->fk, $pk)->delete(); |
|
|
} |
|
|
} |
|
|
$this->trigger('after_delete', $this); |
|
|
$db->commit(); |
|
|
return $result; |
|
|
} catch (\Exception $e) { |
|
|
$db->rollback(); |
|
|
throw $e; |
|
|
} |
|
|
} |
|
|
|
|
|
} |
|
|
|