Think/Model/RelationModel.php
protected function opRelation($opType, $data = '', $name = '')
    {
        $result = false;
        if (empty($data) && !empty($this->data)) {
            $data = $this->data;
        } elseif (!is_array($data)) {
            // 数据无效返回
            return false;
        }
        if (!empty($this->_link)) {
            // 遍历关联定义
            foreach ($this->_link as $key => $val) {
                // 操作制定关联类型
                // 映射名称
                $mappingName = $val['mapping_name'] ?? $key;
                if (empty($name) || true === $name || $mappingName == $name || (is_array($name) && in_array(
                            $mappingName,
                            $name
                        ))
                ) {
                    // 操作制定的关联
                    //  关联类型
                    $mappingType = $val['mapping_type'] ?? $val;
                    //  关联类名
                    $mappingClass = $val['class_name'] ?? $key;
                    // 关联键名
                    $mappingKey = $val['mapping_key'] ?? $this->getPk();
                    // 当前数据对象主键值
                    $pk = $data[$mappingKey];
                    if (strtoupper($mappingClass) == strtoupper($this->name)) {
                        // 自引用关联 获取父键名
                        $mappingFk = $val['parent_key'] ?? 'parent_id';
                    } else {
                        //  关联外键
                        $mappingFk = $val['foreign_key'] ?? strtolower(
                                $this->name
                            ).'_id';
                    }
                    if (!empty($val['condition'])) {
                        $mappingCondition = $val['condition'];
                    } else {
                        $mappingCondition = [];
                        $mappingCondition[$mappingFk] = $pk;
                    }
                    // 获取关联model对象
                    $model = D($mappingClass);
                    $mappingData = $data[$mappingName] ?? false;
                    if (!empty($mappingData) || $opType == 'DEL') {
                        switch ($mappingType) {
                            case static::HAS_ONE:
                                switch (strtoupper($opType)) {
                                    // 增加关联数据
                                    case 'ADD':
                                        $mappingData[$mappingFk] = $pk;
                                        $result = $model->add($mappingData);
                                        break;
                                    // 更新关联数据
                                    case 'SAVE':
                                        $result = $model->where($mappingCondition)->save($mappingData);
                                        break;
                                    // 根据外键删除关联数据
                                    case 'DEL':
                                        $result = $model->where($mappingCondition)->delete();
                                        break;
                                    default:
                                        break;
                                }
                                break;
                            case static::BELONGS_TO:
                                break;
                            case static::HAS_MANY:
                                switch (strtoupper($opType)) {
                                    // 增加关联数据
                                    case 'ADD'   :
                                        $model->startTrans();
                                        foreach ($mappingData as $val) {
                                            $val[$mappingFk] = $pk;
                                            $result = $model->add($val);
                                        }
                                        $model->commit();
                                        break;
                                    // 更新关联数据
                                    case 'SAVE' :
                                        $model->startTrans();
                                        $pk = $model->getPk();
                                        foreach ($mappingData as $vo) {
                                            // 更新数据
                                            if (isset($vo[$pk])) {
                                                $mappingCondition[$pk] = $vo[$pk];
                                                $result = $model->where($mappingCondition)->save(
                                                    $vo
                                                );
                                                // 新增数据
                                            } else {
                                                $vo[$mappingFk] = $data[$mappingKey];
                                                $result = $model->add($vo);
                                            }
                                        }
                                        $model->commit();
                                        break;
                                    // 删除关联数据
                                    case 'DEL' :
                                        $result = $model->where($mappingCondition)->delete();
                                        break;
                                    default:
                                        break;
                                }
                                break;
                            case static::MANY_TO_MANY:
                                // 关联
                                $mappingRelationFk = $val['relation_foreign_key'] ?? $model->getModelName().'_id';
                                $prefix = $this->tablePrefix;
                                if (isset($val['relation_table'])) {
                                    $mappingRelationTable = preg_replace_callback(
                                        "/__([A-Z_-]+)__/sU",
                                        function ($match) use ($prefix) {
                                            return $prefix.strtolower($match[1]);
                                        },
                                        $val['relation_table']
                                    );
                                } else {
                                    $mappingRelationTable = $this->getRelationTableName($model);
                                }
                                if (is_array($mappingData)) {
                                    $ids = [];
                                    foreach ($mappingData as $vo) {
                                        $ids[] = $vo[$mappingKey];
                                    }
                                    $relationId = implode(',', $ids);
                                }
                                switch (strtoupper($opType)) {
                                    // 增加关联数据
                                    case 'ADD':
                                        if (isset($relationId)) {
                                            $this->startTrans();
                                            // 插入关联表数据
                                            $sql = 'INSERT INTO '.$mappingRelationTable.' ('.$mappingFk.','.$mappingRelationFk.') SELECT a.'.$this->getPk(
                                                ).',b.'.$model->getPk().' FROM '.$this->getTableName(
                                                ).' AS a ,'.$model->getTableName()." AS b where a.".$this->getPk(
                                                ).' ='.$pk.' AND  b.'.$model->getPk().' IN ('.$relationId.") ";
                                            $result = $model->execute($sql);
                                            // 提交事务
                                            if (false !== $result) {
                                                $this->commit();
                                            } // 事务回滚
                                            else {
                                                $this->rollback();
                                            }
                                        }
                                        break;
                                    // 更新关联数据
                                    case 'SAVE':
                                        if (isset($relationId)) {
                                            $this->startTrans();
                                            // 删除关联表数据
                                            $this->table($mappingRelationTable)->where($mappingCondition)->delete();
                                            // 插入关联表数据
                                            $sql = 'INSERT INTO '.$mappingRelationTable.' ('.$mappingFk.','.$mappingRelationFk.') SELECT a.'.$this->getPk(
                                                ).',b.'.$model->getPk().' FROM '.$this->getTableName(
                                                ).' AS a ,'.$model->getTableName()." AS b where a.".$this->getPk(
                                                ).' ='.$pk.' AND  b.'.$model->getPk().' IN ('.$relationId.") ";
                                            $result = $model->execute($sql);
                                            // 提交事务
                                            if (false !== $result) {
                                                $this->commit();
                                            } // 事务回滚
                                            else {
                                                $this->rollback();
                                            }
                                        }
                                        break;
                                    // 根据外键删除中间表关联数据
                                    case 'DEL':
                                        $result = $this->table($mappingRelationTable)->where(
                                            $mappingCondition
                                        )->delete();
                                        break;
                                    default:
                                        break;
                                }
                                break;
                        }
                    }
                }
            }
        }

        return $result;
    }
