diff --git a/.github/workflows/test-components.yml b/.github/workflows/test-components.yml new file mode 100644 index 000000000..a67b0764f --- /dev/null +++ b/.github/workflows/test-components.yml @@ -0,0 +1,108 @@ +name: Test for Components + +on: + push: + paths: + - "**" + - "!docs/**" + - "!**.md" + pull_request: + paths: + - "**" + - "!docs/**" + - "!**.md" + schedule: + - cron: '0 2 * * *' +env: + SW_VERSION: 'v6.1.0' +jobs: + php-mysql-replication: + name: Test for PHP MySQL Replication + runs-on: 'ubuntu-latest' + env: + PHP_VERSION: ${{ matrix.php-version }} + strategy: + matrix: + php-version: [ '8.4', '8.3', '8.2' ] + mysql-replication: [ '9.0', '8.0' ] + max-parallel: 2 + fail-fast: false + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php-version }} + tools: phpize + extensions: redis, pdo, pdo_mysql, bcmath, swoole + ini-values: opcache.enable_cli=1 + coverage: none + - name: Setup Packages + run: | + composer require krowinski/php-mysql-replication:^${{ matrix.mysql-replication }} --no-update + composer update -o + - name: Run Test Cases + run: | + composer analyse src + composer analyse:types + serializable-closure: + name: Test for Laravel Serializable Closure + runs-on: 'ubuntu-latest' + env: + PHP_VERSION: ${{ matrix.php-version }} + strategy: + matrix: + php-version: [ '8.4', '8.3', '8.2' ] + serializable-closure: [ '2.0', '1.0' ] + max-parallel: 20 + fail-fast: false + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php-version }} + tools: phpize + extensions: redis, pdo, pdo_mysql, bcmath, swoole + ini-values: opcache.enable_cli=1 + coverage: none + - name: Setup Packages + run: | + composer require laravel/serializable-closure:^${{ matrix.serializable-closure }} --no-update + composer update -o + - name: Run Test Cases + run: | + composer analyse src + composer analyse:types + carbon: + name: Test for Carbon + runs-on: 'ubuntu-latest' + env: + PHP_VERSION: ${{ matrix.php-version }} + strategy: + matrix: + php-version: [ '8.4', '8.3', '8.2' ] + carbon: [ '3.0', '2.0' ] + max-parallel: 20 + fail-fast: false + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php-version }} + tools: phpize + extensions: redis, pdo, pdo_mysql, bcmath, swoole + ini-values: opcache.enable_cli=1 + coverage: none + - name: Setup Packages + run: | + composer require nesbot/carbon:^${{ matrix.carbon }} --no-update + composer update -o + - name: Run Test Cases + run: | + composer analyse src + composer analyse:types diff --git a/composer.json b/composer.json index d9aca89b8..f288abfc4 100644 --- a/composer.json +++ b/composer.json @@ -23,7 +23,7 @@ "google/recaptcha": "^1.2", "guzzlehttp/uri-template": "^1.0", "hyperf/elasticsearch": "~3.2.0", - "krowinski/php-mysql-replication": "^8.0", + "krowinski/php-mysql-replication": "^8.0 || ^9.0", "laravel/serializable-closure": "^1.0 || ^2.0", "league/commonmark": "^1.3 || ^2.0.2", "nesbot/carbon": "^2.0 || ^3.0", diff --git a/src/ide-helper/src/Command/ModelCommand.php b/src/ide-helper/src/Command/ModelCommand.php index 286778105..077335336 100644 --- a/src/ide-helper/src/Command/ModelCommand.php +++ b/src/ide-helper/src/Command/ModelCommand.php @@ -274,6 +274,38 @@ protected function getTypeOverride(string $type): string return $typeOverrides[$type] ?? $type; } + /** + * Get the type name from a Doctrine Type instance. + * Doctrine DBAL v4 compatibility: getName() was removed from Type. + */ + protected function getDoctrineTypeName(\Doctrine\DBAL\Types\Type $type): string + { + // For DBAL v3 and earlier + if (method_exists($type, 'getName')) { + return $type->getName(); + } + + // For DBAL v4, map type instances to their string names + $typeClass = get_class($type); + $typeMap = [ + \Doctrine\DBAL\Types\StringType::class => 'string', + \Doctrine\DBAL\Types\TextType::class => 'text', + \Doctrine\DBAL\Types\IntegerType::class => 'integer', + \Doctrine\DBAL\Types\BigIntType::class => 'bigint', + \Doctrine\DBAL\Types\SmallIntType::class => 'smallint', + \Doctrine\DBAL\Types\FloatType::class => 'float', + \Doctrine\DBAL\Types\DecimalType::class => 'decimal', + \Doctrine\DBAL\Types\BooleanType::class => 'boolean', + \Doctrine\DBAL\Types\DateType::class => 'date', + \Doctrine\DBAL\Types\DateTimeType::class => 'datetime', + \Doctrine\DBAL\Types\DateTimeTzType::class => 'datetimetz', + \Doctrine\DBAL\Types\TimeType::class => 'time', + \Doctrine\DBAL\Types\GuidType::class => 'guid', + ]; + + return $typeMap[$typeClass] ?? 'mixed'; + } + /** * Load the properties from the database table. * @@ -285,23 +317,24 @@ protected function getPropertiesFromTable($model) $connection = $model->getConnection(); $table = $connection->getTablePrefix() . $model->getTable(); $schema = $connection->getDoctrineSchemaManager($table); - $databasePlatform = $schema->getDatabasePlatform(); + $databasePlatform = $connection->getDoctrineConnection()->getDatabasePlatform(); $databasePlatform->registerDoctrineTypeMapping('enum', 'string'); - $platformName = $databasePlatform->getName(); + // Doctrine DBAL v4 compatibility: getName() was removed from AbstractPlatform + $platformName = method_exists($databasePlatform, 'getName') + ? $databasePlatform->getName() + : strtolower((new ReflectionClass($databasePlatform))->getShortName()); $customTypes = $this->config->get("ide-helper.model.custom_db_types.{$platformName}", []); foreach ($customTypes as $yourTypeName => $doctrineTypeName) { $databasePlatform->registerDoctrineTypeMapping($yourTypeName, $doctrineTypeName); } - $database = null; - if (strpos($table, '.')) { - [$database, $table] = explode('.', $table); + [, $table] = explode('.', $table); } - $columns = $schema->listTableColumns($table, $database); + $columns = $schema->listTableColumns($table); if ($columns) { foreach ($columns as $column) { @@ -309,7 +342,9 @@ protected function getPropertiesFromTable($model) if (in_array($name, $model->getDates())) { $type = $this->dateClass; } else { - $type = $column->getType()->getName(); + $columnType = $column->getType(); + // Doctrine DBAL v4 compatibility: getName() was removed, and Type cannot be cast to string + $type = $this->getDoctrineTypeName($columnType); switch ($type) { case 'string': case 'text': diff --git a/src/trigger/composer.json b/src/trigger/composer.json index c07786297..1be0262c0 100644 --- a/src/trigger/composer.json +++ b/src/trigger/composer.json @@ -35,7 +35,7 @@ "hyperf/stringable": "~3.2.0", "hyperf/support": "~3.2.0", "hyperf/tappable": "~3.2.0", - "krowinski/php-mysql-replication": "^8.0", + "krowinski/php-mysql-replication": "^8.0 || ^9.0", "ramsey/uuid": "^4.7" }, "suggest": {