Skip to content

Commit

Permalink
改进实体模型的关联保存和删除
Browse files Browse the repository at this point in the history
  • Loading branch information
liu21st committed Nov 18, 2024
1 parent 8e68ac1 commit 4fc458b
Show file tree
Hide file tree
Showing 4 changed files with 108 additions and 53 deletions.
144 changes: 95 additions & 49 deletions src/Entity.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,14 @@
use think\model\Collection;
use think\model\contract\EnumTransform;
use think\model\contract\FieldTypeTransform;
use think\model\contract\Modelable;
use think\model\contract\Typeable;
use WeakMap;

/**
* Class Entity.
*/
abstract class Entity implements JsonSerializable, ArrayAccess, Arrayable, Jsonable
abstract class Entity implements JsonSerializable, ArrayAccess, Arrayable, Jsonable, Modelable
{
private static ?WeakMap $weakMap = null;

Expand All @@ -58,37 +59,37 @@ public function __construct(array | object $data = [], ?Model $model = null)
}

self::$weakMap[$this] = [
'get' => [],
'data' => [],
'origin' => [],
'schema' => [],
'define' => false,
'model' => $model,
'get' => [],
'data' => [],
'origin' => [],
'schema' => [],
'together' => [],
'strict' => true,
'model' => $model,
];

$model->setEntity($this);
$model->exists(true);

$this->initializeData($data, $model);
$this->initializeData($data);
}