protected function opRelation($opType, $data = '', $name = '')
    {
        $result = false;
        if (empty($data) && !empty($this->data)) {
            $data = $this->data;
        } elseif (!is_array($data)) {
            // 数据无效返回
            return false;
        }
        if (!empty($this->_link)) {
            // 遍历关联定义
            foreach ($this->_link as $key => $val) {
                // 操作制定关联类型
                // 映射名称
                $mappingName = $val['mapping_name'] ?? $key;
                if (empty($name) || true === $name || $mappingName == $name || (is_array($name) && in_array(
                            $mappingName,
                            $name
                        ))
                ) {
                    // 操作制定的关联
                    //  关联类型
                    $mappingType = $val['mapping_type'] ?? $val;
                    //  关联类名
                    $mappingClass = $val['class_name'] ?? $key;
                    // 关联键名
                    $mappingKey = $val['mapping_key'] ?? $this->getPk();
                    // 当前数据对象主键值
                    $pk = $data[$mappingKey];
                    if (strtoupper($mappingClass) == strtoupper($this->name)) {
                        // 自引用关联 获取父键名
                        $mappingFk = $val['parent_key'] ?? 'parent_id';
                    } else {
                        //  关联外键
                        $mappingFk = $val['foreign_key'] ?? strtolower(
                                $this->name
                            ).'_id';
                    }
                    if (!empty($val['condition'])) {
                        $mappingCondition = $val['condition'];
                    } else {
                        $mappingCondition = [];
                        $mappingCondition[$mappingFk] = $pk;
                    }
                    // 获取关联model对象
                    $model = D($mappingClass);
                    $mappingData = $data[$mappingName] ?? false;
                    if (!empty($mappingData) || $opType == 'DEL') {
                        switch ($mappingType) {
                            case static::HAS_ONE:
                                switch (strtoupper($opType)) {
                                    // 增加关联数据
                                    case 'ADD':
                                        $mappingData[$mappingFk] = $pk;
                                        $result = $model->add($mappingData);
                                        break;
                                    // 更新关联数据
                                    case 'SAVE':
                                        $result = $model->where($mappingCondition)->save($mappingData);
                                        break;
                                    // 根据外键删除关联数据
                                    case 'DEL':
                                        $result = $model->where($mappingCondition)->delete();
                                        break;
                                    default:
                                        break;
                                }
                                break;
                            case static::BELONGS_TO:
                                break;
                            case static::HAS_MANY:
                                switch (strtoupper($opType)) {
                                    // 增加关联数据
                                    case 'ADD'   :
                                        $model->startTrans();
                                        foreach ($mappingData as $val) {
                                            $val[$mappingFk] = $pk;
                                            $result = $model->add($val);
                                        }
                                        $model->commit();
                                        break;
                                    // 更新关联数据
                                    case 'SAVE' :
                                        $model->startTrans();
                                        $pk = $model->getPk();
                                        foreach ($mappingData as $vo) {
                                            // 更新数据
                                            if (isset($vo[$pk])) {
                                                $mappingCondition[$pk] = $vo[$pk];
                                                $result = $model->where($mappingCondition)->save(
                                                    $vo
                                                );
                                                // 新增数据
                                            } else {
                                                $vo[$mappingFk] = $data[$mappingKey];
                                                $result = $model->add($vo);
                                            }
                                        }
                                        $model->commit();
                                        break;
                                    // 删除关联数据
                                    case 'DEL' :
                                        $result = $model->where($mappingCondition)->delete();
                                        break;
                                    default:
                                        break;
                                }
                                break;
                            case static::MANY_TO_MANY:
                                // 关联
                                $mappingRelationFk = $val['relation_foreign_key'] ?? $model->getModelName().'_id';
                                $prefix = $this->tablePrefix;
                                if (isset($val['relation_table'])) {
                                    $mappingRelationTable = preg_replace_callback(
                                        "/__([A-Z_-]+)__/sU",
                                        function ($match) use ($prefix) {
                                            return $prefix.strtolower($match[1]);
                                        },
                                        $val['relation_table']
                                    );
                                } else {
                                    $mappingRelationTable = $this->getRelationTableName($model);
                                }
                                if (is_array($mappingData)) {
                                    $ids = [];
                                    foreach ($mappingData as $vo) {
                                        $ids[] = $vo[$mappingKey];
                                    }
                                    $relationId = implode(',', $ids);
                                }
                                switch (strtoupper($opType)) {
                                    // 增加关联数据
                                    case 'ADD':
                                        if (isset($relationId)) {
                                            $this->startTrans();
                                            // 插入关联表数据
                                            $sql = 'INSERT INTO '.$mappingRelationTable.' ('.$mappingFk.','.$mappingRelationFk.') SELECT a.'.$this->getPk(
                                                ).',b.'.$model->getPk().' FROM '.$this->getTableName(
                                                ).' AS a ,'.$model->getTableName()." AS b where a.".$this->getPk(
                                                ).' ='.$pk.' AND  b.'.$model->getPk().' IN ('.$relationId.") ";
                                            $result = $model->execute($sql);
                                            // 提交事务
                                            if (false !== $result) {
                                                $this->commit();
                                            } // 事务回滚
                                            else {
                                                $this->rollback();
                                            }
                                        }
                                        break;
                                    // 更新关联数据
                                    case 'SAVE':
                                        if (isset($relationId)) {
                                            $this->startTrans();
                                            // 删除关联表数据
                                            $this->table($mappingRelationTable)->where($mappingCondition)->delete();
                                            // 插入关联表数据
                                            $sql = 'INSERT INTO '.$mappingRelationTable.' ('.$mappingFk.','.$mappingRelationFk.') SELECT a.'.$this->getPk(
                                                ).',b.'.$model->getPk().' FROM '.$this->getTableName(
                                                ).' AS a ,'.$model->getTableName()." AS b where a.".$this->getPk(
                                                ).' ='.$pk.' AND  b.'.$model->getPk().' IN ('.$relationId.") ";
                                            $result = $model->execute($sql);
                                            // 提交事务
                                            if (false !== $result) {
                                                $this->commit();
                                            } // 事务回滚
                                            else {
                                                $this->rollback();
                                            }
                                        }
                                        break;
                                    // 根据外键删除中间表关联数据
                                    case 'DEL':
                                        $result = $this->table($mappingRelationTable)->where(
                                            $mappingCondition
                                        )->delete();
                                        break;
                                    default:
                                        break;
                                }
                                break;
                        }
                    }
                }
            }
        }

        return $result;
    }
操作关联数据


@param string $opType 操作方式 ADD SAVE DEL
@param mixed $data 数据对象
@param string $name 关联名称

@return mixed