承接 denisyu-1/articulate 相关项目开发

从需求分析到上线部署,全程专人跟进,保证项目质量与交付效率

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

denisyu-1/articulate

最新稳定版本:v0.1.1

Composer 安装命令:

composer require denisyu-1/articulate

包简介

Context-bounded PHP ORM for domain-driven applications

README 文档

README

Context-bounded PHP ORM for domain-driven applications

The Problem

Traditional ORMs force one entity class per table. Auth needs only login and password, but it loads phones, groups, cart, and every other relation. The admin panel needs different fields than the API. Adding one relation to a User entity affects every consumer of that class.

The entity manager accumulates objects in memory for the entire request or process. Long-running jobs, batch imports, or complex flows have no way to release entities that are no longer needed without detaching everything.

Articulate Logo

Articulate addresses these pains with context-bounded entities and scoped unit-of-work management.

Badges

CI Mutation testing PHP Version

Quick Start

use Articulate\Connection;
use Articulate\Modules\EntityManager\EntityManager;

#[Entity]
class User
{
    #[PrimaryKey]
    public ?int $id = null;

    #[Property]
    public string $name;

    #[Property]
    public string $email;
}

$connection = new Connection('mysql:host=127.0.0.1;dbname=myapp', 'user', 'password');
$em = new EntityManager($connection);

$user = new User();
$user->name = 'Jane';
$user->email = 'jane@example.com';
$em->persist($user);
$em->flush();

$user = $em->getRepository(User::class)->find($user->id);

Before / After

Before — one fat entity, every context gets everything:

#[Entity]
class User
{
    public int $id;
    public string $login;
    public string $password;
    public string $name;
    public array $phones;   // Auth doesn't need this
    public array $groups;  // Auth doesn't need this
    public Cart $cart;     // Auth doesn't need this
}

// Auth: loads full user + all relations
$user = $userRepo->find($id);
return $auth->validate($user->login, $user->password);

After — separate entities per context, same table:

#[Entity(tableName: 'user')]
class LoginUser
{
    #[PrimaryKey]
    public int $id;

    #[Property]
    public string $login;

    #[Property]
    public string $password;
}

#[Entity]
class User
{
    #[PrimaryKey]
    public int $id;

    #[Property]
    public string $name;

    #[OneToMany(ownedBy: 'user', targetEntity: Phone::class)]
    public array $phones;

    #[OneToOne(targetEntity: Cart::class, referencedBy: 'user')]
    public Cart $cart;
}

// Auth: loads only id, login, password
$loginUser = $em->getRepository(LoginUser::class)->find($id);
return $auth->validate($loginUser->login, $loginUser->password);

How Articulate Compares?

Doctrine Cycle ORM Articulate
Multiple entity classes per table No built-in support No, one entity per table Yes, first-class context-bounded entities
Memory control Identity map held for process lifetime; clear-all or nothing Similar model Scoped unit-of-work; release entities mid-request
Config style XML/YAML common, attributes optional Annotations/attributes Attributes only (PHP 8.4+)

Articulate is aimed at projects where different bounded contexts need different views of the same data and where memory pressure matters in long-running or batch processes.

Core Concepts

Context-Bounded Entities

Multiple entity classes can point to the same database table, each exposing only the fields and relationships needed for that context. Articulate merges compatible column definitions and validates for conflicts.

Memory-Efficient Unit of Work

  • Clear entities from memory that are no longer needed within specific operations
  • Different units of work can track their own entities independently
  • Entity manager combines all unit-of-work changes into minimal database queries during flush

Useful for processing large datasets, complex business operations spanning multiple contexts, and long-running processes with varying entity lifecycles.

Type Mapping System

Built-in mappings: boolTINYINT(1), intINT, floatFLOAT, stringVARCHAR(255), DateTimeInterfaceDATETIME.

Custom class mappings and TypeConverterInterface for complex types. Priority-based resolution when a class implements multiple interfaces with registered mappings.

Repository Pattern

$userRepo = $em->getRepository(User::class);
$user = $userRepo->find(1);
$users = $userRepo->findBy(['status' => 'active']);
$user = $userRepo->findOneBy(['email' => 'user@example.com']);

Custom repositories via #[Entity(repositoryClass: UserRepository::class)] extending AbstractRepository.

License

Licensed under the Apache License 2.0. See LICENSE.

统计信息

  • 总下载量: 8
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 1
  • 点击次数: 7
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 1
  • Watchers: 0
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: Apache-2.0
  • 更新时间: 2026-02-26

承接程序开发

PHP开发

VUE

Vue开发

前端开发

小程序开发

公众号开发

系统定制

数据库设计

云部署

网站建设

安全加固