php – With doctrine ODM, can I embed many subdocuments in a main document?

I try to save this JSON:

{
  "vendorId": "vendor-fc162cdffd73",
  "company": {
    "companyId": "bcos1.company.1806cf97-a756-4fbf-9081-fc162cdffd73",
    "companyVersion": 1,
    "companyName": "Delivery Inc.",
    "address": {
      "streetAddress": "300 Boren Ave",
      "city": "Seattle",
      "region": "US-WA",
      "country": "US",
      "postalCode": "98109",
      "storeName": "Seattle Store",
      "coordinates": {
        "latitude": "45.992820",
        "longitude": "45.992820"
      }
    },
    "emailAddress": "johndoe@amazon.com",
    "phoneNumber": "1234567890",
    "websiteUrl": "delivery.com",
    "creationDate": "2022-03-06T21:00:52.222Z"
  },
  "creationDate": "2022-04-06T21:00:52.222Z"
}

Company is a subdocument this has address and address has coordinates subdocument. When I try to save with Hydratation, see example: https://www.doctrine-project.org/projects/doctrine-laminas-hydrator/en/3.0/basic-usage.html#example-4-embedded-entities

I got this error:

1) AppTestServicesAccountsServiceTest::testNewAccount with data set #0 (array('{"companyId":"bcos1.com...222Z"}', '', ''))
array_flip(): Can only flip STRING and INTEGER values!

vendor/doctrine/doctrine-laminas-hydrator/src/DoctrineObject.php:488
vendor/doctrine/doctrine-laminas-hydrator/src/DoctrineObject.php:355
vendor/doctrine/doctrine-laminas-hydrator/src/DoctrineObject.php:165
src/App/Document/Repository/AccountRepository.php:67

In DoctrineObject line 488

    protected function toOne(string $target, $value): ?object
    {
        $metadata = $this->objectManager->getClassMetadata($target);
        if (is_array($value) && array_keys($value) !== $metadata->getIdentifier()) {
            // $value is most likely an array of fieldset data
            $identifiers = array_intersect_key(
                $value,
                array_flip($metadata->getIdentifier())
            );
            $object      = $this->find($identifiers, $target) ?: new $target();

            return $this->hydrate($value, $object);
        }

        return $this->find($value, $target);
    }

My code:

        $vendorAccountId = uniqid('vendor-account-id-');
        $account = new Account();

        $hydrator->hydrate($data, $account);

My main Entity:

<?php

namespace AppDocumentEntity;

use DoctrineODMMongoDBMappingAnnotations as MongoDB;

/**
 * @MongoDBDocument(db="awesome-company", collection="Account", repositoryClass="AppDocumentRepositoryAccountRepository")
 */
class Account
{
    /** @MongoDBId(name="_id") */
    private string $id;

    /** @MongoDBField(type="string", name="vendorAccountId") */
    private string $vendorAccountId;

    /**
     * @return string
     */
    public function getVendorAccountId(): string
    {
        return $this->vendorAccountId;
    }

    /**
     * @param string $vendorAccountId
     */
    public function setVendorAccountId(string $vendorAccountId): void
    {
        $this->vendorAccountId = $vendorAccountId;
    }

    /**
     * @MongoDBEmbedOne(targetDocument=Company::class)
     */
    private Company $company;

    /**
     * @MongoDBField(type="string",name="realm")
     **/
    private $realm;

    /**
     * @MongoDBField(type="string",name="domain")
     **/
    private $domain;

    /**
     * @MongoDBField(type="date",name="created_at")
     **/
    private DateTime $createdAt;


    public function __construct()
    {
        $this->company = new Company();
        $this->createdAt = new DateTime();
    }

    /**
     * @return mixed
     */
    public function getCompany()
    {
        return $this->company;
    }

    /**
     * @param mixed $company
     */
    public function setCompany($company): void
    {
        $this->company = $company;
    }

    /**
     * @return mixed
     */
    public function getRealm()
    {
        return $this->realm;
    }

    /**
     * @param mixed $realm
     */
    public function setRealm($realm): void
    {
        $this->realm = $realm;
    }

    /**
     * @return mixed
     */
    public function getDomain()
    {
        return $this->domain;
    }

    /**
     * @param mixed $domain
     */
    public function setDomain($domain): void
    {
        $this->domain = $domain;
    }

    /**
     * @return DateTime
     */
    public function getCreatedAt(): DateTime
    {
        return $this->createdAt;
    }

    /**
     * @return string
     */
    public function getId(): string
    {
        return $this->id;
    }

    /**
     * @param string $id
     */
    public function setId(string $id): void
    {
        $this->id = $id;
    }

}

Company embed document:

<?php

namespace AppDocumentEntity;

use DoctrineODMMongoDBMappingAnnotations as MongoDB;

/** @MongoDBEmbeddedDocument * */
class Company
{
    /**
     * @MongoDBField(type="string",name="company_id")
     **/
    private string $companyId;

    /**
     * @MongoDBField(type="int",name="company_version")
     **/
    private int $companyVersion;

    /**
     * @MongoDBField(type="string",name="company_name")
     **/
    private string $companyName;

    /**
     * @MongoDBEmbedOne(targetDocument=Address::class)
     */
    private Address $address;

    /**
     * @MongoDBField(type="string",name="email_address")
     **/
    private string $emailAddress;

    /**
     * @MongoDBField(type="string",name="phone_number")
     **/
    private string $phoneNumber;

    /**
     * @MongoDBField(type="string",name="website_url")
     **/
    private string $websiteUrl;

    /**
     * @MongoDBField(type="date",name="creation_date")
     **/
    private DateTime $creationDate;


    public function __construct()
    {
        $this->address = new Address();
    }

    public function getCompanyId(): string
    {
        return $this->companyId;
    }

    public function setCompanyId($companyId)
    {
        $this->companyId = $companyId;
    }

    public function getCompanyVersion(): int
    {
        return $this->companyVersion;
    }

    public function setCompanyVersion($companyVersion)
    {
        $this->companyVersion = $companyVersion;
    }

    public function getCreationDate(): DateTime
    {
        return $this->creationDate;
    }

    public function setCreationDate($creationDate)
    {
        $this->creationDate = $creationDate;
    }

    public function getWebsiteUrl(): string
    {
        return $this->websiteUrl;
    }

    public function setWebsiteUrl($websiteUrl)
    {
        $this->websiteUrl = $websiteUrl;
    }

    public function getPhoneNumber(): string
    {
        return $this->phoneNumber;
    }

    public function setPhoneNumber($phoneNumber)
    {
        $this->phoneNumber = $phoneNumber;
    }

    public function getEmailAddress(): string
    {
        return $this->emailAddress;
    }

    public function setEmailAddress($emailAddress)
    {
        $this->emailAddress = $emailAddress;
    }

    public function getAddress(): Address
    {
        return $this->address;
    }

    public function setAddress(Address $address)
    {
        $this->address = $address;
    }

    public function getCompanyName(): string
    {
        return $this->companyName;
    }

    public function setCompanyName($companyName)
    {
        $this->companyName = $companyName;
    }
}

Leave a Comment