atellitech/utils-hyperf
Composer 安装命令:
composer require atellitech/utils-hyperf
包简介
The utilities for Hyperf framework.
关键字:
README 文档
README
Utilities for Hyperf 3.1 applications.
This package provides common development utilities for Hyperf projects, including:
- Base Repository abstraction
- Batch insert / upsert helpers
- Audit log utilities
- Model generator
- Repository / ValueObject / Validator generators
- API spec page generator
- Dependency file generator
Requirements
- PHP 8.3+
- Hyperf 3.1+
- Composer
Installation
composer require atellitech/utils-hyperf
If you are developing this package locally:
composer create-project hyperf/component-creator
Publish Config
php bin/hyperf.php vendor:publish atellitech/utils-hyperf
This will publish the config file to:
config/autoload/audit_log.php
Core Repository
AbstractRepository provides a reusable base repository for Hyperf models.
It is designed for common CRUD operations, query builder access, transaction handling, batch insert, upsert, and MySQL duplicate key update.
Basic Usage
Create a repository class:
<?php declare(strict_types=1); namespace App\Domain\User\Repository; use App\Model\User; use AtelliTech\Hyperf\Utils\Core\AbstractRepository; /** * @extends AbstractRepository<User> */ class UserRepository extends AbstractRepository { protected string $modelClass = User::class; }
Use the repository:
$user = $userRepository->create([ 'name' => 'Eric', 'email' => 'eric@example.com', ]);
Available Methods
Create
public function create(array $data): Model
Creates a new record.
$user = $userRepository->create([ 'name' => 'Eric', 'email' => 'eric@example.com', ]);
The new version checks the result of save() and throws RuntimeException if the record cannot be saved.
Update
public function update(mixed $id, array $data): Model
Updates a record by primary key.
$user = $userRepository->update($id, [ 'name' => 'New Name', ]);
Update With Changes
public function updateWithChanges(mixed $id, array $data): array
Updates a record and returns dirty fields and old/new changes.
$result = $userRepository->updateWithChanges($id, [ 'status' => 'active', ]); $user = $result['model']; $dirty = $result['dirty']; $changes = $result['changes'];
Example result:
[
'model' => $user,
'dirty' => [
'status' => 'active',
],
'changes' => [
'status' => [
'old' => 'inactive',
'new' => 'active',
],
],
]
This is useful for:
- Audit logs
- Change tracking
- Debugging
- Data update notifications
Delete
public function delete(mixed $id): bool
Deletes a record by primary key.
$userRepository->delete($id);
Find One
public function findOne(mixed $pk): ?Model
Finds a record by primary key.
$user = $userRepository->findOne($id); if ($user === null) { // not found }
Find One Or Fail
public function findOneOrFail(mixed $pk): Model
Finds a record by primary key. If the record does not exist, an exception will be thrown.
$user = $userRepository->findOneOrFail($id);
Query Builder
public function query(): Builder
Creates a query builder for the model.
$users = $userRepository->query() ->where('status', 'active') ->orderByDesc('id') ->get();
For backward compatibility, existing projects may still use:
$userRepository->find()
New code should prefer:
$userRepository->query()
Transaction
public function transaction(Closure $callback)
Runs a database transaction.
$userRepository->transaction(function () use ($userRepository) { $userRepository->create([ 'name' => 'Eric', ]); });
The transaction will use the model connection if the model has a custom connection.
Batch Insert
Insert
public function insert(array $rows): bool
Batch inserts records.
$userRepository->insert([ [ 'name' => 'Eric', 'email' => 'eric@example.com', ], [ 'name' => 'John', 'email' => 'john@example.com', ], ]);
Important notes:
insert() does not trigger model events.
insert() does not apply fillable / guarded rules.
insert() does not automatically handle timestamps.
Insert Chunks
public function insertChunks(array $rows, int $chunkSize = 500): bool
Batch inserts records by chunks.
$userRepository->insertChunks($rows, 500);
This is useful for large imports or sync jobs.
Insert With Timestamps
public function insertWithTimestamps(array $rows): bool
Adds created_at and updated_at automatically before insert.
$userRepository->insertWithTimestamps([ [ 'name' => 'Eric', 'email' => 'eric@example.com', ], ]);
Insert Chunks With Timestamps
public function insertChunksWithTimestamps(array $rows, int $chunkSize = 500): bool
Batch inserts records by chunks and automatically adds timestamps.
$userRepository->insertChunksWithTimestamps($rows, 500);
Create Or Update
Update Or Create
public function updateOrCreate(array $attributes, array $values): Model
Creates or updates one record.
$user = $userRepository->updateOrCreate( [ 'email' => 'eric@example.com', ], [ 'name' => 'Eric', 'status' => 'active', ] );
This method is suitable for small amounts of data.
For large sync jobs, prefer upsert() or insertChunksOnDuplicateKeyUpdateWithTimestamps().
Upsert
public function upsert(array $rows, array $uniqueBy, array $updateColumns): int
Batch creates or updates records.
$userRepository->upsert( [ [ 'email' => 'eric@example.com', 'name' => 'Eric', 'status' => 'active', ], [ 'email' => 'john@example.com', 'name' => 'John', 'status' => 'inactive', ], ], ['email'], ['name', 'status', 'updated_at'] );
MySQL ON DUPLICATE KEY UPDATE
Insert On Duplicate Key Update
public function insertOnDuplicateKeyUpdate(array $rows, array $updateColumns): int
Runs MySQL INSERT ... ON DUPLICATE KEY UPDATE.
$userRepository->insertOnDuplicateKeyUpdate( [ [ 'email' => 'eric@example.com', 'name' => 'Eric', 'status' => 'active', ], ], [ 'name', 'status', 'updated_at', ] );
This method depends on MySQL PRIMARY KEY or UNIQUE KEY.
Example:
ALTER TABLE users ADD UNIQUE KEY uk_users_email (email);
Insert Chunks On Duplicate Key Update
public function insertChunksOnDuplicateKeyUpdate( array $rows, array $updateColumns, int $chunkSize = 500 ): int
Runs MySQL duplicate key update by chunks.
$userRepository->insertChunksOnDuplicateKeyUpdate( $rows, ['name', 'status', 'updated_at'], 500 );
Insert Chunks On Duplicate Key Update With Timestamps
public function insertChunksOnDuplicateKeyUpdateWithTimestamps( array $rows, array $updateColumns, int $chunkSize = 500 ): int
Adds created_at and updated_at, then runs MySQL duplicate key update by chunks.
$userRepository->insertChunksOnDuplicateKeyUpdateWithTimestamps( $rows, ['name', 'status', 'updated_at'], 500 );
Repository Upgrade Guide
Summary
The new repository version adds:
query()findOneOrFail()updateWithChanges()insert()insertChunks()insertWithTimestamps()insertChunksWithTimestamps()updateOrCreate()upsert()insertOnDuplicateKeyUpdate()insertChunksOnDuplicateKeyUpdate()insertChunksOnDuplicateKeyUpdateWithTimestamps()
It also improves:
- Save failure handling
- PHPStan compatibility
- Model connection-aware transaction
- Batch insert validation
- Dirty data tracking
Backward Compatibility Notes
find() and query()
Older versions use:
$repo->find()
New code should use:
$repo->query()
To avoid breaking existing projects, find() should be kept as an alias:
public function find(): Builder { return $this->query(); }
create() Transaction Parameter
Older versions supported:
$repo->create($data, true);
The recommended new style is:
$repo->transaction(function () use ($repo, $data) { return $repo->create($data); });
If your projects still use create($data, true), keep the old signature temporarily:
public function create(array $data, bool $useTransaction = false): Model
Recommended migration:
Short term: keep create(array $data, bool $useTransaction = false)
Long term: move transaction control to UseCase / Service
Not Found Exception
Older versions throw:
InvalidArgumentException
The new version may use:
RecordNotFoundException
Please check existing exception handling code.
If you need safer migration, make RecordNotFoundException extend InvalidArgumentException.
Upgrade Checklist
1. Search for create($data, true)
grep -R "create(.*true" app/
Recommended replacement:
$repo->transaction(function () use ($repo, $data) { return $repo->create($data); });
2. Search for find()
grep -R "->find()" app/
If many places use find(), do not remove it.
Keep it as an alias for query().
3. Check exception handling
Search:
grep -R "InvalidArgumentException" app/
If existing code catches InvalidArgumentException for missing records, update it carefully.
4. Check batch insert data shape
All rows must have the same columns.
Invalid:
[
[
'name' => 'A',
'status' => 'active',
],
[
'name' => 'B',
],
]
Valid:
[
[
'name' => 'A',
'status' => 'active',
],
[
'name' => 'B',
'status' => null,
],
]
5. Check unique keys before duplicate key update
Before using:
insertChunksOnDuplicateKeyUpdateWithTimestamps()
Make sure your table has the correct unique key.
Example:
ALTER TABLE users ADD UNIQUE KEY uk_users_email (email);
Model Generator
This generator creates a model class by table name.
Usage
php bin/hyperf.php at:gen:model [--disable-event-dispatcher] [--] <table> [<namespace> [<path> [<connection>]]]
Arguments
table
Table name.
namespace
Namespace of the generated model class.
path
Path of the generated model class file.
connection
Database component ID.
Repository, ValueObject and Validator Generator
Generate repository, value object, or validator by table and output files into a specific domain.
Usage
php bin/hyperf.php at:gen:[repo|vo|validator] [--disable-event-dispatcher] [--] <table> [<domain> [<connection>]]
Arguments
table
Table name.
domain
DDD domain name.
connection
Database component ID.
API Spec Page Generator
Generate API documentation page by namespace and path.
Usage
php bin/hyperf.php at:gen:apidoc [options] [--] [<namespace> [<path>]]
Arguments
namespace
Class namespace.
path
Generated file path.
Dependency File Generator
Generate dependency files for Repository and Service classes by scanning a specific path.
The default scan path is:
{root path}/app
The generated file is:
config/autoload/autoload_dependencies.php
Step 1: Add generated dependency file to config/autoload/dependencies.php
<?php declare(strict_types=1); $src = __DIR__ . '/autoload_dependencies.php'; $autoDependencies = []; if (file_exists($src)) { $autoDependencies = require $src; } return array_merge((array) $autoDependencies, [ // other manual dependencies ]);
Step 2: Execute command
php bin/hyperf.php at:gen:di [options] [--] [<path>]
Arguments
path
Path to scan.
Step 3: Add script to composer.json
{
"scripts": {
"di": "php bin/hyperf.php at:gen:di"
}
}
Then run:
composer di
Audit Log
This package provides audit log support through events and listeners.
Publish Config
php bin/hyperf.php vendor:publish atellitech/utils-hyperf
Config file:
config/autoload/audit_log.php
Example Config
<?php declare(strict_types=1); return [ 'events' => [ // App\Event\UserUpdatedEvent::class, ], ];
Event Interface
Audit log events should implement:
AtelliTech\Hyperf\Utils\Listener\AuditLogEventInterface
Expected event methods include:
getEventName() getTableName() getTableId() getUserId() getOriginalValues() getNewValues()
Development
PHPStan
If PHPStan cannot find the Hyperf BASE_PATH constant, add a PHPStan bootstrap file.
Create:
phpstan-bootstrap.php
<?php declare(strict_types=1); if (! defined('BASE_PATH')) { define('BASE_PATH', __DIR__); }
Then add to phpstan.neon:
parameters: bootstrapFiles: - phpstan-bootstrap.php
Changelog
Added
- Added
query()as the preferred query builder method. - Added
findOneOrFail(). - Added
updateWithChanges(). - Added batch insert support.
- Added chunk insert support.
- Added timestamp insert support.
- Added
updateOrCreate(). - Added
upsert(). - Added MySQL
ON DUPLICATE KEY UPDATEhelpers. - Added model connection-aware transaction handling.
- Added PHPStan-friendly helper methods.
Changed
create()now checks whethersave()succeeds.update()now usesfindOneOrFail()internally.delete()now usesfindOneOrFail()internally.transaction()now uses model connection when available.- Batch insert methods now validate that all rows have the same columns.
Deprecated
find()is kept for backward compatibility.- New code should prefer
query().
Potential Breaking Changes
- Removing
create(array $data, bool $useTransaction = false)may break existing calls usingcreate($data, true). - Removing
find()may break existing code. - Changing not-found exception type may affect existing exception handling.
Recommended Architecture
Repository should focus on data access.
Recommended application structure:
Controller
↓
UseCase / Service / Handler
↓
Repository
↓
Model
Transaction boundaries should usually be controlled by UseCase / Service.
Example:
$this->userRepository->transaction(function () use ($rows) { $this->userRepository->insertChunksWithTimestamps($rows); });
Avoid putting complex business workflows inside repositories.
atellitech/utils-hyperf 适用场景与选型建议
atellitech/utils-hyperf 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 174 次下载、GitHub Stars 达 0, 最近一次更新时间为 2025 年 10 月 25 日, 在 PHP 生态内属于活跃度较高的组件。
它主要适用于以下技术方向: 「php」 「utilities」 「hyperf」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。
我们在过去多个企业项目中使用过 atellitech/utils-hyperf 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。
基于 atellitech/utils-hyperf 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。
线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。
承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。
与 atellitech/utils-hyperf 相关的其它包
同方向 / 同关键字的高下载量 PHP Composer 包推荐,方便对比选型:
An async event for hyperf.
A collection of enhancements and utilities for the Silverstripe UserForms module
php hyperf xxljob
Reusable utilities library for Lacus Solutions' packages (type description, HTML escaping, random sequences)
SForum
统计信息
- 总下载量: 174
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 0
- 点击次数: 7
- 依赖项目数: 0
- 推荐数: 0
其他信息
- 授权协议: MIT
- 更新时间: 2025-10-25