Maintain local ⭤ remote in sync with automatic AT Protocol parity for Laravel (alpha & unstable)
1<?php
2
3namespace SocialDept\AtpParity\Concerns;
4
5use SocialDept\AtpSchema\Data\Data;
6
7/**
8 * Trait for models that sync bidirectionally with AT Protocol.
9 *
10 * Extends HasAtpRecord with additional sync tracking and conflict handling.
11 *
12 * @mixin \Illuminate\Database\Eloquent\Model
13 */
14trait SyncsWithAtp
15{
16 use HasAtpRecord;
17
18 /**
19 * Get the column name for tracking the last sync timestamp.
20 */
21 public function getAtpSyncedAtColumn(): string
22 {
23 return 'atp_synced_at';
24 }
25
26 /**
27 * Get the timestamp of the last sync.
28 */
29 public function getAtpSyncedAt(): ?\DateTimeInterface
30 {
31 $column = $this->getAtpSyncedAtColumn();
32
33 return $this->getAttribute($column);
34 }
35
36 /**
37 * Mark the model as synced with the given metadata.
38 */
39 public function markAsSynced(string $uri, string $cid): void
40 {
41 $uriColumn = config('parity.columns.uri', 'atp_uri');
42 $cidColumn = config('parity.columns.cid', 'atp_cid');
43 $syncColumn = $this->getAtpSyncedAtColumn();
44
45 $this->setAttribute($uriColumn, $uri);
46 $this->setAttribute($cidColumn, $cid);
47 $this->setAttribute($syncColumn, now());
48 }
49
50 /**
51 * Check if the model has local changes since last sync.
52 */
53 public function hasLocalChanges(): bool
54 {
55 $syncedAt = $this->getAtpSyncedAt();
56
57 if (! $syncedAt) {
58 return true;
59 }
60
61 $updatedAt = $this->getAttribute('updated_at');
62
63 if (! $updatedAt) {
64 return false;
65 }
66
67 return $updatedAt > $syncedAt;
68 }
69
70 /**
71 * Update the model from a remote record.
72 */
73 public function updateFromRecord(Data $record, string $uri, string $cid): void
74 {
75 $mapper = $this->getAtpMapper();
76
77 if (! $mapper) {
78 return;
79 }
80
81 $mapper->updateModel($this, $record, [
82 'uri' => $uri,
83 'cid' => $cid,
84 ]);
85
86 $this->setAttribute($this->getAtpSyncedAtColumn(), now());
87 }
88
89 /**
90 * Boot the trait.
91 */
92 public static function bootSyncsWithAtp(): void
93 {
94 // Hook into model events if needed
95 }
96}