1: | <?php declare(strict_types=1); |
2: | |
3: | namespace Salient\Sync\Db; |
4: | |
5: | use Salient\Contract\Core\Provider\ProviderInterface; |
6: | use Salient\Contract\Sync\SyncDefinitionInterface; |
7: | use Salient\Contract\Sync\SyncEntityInterface; |
8: | use Salient\Core\Exception\MethodNotImplementedException; |
9: | use Salient\Core\Facade\Cache; |
10: | use Salient\Core\SqlQuery; |
11: | use Salient\Db\DbConnector; |
12: | use Salient\Sync\Exception\SyncEntityNotFoundException; |
13: | use Salient\Sync\Exception\UnreachableBackendException; |
14: | use Salient\Sync\AbstractSyncProvider; |
15: | use Salient\Utility\Arr; |
16: | use Salient\Utility\Get; |
17: | use Salient\Utility\Str; |
18: | use ADOConnection; |
19: | use ADODB_Exception; |
20: | |
21: | |
22: | |
23: | |
24: | abstract class DbSyncProvider extends AbstractSyncProvider |
25: | { |
26: | private DbConnector $DbConnector; |
27: | private ADOConnection $Db; |
28: | |
29: | |
30: | |
31: | |
32: | |
33: | |
34: | |
35: | abstract protected function getDbConnector(): DbConnector; |
36: | |
37: | |
38: | |
39: | |
40: | public function getBackendIdentifier(): array |
41: | { |
42: | $connector = $this->dbConnector(); |
43: | |
44: | if ($connector->Dsn !== null) { |
45: | |
46: | throw new MethodNotImplementedException( |
47: | static::class, |
48: | __FUNCTION__, |
49: | ProviderInterface::class |
50: | ); |
51: | } |
52: | |
53: | return Arr::trim([ |
54: | Str::lower((string) $connector->Hostname), |
55: | (string) $connector->Port, |
56: | Str::lower((string) $connector->Database), |
57: | Str::lower((string) $connector->Schema), |
58: | ], null, false); |
59: | } |
60: | |
61: | |
62: | |
63: | |
64: | final public function getDefinition(string $entity): SyncDefinitionInterface |
65: | { |
66: | return $this->getDbDefinition($entity); |
67: | } |
68: | |
69: | |
70: | |
71: | |
72: | |
73: | |
74: | |
75: | |
76: | |
77: | |
78: | protected function getDbDefinition(string $entity): DbSyncDefinition |
79: | { |
80: | return $this->builderFor($entity)->build(); |
81: | } |
82: | |
83: | |
84: | |
85: | |
86: | |
87: | |
88: | |
89: | |
90: | |
91: | final protected function builderFor(string $entity): DbSyncDefinitionBuilder |
92: | { |
93: | return DbSyncDefinition::build() |
94: | ->entity($entity) |
95: | ->provider($this); |
96: | } |
97: | |
98: | |
99: | |
100: | |
101: | final public function dbConnector(): DbConnector |
102: | { |
103: | return $this->DbConnector |
104: | ?? ($this->DbConnector = $this->getDbConnector()); |
105: | } |
106: | |
107: | |
108: | |
109: | |
110: | final public function getDb(): ADOConnection |
111: | { |
112: | return $this->Db |
113: | ?? ($this->Db = $this->dbConnector()->getConnection()); |
114: | } |
115: | |
116: | |
117: | |
118: | |
119: | protected function getSqlQuery(ADOConnection $db): SqlQuery |
120: | { |
121: | return new SqlQuery(fn(string $name): string => $db->Param($name)); |
122: | } |
123: | |
124: | |
125: | |
126: | |
127: | public function checkHeartbeat(int $ttl = 300) |
128: | { |
129: | $key = implode(':', [ |
130: | static::class, |
131: | __FUNCTION__, |
132: | Get::hash(implode("\0", $this->getBackendIdentifier())), |
133: | ]); |
134: | |
135: | if (Cache::get($key) === null) { |
136: | try { |
137: | $this->dbConnector()->getConnection(5); |
138: | } catch (ADODB_Exception $ex) { |
139: | throw new UnreachableBackendException( |
140: | $this, |
141: | $ex->getMessage(), |
142: | $ex, |
143: | ); |
144: | } |
145: | Cache::set($key, true, $ttl); |
146: | } |
147: | |
148: | return $this; |
149: | } |
150: | |
151: | |
152: | |
153: | |
154: | |
155: | |
156: | |
157: | |
158: | |
159: | |
160: | protected function first(array $rows, string $entity, $id): array |
161: | { |
162: | $row = array_shift($rows); |
163: | if ($row === null) { |
164: | throw new SyncEntityNotFoundException($this, $entity, $id); |
165: | } |
166: | |
167: | return $row; |
168: | } |
169: | } |
170: | |