Maintain local ⭤ remote in sync with automatic AT Protocol parity for Laravel (alpha & unstable)
1<?php
2
3namespace SocialDept\AtpParity\Sync;
4
5use Illuminate\Database\Eloquent\Model;
6use SocialDept\AtpParity\Concerns\SyncsWithAtp;
7use SocialDept\AtpSchema\Data\Data;
8
9/**
10 * Detects conflicts between local and remote record versions.
11 */
12class ConflictDetector
13{
14 /**
15 * Check if there's a conflict between local model and remote record.
16 */
17 public function hasConflict(Model $model, Data $record, string $cid): bool
18 {
19 // No conflict if model doesn't have local changes
20 if (! $this->modelHasLocalChanges($model)) {
21 return false;
22 }
23
24 // No conflict if CID matches (same version)
25 if ($this->getCid($model) === $cid) {
26 return false;
27 }
28
29 return true;
30 }
31
32 /**
33 * Check if the model has local changes since last sync.
34 */
35 protected function modelHasLocalChanges(Model $model): bool
36 {
37 // Use trait method if available
38 if ($this->usesTrait($model, SyncsWithAtp::class)) {
39 return $model->hasLocalChanges();
40 }
41
42 // Fallback: compare updated_at with a sync timestamp if available
43 $syncedAt = $model->getAttribute('atp_synced_at');
44
45 if (! $syncedAt) {
46 return true;
47 }
48
49 $updatedAt = $model->getAttribute('updated_at');
50
51 if (! $updatedAt) {
52 return false;
53 }
54
55 return $updatedAt > $syncedAt;
56 }
57
58 /**
59 * Get the CID from a model.
60 */
61 protected function getCid(Model $model): ?string
62 {
63 $column = config('parity.columns.cid', 'atp_cid');
64
65 return $model->getAttribute($column);
66 }
67
68 /**
69 * Check if a model uses a specific trait.
70 *
71 * @param class-string $trait
72 */
73 protected function usesTrait(Model $model, string $trait): bool
74 {
75 return in_array($trait, class_uses_recursive($model));
76 }
77}