diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml new file mode 100644 index 00000000..a8874e4f --- /dev/null +++ b/.github/workflows/codeql-analysis.yml @@ -0,0 +1,20 @@ +name: "CodeQL" + +on: [ pull_request ] +jobs: + lint: + name: CodeQL + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 2 + + - run: git checkout HEAD^2 + + - name: Run CodeQL + run: | + docker run --rm -v $PWD:/app composer sh -c \ + "composer install --profile --ignore-platform-reqs && composer check" \ No newline at end of file diff --git a/composer.json b/composer.json index 128e5a84..a94a951e 100644 --- a/composer.json +++ b/composer.json @@ -19,7 +19,7 @@ "test": "./vendor/bin/phpunit", "lint": "./vendor/bin/pint --test", "format": "./vendor/bin/pint", - "check": "./vendor/bin/phpstan analyse --level=8 --memory-limit=2G src tests" + "check": "./vendor/bin/phpstan analyse --level 3 src tests --memory-limit 2G" }, "require": { "php": ">=8.1", diff --git a/composer.lock b/composer.lock index a2d6167e..999471ad 100644 --- a/composer.lock +++ b/composer.lock @@ -2641,16 +2641,16 @@ }, { "name": "myclabs/deep-copy", - "version": "1.12.1", + "version": "1.13.0", "source": { "type": "git", "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "123267b2c49fbf30d78a7b2d333f6be754b94845" + "reference": "024473a478be9df5fdaca2c793f2232fe788e414" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/123267b2c49fbf30d78a7b2d333f6be754b94845", - "reference": "123267b2c49fbf30d78a7b2d333f6be754b94845", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/024473a478be9df5fdaca2c793f2232fe788e414", + "reference": "024473a478be9df5fdaca2c793f2232fe788e414", "shasum": "" }, "require": { @@ -2689,7 +2689,7 @@ ], "support": { "issues": "https://github.com/myclabs/DeepCopy/issues", - "source": "https://github.com/myclabs/DeepCopy/tree/1.12.1" + "source": "https://github.com/myclabs/DeepCopy/tree/1.13.0" }, "funding": [ { @@ -2697,7 +2697,7 @@ "type": "tidelift" } ], - "time": "2024-11-08T17:47:46+00:00" + "time": "2025-02-12T12:17:51+00:00" }, { "name": "nikic/php-parser", @@ -4675,7 +4675,7 @@ ], "aliases": [], "minimum-stability": "stable", - "stability-flags": [], + "stability-flags": {}, "prefer-stable": false, "prefer-lowest": false, "platform": { diff --git a/src/Migration/Destinations/Appwrite.php b/src/Migration/Destinations/Appwrite.php index f0229c24..e1b9eac2 100644 --- a/src/Migration/Destinations/Appwrite.php +++ b/src/Migration/Destinations/Appwrite.php @@ -943,7 +943,7 @@ protected function createDocument(Document $resource, bool $isLast): bool continue; } - /** @var $attribute \Utopia\Database\Document */ + /** @var \Utopia\Database\Document $attribute */ $found = false; foreach ($collection->getAttribute('attributes', []) as $attribute) { if ($attribute->getAttribute('key') == $key) { diff --git a/src/Migration/Resource.php b/src/Migration/Resource.php index 5d043af3..c92de1ed 100644 --- a/src/Migration/Resource.php +++ b/src/Migration/Resource.php @@ -155,7 +155,7 @@ public function setMessage(string $message): self } /** - * @returns array + * @return array */ public function getPermissions(): array { diff --git a/src/Migration/Sources/Appwrite.php b/src/Migration/Sources/Appwrite.php index 0b2ca8dd..bd8f3f78 100644 --- a/src/Migration/Sources/Appwrite.php +++ b/src/Migration/Sources/Appwrite.php @@ -643,7 +643,7 @@ private function exportDocuments(int $batchSize): void $attributes = $this->cache->get(Attribute::getName()); foreach ($attributes as $attribute) { - /** @var Attribute|Relationship $attribute */ + /** @var Relationship $attribute */ if ( $attribute->getCollection()->getId() === $collection->getId() && $attribute->getType() === Attribute::TYPE_RELATIONSHIP && @@ -660,6 +660,7 @@ private function exportDocuments(int $batchSize): void $manyToMany[] = $attribute->getKey(); } } + /** @var Attribute|Relationship $attribute */ $queries[] = Query::select($selects); @@ -1132,7 +1133,7 @@ protected function exportGroupStorage(int $batchSize, array $resources): void try { if (in_array(Resource::TYPE_BUCKET, $resources)) { - $this->exportBuckets($batchSize, true); + $this->exportBuckets($batchSize); } } catch (\Throwable $e) { $this->addError( diff --git a/src/Migration/Sources/Firebase.php b/src/Migration/Sources/Firebase.php index 015ae73d..376b337b 100644 --- a/src/Migration/Sources/Firebase.php +++ b/src/Migration/Sources/Firebase.php @@ -115,6 +115,9 @@ protected function call(string $method, string $path = '', array $headers = [], return parent::call($method, $path, $headers, $params, $responseHeaders); } + /** + * @return array + */ public static function getSupportedResources(): array { return [ @@ -272,10 +275,11 @@ protected function exportGroupDatabases(int $batchSize, array $resources): void throw $e; } + $database = new Database('default', 'default'); + $database->setOriginalId('(default)'); + try { if (\in_array(Resource::TYPE_DATABASE, $resources)) { - $database = new Database('default', 'default'); - $database->setOriginalId('(default)'); $this->callback([$database]); } } catch (\Throwable $e) { @@ -368,7 +372,7 @@ private function exportDB(int $batchSize, bool $pushDocuments, Database $databas /** * @throws \Exception */ - private function convertAttribute(Collection $collection, string $key, array $field): Attribute + private function convertAttribute(Collection $collection, string $key, array $field, bool $array = false): Attribute { if (array_key_exists('booleanValue', $field)) { return new Boolean( @@ -376,7 +380,7 @@ private function convertAttribute(Collection $collection, string $key, array $fi $collection, required:false, default: null, - array: false, + array: $array, ); } elseif (array_key_exists('bytesValue', $field)) { return new Text( @@ -384,7 +388,7 @@ private function convertAttribute(Collection $collection, string $key, array $fi $collection, required: false, default: null, - array: false, + array: $array, size: 1000000, ); } elseif (array_key_exists('doubleValue', $field)) { @@ -393,7 +397,7 @@ private function convertAttribute(Collection $collection, string $key, array $fi $collection, required: false, default: null, - array: false, + array: $array, ); } elseif (array_key_exists('integerValue', $field)) { return new Integer( @@ -401,7 +405,7 @@ private function convertAttribute(Collection $collection, string $key, array $fi $collection, required: false, default: null, - array: false, + array: $array, ); } elseif (array_key_exists('mapValue', $field)) { return new Text( @@ -409,7 +413,7 @@ private function convertAttribute(Collection $collection, string $key, array $fi $collection, required: false, default: null, - array: false, + array: $array, size: 1000000, ); } elseif (array_key_exists('nullValue', $field)) { @@ -418,7 +422,7 @@ private function convertAttribute(Collection $collection, string $key, array $fi $collection, required: false, default: null, - array: false, + array: $array, size: 1000000, ); } elseif (array_key_exists('referenceValue', $field)) { @@ -427,7 +431,7 @@ private function convertAttribute(Collection $collection, string $key, array $fi $collection, required: false, default: null, - array: false, + array: $array, size: 1000000, ); //TODO: This should be a reference attribute } elseif (array_key_exists('stringValue', $field)) { @@ -436,7 +440,7 @@ private function convertAttribute(Collection $collection, string $key, array $fi $collection, required: false, default: null, - array: false, + array: $array, size: 1000000, ); } elseif (array_key_exists('timestampValue', $field)) { @@ -445,7 +449,7 @@ private function convertAttribute(Collection $collection, string $key, array $fi $collection, required: false, default: null, - array: false, + array: $array, ); } elseif (array_key_exists('geoPointValue', $field)) { return new Text( @@ -453,7 +457,7 @@ private function convertAttribute(Collection $collection, string $key, array $fi $collection, required: false, default: null, - array: false, + array: $array, size: 1000000, ); } elseif (array_key_exists('arrayValue', $field)) { @@ -470,7 +474,7 @@ private function calculateArrayType(Collection $collection, string $key, array $ foreach ($data['values'] as $field) { if (! $previousType) { - $previousType = $this->convertAttribute($collection, $key, $field); + $previousType = $this->convertAttribute($collection, $key, $field, true); } elseif ($previousType->getName() != ($this->convertAttribute($collection, $key, $field))->getName()) { $isSameType = false; break; @@ -478,11 +482,9 @@ private function calculateArrayType(Collection $collection, string $key, array $ } if ($isSameType) { - $previousType->setArray(true); - return $previousType; } else { - return new Text($key, $collection, false, true, null, 1000000); + return new Text($key, $collection, false, true, true, 1000000); } } @@ -521,7 +523,7 @@ private function exportCollection(Collection $collection, int $batchSize, bool $ } } - $documents[] = $this->convertDocument($collection, $document); + $documents[] = $this->convertDocument($collection, $document, $documentSchema); } // Transfer Documents @@ -557,13 +559,13 @@ private function exportCollection(Collection $collection, int $batchSize, bool $ private function calculateValue(array $field) { if (array_key_exists('booleanValue', $field)) { - return $field['booleanValue']; + return boolval($field['booleanValue']); } elseif (array_key_exists('bytesValue', $field)) { return $field['bytesValue']; } elseif (array_key_exists('doubleValue', $field)) { - return $field['doubleValue']; + return floatval($field['doubleValue']); } elseif (array_key_exists('integerValue', $field)) { - return $field['integerValue']; + return intval($field['integerValue']); } elseif (array_key_exists('mapValue', $field)) { return json_encode($field['mapValue']); } elseif (array_key_exists('nullValue', $field)) { @@ -575,9 +577,13 @@ private function calculateValue(array $field) } elseif (array_key_exists('timestampValue', $field)) { return $field['timestampValue']; } elseif (array_key_exists('geoPointValue', $field)) { - return [$field['geoPointValue']['latitude'], $field['geoPointValue']['longitude']]; + return json_encode($field['geoPointValue']); } elseif (array_key_exists('arrayValue', $field)) { - //TODO: + $values = []; + foreach ($field['arrayValue']['values'] as $value) { + $values[] = $this->calculateValue($value); + } + return array_values($values); } elseif (array_key_exists('referenceValue', $field)) { //TODO: } else { @@ -585,11 +591,19 @@ private function calculateValue(array $field) } } - private function convertDocument(Collection $collection, array $document): Document + private function convertDocument(Collection $collection, array $document, array $documentSchema): Document { $data = []; foreach ($document['fields'] as $key => $field) { - $data[$key] = $this->calculateValue($field); + $value = $this->calculateValue($field); + + if ($documentSchema[$key]->getType() === Attribute::TYPE_STRING && is_array($value)) { + $value = array_map(function ($item) { + return strval($item); + }, $value); + }; + + $data[$key] = $value; } $documentId = explode('/', $document['name']); diff --git a/src/Migration/Transfer.php b/src/Migration/Transfer.php index 733709de..a33aaad7 100644 --- a/src/Migration/Transfer.php +++ b/src/Migration/Transfer.php @@ -105,8 +105,6 @@ public function __construct(Source $source, Destination $destination) $this->source->registerCache($this->cache); $this->destination->registerCache($this->cache); $this->destination->setSource($source); - - return $this; } public function getStatusCounters(): array @@ -186,8 +184,8 @@ public function getStatusCounters(): array public function run( array $resources, callable $callback, - string $rootResourceId = null, - string $rootResourceType = null, + ?string $rootResourceId = null, + ?string $rootResourceType = null, ): void { // Allows you to push entire groups if you want. $computedResources = []; @@ -196,12 +194,14 @@ public function run( foreach ($resources as $resource) { if (is_array($resource)) { + /** @var array $resource */ $computedResources = array_merge($computedResources, $resource); } else { $computedResources[] = $resource; } } + /** @var array $computedResources */ $computedResources = array_map('strtolower', $computedResources); if ($rootResourceId !== '') {