espocrm-development by bobmatnyc/claude-mpm-skills
npx skills add https://github.com/bobmatnyc/claude-mpm-skills --skill espocrm-developmentEspoCRM 是一个元数据驱动的 CRM 平台,其配置存储在 JSON 文件中,业务逻辑属于服务层,数据访问通过 ORM EntityManager 进行。此技能旨在强化架构模式,以防止常见错误,例如传递容器依赖、绕过服务层或在钩子中实现业务逻辑。
在开发自定义 EspoCRM 模块、实体、关系、钩子、服务、API 端点或集成时激活。特别适用于以下情况: 使用 ORM(需要 EntityManager)、实现业务逻辑(应放在服务中)、创建钩子(使用接口)、修改元数据(需要重建缓存)、构建自定义字段类型、使用 SelectBuilder 创建复杂查询、实现自定义 API 操作或打包扩展。
业务逻辑在服务中,不在钩子中 | 数据访问通过 ENTITYMANAGER,绝不直接使用 PDO | 绝不传递容器作为依赖
直接访问容器或在钩子中编写业务逻辑违反了架构原则。
设置开发环境 - 使用 ext-template,在 src/ 目录下工作(EspoCRM 7.4+),理解元数据结构:custom/Espo/Modules/{ModuleName}/Resources/metadata/
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
使用 EntityManager 访问数据
use Espo\ORM\EntityManager;
public function __construct(private EntityManager $entityManager) {}
// 查找实体
$account = $this->entityManager->getEntityById('Account', $id);
// 带条件查询
$collection = $this->entityManager
->getRDBRepository('Contact')
->where(['accountId' => $accountId])
->find();
在服务中实现业务逻辑
namespace Espo\Modules\MyModule\Services;
use Espo\Services\Record;
class MyEntity extends Record {
public function customAction(string $id, object $data): object {
// 业务逻辑在此
$entity = $this->entityManager->getEntityById($this->entityType, $id);
// ... 处理 ...
$this->entityManager->saveEntity($entity);
return $entity;
}
}
为生命周期事件注册钩子
namespace Espo\Modules\MyModule\Hooks\Account;
use Espo\ORM\Entity;
use Espo\Core\Hook\Hook\BeforeSave;
class MyHook implements BeforeSave {
public function beforeSave(Entity $entity, array $options): void {
// 仅用于验证或副作用
if ($entity->isAttributeChanged('status')) {
// 响应变更
}
}
}
变更后重建缓存
bin/command rebuild
EspoCRM 提供 7 种钩子类型 - 务必使用接口:BeforeSave(保存前验证)、AfterSave(保存后副作用)、BeforeRemove(删除前验证)、AfterRemove(删除后清理)、AfterRelate(关系创建)、AfterUnrelate(关系移除)、AfterMassRelate(批量关系操作)。
正确模式:
✅ 服务注入依赖
✅ 使用 EntityManager 进行数据访问
✅ 钩子使用接口
✅ 所有方法都有类型声明
✅ 使用异常进行错误处理
错误模式:
❌ 传递容器作为依赖
❌ 直接使用 PDO 访问数据库
❌ 在钩子中编写业务逻辑
❌ 使用钩子基类而非接口
❌ 缺少类型声明
bin/command rebuild)EspoCRM 是元数据驱动且具有服务层架构的。
理解元数据系统。使用 EntityManager 处理数据。在服务中实现业务逻辑。仅将钩子用于生命周期事件。变更后重建缓存。
这就是 EspoCRM 之道。
每周安装
68
仓库
GitHub 星标
18
首次出现
2026年1月23日
安全审计
安装于
gemini-cli53
codex53
claude-code53
opencode52
github-copilot50
cursor48
EspoCRM is a metadata-driven CRM platform where configuration lives in JSON files, business logic belongs in Services, and data access happens through ORM EntityManager. This skill enforces architectural patterns to prevent common mistakes like passing Container dependencies, bypassing the service layer, or implementing business logic in hooks.
Activate when developing custom EspoCRM modules, entities, relationships, hooks, services, API endpoints, or integrations. Use especially when: working with ORM (EntityManager required), implementing business logic (belongs in Services), creating hooks (use interfaces), modifying metadata (requires cache rebuild), building custom field types, creating complex queries with SelectBuilder, implementing custom API actions, or packaging extensions.
BUSINESS LOGIC IN SERVICES, NOT HOOKS | DATA ACCESS VIA ENTITYMANAGER, NEVER DIRECT PDO | NEVER PASS CONTAINER AS DEPENDENCY
Accessing Container directly or writing business logic in hooks violates architecture.
Setup Development Environment - Use ext-template, work in src/ directory (EspoCRM 7.4+), understand metadata structure: custom/Espo/Modules/{ModuleName}/Resources/metadata/
Access Data with EntityManager
use Espo\ORM\EntityManager;
public function __construct(private EntityManager $entityManager) {}
// Find entity
$account = $this->entityManager->getEntityById('Account', $id);
// Query with conditions
$collection = $this->entityManager
->getRDBRepository('Contact')
->where(['accountId' => $accountId])
->find();
Implement Business Logic in Services
namespace Espo\Modules\MyModule\Services;
use Espo\Services\Record;
class MyEntity extends Record {
public function customAction(string $id, object $data): object {
// Business logic here
$entity = $this->entityManager->getEntityById($this->entityType, $id);
// ... process ...
$this->entityManager->saveEntity($entity);
return $entity;
}
}
Register Hooks for Lifecycle Events
namespace Espo\Modules\MyModule\Hooks\Account;
use Espo\ORM\Entity;
use Espo\Core\Hook\Hook\BeforeSave;
class MyHook implements BeforeSave {
public function beforeSave(Entity $entity, array $options): void {
// Validation or side effects only
if ($entity->isAttributeChanged('status')) {
// React to changes
}
}
}
Rebuild Cache After Changes
bin/command rebuild
EspoCRM provides 7 hook types - ALWAYS use interfaces: BeforeSave (validation before save), AfterSave (side effects after save), BeforeRemove (validation before delete), AfterRemove (cleanup after delete), AfterRelate (relationship creation), AfterUnrelate (relationship removal), AfterMassRelate (bulk relationship operations).
Correct Pattern:
✅ Service with injected dependencies
✅ EntityManager for data access
✅ Hooks using interfaces
✅ Type declarations on all methods
✅ Exceptions for error handling
Incorrect Patterns:
❌ Passing Container as dependency
❌ Direct PDO database access
❌ Business logic in hooks
❌ Hook base classes instead of interfaces
❌ Missing type declarations
bin/command rebuild)EspoCRM is metadata-driven with a service layer architecture.
Understand the metadata system. Use EntityManager for data. Implement business logic in Services. Use hooks for lifecycle events only. Rebuild cache after changes.
This is the EspoCRM way.
Weekly Installs
68
Repository
GitHub Stars
18
First Seen
Jan 23, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykWarn
Installed on
gemini-cli53
codex53
claude-code53
opencode52
github-copilot50
cursor48
React 组合模式指南:Vercel 组件架构最佳实践,提升代码可维护性
120,000 周安装