Skip to content

Commit 51ff0a6

Browse files
authored
Merge pull request #542 from utopia-php/feat-multi-tenant-insert
Feat multi tenant insert
2 parents 01da5dd + 2e01c99 commit 51ff0a6

File tree

10 files changed

+272
-118
lines changed

10 files changed

+272
-118
lines changed

Dockerfile

Lines changed: 6 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
FROM composer:2.0 AS composer
1+
FROM composer:2.8 AS composer
22

33
WORKDIR /usr/local/src/
44

@@ -11,13 +11,12 @@ RUN composer install \
1111
--no-plugins \
1212
--no-scripts \
1313
--prefer-dist
14-
15-
FROM php:8.3.10-cli-alpine3.20 AS compile
14+
15+
FROM php:8.3.19-cli-alpine3.21 AS compile
1616

1717
ENV PHP_REDIS_VERSION="6.0.2" \
18-
PHP_SWOOLE_VERSION="v5.1.3" \
19-
PHP_MONGO_VERSION="1.16.1" \
20-
PHP_XDEBUG_VERSION="3.3.2"
18+
PHP_SWOOLE_VERSION="v5.1.7" \
19+
PHP_XDEBUG_VERSION="3.4.2"
2120

2221
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
2322

@@ -58,20 +57,10 @@ RUN \
5857
&& ./configure --enable-http2 \
5958
&& make && make install
6059

61-
## MongoDB Extension
62-
FROM compile AS mongodb
63-
RUN \
64-
git clone --depth 1 --branch $PHP_MONGO_VERSION https://github.com/mongodb/mongo-php-driver.git \
65-
&& cd mongo-php-driver \
66-
&& git submodule update --init \
67-
&& phpize \
68-
&& ./configure \
69-
&& make && make install
70-
7160
## PCOV Extension
7261
FROM compile AS pcov
7362
RUN \
74-
git clone https://github.com/krakjoe/pcov.git \
63+
git clone --depth 1 https://github.com/krakjoe/pcov.git \
7564
&& cd pcov \
7665
&& phpize \
7766
&& ./configure --enable-pcov \
@@ -97,7 +86,6 @@ WORKDIR /usr/src/code
9786

9887
RUN echo extension=redis.so >> /usr/local/etc/php/conf.d/redis.ini
9988
RUN echo extension=swoole.so >> /usr/local/etc/php/conf.d/swoole.ini
100-
RUN echo extension=mongodb.so >> /usr/local/etc/php/conf.d/mongodb.ini
10189
RUN echo extension=pcov.so >> /usr/local/etc/php/conf.d/pcov.ini
10290
RUN echo extension=xdebug.so >> /usr/local/etc/php/conf.d/xdebug.ini
10391

@@ -110,7 +98,6 @@ RUN echo "memory_limit=1024M" >> $PHP_INI_DIR/php.ini
11098
COPY --from=composer /usr/local/src/vendor /usr/src/code/vendor
11199
COPY --from=swoole /usr/local/lib/php/extensions/no-debug-non-zts-20230831/swoole.so /usr/local/lib/php/extensions/no-debug-non-zts-20230831/
112100
COPY --from=redis /usr/local/lib/php/extensions/no-debug-non-zts-20230831/redis.so /usr/local/lib/php/extensions/no-debug-non-zts-20230831/
113-
COPY --from=mongodb /usr/local/lib/php/extensions/no-debug-non-zts-20230831/mongodb.so /usr/local/lib/php/extensions/no-debug-non-zts-20230831/
114101
COPY --from=pcov /usr/local/lib/php/extensions/no-debug-non-zts-20230831/pcov.so /usr/local/lib/php/extensions/no-debug-non-zts-20230831/
115102
COPY --from=xdebug /usr/local/lib/php/extensions/no-debug-non-zts-20230831/xdebug.so /usr/local/lib/php/extensions/no-debug-non-zts-20230831/
116103

docker-compose.yml

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -70,17 +70,6 @@ services:
7070
- "8704:3306"
7171
environment:
7272
- MYSQL_ROOT_PASSWORD=password
73-
74-
mongo:
75-
image: mongo:5.0
76-
container_name: utopia-mongo
77-
networks:
78-
- database
79-
ports:
80-
- "8705:27017"
81-
environment:
82-
MONGO_INITDB_ROOT_USERNAME: root
83-
MONGO_INITDB_ROOT_PASSWORD: example
8473

8574
mysql:
8675
image: mysql:8.0.41

src/Database/Adapter.php

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ abstract class Adapter
1818

1919
protected ?int $tenant = null;
2020

21+
protected bool $tenantPerDocument = false;
22+
2123
protected int $inTransaction = 0;
2224

