migrations icon indicating copy to clipboard operation
migrations copied to clipboard

Custom doctrine types keep getting their definition generated in migrations

Open geoffroyp opened this issue 1 year ago • 2 comments

Q A
ORM 3.2.0
DBAL 4.0.3

Support Question

I have recently upgrade doctrine to DBAL 4 / ORM 3, and when I run make:migration, then run doctrine:migration:migration, then run make:migration again, the exact same file is generated, with the same changes.... From what I see, the big majority of those changes are related to custom doctrine type, and I believe it is related to the fact that "Type::requiresSQLCommentHint()" has been removed from doctrine

My problem seems very similar to https://github.com/doctrine/migrations/issues/1434 that you closed, except that in my case, I'm using MySQL and I removed all comments related to DC2Type. But still, make:migration keeps generating those changes, over and over again.

Any way to fix this?

geoffroyp avatar Jun 18 '24 15:06 geoffroyp

Please share a reproducer for the issue.

Also, which version of doctrine/migrations are you using ?

stof avatar Jun 19 '24 16:06 stof

I am using doctrine/doctrine-migrations-bundle v3.3.1, which itself uses doctrine/migrations v3.7.4

Here's an example of custom type that keeps getting generated, but used to work perfectly before, with DC2Type comments:

<?php

namespace App\Doctrine\Types;

use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Types\Type;
use Override;

class AmountType extends Type
{
	public const AMOUNT = 'amount';

	/**
	 * {@inheritDoc}
	 */
	#[Override]
	public function convertToPHPValue($value, AbstractPlatform $platform): ?float
	{
		return null !== $value ? (float) $value : null;
	}

	/**
	 * {@inheritDoc}
	 */
	#[Override]
	public function getSQLDeclaration(array $column, AbstractPlatform $platform): string
	{
		$column['precision'] = max($column['precision'], 16);
		$column['scale'] = max($column['scale'], 2);

		$declaration = 'DECIMAL(' . $column['precision'] . ', ' . $column['scale'] . ')';
		$declaration .= $column['unsigned'] ? ' UNSIGNED' : '';

		return $declaration;
	}
}

and another example:

<?php

namespace App\Doctrine\Types;

use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Types\IntegerType;
use Override;

class TinyInt extends IntegerType
{
	public const string TINYINT = 'tinyint';

	/**
	 * @param array $column
	 * @param AbstractPlatform $platform
	 *
	 * @return string
	 */
	#[Override]
	public function getSQLDeclaration(array $column, AbstractPlatform $platform): string
	{
		$autoinc = '';
		if (!empty($column['autoincrement'])) {
			$autoinc = ' AUTO_INCREMENT';
		}

		return 'TINYINT' . (!empty($column['unsigned']) ? ' UNSIGNED' : '') . $autoinc;
	}
	
	public function requiresSQLCommentHint(AbstractPlatform $platform): bool
	{
		return true;
	}
	
	public function getName(): string
	{
		return self::TINYINT;
	}
}

so, when I run make:migration, then run doctrine:migration:migrate, then run make:migration again, every column using one of these customTypes are getting their definition generated every time

Let me know if I shall add more details / code.

geoffroyp avatar Jun 21 '24 08:06 geoffroyp

Hello @geoffroyp ,

Have you found a solution? I have exactly the same problem. Thanks :)

GaylordP avatar Apr 13 '25 14:04 GaylordP

Nope, I have downgraded my doctrine so far, waiting for a fix about it.

Judging by your message, I believe it's still not fixed... :(

geoffroyp avatar Apr 18 '25 13:04 geoffroyp

May be also related to https://github.com/doctrine/dbal/issues/6743, I have working TinyInt with some workaround in that issue, this can be solved just by removing (1) part from mysql boolean definition TINYINT(1), there was also PR https://github.com/doctrine/dbal/pull/6569 but it was closed due to inactivity.

rixafy avatar Jun 05 '25 16:06 rixafy

Hi,

I recently decided to spend some time digging into this issue again. It seems a few of us still encounter the migration diff problem with tinyint on MySQL when using Doctrine.

I finally found a solution that works for my case. It’s the best way but it stops the endless diffs in migrations.

What I did:

Custom type : Tinyint

use Doctrine\DBAL\Types\IntegerType;
use Doctrine\DBAL\Platforms\AbstractPlatform;

class TinyintType extends IntegerType
{
    public const TINYINT = 'tinyint';

    public function getName(): string
    {
        return self::TINYINT;
    }

    public function getSQLDeclaration(array $column, AbstractPlatform $platform): string
    {
        $declaration = 'TINYINT' . (!empty($column['unsigned']) ? ' UNSIGNED' : '');

        return !empty($column['autoincrement']) ? $declaration . ' AUTO_INCREMENT' : $declaration;
    }
}

Custom type : Boolean This one only overrides the getSQLDeclaration() for boolean, but I still use Types::BOOLEAN in my entity code. Without this override, I consistently saw migrations trying to re-apply TINYINT(1) for boolean columns.

use Doctrine\DBAL\Types\BooleanType;
use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Types\Types;

class GABooleanType extends BooleanType
{
    public function getName(): string
    {
        return Types::BOOLEAN;
    }

    public function getSQLDeclaration(array $column, AbstractPlatform $platform): string
    {
        return 'TINYINT';
    }
}

Doctrine config Note the importance of the mapping_types section.

doctrine:
  dbal:
    default_connection: default
    connections:
      default:
        driver: 'pdo_mysql'
        server_version: '8.0.41'
        charset: utf8mb4
        default_table_options:
          charset: utf8mb4
          collation: utf8mb4_unicode_ci
        url: '%doctrine-url%'
        mapping_types:
          tinyint: tinyint
          boolean: boolean
      profiling_collect_backtrace: '%kernel.debug%'
      use_savepoints: true
    types:
      tinyint: App\Doctrine\DBAL\Types\TinyintType
      boolean: App\Doctrine\DBAL\Types\GABooleanType
[...]

In my case, the project is still in development, so I was able to reset the migrations folder (delete all files and generate a fresh migration). The goal was to start from a clean schema, removing all leftover COMMENT from previous Doctrine versions for custom types.

Obviously, in a production you can't just reset the DB schema this way. You’d need a different process.

Hope this helps others facing the same issue.

kruggs avatar Jul 23 '25 14:07 kruggs