Skip to content

Commit f5c1d2c

Browse files
authored
Merge pull request #119 from utopia-php/fix-array-export
Fix array export
2 parents b6985b2 + f45c403 commit f5c1d2c

File tree

3 files changed

+64
-33
lines changed

3 files changed

+64
-33
lines changed

composer.lock

Lines changed: 19 additions & 19 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Migration/Destinations/CSV.php

Lines changed: 39 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
use Utopia\Database\Exception\Conflict;
88
use Utopia\Database\Exception\Structure;
99
use Utopia\Migration\Destination;
10-
use Utopia\Migration\Resource;
10+
use Utopia\Migration\Resource as UtopiaResource;
1111
use Utopia\Migration\Resources\Database\Row;
1212
use Utopia\Migration\Transfer;
1313
use Utopia\Storage\Device;
@@ -37,7 +37,7 @@ public function __construct(
3737
array $allowedColumns = [],
3838
private readonly string $delimiter = ',',
3939
private readonly string $enclosure = '"',
40-
private readonly string $escape = '\\',
40+
private readonly string $escape = '"',
4141
private readonly bool $includeHeaders = true,
4242
) {
4343
$this->deviceForFiles = $deviceForFiles;
@@ -61,7 +61,7 @@ public static function getName(): string
6161
public static function getSupportedResources(): array
6262
{
6363
return [
64-
Resource::TYPE_ROW,
64+
UtopiaResource::TYPE_ROW,
6565
];
6666
}
6767

@@ -95,7 +95,7 @@ protected function import(array $resources, callable $callback): void
9595
}
9696

9797
foreach ($buffer['lines'] as $line) {
98-
if (\fputcsv($handle, $line, $this->delimiter, $this->enclosure, $this->escape) === false) {
98+
if (!$this->writeCSVLine($handle, $line)) {
9999
throw new \Exception("Failed to write CSV line to file: $log");
100100
}
101101
}
@@ -138,7 +138,7 @@ protected function import(array $resources, callable $callback): void
138138
$flushBuffer();
139139
}
140140

141-
$resource->setStatus(Resource::STATUS_SUCCESS);
141+
$resource->setStatus(UtopiaResource::STATUS_SUCCESS);
142142
if (isset($this->cache)) {
143143
$this->cache->update($resource);
144144
}
@@ -166,13 +166,11 @@ public function shutdown(): void
166166
$sourcePath = $this->local->getPath($filename);
167167
$destPath = $this->deviceForFiles->getPath($this->directory . '/' . $filename);
168168

169-
// Check if the CSV file was actually created
170169
if (!$this->local->exists($sourcePath)) {
171170
throw new \Exception("No data to export for resource: $this->resourceId");
172171
}
173172

174173
try {
175-
// Transfer expects absolute paths within each device
176174
$result = $this->local->transfer(
177175
$sourcePath,
178176
$destPath,
@@ -192,6 +190,29 @@ public function shutdown(): void
192190
}
193191
}
194192

193+
/**
194+
* Write a CSV line with RFC 4180 compliant escaping (double-quote method)
195+
*
196+
* @param resource $handle
197+
* @param array $fields
198+
* @return bool
199+
*/
200+
protected function writeCSVLine($handle, array $fields): bool
201+
{
202+
$parts = [];
203+
204+
foreach ($fields as $field) {
205+
$field = (string)$field;
206+
if (\strpbrk($field, $this->delimiter . "\n\r" . $this->enclosure) !== false) {
207+
$parts[] = $this->enclosure . \str_replace($this->enclosure, $this->enclosure . $this->enclosure, $field) . $this->enclosure;
208+
} else {
209+
$parts[] = $field;
210+
}
211+
}
212+
213+
return \fwrite($handle, \implode($this->delimiter, $parts) . "\n") !== false;
214+
}
215+
195216
/**
196217
* Helper to ensure a directory exists.
197218
* @throws \Exception
@@ -222,18 +243,25 @@ protected function sanitizeFilename(string $filename): string
222243
*/
223244
protected function resourceToCSVData(Row $resource): array
224245
{
246+
$rowData = $resource->getData();
247+
225248
$data = [
226249
'$id' => $resource->getId(),
227250
'$permissions' => $resource->getPermissions(),
228-
'$createdAt' => $resource->getCreatedAt(),
229-
'$updatedAt' => $resource->getUpdatedAt(),
251+
'$createdAt' => $rowData['$createdAt'] ?? '',
252+
'$updatedAt' => $rowData['$updatedAt'] ?? '',
230253
];
231254

255+
unset(
256+
$rowData['$createdAt'],
257+
$rowData['$updatedAt'],
258+
);
259+
232260
// Add all attributes if no filter specified, otherwise only allowed ones
233261
if (empty($this->allowedColumns)) {
234-
$data = \array_merge($data, $resource->getData());
262+
$data = \array_merge($data, $rowData);
235263
} else {
236-
foreach ($resource->getData() as $key => $value) {
264+
foreach ($rowData as $key => $value) {
237265
if (isset($this->allowedColumns[$key])) {
238266
$data[$key] = $value;
239267
}
@@ -291,5 +319,4 @@ protected function convertObjectToCSV($value): string
291319
}
292320
return \json_encode($value);
293321
}
294-
295322
}

src/Migration/Sources/Appwrite.php

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,8 @@ public function __construct(
7272
protected string $endpoint,
7373
protected string $key,
7474
protected string $source = self::SOURCE_API,
75-
protected ?UtopiaDatabase $dbForProject = null
75+
protected ?UtopiaDatabase $dbForProject = null,
76+
protected array $queries = [],
7677
) {
7778
$this->client = (new Client())
7879
->setEndpoint($endpoint)
@@ -1100,7 +1101,10 @@ private function exportRows(int $batchSize): void
11001101
$lastRow = null;
11011102

11021103
while (true) {
1103-
$queries = [$this->database->queryLimit($batchSize)];
1104+
$queries = [
1105+
$this->database->queryLimit($batchSize),
1106+
...$this->queries,
1107+
];
11041108

11051109
$rows = [];
11061110

0 commit comments

Comments
 (0)