/**
* 数据读取 类型转换.
*
* @param array|object $data 实体模型数据
* @param Model $model Model对象
*
* @return void
*/
protected function initializeData(array | object $data, $model)
protected function initializeData(array | object $data)
{
// 获取字段列表
$schema = $this->getFields();
$fields = array_keys($schema);

// 实体模型赋值
foreach ($data as $name => $val) {
$trueName = $model->getRealFieldName($name);
$trueName = $this->getRealFieldName($name);
if (in_array($trueName, $fields)) {
// 读取数据后进行类型转换
$value = $this->readTransform($val, $schema[$trueName] ?? 'string');
Expand All @@ -97,30 +98,40 @@ protected function initializeData(array | object $data, $model)
$origin[$trueName] = $value;
}

if ($model->getPk() == $trueName) {
if ($this->model()->getPk() == $trueName) {
// 记录主键值
$model->setKey($val);
$this->model()->setKey($val);
}
}

$this->setWeakMap('origin', $origin);
$this->setWeakData('origin', $origin);

if (self::$weakMap[$this]['define']) {
// 非属性定义模式下 采用动态属性
$this->setWeakMap('data', $origin);
if (!self::$weakMap[$this]['strict']) {
// 非严格定义模式下 采用动态属性
$this->setWeakData('data', $origin);
}
}

protected function setWeakMap($name, $value)
protected function setWeakData($name, $value)
{
self::$weakMap[$this][$name] = $value;
}

protected function getWeakData($name, $default = null)
{
return self::$weakMap[$this][$name] ?? $default;
}

protected function setData($key, $name, $value)
{
self::$weakMap[$this][$key][$name] = $value;
}

protected function getRealFieldName(string $name)
{
return self::$weakMap[$this]['model']->getRealFieldName($name);
}

/**
* 数据读取 类型转换.
*
Expand Down Expand Up @@ -253,14 +264,15 @@ protected function getFields(?string $field = null)
}

if (empty($schema)) {
$this->setWeakMap('define', false);
// 采用非严格模式
$this->setWeakData('strict', false);
// 获取数据表信息
$schema = $weakMap['model']->getFieldsType($weakMap['model']->getTable());
$type = $weakMap['model']->getType();
$schema = array_merge($schema, $type);
}

$this->setWeakMap('schema', $schema);
$this->setWeakData('schema', $schema);

if ($field) {
return $schema[$field] ?? 'string';
Expand All @@ -287,6 +299,20 @@ protected function parseData(array | object $data): array
return $data;
}

/**
* 关联数据写入.
*
* @param array $relation 关联
*
* @return $this
*/
public function together(array $relation)
{
$this->setWeakData('together', $relation);

return $this;
}

/**
* 保存模型实例数据.
*
Expand Down Expand Up @@ -385,6 +411,7 @@ protected function insertData(Model $model, array $data): bool
$result = $model->db()->field($fields)->insert($data, true);

$this->setKey($result);
$model->setKey($result);
$model->trigger('AfterInsert');
return true;
}
Expand Down Expand Up @@ -422,19 +449,36 @@ protected function updateData(Model $model, array $data): bool
}

/**
* 保存模型关联数据(一对一).
* 写入模型关联数据(一对一).
*
* @param array $relations 数据
* @return bool
*/
protected function relationSave(array $relations = [])
{
foreach ($relations as $name => $relation) {
$relationKey = $this->getRelationKey($name);
if ($relationKey && property_exists($relation, $relationKey)) {
$relation->$relationKey = self::$weakMap[$this]['model']->getKey();
if (in_array($name, $this->getWeakData('together'))) {
$relationKey = $this->getRelationKey($name);
if ($relationKey && property_exists($relation, $relationKey)) {
$relation->$relationKey = self::$weakMap[$this]['model']->getKey();
}
$relation->save();
}
}
}

/**
* 删除模型关联数据(一对一).
*
* @param array $relations 数据
* @return bool
*/
protected function relationDelete(array $relations = [])
{
foreach ($relations as $name => $relation) {
if (in_array($name, $this->getWeakData('together'))) {
$relation->delete();
}
$relation->save();
}
}

Expand Down Expand Up @@ -464,17 +508,19 @@ public function delete(): bool
return true;
}

$model = self::$weakMap[$this]['model'];
if (!$model->getKey() || false === $model->trigger('BeforeDelete')) {
return false;
foreach ($this->getData() as $name => $val) {
if ($val instanceof Entity || $val instanceof Collection) {
$relations[$name] = $val;
}
}

$result = $model
->where($model->getPk(), $model->getKey())
->delete();
$result = $this->model()->delete();

if ($result) {
$model->trigger('AfterDelete');
// 删除关联数据
if (!empty($relations)) {
$this->relationDelete($relations);
}
}

return true;
Expand Down Expand Up @@ -541,8 +587,7 @@ public static function destroy($data): bool
*/
protected function setKey($value)
{
self::$weakMap[$this]['model']->setKey($value);
$pk = self::$weakMap[$this]['model']->getPk();
$pk = $this->model()->getPk();
if (is_string($pk)) {
$this->$pk = $value;
}
Expand All @@ -555,17 +600,19 @@ protected function setKey($value)
*/
protected function getData(): array
{
$class = new class {
function getPublicVars($object)
{
return get_object_vars($object);
}
};
if (self::$weakMap[$this]['strict']) {
$class = new class {
function getPublicVars($object)
{
return get_object_vars($object);
}
};

$data = $class->getPublicVars($this);
if (empty($data) && !empty(self::$weakMap[$this]['data'])) {
$data = $class->getPublicVars($this);
} else {
$data = self::$weakMap[$this]['data'];
}

return $data;
}

Expand Down Expand Up @@ -594,14 +641,13 @@ public function toArray(array $allow = []): array
if (method_exists($this, $method)) {
// 使用获取器转换输出
$item = $this->$method($item, $data);

$this->setData('get', $name, $item);
}
}
}

// 输出额外属性
foreach (self::$weakMap[$this]['get'] as $name => $val) {
foreach ($this->getWeakData('get') as $name => $val) {
if (!empty($allow) && !in_array($name, $allow)) {
continue;
}
Expand Down Expand Up @@ -632,7 +678,7 @@ public function isEmpty(): bool
*/
public function get(string $name)
{
$name = self::$weakMap[$this]['model']->getRealFieldName($name);
$name = $this->getRealFieldName($name);
if (array_key_exists($name, self::$weakMap[$this]['get'])) {
return self::$weakMap[$this]['get'][$name];
}
Expand All @@ -649,7 +695,7 @@ public function get(string $name)

public function getValue($name)
{
return self::$weakMap[$this]['define'] ? ($this->$name ?? null) : (self::$weakMap[$this]['data'][$name] ?? null);
return self::$weakMap[$this]['strict'] ? ($this->$name ?? null) : (self::$weakMap[$this]['data'][$name] ?? null);
}

/**
Expand Down Expand Up @@ -686,7 +732,7 @@ public function __get(string $name)
*/
public function __set(string $name, $value): void
{
$name = self::$weakMap[$this]['model']->getRealFieldName($name);
$name = $this->getRealFieldName($name);

$this->setData('data', $name, $value);
}
Expand All @@ -700,7 +746,7 @@ public function __set(string $name, $value): void
*/
public function __isset(string $name): bool
{
$name = self::$weakMap[$this]['model']->getRealFieldName($name);
$name = $this->getRealFieldName($name);
return isset(self::$weakMap[$this]['data'][$name]);
}

Expand All @@ -713,7 +759,7 @@ public function __isset(string $name): bool
*/
public function __unset(string $name): void
{
$name = self::$weakMap[$this]['model']->getRealFieldName($name);
$name = $this->getRealFieldName($name);
unset(self::$weakMap[$this]['data'][$name]);
}

Expand Down
4 changes: 2 additions & 2 deletions src/Model.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
use JsonSerializable;
use think\contract\Arrayable;
use think\contract\Jsonable;
use think\model\contract\Modelable;
use think\db\BaseQuery as Query;

/**
Expand All @@ -37,7 +38,7 @@
* @method static void onBeforeRestore(Model $model) before_restore事件定义
* @method static void onAfterRestore(Model $model) after_restore事件定义
*/
abstract class Model implements JsonSerializable, ArrayAccess, Arrayable, Jsonable
abstract class Model implements JsonSerializable, ArrayAccess, Arrayable, Jsonable, Modelable
{
use model\concern\Attribute;
use model\concern\RelationShip;
Expand Down Expand Up @@ -781,7 +782,6 @@ protected function updateData(): bool
$db = $this->db(null);

$db->transaction(function () use ($data, $allowFields, $db) {
$this->key = null;
$where = $this->getWhere();
$result = $db->where($where)
->strict(false)
Expand Down
4 changes: 2 additions & 2 deletions src/model/Collection.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
namespace think\model;

use think\Collection as BaseCollection;
use think\Model;
use think\model\contract\Modelable as Model;
use think\Paginator;

/**
Expand Down Expand Up @@ -172,7 +172,7 @@ public function scene(string $scene)
*/
public function setParent($parent)
{
$this->each(function ($model) use ($parent) {
$this->each(function (Model $model) use ($parent) {
$model->setParent($parent);
});

Expand Down
9 changes: 9 additions & 0 deletions src/model/contract/Modelable.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php

declare (strict_types = 1);

namespace think\model\contract;

interface Modelable
{
}

0 comments on commit 4fc458b

Please sign in to comment.