22
33namespace Composite \DB ;
44
5+ use Composite \DB \Exceptions \DbException ;
56use Composite \DB \MultiQuery \MultiInsert ;
67use Composite \DB \MultiQuery \MultiSelect ;
7- use Composite \Entity \Helpers \DateTimeHelper ;
88use Composite \Entity \AbstractEntity ;
9- use Composite \DB \ Exceptions \ DbException ;
9+ use Composite \Entity \ Helpers \ DateTimeHelper ;
1010use Doctrine \DBAL \Connection ;
11- use Doctrine \DBAL \Platforms \PostgreSQLPlatform ;
1211use Ramsey \Uuid \UuidInterface ;
1312
1413abstract class AbstractTable
1514{
16- use SelectRawTrait;
15+ use Helpers \SelectRawTrait;
16+ use Helpers \DatabaseSpecificTrait;
1717
1818 protected readonly TableConfig $ config ;
1919
20+
2021 abstract protected function getConfig (): TableConfig ;
2122
2223 public function __construct ()
@@ -44,49 +45,51 @@ public function getConnectionName(): string
4445 * @return void
4546 * @throws \Throwable
4647 */
47- public function save (AbstractEntity & $ entity ): void
48+ public function save (AbstractEntity $ entity ): void
4849 {
4950 $ this ->config ->checkEntity ($ entity );
5051 if ($ entity ->isNew ()) {
5152 $ connection = $ this ->getConnection ();
5253 $ this ->checkUpdatedAt ($ entity );
5354
54- $ insertData = $ this ->formatData ($ entity ->toArray ());
55+ $ insertData = $ this ->prepareDataForSql ($ entity ->toArray ());
5556 $ this ->getConnection ()->insert ($ this ->getTableName (), $ insertData );
5657
57- if ($ this ->config ->autoIncrementKey ) {
58- $ insertData [$ this ->config ->autoIncrementKey ] = intval ($ connection -> lastInsertId () );
59- $ entity = $ entity :: fromArray ( $ insertData );
60- } else {
61- $ entity-> resetChangedColumns ( );
58+ if ($ this ->config ->autoIncrementKey && ( $ lastInsertedId = $ connection -> lastInsertId ()) ) {
59+ $ insertData [$ this ->config ->autoIncrementKey ] = intval ($ lastInsertedId );
60+ $ entity:: schema ()
61+ -> getColumn ( $ this -> config -> autoIncrementKey )
62+ -> setValue ( $ entity, $ insertData [ $ this -> config -> autoIncrementKey ] );
6263 }
64+ $ entity ->resetChangedColumns ($ insertData );
6365 } else {
6466 if (!$ changedColumns = $ entity ->getChangedColumns ()) {
6567 return ;
6668 }
67- $ connection = $ this ->getConnection ();
68- $ where = $ this ->getPkCondition ($ entity );
69-
69+ $ changedColumns = $ this ->prepareDataForSql ($ changedColumns );
7070 if ($ this ->config ->hasUpdatedAt () && property_exists ($ entity , 'updated_at ' )) {
7171 $ entity ->updated_at = new \DateTimeImmutable ();
7272 $ changedColumns ['updated_at ' ] = DateTimeHelper::dateTimeToString ($ entity ->updated_at );
7373 }
74+ $ whereParams = $ this ->getPkCondition ($ entity );
7475 if ($ this ->config ->hasOptimisticLock ()
7576 && method_exists ($ entity , 'getVersion ' )
7677 && method_exists ($ entity , 'incrementVersion ' )) {
77- $ where ['lock_version ' ] = $ entity ->getVersion ();
78+ $ whereParams ['lock_version ' ] = $ entity ->getVersion ();
7879 $ entity ->incrementVersion ();
7980 $ changedColumns ['lock_version ' ] = $ entity ->getVersion ();
8081 }
81- $ entityUpdated = $ connection ->update (
82- table: $ this ->getTableName (),
83- data: $ changedColumns ,
84- criteria: $ where ,
82+ $ updateString = implode (', ' , array_map (fn ($ key ) => $ this ->escapeIdentifier ($ key ) . "=? " , array_keys ($ changedColumns )));
83+ $ whereString = implode (' AND ' , array_map (fn ($ key ) => $ this ->escapeIdentifier ($ key ) . "=? " , array_keys ($ whereParams )));
84+
85+ $ entityUpdated = (bool )$ this ->getConnection ()->executeStatement (
86+ sql: "UPDATE " . $ this ->escapeIdentifier ($ this ->getTableName ()) . " SET $ updateString WHERE $ whereString; " ,
87+ params: array_merge (array_values ($ changedColumns ), array_values ($ whereParams )),
8588 );
8689 if ($ this ->config ->hasOptimisticLock () && !$ entityUpdated ) {
8790 throw new Exceptions \LockException ('Failed to update entity version, concurrency modification, rolling back. ' );
8891 }
89- $ entity ->resetChangedColumns ();
92+ $ entity ->resetChangedColumns ($ changedColumns );
9093 }
9194 }
9295
@@ -101,7 +104,7 @@ public function saveMany(array $entities): void
101104 if ($ entity ->isNew ()) {
102105 $ this ->config ->checkEntity ($ entity );
103106 $ this ->checkUpdatedAt ($ entity );
104- $ rowsToInsert [] = $ this ->formatData ($ entity ->toArray ());
107+ $ rowsToInsert [] = $ this ->prepareDataForSql ($ entity ->toArray ());
105108 unset($ entities [$ i ]);
106109 }
107110 }
@@ -113,14 +116,15 @@ public function saveMany(array $entities): void
113116 }
114117 if ($ rowsToInsert ) {
115118 $ chunks = array_chunk ($ rowsToInsert , 1000 );
119+ $ connection = $ this ->getConnection ();
116120 foreach ($ chunks as $ chunk ) {
117121 $ multiInsert = new MultiInsert (
122+ connection: $ connection ,
118123 tableName: $ this ->getTableName (),
119124 rows: $ chunk ,
120125 );
121126 if ($ multiInsert ->getSql ()) {
122- $ stmt = $ this ->getConnection ()->prepare ($ multiInsert ->getSql ());
123- $ stmt ->executeQuery ($ multiInsert ->getParameters ());
127+ $ connection ->executeStatement ($ multiInsert ->getSql (), $ multiInsert ->getParameters ());
124128 }
125129 }
126130 }
@@ -135,7 +139,7 @@ public function saveMany(array $entities): void
135139 * @param AbstractEntity $entity
136140 * @throws \Throwable
137141 */
138- public function delete (AbstractEntity & $ entity ): void
142+ public function delete (AbstractEntity $ entity ): void
139143 {
140144 $ this ->config ->checkEntity ($ entity );
141145 if ($ this ->config ->hasSoftDelete ()) {
@@ -144,8 +148,12 @@ public function delete(AbstractEntity &$entity): void
144148 $ this ->save ($ entity );
145149 }
146150 } else {
147- $ where = $ this ->getPkCondition ($ entity );
148- $ this ->getConnection ()->delete ($ this ->getTableName (), $ where );
151+ $ whereParams = $ this ->getPkCondition ($ entity );
152+ $ whereString = implode (' AND ' , array_map (fn ($ key ) => $ this ->escapeIdentifier ($ key ) . "=? " , array_keys ($ whereParams )));
153+ $ this ->getConnection ()->executeQuery (
154+ sql: "DELETE FROM " . $ this ->escapeIdentifier ($ this ->getTableName ()) . " WHERE $ whereString; " ,
155+ params: array_values ($ whereParams ),
156+ );
149157 }
150158 }
151159
@@ -192,8 +200,15 @@ protected function _countAll(array|Where $where = []): int
192200 */
193201 protected function _findByPk (mixed $ pk ): mixed
194202 {
195- $ where = $ this ->getPkCondition ($ pk );
196- return $ this ->_findOne ($ where );
203+ $ whereParams = $ this ->getPkCondition ($ pk );
204+ $ whereString = implode (' AND ' , array_map (fn ($ key ) => $ this ->escapeIdentifier ($ key ) . "=? " , array_keys ($ whereParams )));
205+ $ row = $ this ->getConnection ()
206+ ->executeQuery (
207+ sql: "SELECT * FROM " . $ this ->escapeIdentifier ($ this ->getTableName ()) . " WHERE $ whereString; " ,
208+ params: array_values ($ whereParams ),
209+ )
210+ ->fetchAssociative ();
211+ return $ this ->createEntity ($ row );
197212 }
198213
199214 /**
@@ -304,7 +319,14 @@ protected function getPkCondition(int|string|array|AbstractEntity|UuidInterface
304319 {
305320 $ condition = [];
306321 if ($ data instanceof AbstractEntity) {
307- $ data = $ data ->toArray ();
322+ if ($ data ->isNew ()) {
323+ $ data = $ data ->toArray ();
324+ } else {
325+ foreach ($ this ->config ->primaryKeys as $ key ) {
326+ $ condition [$ key ] = $ data ->getOldValue ($ key );
327+ }
328+ return $ condition ;
329+ }
308330 }
309331 if (is_array ($ data )) {
310332 foreach ($ this ->config ->primaryKeys as $ key ) {
@@ -324,20 +346,4 @@ private function checkUpdatedAt(AbstractEntity $entity): void
324346 $ entity ->updated_at = new \DateTimeImmutable ();
325347 }
326348 }
327-
328- /**
329- * @param array<string, mixed> $data
330- * @return array<string, mixed>
331- * @throws \Doctrine\DBAL\Exception
332- */
333- private function formatData (array $ data ): array
334- {
335- $ supportsBoolean = $ this ->getConnection ()->getDatabasePlatform () instanceof PostgreSQLPlatform;
336- foreach ($ data as $ columnName => $ value ) {
337- if (is_bool ($ value ) && !$ supportsBoolean ) {
338- $ data [$ columnName ] = $ value ? 1 : 0 ;
339- }
340- }
341- return $ data ;
342- }
343349}
0 commit comments