Dodajemy nowy typ do Doctrine
Doctrine, czyli dość znana i rozpowszechniona (zwłaszcza wśród entuzjastów Symfony) biblioteka do kompleksowej obsługi komunikacji z różnymi typami baz danych, nie posiada niestety wszystkich możliwych typów do zastosowania w kolumnach. Takim dość często potrzebnym typem, staje się TinyInt
- oto jak można go dodać.
Czemu Doctrine nie posiada zaimplementowanego TinyInt ?
Odpowiedz padła we wstępie - dlatego, że jest to biblioteka, która służy do ujednolicenia interfejsu przy komunikacji z różnymi systemami bazodanowymi: a TinyInt
jest typem lokalnym
dla baz danych opartych na MySql (w tym MariaDB). Dla przykładu: typu TinyInt
nie uświadczymy (za to uświadczymy inne) w takich bazach danych PostgreSQL czy SQLite.
Jest oczywiście SmallInt
czy varchar
- jednak ten pierwszy ma dość duży zakres, a ten drugi jest typem znakowym (a bazy danych zdecydowanie wolą liczby). Dobrze skrojona aplikacja na miarę, nie powinna mieć zbyt dużych luzów czy innych niedopowiedzeń - wpływa to na efektywność całego systemu.
Dodajemy nowy typ do Doctrine
W tym celu należy utworzyć nową klasę, która będzie rozszerzać klase typów Doctrine - czyli:
use Doctrine\DBAL\Types\Type;
Które to wymusi na nas, zaimplementowanie kilku wymaganych metod - cała przygotowana klasa Typu TinyInt
wygląda następująco:
<?php
namespace App\Doctrine\Column\Type;
use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Types\Type;
class TinyIntType extends Type
{
const NAME = 'tinyint';
const DB_TYPE = 'TINYINT';
/** {@inheritdoc} */
public function getSQLDeclaration(array $column, AbstractPlatform $platform): string
{
return self::DB_TYPE;
}
/** {@inheritdoc} */
public function convertToPHPValue($value, AbstractPlatform $platform): mixed
{
return $value;
}
/** {@inheritdoc} */
public function convertToDatabaseValue($value, AbstractPlatform $platform): mixed
{
return $value;
}
/** {@inheritdoc} */
public function getName(): string
{
return self::NAME;
}
}
Jak widać oprócz getterów do określenia nazwy typu oraz deklaracji w SQL mamy też metody konwertujące wartości- ale w typ wypadku, nie ma takiej potrzeby.
Należy jeszcze tak utworzoną klasę dodać do EntityManagerInterface
Doctrine w symfony - można to zrobić np. na Kernelu
na metodzie boot
- jak w przykładzie poniżej:
<?php
namespace App;
use App\Doctrine\Column\Type\TinyIntType;
use Doctrine\DBAL\Exception;
use Doctrine\DBAL\Types\Type;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait;
use Symfony\Component\HttpKernel\Kernel as BaseKernel;
/**
* @SuppressWarnings(PHPMD.StaticAccess)
*/
class Kernel extends BaseKernel
{
use MicroKernelTrait;
public function boot(): void
{
parent::boot();
$this->addDoctrineTypes();
}
private function addDoctrineTypes(): void
{
if (! $this->container) {
return;
}
$entityManager = $this->container->get('doctrine.orm.default_entity_manager');
if (!$entityManager) {
return;
}
$this->addDoctrineTinyIntType($entityManager); // @phpstan-ignore-line
}
/**
* @throws Exception
*/
private function addDoctrineTinyIntType(EntityManagerInterface $entityManager): void
{
if (Type::hasType(TinyIntType::NAME)) {
return;
}
Type::addType(
TinyIntType::NAME,
TinyIntType::class
);
$entityManager
->getConnection()
->getDatabasePlatform()
->registerDoctrineTypeMapping(
TinyIntType::DB_TYPE,
TinyIntType::NAME
);
}
}
I to w sumie tyle - dodaliśmy nowy typ do Doctrine. Teraz wystarczy na danych deklaracjach kolumn w Entity
podmienić na nowy typ tinyint
, wykonać bin/console d:s:u --force
oraz sprawdzić czy zmiany faktycznie zaszły na poszczególnych tabelach bazy danych.