Maintain local ⭤ remote in sync with automatic AT Protocol parity for Laravel (alpha & unstable)
1<?php
2
3namespace SocialDept\AtpParity\Concerns;
4
5use Illuminate\Database\Eloquent\Relations\BelongsTo;
6use Illuminate\Database\Eloquent\Relations\HasMany;
7
8/**
9 * Trait for Eloquent models with AT Protocol relationships.
10 *
11 * Provides helpers for defining relationships based on AT Protocol URI references.
12 * Common relationship patterns:
13 *
14 * - reply.parent -> parent_uri column
15 * - reply.root -> root_uri column
16 * - embed.record (quote) -> quoted_uri column
17 * - like.subject -> subject_uri column
18 * - follow.subject -> subject_did column
19 * - repost.subject -> subject_uri column
20 *
21 * @mixin \Illuminate\Database\Eloquent\Model
22 */
23trait HasAtpRelationships
24{
25 /**
26 * Define an AT Protocol relationship via URI reference.
27 *
28 * This creates a BelongsTo relationship where the foreign key is an AT Protocol URI
29 * stored in the specified column, matched against the related model's atp_uri column.
30 *
31 * Example:
32 * ```php
33 * public function parent(): BelongsTo
34 * {
35 * return $this->atpBelongsTo(Post::class, 'parent_uri');
36 * }
37 * ```
38 *
39 * @param class-string<\Illuminate\Database\Eloquent\Model> $related
40 */
41 public function atpBelongsTo(string $related, string $uriColumn, ?string $ownerKey = null): BelongsTo
42 {
43 $ownerKey = $ownerKey ?? config('parity.columns.uri', 'atp_uri');
44
45 // Create a custom BelongsTo that uses URI matching
46 return $this->belongsTo($related, $uriColumn, $ownerKey);
47 }
48
49 /**
50 * Define an inverse AT Protocol relationship via URI reference.
51 *
52 * This creates a HasMany relationship where related models have a column
53 * containing this model's AT Protocol URI.
54 *
55 * Example:
56 * ```php
57 * public function replies(): HasMany
58 * {
59 * return $this->atpHasMany(Post::class, 'parent_uri');
60 * }
61 * ```
62 *
63 * @param class-string<\Illuminate\Database\Eloquent\Model> $related
64 */
65 public function atpHasMany(string $related, string $foreignKey, ?string $localKey = null): HasMany
66 {
67 $localKey = $localKey ?? config('parity.columns.uri', 'atp_uri');
68
69 return $this->hasMany($related, $foreignKey, $localKey);
70 }
71
72 /**
73 * Define an AT Protocol relationship via DID reference.
74 *
75 * This creates a BelongsTo relationship where the foreign key is a DID
76 * stored in the specified column, matched against a did column on the related model.
77 *
78 * Example:
79 * ```php
80 * public function subject(): BelongsTo
81 * {
82 * return $this->atpBelongsToByDid(User::class, 'subject_did');
83 * }
84 * ```
85 *
86 * @param class-string<\Illuminate\Database\Eloquent\Model> $related
87 */
88 public function atpBelongsToByDid(string $related, string $didColumn, string $ownerKey = 'did'): BelongsTo
89 {
90 return $this->belongsTo($related, $didColumn, $ownerKey);
91 }
92
93 /**
94 * Define an inverse AT Protocol relationship via DID reference.
95 *
96 * Example:
97 * ```php
98 * public function followers(): HasMany
99 * {
100 * return $this->atpHasManyByDid(Follow::class, 'subject_did');
101 * }
102 * ```
103 *
104 * @param class-string<\Illuminate\Database\Eloquent\Model> $related
105 */
106 public function atpHasManyByDid(string $related, string $foreignKey, string $localKey = 'did'): HasMany
107 {
108 return $this->hasMany($related, $foreignKey, $localKey);
109 }
110
111 /**
112 * Get a related model by AT Protocol URI.
113 *
114 * @param class-string<\Illuminate\Database\Eloquent\Model> $modelClass
115 * @return \Illuminate\Database\Eloquent\Model|null
116 */
117 public function findByAtpUri(string $modelClass, ?string $uri)
118 {
119 if (! $uri) {
120 return null;
121 }
122
123 $column = config('parity.columns.uri', 'atp_uri');
124
125 return $modelClass::where($column, $uri)->first();
126 }
127}