public function testAcceptanceSynchronization_toCollectionAsObjectsWithId()
 {
     $o = function ($id, $label) {
         return (object) compact('id', 'label');
     };
     $article = $this->findArticle();
     $toCollection = $this->getToCollection($o);
     $repository = $this->em->getRepository('Psc\\Doctrine\\TestEntities\\Tag');
     $synchronizer = new \Psc\Doctrine\ActionsCollectionSynchronizer();
     $synchronizer->onHydrate(function ($toObject) use($repository) {
         $qb = $repository->createQueryBuilder('tag');
         $qb->where($qb->expr()->orX($qb->expr()->eq('tag.label', ':label'), $qb->expr()->eq('tag.id', ':id')));
         $qb->setParameter('id', $toObject->id)->setParameter('label', $toObject->label);
         $result = $repository->deliverQuery($qb, NULL, 'singleOrNull');
         //\Psc\Doctrine\Helper::dump($result);
         return $result;
     });
     $synchronizer->onHash(function (Entity $tag) {
         return $tag->getIdentifier();
     });
     $synchronizer->onInsert(function ($o) use($repository, $article) {
         //print "insert ".$o->label."\n";
         $tag = new Tag($o->label);
         $article->addTag($tag);
         $repository->persist($tag);
     });
     $synchronizer->onDelete(function (Entity $tag) use($repository, $article) {
         //print "remove ".$tag->getLabel()."\n";
         $article->removeTag($tag);
         // wenn tag 0 verknüpfungen hat, könnte man es hier auch löschen
     });
     $synchronizer->onUpdate(function (Entity $tag, $o) use($repository, $article) {
         //print "update ".$tag->getLabel()."\n";
         $tag->setLabel($o->label);
         $article->addTag($tag);
         $repository->persist($tag);
     });
     $synchronizer->process($article->getTags(), $toCollection);
     $this->em->flush();
     $this->assertSyncResult();
 }
 /**
  * @param array $flat der Output der Funktion Psc.UI.Navigation::serialize() als decodierter JSON-Array
  * @return Psc\System\Logger
  */
 public function persistFromUI(array $flat)
 {
     $logger = new \Psc\System\BufferLogger();
     $em = $this->dc->getEntityManager();
     try {
         $em->getConnection()->beginTransaction();
         $repository = $this->repository;
         $pageRepository = $em->getRepository($this->container->getRoleFQN('Page'));
         $controller = $this;
         $bridge = new DoctrineBridge($em);
         $this->initDoctrineBridge($bridge);
         $bridge->beginTransaction();
         $jsonNodes = array();
         $synchronizer = new \Psc\Doctrine\ActionsCollectionSynchronizer();
         $hydrator = new \Psc\Doctrine\UniqueEntityHydrator($repository);
         $synchronizer->onHydrate(function ($jsonNode) use($hydrator) {
             return $hydrator->getEntity((array) $jsonNode);
             // hydriert nach id
         });
         $persistNode = function (Entity $node, $jsonNode) use($bridge, $pageRepository, $repository, &$jsonNodes, $logger, $controller) {
             $node->setContext($repository->getContext());
             $node->setParent(isset($jsonNode->parent) ? $jsonNodes[$jsonNode->parent->guid] : NULL);
             // ist immer schon definiert
             $node->setI18nTitle((array) $jsonNode->title);
             $node->setImage(isset($jsonNode->image) ? $jsonNode->image : NULL);
             $logger->writeln(sprintf("persist %snode: '%s'", $node->isNew() ? 'new ' : ':' . $node->getIdentifier() . ' ', $node->getTitle($repository->displayLocale)));
             if (isset($jsonNode->pageId) && $jsonNode->pageId > 0) {
                 $page = $pageRepository->hydrate($jsonNode->pageId);
                 $node->setPage($page);
                 $logger->writeln('  page: ' . $node->getPage()->getSlug());
             } else {
                 $defaultSlug = current($node->getI18nSlug());
                 // not matter what current language is, this is the default language
                 $page = $controller->createNewPage($defaultSlug);
                 $node->setPage($page);
                 $pageRepository->persist($page);
             }
             // flat ist von oben nach unten sortiert:
             // wenn wir also oben anfangen müssen wir die weiteren immmer nach unten anhängen
             if ($node->getParent() != NULL) {
                 $logger->writeln('  parent: ' . $node->getParent()->getTitle($repository->displayLocale));
             }
             $bridge->persist($node);
             // index nach guid damit wir sowohl neue als auch bestehende haben
             $jsonNodes[$jsonNode->guid] = $node;
         };
         $synchronizer->onInsert(function ($jsonNode) use($controller, $persistNode) {
             $persistNode($node = $controller->createNewNode($jsonNode), $jsonNode);
         });
         $synchronizer->onUpdate(function ($node, $jsonNode) use($repository, $persistNode, $logger) {
             $persistNode($node, $jsonNode);
         });
         $synchronizer->onDelete(function ($node) use($em, $logger, $repository) {
             $logger->writeln(sprintf("remove node: '%s'", $node->getTitle($repository->displayLocale)));
             $em->remove($node);
         });
         $synchronizer->onHash(function (Entity $node) {
             return $node->getIdentifier();
         });
         $synchronizer->process($this->repository->findAllNodes($this->context), $flat);
         $bridge->commit();
         $em->flush();
         $em->getConnection()->commit();
     } catch (\Exception $e) {
         $em->getConnection()->rollback();
         throw $e;
     }
     return $logger;
 }