socialdept/atp-parity
Composer 安装命令:
composer require socialdept/atp-parity
包简介
AT Protocol record mapping and sync for Laravel Eloquent models
README 文档
README
Bidirectional mapping between AT Protocol records and Laravel Eloquent models.
What is Parity?
Parity is a Laravel package that bridges your Eloquent models with AT Protocol records. It provides bidirectional mapping, automatic firehose synchronization, and type-safe transformations between your database and the decentralized social web.
Think of it as Laravel's model casts, but for AT Protocol records.
Why use Parity?
- Laravel-style code - Familiar patterns you already know
- Bidirectional mapping - Transform records to models and back
- Firehose sync - Automatically sync network events to your database
- Type-safe DTOs - Full integration with atp-schema generated types
- Model traits - Add AT Protocol awareness to any Eloquent model
- Flexible mappers - Define custom transformations for your domain
- Blob handling - Download, upload, and serve images and videos
Quick Example
use SocialDept\AtpParity\RecordMapper; use SocialDept\AtpSchema\Data\Data; use Illuminate\Database\Eloquent\Model; class PostMapper extends RecordMapper { public function recordClass(): string { return \SocialDept\AtpSchema\Generated\App\Bsky\Feed\Post::class; } public function modelClass(): string { return \App\Models\Post::class; } protected function recordToAttributes(Data $record): array { return [ 'content' => $record->text, 'published_at' => $record->createdAt, ]; } protected function modelToRecordData(Model $model): array { return [ 'text' => $model->content, 'createdAt' => $model->published_at->toIso8601String(), ]; } }
Installation
composer require socialdept/atp-parity
Optionally publish the configuration:
php artisan vendor:publish --tag=parity-config
Getting Started
Once installed, you're three steps away from syncing AT Protocol records:
1. Create a Mapper
Define how your record maps to your model:
class PostMapper extends RecordMapper { public function recordClass(): string { return Post::class; // Your atp-schema DTO or custom Record } public function modelClass(): string { return \App\Models\Post::class; } protected function recordToAttributes(Data $record): array { return ['content' => $record->text]; } protected function modelToRecordData(Model $model): array { return ['text' => $model->content]; } }
2. Register Your Mapper
// config/parity.php return [ 'mappers' => [ App\AtpMappers\PostMapper::class, ], ];
3. Add the Trait to Your Model
use SocialDept\AtpParity\Concerns\HasAtpRecord; class Post extends Model { use HasAtpRecord; }
Your model can now convert to/from AT Protocol records and query by URI.
What can you build?
- Data mirrors - Keep local copies of AT Protocol data
- AppViews - Build custom applications with synced data
- Analytics platforms - Store and analyze network activity
- Content aggregators - Collect and organize posts locally
- Moderation tools - Track and manage content in your database
- Hybrid applications - Combine local and federated data
Ecosystem Integration
Parity is designed to work seamlessly with the other atp-* packages:
| Package | Integration |
|---|---|
| atp-schema | Records extend Data, use generated DTOs directly |
| atp-client | RecordHelper for fetching and hydrating records |
| atp-signals | ParitySignal for automatic firehose sync |
Using with atp-schema
Use generated schema classes directly with SchemaMapper:
use SocialDept\AtpSchema\Generated\App\Bsky\Feed\Post; use SocialDept\AtpParity\Support\SchemaMapper; $mapper = new SchemaMapper( schemaClass: Post::class, modelClass: \App\Models\Post::class, toAttributes: fn(Post $p) => [ 'content' => $p->text, 'published_at' => $p->createdAt, ], toRecordData: fn($m) => [ 'text' => $m->content, 'createdAt' => $m->published_at->toIso8601String(), ], ); $registry->register($mapper);
Using with atp-client
Fetch records by URI and convert directly to models:
use SocialDept\AtpParity\Support\RecordHelper; $helper = app(RecordHelper::class); // Fetch as typed DTO $record = $helper->fetch('at://did:plc:xxx/app.bsky.feed.post/abc123'); // Fetch and convert to model (unsaved) $post = $helper->fetchAsModel('at://did:plc:xxx/app.bsky.feed.post/abc123'); // Fetch and sync to database (upsert) $post = $helper->sync('at://did:plc:xxx/app.bsky.feed.post/abc123');
The helper automatically resolves the DID to find the correct PDS endpoint, so it works with any AT Protocol server - not just Bluesky.
Using with atp-signals
Enable automatic firehose synchronization by registering the ParitySignal:
// config/signal.php return [ 'signals' => [ \SocialDept\AtpParity\Signals\ParitySignal::class, ], ];
Run php artisan signal:consume and your models will automatically sync with matching firehose events.
Importing Historical Data
For existing records created before you started consuming the firehose:
# Import a user's records php artisan parity:import did:plc:z72i7hdynmk6r22z27h6tvur # Check import status php artisan parity:import-status
Or programmatically:
use SocialDept\AtpParity\Import\ImportService; $service = app(ImportService::class); $result = $service->importUser('did:plc:z72i7hdynmk6r22z27h6tvur'); echo "Synced {$result->recordsSynced} records";
Documentation
For detailed documentation on specific topics:
- Record Mappers - Creating and using mappers
- Model Traits - HasAtpRecord and SyncsWithAtp
- Automatic Syncing - Auto-sync models with AT Protocol
- Blob Handling - Downloading, uploading, and serving blobs
- atp-schema Integration - Using generated DTOs
- atp-client Integration - RecordHelper and fetching
- atp-signals Integration - ParitySignal and firehose sync
- Importing - Syncing historical data
Model Traits
HasAtpRecord
Add AT Protocol awareness to your models:
use SocialDept\AtpParity\Concerns\HasAtpRecord; class Post extends Model { use HasAtpRecord; protected $fillable = ['content', 'atp_uri', 'atp_cid']; }
Available methods:
// Get AT Protocol metadata $post->getAtpUri(); // at://did:plc:xxx/app.bsky.feed.post/rkey $post->getAtpCid(); // bafyre... $post->getAtpDid(); // did:plc:xxx (extracted from URI) $post->getAtpCollection(); // app.bsky.feed.post (extracted from URI) $post->getAtpRkey(); // rkey (extracted from URI) // Check sync status $post->hasAtpRecord(); // true if synced // Convert to record DTO $record = $post->toAtpRecord(); // Query scopes Post::withAtpRecord()->get(); // Only synced posts Post::withoutAtpRecord()->get(); // Only unsynced posts Post::whereAtpUri($uri)->first(); // Find by URI
SyncsWithAtp
Extended trait for bidirectional sync tracking:
use SocialDept\AtpParity\Concerns\SyncsWithAtp; class Post extends Model { use SyncsWithAtp; }
Additional methods:
// Track sync status $post->getAtpSyncedAt(); // Last sync timestamp $post->hasLocalChanges(); // True if updated since last sync // Mark as synced $post->markAsSynced($uri, $cid); // Update from remote $post->updateFromRecord($record, $uri, $cid);
HasAtpBlobs
Add blob handling to models with images or other binary content:
use SocialDept\AtpParity\Concerns\HasAtpRecord; use SocialDept\AtpParity\Concerns\HasAtpBlobs; class Post extends Model { use HasAtpRecord, HasAtpBlobs; protected $casts = ['atp_blobs' => 'array']; }
Available methods:
// Get URLs for blobs $url = $post->getAtpBlobUrl('avatar'); // Single blob URL $urls = $post->getAtpBlobUrls('images'); // Array of URLs // Download blobs locally $post->downloadAtpBlobs(); // Check status $post->hasAtpBlobs(); // Has any blob data $post->hasLocalBlobs(); // All blobs downloaded locally
See Blob Handling for complete documentation including MediaLibrary integration.
AutoSyncsWithAtp
Automatically sync models with AT Protocol on create, update, and delete:
use SocialDept\AtpParity\Concerns\AutoSyncsWithAtp; class Post extends Model { use AutoSyncsWithAtp; public function syncAsDid(): ?string { return $this->user->did; } public function shouldAutoSync(): bool { return $this->status === 'published'; } }
When enabled, the model automatically syncs:
$post = Post::create(['content' => 'Hello!']); // Syncs to ATP $post->update(['content' => 'Updated']); // Updates ATP record $post->delete(); // Removes from ATP
Failed syncs due to expired OAuth sessions can be captured and retried after re-authentication. See Automatic Syncing for complete documentation including pending sync configuration.
Database Migration
Add AT Protocol columns to your models:
Schema::table('posts', function (Blueprint $table) { $table->string('atp_uri')->nullable()->unique(); $table->string('atp_cid')->nullable(); $table->timestamp('atp_synced_at')->nullable(); // For SyncsWithAtp $table->json('atp_blobs')->nullable(); // For HasAtpBlobs });
Publish and run Parity's core migration:
php artisan vendor:publish --tag=parity-migrations php artisan migrate
Optional migrations are published separately based on which features you use:
# Manual conflict resolution (conflicts.strategy = 'manual') php artisan vendor:publish --tag=parity-migrations-conflicts # Filesystem blob storage (blobs.storage_driver = 'filesystem') php artisan vendor:publish --tag=parity-migrations-blobs # Database pending sync storage (pending_syncs.storage = 'database') php artisan vendor:publish --tag=parity-migrations-pending-syncs
Configuration
// config/parity.php return [ // Registered mappers 'mappers' => [ App\AtpMappers\PostMapper::class, App\AtpMappers\ProfileMapper::class, ], // Column names for AT Protocol metadata 'columns' => [ 'uri' => 'atp_uri', 'cid' => 'atp_cid', ], // Blob handling configuration 'blobs' => [ // 'filesystem' (requires migrations) or 'medialibrary' (no extra migrations) 'storage_driver' => \SocialDept\AtpParity\Enums\BlobStorageDriver::Filesystem, 'download_on_import' => env('PARITY_BLOB_DOWNLOAD', false), 'disk' => env('PARITY_BLOB_DISK', 'local'), 'url_strategy' => \SocialDept\AtpParity\Enums\BlobUrlStrategy::Cdn, ], ];
Creating Custom Records
Extend the Record base class for custom AT Protocol records:
use SocialDept\AtpParity\Data\Record; use Carbon\Carbon; class PostRecord extends Record { public function __construct( public readonly string $text, public readonly Carbon $createdAt, public readonly ?array $facets = null, ) {} public static function getLexicon(): string { return 'app.bsky.feed.post'; } public static function fromArray(array $data): static { return new static( text: $data['text'], createdAt: Carbon::parse($data['createdAt']), facets: $data['facets'] ?? null, ); } }
The Record class extends atp-schema's Data and implements atp-client's Recordable interface, ensuring full compatibility with the ecosystem.
Requirements
- PHP 8.2+
- Laravel 10, 11, or 12
- socialdept/atp-schema ^0.3
- socialdept/atp-client ^0.0
- socialdept/atp-resolver ^1.1
- socialdept/atp-signals ^1.1
Testing
composer test
Resources
- AT Protocol Documentation
- Bluesky API Docs
- atp-schema - Generated AT Protocol DTOs
- atp-client - AT Protocol HTTP client
- atp-signals - Firehose event consumer
Support & Contributing
Found a bug or have a feature request? Open an issue.
Want to contribute? Check out the contribution guidelines.
Changelog
Please see changelog for recent changes.
Credits
- Miguel Batres - founder & lead maintainer
- All contributors
License
Parity is open-source software licensed under the MIT license.
Built for the Atmosphere - By Social Dept.
socialdept/atp-parity 适用场景与选型建议
socialdept/atp-parity 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 757 次下载、GitHub Stars 达 0, 最近一次更新时间为 2025 年 12 月 04 日, 在 PHP 生态内属于活跃度较高的组件。
它主要适用于以下技术方向: 「sync」 「laravel」 「parity」 「atp」 「at protocol」 「bluesky」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。
我们在过去多个企业项目中使用过 socialdept/atp-parity 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。
基于 socialdept/atp-parity 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。
线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。
承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。
与 socialdept/atp-parity 相关的其它包
同方向 / 同关键字的高下载量 PHP Composer 包推荐,方便对比选型:
A sleek PHP wrapper around rclone with Laravel-style fluent API syntax
Sync content to other sites on element save.
Production-ready third-party integrations for Laravel. Credential management, API request logging, rate limiting, sync scheduling, OAuth2, and health monitoring.
Synchronizing data between Laravel's framework
Alfabank REST API integration
This behavior for automatic or manual sync data between two models, without declaration relation. This behavior must be attached on master model. Main purposes - for sync rarely modified data from more reliable database storage to redis storage for frequently access; Support actual data state in so
统计信息
- 总下载量: 757
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 0
- 点击次数: 34
- 依赖项目数: 0
- 推荐数: 0
其他信息
- 授权协议: MIT
- 更新时间: 2025-12-04
