sf_tristanb
sf_tristanb

Reputation: 8855

How to handle in a generic way the session storage of filters avoiding the "Entity must be managed"

We've all been confronted to that problem : "Entity must be managed" when we are trying to setFilters() / getFilters()

So how to handle the session storage of filters in a generic way, in order to avoid merging and detaching or re-hydrating manually the entities ?

See the answer just below.

Upvotes: 0

Views: 189

Answers (1)

sf_tristanb
sf_tristanb

Reputation: 8855

Well, some colleague (@benji07) at work have written this :

/**
 * Set filters
 * @param string $name    Name of the key to store filters
 * @param array  $filters Filters
 */
public function setFilters($name, array $filters = array())
{
    foreach ($filters as $key => $value) {
        // Transform entities objects into a pair of class/id
        if (is_object($value)) {
            if ($value instanceof ArrayCollection) {
                if (count($value)) {
                    $filters[$key] = array(
                        'class' => get_class($value->first()),
                        'ids' => array()
                    );
                    foreach ($value as $v) {
                        $identifier = $this->getDoctrine()->getEntityManager()->getUnitOfWork()->getEntityIdentifier($v);
                        $filters[$key]['ids'][] = $identifier['id'];
                    }
                }
            }
            elseif (!$value instanceof \DateTime) {
                $filters[$key] = array(
                    'class' => get_class($value),
                    'id'    => $this->getDoctrine()->getEntityManager()->getUnitOfWork()->getEntityIdentifier($value)
                );
            }
        }
    }

    $this->getRequest()->getSession()->set(
        $name,
        $filters
    );
}

/**
 * Get Filters
 * @param string $name    Name of the key to get filters
 * @param array  $filters Filters
 *
 * @return array
 */
public function getFilters($name, array $filters = array())
{
    $filters = array_merge(
        $this->getRequest()->getSession()->get(
            $name,
            array()
        ),
        $filters
    );

    foreach ($filters as $key => $value) {
        // Get entities from pair of class/id
        if (is_array($value) && isset($value['class']) && isset($value['id'])) {
            $filters[$key] = $this->getDoctrine()->getEntityManager()->find($value['class'], $value['id']);
        } elseif (isset($value['ids'])) {
            $data = $this->getDoctrine()->getEntityManager()->getRepository($value['class'])->findBy(array('id' => $value['ids']));
            $filters[$key] = new ArrayCollection($data);
        }
    }

    return $filters;
}

It works for basic entities, and multivalued choices

PS: Don't forget to add a use statement for the ArrayCollection

Disclaimer, we don't know if it's a good practice, and we know at least one limitation : you have to be sure that the object you try to save in the session has an id (it's 99,9% the case)

Upvotes: 1

Related Questions