The initial stab at Conflict module for Drupal 8 will only do a few simple things.
The goal is to keep the module pluggable and to not to depend on Multiversion or Replication module.
Here are the main things we should start with:
Step 1: Implement the ConflictManager service
- Provide a basic manager called
ConflictManagerthat can do two main things; resolve lowest common ancestor (LCA) for two revision (in a pluggable way), and do a merge between three revisions of an entity (in a pluggable way).
- The way we should make these things pluggable is by using tagged services, similar to how
ReplicatorManagerworks in the Workspace module
ConflictManagerInterfaceshould therefor have four public methods:
::addAncestorResolver(ConflictAncestorResolverInterface $resolver)- Used by the container system
::addConflictResolver(ConflictResolverInterface $resolver)- Used by the container system
::resolveLowestCommonAncestor($revision1, $revision2)- This method will be responsible for finding the lowest common ancestor for two given revisions objects of an entity. All this method should do is to pass off the responsibility to the first tagged ancestor resolver service, as per above.
::resolveConflict($revision1, $revision2, $revision3)- This method will be responsible for fixing the conflict between three revisions. All this method should do is to pass off the responsibility to the first tagged conflict resolver service, as per above.
Step 2: Implement two different ancestor resolvers
Since the LCA resolution is pluggable inside
ConflictManager::resolveLowestCommonAncestor() we should provide two different implementations for this:
- A simple resolver which find the LCA for revisions that use the default linear revision system provided by core. This resolver will work with any Drupal 8 site.
- A more complicated resolver that uses the relaxedws/lca library and
RevisionTreeIndexfrom Multiversion module. This step depends on . This resolver will only work with sites that uses Multiversion module.
Step 3: Implement two conflict resolvers
- A simple resolver that just returns the revision with the largest revision ID. This resolver will work with any Drupal 8 site.
- A more complex resolver that uses the Serialization module to normalize the given revisions into arrays and then use the relaxedws/merge library to perform the merge. This resolver will only work with sites that uses Multiversion module.
The merge process would roughly work like the below (please note this is only example code and might not be fully accurate).
Note that this is a test case inside Conflict module without Multiversion module, so revisions are not stored as trees. We should also add tests in Multiversion module with full revision trees.
$storage = $this->entityManager->getStorage('entity_test'); $serializer = \Drupal::service('serializer'); $conflict = \Drupal::service('conflict.manager'); // Create a few revisions. $entity = $storage->create(['name' => 'rev 1']); $entity->save(); $entity->name = 'rev 2'; $entity->save(); $entity->name = 'rev 3'; $entity->save(); $rev1 = $storage->loadRevision(1); $rev2 = $storage->loadRevision(2); $rev3 = $storage->loadRevision(3); // Resolve the conflict and return a merged version of the revision object. $merged = $conflict->resolveConflict($rev1, $rev2, $rev3); $this->assertEqual($merged->name, 'rev 3');
Step 4: Tests, tests, tests, and more tests!
The heading says it all :)