BaaS Entity 模块
动态实体管理模块 - 实现运行时数据模型定义和 CRUD 操作。
📦 模块信息
- 依赖: baas_tenant, baas_project
- 位置:
web/modules/custom/baas_entity/
🏗️ 架构设计
核心概念
动态实体(Dynamic Entity)是 BaaS 平台的数据模型核心:
- 运行时定义数据结构
- 自动生成数据表和 Entity 类
- 支持多种字段类型
- 项目级数据隔离
数据库表
baas_entity_template - 实体模板
CREATE TABLE baas_entity_template (
template_id SERIAL PRIMARY KEY,
project_id VARCHAR(255) NOT NULL,
entity_name VARCHAR(255) NOT NULL,
label VARCHAR(255),
description TEXT,
created INTEGER,
updated INTEGER
);baas_entity_field - 实体字段
CREATE TABLE baas_entity_field (
field_id SERIAL PRIMARY KEY,
template_id INTEGER NOT NULL,
field_name VARCHAR(255) NOT NULL,
field_type VARCHAR(50) NOT NULL,
label VARCHAR(255),
required BOOLEAN DEFAULT FALSE,
settings TEXT
);🔧 主要类和方法
EntityTemplateManager
实体模板管理 - src/Service/EntityTemplateManager.php
// 创建实体模板
public function createTemplate(array $template_data): int
// 添加字段
public function addField(int $template_id, array $field_data): int
// 获取模板
public function getTemplate(int $template_id): ?array
// 生成实体类文件
public function generateEntityClasses(int $template_id): boolDynamicEntityService
实体 CRUD 操作 - src/Service/DynamicEntityService.php
// 创建实体记录
public function create(string $entity_name, array $data): int
// 查询实体列表
public function query(string $entity_name, array $conditions = []): array
// 更新实体
public function update(string $entity_name, int $id, array $data): bool
// 删除实体
public function delete(string $entity_name, int $id): boolProjectTableNameGenerator
表名生成服务 - src/Service/ProjectTableNameGenerator.php
// 生成表名
public function generateTableName(
string $tenant_id,
string $project_id,
string $entity_name
): string
// 示例: baas_856064_users
// 856064 = MD5(tenant_id + project_id) 前6位📂 动态实体文件生成
概述
当创建实体模板时,系统会自动生成两个 PHP 类文件:Entity 类和Storage 类。这些文件存储在 web/sites/default/files/dynamic_entities/ 目录中,遵循租户和项目的层级结构。
生成目的
- Drupal 标准兼容 - 生成的类继承自 Drupal 核心的
ContentEntityBase和SqlContentEntityStorage - 数据隔离 - 每个类内置租户ID和项目ID常量,确保数据查询的隔离性
- 自动注册 - 通过
ProjectEntityRegistry服务动态注册到 Drupal 实体系统 - 类型安全 - 提供类型提示和IDE自动补全支持
目录结构
dynamic_entities/
└── {tenant_hash}/ # 租户哈希 (如: 7375b0cd)
└── projects/
└── {tenant_hash}_{project_hash}/ # 项目哈希 (如: 7375b0cd_6888d012be80c)
├── Entity/ # 实体类目录
│ ├── Project{Hash}Users.php # 用户实体类
│ ├── Project{Hash}Activities.php # 活动实体类
│ ├── Project{Hash}Teams.php # 团队实体类
│ ├── Project{Hash}Positions.php # 位置实体类
│ ├── Project{Hash}UserActivities.php # 用户活动关联类
│ └── Project{Hash}SystemConfig.php # 系统配置类
└── Storage/ # 存储类目录
├── Project{Hash}UsersStorage.php
├── Project{Hash}ActivitiesStorage.php
├── Project{Hash}TeamsStorage.php
├── Project{Hash}PositionsStorage.php
├── Project{Hash}UserActivitiesStorage.php
└── Project{Hash}SystemConfigStorage.php示例: Groups 项目 (tenant_7375b0cd_project_6888d012be80c) 的实体文件
- 租户哈希:
7375b0cd - 项目哈希:
7375b0cd_6888d012be80c - 类名前缀:
Project7375b0cd6888d012be80c - 数据表名:
baas_856064_users(856064 = MD5 前6位)
Entity 类结构
namespace Drupal\baas_project\Entity\Dynamic;
use Drupal\Core\Entity\ContentEntityBase;
/**
* 定义项目级动态实体类: users.
*
* 此文件由BaaS项目系统自动生成。
* 生成时间: 2025-10-11 22:40:14
* 表名: baas_856064_users
* 实体类型ID: baas_856064_users
*/
class Project7375b0cd6888d012be80cUsers extends ContentEntityBase {
const TENANT_ID = '7375b0cd';
const PROJECT_ID = '7375b0cd_6888d012be80c';
const ENTITY_NAME = 'users';
// 自动注入租户和项目ID
public function __construct(array $values = [], ...) {
parent::__construct($values, 'baas_856064_users', NULL, ...);
$this->set('tenant_id', self::TENANT_ID);
$this->set('project_id', self::PROJECT_ID);
}
// 定义基础字段(id, uuid, tenant_id, project_id等)
public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
// ...
}
}Storage 类结构
namespace Drupal\baas_project\Storage\Dynamic;
use Drupal\Core\Entity\Sql\SqlContentEntityStorage;
/**
* 项目级动态实体存储类: users.
*/
class Project7375b0cd6888d012be80cUsersStorage extends SqlContentEntityStorage {
const TENANT_ID = '7375b0cd';
const PROJECT_ID = '7375b0cd_6888d012be80c';
const ENTITY_NAME = 'users';
// 确保查询时自动过滤租户和项目
public function loadByProperties(array $values = []) {
$values['tenant_id'] = self::TENANT_ID;
$values['project_id'] = self::PROJECT_ID;
return parent::loadByProperties($values);
}
}生成流程
关键特性
- 自动化生成 - 无需手动编写实体类代码
- 命名空间隔离 - 使用项目哈希值确保类名唯一性
- 数据隔离保证 - 内置常量和自动过滤确保多租户安全
- 动态注册 - 无需重启服务,实时生效
- 标准兼容 - 完全遵循 Drupal Entity API 规范
EntityDataApiController
实体 API 控制器 - src/Controller/EntityDataApiController.php
// GET /api/v1/{tenant_id}/projects/{project_id}/entities/{entity_name}
public function listEntities(Request $request): JsonResponse
// POST /api/v1/{tenant_id}/projects/{project_id}/entities/{entity_name}
public function createEntity(Request $request): JsonResponse
// PUT /api/v1/{tenant_id}/projects/{project_id}/entities/{entity_name}/{id}
public function updateEntity(Request $request, int $id): JsonResponse📖 使用示例
创建实体模板
$template_manager = \Drupal::service('baas_entity.template_manager');
// 创建用户实体模板
$template_id = $template_manager->createTemplate([
'project_id' => 'tenant_7375b0cd_project_6888d012be80c',
'entity_name' => 'users',
'label' => '用户',
'description' => '用户实体',
]);
// 添加字段
$template_manager->addField($template_id, [
'field_name' => 'name',
'field_type' => 'string',
'label' => '姓名',
'required' => true,
]);
$template_manager->addField($template_id, [
'field_name' => 'email',
'field_type' => 'string',
'label' => '邮箱',
'required' => true,
]);CRUD 操作
$entity_service = \Drupal::service('baas_entity.dynamic_entity');
// 创建
$id = $entity_service->create('users', [
'name' => '张三',
'email' => 'zhangsan@example.com',
]);
// 查询
$users = $entity_service->query('users', [
'status' => 'active',
]);
// 更新
$entity_service->update('users', $id, [
'name' => '张三(已更新)',
]);
// 删除
$entity_service->delete('users', $id);🔌 服务注册
baas_entity.services.yml:
services:
baas_entity.template_manager:
class: Drupal\baas_entity\Service\EntityTemplateManager
arguments:
- '@database'
- '@baas_project.table_name_generator'
baas_entity.dynamic_entity:
class: Drupal\baas_entity\Service\DynamicEntityService
arguments:
- '@database'
- '@baas_entity.template_manager'
baas_project.table_name_generator:
class: Drupal\baas_entity\Service\ProjectTableNameGenerator🔗 相关文档
Last updated on