mongodb-odm icon indicating copy to clipboard operation
mongodb-odm copied to clipboard

Custom types are not correctly transformered for embedded documents

Open o10g opened this issue 4 years ago • 1 comments

Bug Report

Q A
BC Break no
Version 2.1.1

Summary

Let's say we have User document with embedded document Identities. Some of fields in Identities has to be encrypted in the database. To achieve it, the new type was registered and assigned to the appropriate fields. In the repository class we need to filter by the encrypted field while in code we have it decrypted. So query builder is used this way:

$passportNumber = 'FB555555';
$qb = $this->dm->createQueryBuilder(User::class);
$qb->field('identifiers.passportNumber')->equals(new PassportNumber($passportNumber));
$qb->getQuery()->toArray();

But the query doesn't find anything because PassportNumberType::convertToDatabaseValue is never called.

Current behavior

PassportNumber is not encrypted because PassportNumberType::convertToDatabaseValue is never called. It is never called, because \Doctrine\ODM\MongoDB\Persisters\DocumentPersister::convertToDatabaseValue can't see the field in the class as this line of code $this->class->hasField($fieldName) returns false.

How to reproduce

Here is a small code samples (namespaces, use statement and other unnecessary code is omitted):

/**
 * @MongoDB\Document()
 */
class User
{
    /**
     * @MongoDB\Id
     */
    private $id;

    /**
     * @var Identifiers|null
     * @MongoDB\EmbedOne(targetDocument="App\Document\User\Identities")
     */
    private $identities;
}

/**
 * @MongoDB\EmbeddedDocument
 */
class Identifiers
{
    /**
     * @MongoDB\Field(type="passport_number", name="passport_number")
     */
    private PassportNumber $passportNumber;
}



class PassportNumberType extends Type
{
    public function convertToPHPValue($value): PassportNumber
    {
        return new PassportNumber(str_replace('encrypted_', 'decrypted_', $value));
    }

    public function convertToDatabaseValue($value): string
    {
        /** @var $value PassportNumber */
        return 'encrypted_' . $value->value();
    }
}

class PassportNumber
{
    private ?string $id;

    public function __construct(?string $id)
    {
        $this->id = $id;
    }

    public function value(): ?string
    {
        return $this->id;
    }
}

Expected behavior

The value for the custom type in the embedded documents should be processed in the way it is defined in the custom type definition.

o10g avatar Jul 23 '20 09:07 o10g

Thanks for the report! Unfortunately issue you are experiencing is currently "by design" as query builder always expected database types and needed help with type transformation. This changed a bit with 2.1 when query builder started recognizing simple cases but it's far from being perfect. If you feel like taking a stab at expanding the feature please feel free to make it a feature for 2.2. Probably we still won't be able to cover everything for embeddables (mostly because of discriminator maps and embed many) but it still might be useful.

malarzm avatar Jul 23 '20 09:07 malarzm