0

Following Symfony doc, I tried to add TINYINT as entity column type.

So far it works well, but two problem remain...

  1. Each time I want to perform a migration, Doctrine can't reconize TINYINT for the associated columns, and perform the migration queries again.

  2. In form builders, by default TINYINT is reconized as TextType and not NumberType

Do you know what I'm missing to fix those two issues?

TinyintType.php

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

class TinyintType extends Type {
    const TINYINT='tinyint';

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

    /**
     * @param array $fieldDeclaration
     * @param AbstractPlatform $platform
     * @return string
     */
    public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform) {
        return $fieldDeclaration['unsigned'] === true ? 'TINYINT(1) UNSIGNED' : 'TINYINT(1)';
    }

    public function canRequireSQLConversion() {
        return true;
    }

    /**
     * @param $value
     * @param AbstractPlatform $platform
     * @return int|null
     */
    public function convertToPHPValue($value, AbstractPlatform $platform) {
        return $value === null ? null : (int)$value;
    }

    /**
     * @param mixed $value
     * @param AbstractPlatform $platform
     * @return int|mixed|null
     */
    public function convertToDatabaseValue($value, AbstractPlatform $platform) {
        return $value === null ? null : (int)$value;
    }

    /**
     * @return int
     */
    public function getBindingType() {
        return ParameterType::INTEGER;
    }
}

doctrine.yaml

doctrine:
    dbal:
        url: '%env(resolve:DATABASE_URL)%'
        server_version: '5.7'
        types:
            tinyint: 'App\Doctrine\DBAL\Types\TinyintType'
    orm:
        auto_generate_proxy_classes: true
        naming_strategy: doctrine.orm.naming_strategy.underscore_number_aware
        auto_mapping: true
        mappings:
            App:
                is_bundle: false
                type: annotation
                dir: '%kernel.project_dir%/src/Entity'
                prefix: 'App\Entity'
                alias: App
Preciel
  • 2,666
  • 3
  • 20
  • 45
  • According to [this](https://stackoverflow.com/a/11472344/231316), there might be an extra `mapping_types` for migrations that _might_ help Doctrine. – Chris Haas Nov 03 '20 at 15:27
  • I tried this, but doctrine keep generating the same migration file as if the DB type hasn't changed @ChrisHaas – Preciel Nov 03 '20 at 15:38

2 Answers2

3

First issue: From https://blog.vandenbrand.org/2015/06/25/creating-a-custom-doctrine-dbal-type-the-right-way/

The solution is to add a comment to the field to store the metadata in. This seems to be missing in the docs but I’ve found some JIRA issue describing the feature. We have to change our column definition so the metadata of the type doesn’t get lost

So your getSQLDeclaration should be like this:

public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
{
    return 'TINYINT'.(!empty($fieldDeclaration['unsigned']) ? ' UNSIGNED' : '').' COMMENT \'(DC2Type:tinyint)\'';
}

Second issue: That's because, by default symfony forms uses text type (symfony/form/FormBuilder.php::create)

if (null === $type && null === $this->getDataClass()) {
    $type = 'Symfony\Component\Form\Extension\Core\Type\TextType';
}

You should set your type explicitly if you want to set another type.

Urmat Zhenaliev
  • 1,497
  • 8
  • 22
  • 1
    I can't personally confirm that the comment thing works, but I see that it exists in the codebase with an [actual method for parsing](https://github.com/doctrine/dbal/blob/c6d37b4c42aaa3c3ee175f05eca68056f4185646/lib/Doctrine/DBAL/Schema/AbstractSchemaManager.php#L1127), and there'd a [thread here](https://stackoverflow.com/a/10689771/231316), so this seems like an official although undocumented way to do it! – Chris Haas Nov 03 '20 at 19:15
  • I remember similar thing with array type indeed, I will try it out asap, but seems correct to me. Thanks – Preciel Nov 03 '20 at 22:32
  • 1
    Worked, migration are detected just fine now. Thanks ! – Preciel Nov 04 '20 at 22:13
2

While the information in the accepted answer are ok, I missed a solution to copy&paste here, so here it is.

Type declaration:

<?php

namespace AppBundle\Doctrine;

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

class TinyintType extends SmallIntType
{
    public function getSQLDeclaration(array $column, AbstractPlatform $platform)
    {
        return 'TINYINT' . (!empty($column['unsigned']) ? ' UNSIGNED' : '');
    }


    public function requiresSQLCommentHint(AbstractPlatform $platform)
    {
        return true;
    }

    public function getName()
    {
        return 'tinyint';
    }
}

And type registration somewhere in the initialization code:

\Doctrine\DBAL\Types\Type::addType('tinyint', TinyintType::class);
fracz
  • 20,536
  • 18
  • 103
  • 149