From 1c8a53f4257c56e63749bf55042790c29d221cc1 Mon Sep 17 00:00:00 2001 From: Adam Dyson Date: Thu, 10 Jul 2025 11:36:47 +1000 Subject: [PATCH 1/9] Update composer psalm version to support PHP 8.4 --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 85e415c..73a0725 100644 --- a/composer.json +++ b/composer.json @@ -38,7 +38,7 @@ "require-dev": { "phpunit/phpunit": "^9.5", "spiral/tokenizer": "^2.8", - "vimeo/psalm": "^5.12", + "vimeo/psalm": "^5.12 || ^6.12", "symfony/console": "^6.0 || ^7.0", "spiral/code-style": "^2.2" }, From 136641b56733d87d54bd9a23ab56cb174977f01c Mon Sep 17 00:00:00 2001 From: Adam Dyson Date: Thu, 10 Jul 2025 11:37:29 +1000 Subject: [PATCH 2/9] Update contributing instructions for running docker compose --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d1d132e..9d9912c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -14,7 +14,7 @@ To test Cycle ORM Schema Builder locally, download the `cycle/schema-builder` re ```bash $ cd tests/ -$ docker-composer up +$ docker compose up ``` To run full test suite: From ada4ce01b2bbeeb42059ed3c036bad526b5b0c82 Mon Sep 17 00:00:00 2001 From: Adam Dyson Date: Thu, 10 Jul 2025 11:38:19 +1000 Subject: [PATCH 3/9] Added further unit tests proving an issue with merging attributes when a default value is defined --- tests/Schema/Driver/MySQL/ColumnTest.php | 56 ++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/tests/Schema/Driver/MySQL/ColumnTest.php b/tests/Schema/Driver/MySQL/ColumnTest.php index 6fe1f2a..d487431 100644 --- a/tests/Schema/Driver/MySQL/ColumnTest.php +++ b/tests/Schema/Driver/MySQL/ColumnTest.php @@ -36,4 +36,60 @@ public function testAttributesUnsigned(): void $this->assertTrue($table->column('name')->getAttributes()['unsigned']); $this->assertTrue($table->column('name')->isUnsigned()); } + + public function testUnsignedColumnWithAdditionalAttributes(): void + { + $comment = 'Foo Bar Baz'; + + $field = new Field(); + $field->setType('boolean'); + $field->setColumn('foo'); + $field->getAttributes()->set('comment', $comment); + $field->getAttributes()->set('unsigned', true); + + $table = $this->getStub(); + $column = Column::parse($field); + + $column->render($table->column('foo')); + + $table->save(); + + $table = $this->getStub(); + $this->assertTrue($table->hasColumn('foo')); + $this->assertArrayHasKey('comment', $table->column('foo')->getAttributes()); + $this->assertArrayHasKey('unsigned', $table->column('foo')->getAttributes()); + $this->assertSame($comment, $table->column('foo')->getAttributes()['comment']); + $this->assertSame($comment, $table->column('foo')->getComment()); + $this->assertTrue($table->column('foo')->getAttributes()['unsigned']); + $this->assertTrue($table->column('foo')->isUnsigned()); + } + + public function testUnsignedColumnWithAdditionalAttributesAndDefault(): void + { + $comment = 'Foo Bar Baz'; + + $field = new Field(); + $field->setType('boolean'); + $field->setColumn('foo'); + $field->getAttributes()->set('comment', $comment); + $field->getAttributes()->set('unsigned', true); + $field->getOptions()->set('default', false); + + $table = $this->getStub(); + $column = Column::parse($field); + + $column->render($table->column('foo')); + + $table->save(); + + $table = $this->getStub(); + $this->assertTrue($table->hasColumn('foo')); + $this->assertArrayHasKey('comment', $table->column('foo')->getAttributes()); + $this->assertArrayHasKey('unsigned', $table->column('foo')->getAttributes()); + $this->assertFalse($table->column('foo')->getDefaultValue()); + $this->assertSame($comment, $table->column('foo')->getAttributes()['comment']); + $this->assertSame($comment, $table->column('foo')->getComment()); + $this->assertTrue($table->column('foo')->getAttributes()['unsigned']); + $this->assertTrue($table->column('foo')->isUnsigned()); + } } From 510aef1a1d11ab7d998d8fba65d47c414ae0e400 Mon Sep 17 00:00:00 2001 From: Adam Dyson Date: Thu, 10 Jul 2025 11:48:06 +1000 Subject: [PATCH 4/9] Added a fix ensuring attributes are merged correctly --- src/Table/Column.php | 6 +----- tests/Schema/Driver/MySQL/ColumnTest.php | 2 +- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/Table/Column.php b/src/Table/Column.php index 65bd383..08ac4b4 100644 --- a/src/Table/Column.php +++ b/src/Table/Column.php @@ -140,11 +140,7 @@ public function render(AbstractColumn $column): void if ($this->hasDefault() && $this->getDefault() !== null) { $column->defaultValue($this->getDefault()); - return; - } - - if ($this->hasOption(self::OPT_CAST_DEFAULT)) { - // cast default value + } elseif ($this->hasOption(self::OPT_CAST_DEFAULT)) { $column->defaultValue($this->castDefault($column)); } diff --git a/tests/Schema/Driver/MySQL/ColumnTest.php b/tests/Schema/Driver/MySQL/ColumnTest.php index d487431..5fa9291 100644 --- a/tests/Schema/Driver/MySQL/ColumnTest.php +++ b/tests/Schema/Driver/MySQL/ColumnTest.php @@ -86,7 +86,7 @@ public function testUnsignedColumnWithAdditionalAttributesAndDefault(): void $this->assertTrue($table->hasColumn('foo')); $this->assertArrayHasKey('comment', $table->column('foo')->getAttributes()); $this->assertArrayHasKey('unsigned', $table->column('foo')->getAttributes()); - $this->assertFalse($table->column('foo')->getDefaultValue()); + $this->assertSame(0, $table->column('foo')->getDefaultValue()); $this->assertSame($comment, $table->column('foo')->getAttributes()['comment']); $this->assertSame($comment, $table->column('foo')->getComment()); $this->assertTrue($table->column('foo')->getAttributes()['unsigned']); From 0ef8c4855652be0f7bfb583b8e8b4d1d83db7bfa Mon Sep 17 00:00:00 2001 From: Adam Dyson Date: Thu, 10 Jul 2025 12:07:47 +1000 Subject: [PATCH 5/9] Bump actions/cache version to stop pipeline winging about deprecations --- .github/workflows/main.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 20f3af2..f606dc5 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -34,7 +34,7 @@ jobs: id: composer-cache run: echo "::set-output name=dir::$(composer config cache-files-dir)" - name: Restore Composer Cache - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: ${{ steps.composer-cache.outputs.dir }} key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} @@ -81,7 +81,7 @@ jobs: id: composer-cache run: echo "::set-output name=dir::$(composer config cache-files-dir)" - name: Restore Composer Cache - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: ${{ steps.composer-cache.outputs.dir }} key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} From 7bb868b96ee8388980e810f7c224305a5a866ab9 Mon Sep 17 00:00:00 2001 From: Adam Dyson Date: Thu, 10 Jul 2025 12:24:46 +1000 Subject: [PATCH 6/9] Updated main workflow, copied verbatim from cycle/database --- .github/workflows/main.yml | 82 +++++++++++++++++++------------------- 1 file changed, 42 insertions(+), 40 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index f606dc5..21429e7 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -1,4 +1,8 @@ -on: +--- + +name: build + +on: # yamllint disable-line rule:truthy push: branches: - master @@ -6,55 +10,54 @@ on: - '*.*.*' pull_request: null -name: build - jobs: test: name: Test PHP ${{ matrix.php-versions }} with Code Coverage runs-on: ubuntu-latest strategy: matrix: - php-versions: ['8.0', '8.1', '8.2', '8.3'] + php-versions: ['8.0', '8.1', '8.2', '8.3', '8.4'] steps: - - name: Checkout + - name: Install ODBC driver. + run: | + sudo curl https://packages.microsoft.com/config/ubuntu/$(lsb_release -rs)/prod.list | sudo tee /etc/apt/sources.list.d/mssql-release.list + sudo ACCEPT_EULA=Y apt-get install -y msodbcsql18 + + - name: 📦 Checkout uses: actions/checkout@v2 - - name: Setup DB services + - name: 🛠️ Setup DB services run: | cd tests docker compose up -d cd .. - - name: Setup PHP ${{ matrix.php-versions }} + - name: 🛠️ Setup PHP ${{ matrix.php-versions }} uses: shivammathur/setup-php@v2 with: php-version: ${{ matrix.php-versions }} coverage: pcov tools: pecl extensions: mbstring, pdo, pdo_sqlite, pdo_pgsql, pdo_sqlsrv, pdo_mysql - - name: Get Composer Cache Directory - id: composer-cache - run: echo "::set-output name=dir::$(composer config cache-files-dir)" - - name: Restore Composer Cache - uses: actions/cache@v4 + + - name: Validate composer.json and composer.lock + run: composer validate --ansi --strict + + - name: 📥 Install dependencies with composer + uses: ramsey/composer-install@v3 with: - path: ${{ steps.composer-cache.outputs.dir }} - key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} - restore-keys: ${{ runner.os }}-composer- - - name: Install dependencies with composer - if: matrix.php-versions != '8.3' - run: composer update --prefer-dist --no-interaction --no-progress --optimize-autoloader --ansi - - name: Install dependencies with composer php 8.3 - if: matrix.php-versions == '8.3' - run: composer update --ignore-platform-reqs --prefer-dist --no-interaction --no-progress --optimize-autoloader --ansi - - name: Execute Tests + dependency-versions: "highest" + + - name: 🚀 Execute Tests run: | vendor/bin/phpunit --coverage-clover=coverage.clover - - name: Upload coverage to Codecov + + - name: 🦆 Upload coverage to Codecov continue-on-error: true # if is fork uses: codecov/codecov-action@v1 with: token: ${{ secrets.CODECOV_TOKEN }} file: ./coverage.clover - - name: Upload coverage to Scrutinizer + + - name: 🦆 Upload coverage to Scrutinizer continue-on-error: true # if is fork uses: sudo-bot/action-scrutinizer@latest with: @@ -64,32 +67,31 @@ jobs: name: SQLite PHP ${{ matrix.php-versions }} runs-on: ubuntu-latest strategy: - fail-fast: false matrix: - php-versions: ['8.0', '8.1'] + php-versions: ['8.0', '8.1', '8.2', '8.3', '8.4'] steps: - - name: Checkout + - name: 📦 Checkout uses: actions/checkout@v2 - - name: Setup PHP ${{ matrix.php-versions }} + - name: 🛠️ Setup PHP ${{ matrix.php-versions }} uses: shivammathur/setup-php@v2 with: php-version: ${{ matrix.php-versions }} coverage: pcov tools: pecl extensions: mbstring, pdo, pdo_sqlite - - name: Get Composer Cache Directory - id: composer-cache - run: echo "::set-output name=dir::$(composer config cache-files-dir)" - - name: Restore Composer Cache - uses: actions/cache@v4 + + - name: 🤖 Validate composer.json and composer.lock + run: composer validate --ansi --strict + + - name: 📥 Install dependencies with composer + uses: ramsey/composer-install@v3 with: - path: ${{ steps.composer-cache.outputs.dir }} - key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} - restore-keys: ${{ runner.os }}-composer- - - name: Install Dependencies - run: composer install --no-interaction --prefer-dist - - name: Execute Tests + dependency-versions: "highest" + + - name: 🚀 Execute Tests env: DB: sqlite run: | - vendor/bin/phpunit tests/Schema/Driver/SQLite --colors=always + vendor/bin/phpunit --group driver-sqlite --colors=always + +... From d0d4f3c7c1b69b5c9496cc523ee208a16f8b02b6 Mon Sep 17 00:00:00 2001 From: Adam Dyson Date: Thu, 10 Jul 2025 12:32:28 +1000 Subject: [PATCH 7/9] Added trustServerCertificate to sqlserver connection --- tests/bootstrap.php | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/bootstrap.php b/tests/bootstrap.php index b23e6b9..22af149 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -47,6 +47,7 @@ database: 'tempdb', host: '127.0.0.1', port: 11433, + trustServerCertificate: true, user: 'SA', password: 'YourStrong!Passw0rd', ), From 8a1662a31bff18aec7bd28f87e29660a647cc98e Mon Sep 17 00:00:00 2001 From: Adam Dyson Date: Thu, 10 Jul 2025 12:50:18 +1000 Subject: [PATCH 8/9] Updated psalm baseline --- psalm-baseline.xml | 332 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 320 insertions(+), 12 deletions(-) diff --git a/psalm-baseline.xml b/psalm-baseline.xml index 6804979..aeb576b 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -1,5 +1,5 @@ - + @@ -17,6 +17,17 @@ getOuterKey()]]> + + + + + + + + + + + @@ -25,13 +36,40 @@ + + + + ]]> + + + + + + + + + + + + + + + + + + + + + + + column)]]> type)]]> @@ -45,12 +83,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -58,33 +145,128 @@ target === null]]> type === null]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + entity->getFields()->getNames()]]> + + + + + + + entity->getFields()->getNames()]]> + + + + + + + entity->getFields()->getNames()]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + getColumns()]]> getColumns()]]> @@ -113,24 +295,80 @@ + + + + + + + + + + + + + + + + + + + + + + reflector->sortedTables()]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -151,14 +389,6 @@ - - - - - - - - children[$entity]]]> relations[$entity]]]> @@ -167,28 +397,61 @@ tables[$entity]['schema']]]> tables[$entity]['table']]]> + + + + + + + + + + + options->get(self::INDEX_CREATE)]]> + + + + + + + + + + options->get(self::INDEX_CREATE)]]> + + + + + + options->get(self::INDEX_CREATE)]]> + + + + + + options->get(Relation::THROUGH_ENTITY)]]> options->get(self::INDEX_CREATE)]]> @@ -204,6 +467,12 @@ + + + + + + @@ -223,6 +492,10 @@ + + + + options->get(Relation::MORPH_KEY)]]> options->get(Relation::NULLABLE)]]> @@ -230,6 +503,10 @@ + + + + options->get(Relation::MORPH_KEY)]]> options->get(Relation::NULLABLE)]]> @@ -270,6 +547,10 @@ + + + + options->get(self::INDEX_CREATE)]]> @@ -313,6 +594,12 @@ + + + + + + @@ -326,6 +613,9 @@ + + + @@ -375,6 +665,16 @@ + + + + + + + + + + @@ -384,12 +684,23 @@ + + + + + + + + + + + @@ -399,9 +710,6 @@ field->getAttributes())]]> - - - getEnumValues()[0]]]> From 47e3c88f6717627d1f4d92998520a74eaf74fb0c Mon Sep 17 00:00:00 2001 From: Adam Dyson Date: Thu, 10 Jul 2025 12:59:03 +1000 Subject: [PATCH 9/9] Suppress some UnusedMethod for psalm --- src/Table/Column.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Table/Column.php b/src/Table/Column.php index 08ac4b4..3e1d86e 100644 --- a/src/Table/Column.php +++ b/src/Table/Column.php @@ -59,6 +59,11 @@ public static function parse(Field $field): self return $column; } + /** + * Get column name. + * + * @psalm-suppress UnusedMethod + */ public function getName(): string { return $this->field->getColumn(); @@ -67,6 +72,7 @@ public function getName(): string /** * Get column type. * + * @psalm-suppress UnusedMethod */ public function getType(): string {