Doctrine používá classname místo value

- zoid
 - Člen | 12
 
Zdravím,
Mám problém s doctrine. Udělal jsem si vlastní typ pro UUID (ukládám ho jako Binary(16) místo stringu – kvůli výkonu a velikosti indexů). V PHP mám pro to speciální třídu (HexString) která kontroluje, zda se jedná o validní hex. dec. string. To používám jako primární klíč pro entity.
Pokud vytáhnu entitu přes $em->findBy(), vytáhne mi to správně entitu a všechny její vazby, pokud ale použiju queryBuilder, vytáhne mi to správně entitu, ale vazby jsou null – generuje to totiž tento dotaz:
SELECT t0.id AS id_1, t0.payment_type AS payment_type_2, t0.variable AS
       variable_3, t0.paid AS
       paid_4, t0.price AS price_5, t0.price_include_vat AS
       price_include_vat_6, t0.order_id AS order_id_7
FROM order_payments t0
WHERE t0.order_id = Peblo\Shared\Types\HexString
Nevím proč, ale místo, aby vygeneroval query where order_id = (id entity),
použije to název typu, ve kterém je ID uchováno.
Typ registruju do doctrine v bootstrapu. Níže přikládám kód mé třídy a
typu v doctrine:
final class HexString
{
    /** @var string */
    private $value;
    /**
     * HexString constructor.
     * @param string $value
     */
    private function __construct(string $value)
    {
        if (!static::isValid($value)) {
            throw new InvalidParameterException('Invalid hex value');
        }
        $this->value = $value;
    }
    /**
     * @return string
     */
    public function __toString() : string
    {
        return $this->value;
    }
    /**
     * @param string $value
     * @return HexString
     */
    public static function from(?string $value): ?self
    {
        if($value === null) return null;
        return new self($value);
    }
    /**
     * @return string
     */
    public function getValue(): string
    {
        return $this->value;
    }
    /**
     * @param string $value
     * @return bool
     */
    private static function isValid(string $value): bool
    {
        if (Strings::length($value) !== 32) {
            return false;
        }
        return ctype_xdigit($value);
    }
}
final class BinaryUuidType extends Type
{
    const TypeName = 'uuid';
    /**
     * @param array $fieldDeclaration
     * @param AbstractPlatform $platform
     * @return string
     */
    public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform) : string
    {
        $length = isset($fieldDeclaration['length']) ? $fieldDeclaration['length'] : 16;
        return "BINARY($length)";
    }
    /**
     * @param mixed $value
     * @param AbstractPlatform $platform
     * @return null|HexString
     */
    public function convertToPHPValue($value, AbstractPlatform $platform) :? HexString
    {
        return $value === null ? null : HexString::from(self::hexToString($value));
    }
    /**
     * @param HexString $value
     * @param AbstractPlatform $platform
     * @return null|string
     */
    public function convertToDatabaseValue($value, AbstractPlatform $platform) :? string
    {
        return $value === null ? null : pack('H*', $value->getValue());
    }
    /**
     * @return string
     */
    public function getName() : string
    {
        return self::TypeName;
    }
    /**
     * @param $hex
     * @return string
     */
    public static function hexToString($hex) : string
    {
        return unpack("H*", $hex)[1];
    }
}
Děkuji za jakékoliv rady :)
Editoval zoid (6. 1. 2018 17:59)

- zoid
 - Člen | 12
 
akadlec napsal(a):
broblém je právě s tím custom typem a binary. To samé dělá doctrine pokud použiješ uuid od ramseyho. Je potřeba trochu přiohnout doctrine aby to id převáděl na binary hodnotu.
Ahoj, mohl bych vědet, jak doctrine přiohnout? Popř. pokud s tímto máš zkušenosti, mohl bys mě navést na nějaký workaround? Vážně by mi to pomohlo.
Díky :)

- akadlec
 - Člen | 1326
 
Já to vyřešil tak že tam kde dělám selecty jednoho záznamu podle ID, dělám select pomocí query builderu
	public function byId(Uuid\UuidInterface $id)
	{
		$this->filter[] = function (Doctrine\QueryBuilder $qb) use ($id) {
			$qb->andWhere('ch.id = :id')->setParameter('id', $id->getBytes());
		};
	}
a tam rovnou setuju jako binární hodnota.
No pak je ještě problém v kolekcích když potřebuješ dělat delete.
v BasicEntityPersister
    public function delete($entity)
    {
        $class      = $this->class;
        $identifier = $this->em->getUnitOfWork()->getEntityIdentifier($entity);
        foreach ($identifier as $key=>$value) {
            if ($value instanceof Uuid) {
                $identifier[$key] = $value->getBytes();
            } else {
                $identifier[$key] = $value;
            }
        }
a v JoinedSubclassPersister
    public function delete($entity)
    {
        $identifier = $this->em->getUnitOfWork()->getEntityIdentifier($entity);
        foreach ($identifier as $key=>$value) {
            if ($value instanceof Uuid) {
                $identifier[$key] = $value->getBytes();
            } else {
                $identifier[$key] = $value;
            }
        }
jestli je to to nej řešení nevím, můj problém to vyřešilo. Zkoušel sem hledat jestli to někoho s ramseymym taky nepáli ale asi ne.
Editoval akadlec (8. 1. 2018 12:42)

- zoid
 - Člen | 12
 
Jan Endel:
Typ registruji takto:
Doctrine\DBAL\Types\Type::addType(BinaryUuidType::TypeName, BinaryUuidType::class);
Zkoušel jsem si i vytáhnout connection a zaregistrovat do databasePlatform,
ale bohužel se stejným efektem.
K tobě Adame:
Nemám problém při tahání entit podle ID – to je má chyba, že jsem
zjednodušil příklad. U tahání podle ID mi vše funguje jak má, problém
je, pokud vytáhnu entity přes queryBuilder – např.
$qb->select('o')->from(Order::class, 'o'); Vytáhne mi to
všechny objednávky (správně), ale jejich relace (vazby, jejiž klíče nemá
entita order v sobě – jsou řešeny joinColumnem v druhé entitě, pokud
je joinColumn přímo v order, je vše ok) to neumí načíst, vytváří to ty
divné query viz první post.
Editoval zoid (8. 1. 2018 15:22)

- zoid
 - Člen | 12
 
Tak nakonec jsem to vyřešil – nevím sice kde byl problém :D ale jelikož ukládám uuid jako binary, zkusil jsem ten svůj doctrine UuidType podědit přímo od BinaryType a teď už to vypadá, že vše funguje.
Podezření mám na tuhle metodu:
    /**
     * {@inheritdoc}
     */
    public function getBindingType()
    {
        return \PDO::PARAM_LOB;
    }