2325
/**
@@ -190,6 +192,34 @@ public function getTenant(): ?int
190192
return $this->tenant;
191193
}
192194

195+
/**
196+
* Set Tenant Per Document.
197+
*
198+
* Set whether to use a different tenant for each document
199+
*
200+
* @param bool $tenantPerDocument
201+
*
202+
* @return bool
203+
*/
204+
public function setTenantPerDocument(bool $tenantPerDocument): bool
205+
{
206+
$this->tenantPerDocument = $tenantPerDocument;
207+
208+
return true;
209+
}
210+
211+
/**
212+
* Get Tenant Per Document.
213+
*
214+
* Get whether to use a different tenant for each document
215+
*
216+
* @return bool
217+
*/
218+
public function getTenantPerDocument(): bool
219+
{
220+
return $this->tenantPerDocument;
221+
}
222+
193223
/**
194224
* Set metadata for query comments
195225
*
@@ -261,7 +291,7 @@ abstract public function setTimeout(int $milliseconds, string $event = Database:
261291
public function clearTimeout(string $event): void
262292
{
263293
// Clear existing callback
264-
$this->before($event, 'timeout', null);
294+
$this->before($event, 'timeout');
265295
}
266296

267297
/**
@@ -301,7 +331,6 @@ abstract public function rollbackTransaction(): bool;
301331
* Check if a transaction is active.
302332
*
303333
* @return bool
304-
* @throws DatabaseException
305334
*/
306335
public function inTransaction(): bool
307336
{
@@ -482,7 +511,7 @@ abstract public function createAttribute(string $collection, string $id, string
482511
* @param int $size
483512
* @param bool $signed
484513
* @param bool $array
485-
* @param string $newKey
514+
* @param string|null $newKey
486515
*
487516
* @return bool
488517
*/
@@ -620,6 +649,7 @@ abstract public function createDocuments(string $collection, array $documents):
620649
* Update Document
621650
*
622651
* @param string $collection
652+
* @param string $id
623653
* @param Document $document
624654
*
625655
* @return Document

src/Database/Adapter/MariaDB.php

Lines changed: 35 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -382,10 +382,9 @@ public function createAttribute(string $collection, string $id, string $type, in
382382
* @param int $size
383383
* @param bool $signed
384384
* @param bool $array
385-
* @param string $newKey
385+
* @param string|null $newKey
386386
* @return bool
387-
* @throws Exception
388-
* @throws PDOException
387+
* @throws DatabaseException
389388
*/
390389
public function updateAttribute(string $collection, string $id, string $type, int $size, bool $signed = true, bool $array = false, ?string $newKey = null): bool
391390
{
@@ -853,7 +852,7 @@ public function createDocument(string $collection, Document $document): Document
853852
$attributes['_permissions'] = \json_encode($document->getPermissions());
854853

855854
if ($this->sharedTables) {
856-
$attributes['_tenant'] = $this->tenant;
855+
$attributes['_tenant'] = $document->getTenant();
857856
}
858857

859858
$name = $this->filter($collection);
@@ -896,58 +895,46 @@ public function createDocument(string $collection, Document $document): Document
896895

897896
$attributeIndex = 0;
898897
foreach ($attributes as $value) {
899-
if (is_array($value)) {
900-
$value = json_encode($value);
898+
if (\is_array($value)) {
899+
$value = \json_encode($value);
901900
}
902901

903902
$bindKey = 'key_' . $attributeIndex;
904903
$attribute = $this->filter($attribute);
905-
$value = (is_bool($value)) ? (int)$value : $value;
904+
$value = (\is_bool($value)) ? (int)$value : $value;
906905
$stmt->bindValue(':' . $bindKey, $value, $this->getPDOType($value));
907906
$attributeIndex++;
908907
}
909908

910909
$permissions = [];
911910
foreach (Database::PERMISSIONS as $type) {
912911
foreach ($document->getPermissionsByType($type) as $permission) {
912+
$tenantBind = $this->sharedTables ? ", :_tenant" : '';
913913
$permission = \str_replace('"', '', $permission);
914-
$permission = "('{$type}', '{$permission}', '{$document->getId()}'";
915-
916-
if ($this->sharedTables) {
917-
$permission .= ", :_tenant)";
918-
} else {
919-
$permission .= ")";
920-
}
921-
914+
$permission = "('{$type}', '{$permission}', :_uid {$tenantBind})";
922915
$permissions[] = $permission;
923916
}
924917
}
925918

926919
if (!empty($permissions)) {
920+
$tenantColumn = $this->sharedTables ? ', _tenant' : '';
927921
$permissions = \implode(', ', $permissions);
928922

929923
$sqlPermissions = "
930-
INSERT INTO {$this->getSQLTable($name . '_perms')} (_type, _permission, _document
931-
";
932-
933-
if ($this->sharedTables) {
934-
$sqlPermissions .= ', _tenant)';
935-
} else {
936-
$sqlPermissions .= ")";
937-
}
924+
INSERT INTO {$this->getSQLTable($name . '_perms')} (_type, _permission, _document {$tenantColumn})
925+
VALUES {$permissions};
926+
";
938927

939-
$sqlPermissions .= " VALUES {$permissions}";
940-
$sqlPermissions = $this->trigger(Database::EVENT_PERMISSIONS_CREATE, $sqlPermissions);
941928
$stmtPermissions = $this->getPDO()->prepare($sqlPermissions);
942-
929+
$stmtPermissions->bindValue(':_uid', $document->getId());
943930
if ($this->sharedTables) {
944-
$stmtPermissions->bindValue(':_tenant', $this->tenant);
931+
$stmtPermissions->bindValue(':_tenant', $document->getTenant());
945932
}
946933
}
947934

948935
$stmt->execute();
949936

950-
$document['$internalId'] = $this->getDocument($collection, $document->getId(), [Query::select(['$internalId'])])->getInternalId();
937+
$document['$internalId'] = $this->pdo->lastInsertId();
951938

952939
if (empty($document['$internalId'])) {
953940
throw new DatabaseException('Error creating document empty "$internalId"');
@@ -1014,10 +1001,7 @@ public function createDocuments(string $collection, array $documents): array
10141001
$permissions = [];
10151002
$documentIds = [];
10161003

1017-
foreach ($documents as $document) {
1018-
/**
1019-
* @var Document $document
1020-
*/
1004+
foreach ($documents as $index => $document) {
10211005
$attributes = $document->getAttributes();
10221006
$attributes['_uid'] = $document->getId();
10231007
$attributes['_createdAt'] = $document->getCreatedAt();
@@ -1032,7 +1016,7 @@ public function createDocuments(string $collection, array $documents): array
10321016
}
10331017

10341018
if ($this->sharedTables) {
1035-
$attributes['_tenant'] = $this->tenant;
1019+
$attributes['_tenant'] = $document->getTenant();
10361020
}
10371021

10381022
$bindKeys = [];
@@ -1052,25 +1036,20 @@ public function createDocuments(string $collection, array $documents): array
10521036
$batchKeys[] = '(' . \implode(', ', $bindKeys) . ')';
10531037
foreach (Database::PERMISSIONS as $type) {
10541038
foreach ($document->getPermissionsByType($type) as $permission) {
1039+
$tenantBind = $this->sharedTables ? ", :_tenant_{$index}" : '';
10551040
$permission = \str_replace('"', '', $permission);
1056-
$permission = "('{$type}', '{$permission}', '{$document->getId()}'";
1057-
1058-
if ($this->sharedTables) {
1059-
$permission .= ", :_tenant)";
1060-
} else {
1061-
$permission .= ")";
1062-
}
1063-
1041+
$permission = "('{$type}', '{$permission}', :_uid_{$index} {$tenantBind})";
10641042
$permissions[] = $permission;
10651043
}
10661044
}
10671045
}
10681046

1069-
$stmt = $this->getPDO()->prepare(
1070-
"
1047+
$batchKeys = \implode(', ', $batchKeys);
1048+
1049+
$stmt = $this->getPDO()->prepare("
10711050
INSERT INTO {$this->getSQLTable($name)} {$columns}
1072-
VALUES " . \implode(', ', $batchKeys)
1073-
);
1051+
VALUES {$batchKeys}
1052+
");
10741053

10751054
foreach ($bindValues as $key => $value) {
10761055
$stmt->bindValue($key, $value, $this->getPDOType($value));
@@ -1079,22 +1058,21 @@ public function createDocuments(string $collection, array $documents): array
10791058
$stmt->execute();
10801059

10811060
if (!empty($permissions)) {
1061+
$tenantColumn = $this->sharedTables ? ', _tenant' : '';
1062+
$permissions = \implode(', ', $permissions);
1063+
10821064
$sqlPermissions = "
1083-
INSERT INTO {$this->getSQLTable($name . '_perms')} (_type, _permission, _document
1065+
INSERT INTO {$this->getSQLTable($name . '_perms')} (_type, _permission, _document {$tenantColumn})
1066+
VALUES {$permissions};
10841067
";
10851068

1086-
if ($this->sharedTables) {
1087-
$sqlPermissions .= ', _tenant)';
1088-
} else {
1089-
$sqlPermissions .= ")";
1090-
}
1091-
1092-
$sqlPermissions .= " VALUES " . \implode(', ', $permissions);
1093-
10941069
$stmtPermissions = $this->getPDO()->prepare($sqlPermissions);
10951070

1096-
if ($this->sharedTables) {
1097-
$stmtPermissions->bindValue(':_tenant', $this->tenant);
1071+
foreach ($documents as $index => $document) {
1072+
$stmtPermissions->bindValue(":_uid_{$index}", $document->getId());
1073+
if ($this->sharedTables) {
1074+
$stmtPermissions->bindValue(":_tenant_{$index}", $document->getTenant());
1075+
}
10981076
}
10991077

11001078
$stmtPermissions?->execute();
@@ -2228,7 +2206,7 @@ public function find(string $collection, array $queries = [], ?int $limit = 25,
22282206
unset($results[$index]['_id']);
22292207
}
22302208
if (\array_key_exists('_tenant', $document)) {
2231-
$results[$index]['$tenant'] = $document['_tenant'];
2209+
$document['$tenant'] = $document['_tenant'] === null ? null : (int)$document['_tenant'];
22322210
unset($results[$index]['_tenant']);
22332211
}
22342212
if (\array_key_exists('_createdAt', $document)) {

0 commit comments

Comments
 (0)