Symfony2 Mongodb : save object into another

846 views Asked by At

I'm using Symfony2 with mongodb & doctrine-odm which have a strange behavior. I have an importFile document and a context document. The contexte document is referenced into the importFile one as below :

/**
* @MongoDB\Document
*/
class ImportFile
{
[...]
/**
 * @MongoDB\ReferenceOne(targetDocument="Contexte")
 */
private $contexte;

(getter and setter are ok).

My contexte document already exist, and lives into the session. If i dump the context object, i do have all required object info, with his id, and all his properties.

In my controller, i want to save this contexte object into my importFile one :

$dm = $this->getDocumentManager();
$importFile->setContexte($contexte); // contexte object already exists and persisted
$dm->persist($importFile);
$dm->flush();

it looks very simple, and should works like that, but on the flush, i get a mongodb error :

Cannot create a DBRef without an identifier. UnitOfWork::getDocumentIdentifier() did not return an identifier for class Contexte

i don't know what i'm doing wrong. Any help ?

2

There are 2 answers

0
Lazaro Reyes On

Haven't you done a var_dump($importFile) maybe when you are retrieving the object, is just null

0
Serhii Popov On

Maybe it will help someone.

In my case main problem was that after validation ZF2 return empty string for identifier.

Doctrine generate new identifier only when default value is NULL https://github.com/doctrine/mongodb-odm/blob/master/lib/Doctrine/ODM/MongoDB/UnitOfWork.php#L1017.

Simplified example of my code (see comments):

namespace Ageme\Project\Controller;

use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
use Doctrine\ODM\MongoDB\DocumentManager;

class ProjectController extends AbstractActionController {
//...

    protected function saveAction() {
        /** @var DocumentManager $dm */
        $request = $this->getRequest();
        $route = $this->getEvent()->getRouteMatch();

        $sm = $this->getServiceLocator();
        $fm = $sm->get('FormElementManager');
        $dm = $sm->get('doctrine.documentmanager.odm_default');

        $project = ($project = $dm->find('Ageme\Project\Document\Project', $route->getParam('id')))
            ? $project
            : $sm->get('Ageme\Project\Document\Project');

        $form = $fm->get('Ageme\Project\Form\ProjectForm');
        $form->bind($project);

        if ($request->isPost()) {
            $form->setData($request->getPost());
            if ($form->isValid()) { 
                // after validation $project->getId() === '', 
                // but for new object must equal $project->getId() === null
                $sm->get('ProjectService')->run('save', $project);
                $this->flashMessenger()->addSuccessMessage('Project saved');
                $this->redirect()->toRoute('default', 
                ['controller' => $route->getParam('controller'), 'lang' => $route->getParam('lang')]
                );
            }
        }

        return new ViewModel([
            'form' => $form,
        ]);
    }
    //...
}

I add next filter to fix my problem

namespace Ageme\Project\Form;

use Zend\Form\Fieldset;
use Zend\InputFilter\InputFilterProviderInterface;

use DoctrineModule\Persistence\ProvidesObjectManager;
use DoctrineModule\Persistence\ObjectManagerAwareInterface;

class ProjectFieldset 
    extends Fieldset 
    implements InputFilterProviderInterface, ObjectManagerAwareInterface {

    use ProvidesObjectManager;

    public function init() {
        $this->setName('project')
            ->setAttributes(['id' => 'project']);

        $this->add([
            'type' => 'Zend\Form\Element\Hidden',
            'name' => 'id'
        ]);
        //...
    }

    public function getInputFilterSpecification() {
        return [
            'id' => [
                'required' => true,
                'allow_empty' => true,
                'filters' => [
                    [
                        "name" => "Callback",
                        "options" => [
                             "callback" => function ($input) {
                                  return $input ?: null; // this code return correct value
                             }
                         ]
                    ]
                ],
            ],
            //...           
        ];
    }
}