Doctrine používá classname místo value

zoid
Člen | 12
+
0
-

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)

akadlec
Člen | 1326
+
+1
-

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.

zoid
Člen | 12
+
0
-

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
+
0
-

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)

Jan Endel
Člen | 1016
+
0
-

Jak ten typ registruješ do Doctrine?

zoid
Člen | 12
+
0
-

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
+
0
-

Stále aktuální, kdyby byl někdo ochoten poradit :).

zoid
Člen | 12
+
+1
-

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;
}