2

I'm looking for a way to have an associative array keys for a ODM ArrayCollection.

The entity has the following mapping:

/**
 * $fields
 *
 * The entities fields
 *
 * @ODM\ReferenceMany(targetDocument="JobboardEntity\Entity\EntityField", sort={"name"="asc"}, cascade={"all"})
 * @var \Doctrine\Common\Collections\ArrayCollection
 */
protected $fields;

/**
 * addField
 *
 * Add a single field to the field collection
 *
 * @param EntityField $field The field to add
 */
public function addField(EntityField $field)
{
    $this->fields[$field->getFieldName()] = $field;
}

Notice in the addField method I am giving the item a index of $field->getFieldName().

Unfortunately, Doctrine forgets this key and returns an ArrayCollection with numeric indexes rather than the previously set strings.

This means that in order to correctly implement $this->hasField($fieldName) or $this->getField($fieldName) I would need to loop over the collection and test the fieldName value

For example

public function hasField($fieldName)
{
    foreach($this->fields as $field) {
        if ($fieldName === $field->getFieldName()) {
            return true;
        }
    }
    return false;
}

This, in my option, is a poor solution as I would need to load the entire collection to just check the key!

Having looked into the issue I can see that ORM has this implemented with IndexBy mapping.

Is there any similar functionality for Doctrine ODM? What is the correct way to accomplish this?

Community
  • 1
  • 1
AlexP
  • 9,906
  • 1
  • 24
  • 43

1 Answers1

1

Have a look at the Collection Strategies.

If you use @ODM\ReferenceMany(strategy="set") (works with EmbedMany as well) the collection will be stored as as BSON Object with the respective keys being set on load:

I'm not entirely sure about performance impact in the DB itself. I guess storing the collection as BSON Object is a bit slower but as you said, it's not a good thing to load the entire collection (and the entities you're checking against) and it helps to keep the code a bit cleaner.