/**
  * Kompiliert den Synchronizer und initialisiert
  *
  * wenn angegeben $add angegben wird, wird diese Closure mit $entity (der Parameter der init() Funktion) und $otherEntity aufgerufen
  * bei $add ist $otherEntity ein Entity aus der $toCollection welches nicht in der $fromColleciton ist
  * bei $remove ist $otherEntity ein Entity aus der $fromCollection welches nicht in der $toCollection ist
  * als dritter parameter wird das $repository des Entities in der Collection übergeben (also nicht das von $entity)
  *
  * die Standard-Adder sind nur für den Fall, dass diese Klasse auch die owning Side ist
  * sie rufen also $entity->addXXX($toEntity) auf
  * bzw
  * $entity->removeXXX($fromEntity)
  * 
  * @param Closure $adder function ($entity, $toEntity, $collectionRepository)  persist nicht vergesen!
  * @param Closure $remover function ($entity, $fromEntity, $collectionRepository) 
  */
 public function init(Entity $entity, Closure $adder = NULL, Closure $remover = NULL)
 {
     parent::init($entity);
     list($add, $remove) = $this->getRelationInterface();
     if (!$adder) {
         $adder = function ($entity, $toEntity, $repository) use($add) {
             $repository->persist($toEntity);
             $entity->{$add}($toEntity);
         };
     }
     if (!$remover) {
         $remover = function ($entity, $fromEntity, $repository) use($remove) {
             $repository->persist($fromEntity);
             $entity->{$remove}($fromEntity);
         };
     }
     $repository = $this->collectionRepository;
     // insert: in $toCollection gibt es ein $toEntity, welches noch nicht in $fromCollection war
     $this->innerSynchronizer->onInsert(function ($toEntity) use($repository, $entity, $adder) {
         $adder($entity, $toEntity, $repository);
     });
     // update bzw merge: das $toEntity war bereits in der $fromCollection und ist in der $toCollection
     $this->innerSynchronizer->onUpdate(function ($toEntity) use($repository, $entity, $adder) {
         $adder($entity, $toEntity, $repository, $isUpdate = TRUE);
     });
     // delete: das $fromEntity war vorher in der $fromCollection und ist nicht mehr in der $toCollection
     $this->innerSynchronizer->onDelete(function (Entity $fromEntity) use($entity, $remover, $repository) {
         $remover($entity, $fromEntity, $repository);
         // wenn $fromEntity 0 verknüpfungen hat, könnte man es hier auch löschen, dies macht aber das relationinterface
     });
     return $this;
 }
 /**
  * Initialisiert die Defaults für alle on* Methoden für das Entity mit der Collection
  *
  * ein CollectionSynchronizer kann mehrere Collections eines Types von mehreren Entities synchronisieren wenn jeweils init() für das aktuelle Entity aufgerufen wird
  *
  * new Synchronizer();
  * foreach ($articles as $article) {
  *   $synchronizer->init($article);
  *
  *   $synchronizer->process($article->getTags(), $formData[$article->getId()]);
  * }
  */
 public function init(Entity $entity)
 {
     parent::init($entity);
     $hydrator = $this->hydrator;
     $factory = $this->factory;
     $repository = $hydrator->getRepository();
     $identifier = $factory->getEntityMeta()->getIdentifier();
     $skipFields = array();
     if ($identifier->isAutogeneratedValue()) {
         $skipFields[$identifier->getName()] = TRUE;
     }
     list($add, $remove) = $this->getRelationInterface();
     // hydrate
     $this->onHydrate(function ($toObject) use($hydrator) {
         return $hydrator->getEntity((array) $toObject);
         // convention: $field=>value für alle unique constraint-felder
     });
     // hash
     $this->onHash(function (Entity $entity) {
         return $entity->getIdentifier();
     });
     // insert
     $this->onInsert(function ($toObject) use($factory, $repository, $entity, $add, $skipFields) {
         $factory->reset();
         foreach ($toObject as $field => $value) {
             if (!array_key_exists($field, $skipFields)) {
                 $factory->set($field, $value);
             }
         }
         $collectionEntity = $factory->getEntity();
         $entity->{$add}($collectionEntity);
         $repository->persist($collectionEntity);
     });
     // update (merge)
     $this->onUpdate(function (Entity $collectionEntity, $toObject) use($repository, $entity, $add, $skipFields) {
         foreach ($toObject as $field => $value) {
             if (!array_key_exists($field, $skipFields)) {
                 $collectionEntity->callSetter($field, $value);
             }
         }
         $entity->{$add}($collectionEntity);
         $repository->persist($collectionEntity);
     });
     // delete
     $this->onDelete(function (Entity $collectionEntity) use($entity, $remove) {
         $entity->{$remove}($collectionEntity);
         // wenn tag 0 verknüpfungen hat, könnte man es hier auch löschen
     });
     return $this;
 }