Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replication filter #6

Merged
merged 34 commits into from Jun 14, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
e70f54c
Add replication task interface and class
josephdpurcell May 20, 2016
093e6cc
Add ReplicationFilterManager
josephdpurcell May 21, 2016
13eaf4b
Pass filter manager to changes factory
josephdpurcell May 21, 2016
529eb2c
Add uuids and filters to ChangesInterface
josephdpurcell May 21, 2016
a4c0624
Implement uuids and filters on Changes
josephdpurcell May 21, 2016
e9baef0
Test filtering by UUIDs
josephdpurcell May 21, 2016
e9bdd69
Add replication filter interface
josephdpurcell May 21, 2016
de8ed02
Add base replication filter base class
josephdpurcell May 21, 2016
05a1d00
Add published filter
josephdpurcell May 21, 2016
8ad97ec
Add test for published filter
josephdpurcell May 21, 2016
d099d63
Remove functional test
josephdpurcell May 21, 2016
c762847
Remove var dump
josephdpurcell May 21, 2016
316a04a
Modify published filter
josephdpurcell May 21, 2016
9724015
Update comments on Changes classes
josephdpurcell May 24, 2016
886bcd1
Set workspace on storage in Changes class
josephdpurcell May 24, 2016
14d28bb
Add a ReplicationFilterTest
josephdpurcell May 24, 2016
6948ae8
Remove unused variable
josephdpurcell May 24, 2016
c96626d
Update documentation of ReplicationFilterInterface
josephdpurcell May 24, 2016
1b16375
Remove NULL from filter param
josephdpurcell May 24, 2016
ea218ba
Modify published filter to only work on nodes
josephdpurcell May 24, 2016
a21f684
Remove blank line
josephdpurcell May 24, 2016
f08fcd4
Add entity type filter
josephdpurcell May 24, 2016
dfd4aa0
Add test for entity type filter
josephdpurcell May 24, 2016
9a215e4
Tweak type handling in Changes
josephdpurcell Jun 1, 2016
afb0dc4
Tweak doc and default type in ReplicationTask
josephdpurcell Jun 1, 2016
c49aa15
Allow empty parameter to reset
josephdpurcell Jun 1, 2016
d48dd3f
Fix entity type filter
josephdpurcell Jun 7, 2016
3d972a7
Change method name in test
josephdpurcell Jun 7, 2016
1c505fa
Remove UUIDs from Changes class
josephdpurcell Jun 9, 2016
1abf13f
Add UuidFilter
josephdpurcell Jun 9, 2016
7b64fe1
Add UuidFilter test
josephdpurcell Jun 9, 2016
8dc95b8
Update functional test for UUIDs
josephdpurcell Jun 9, 2016
13f7b76
Remove UUIDs from ReplicationTask
josephdpurcell Jun 9, 2016
54a577d
Automatically select UUID filter if uuids param sent
josephdpurcell Jun 9, 2016
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
9 changes: 7 additions & 2 deletions replication.services.yml
Expand Up @@ -3,10 +3,15 @@ services:
class: Drupal\replication\ProcessFileAttachment
arguments: ['@current_user', '@entity_type.manager', '@multiversion.entity_index.factory']

#Managers
plugin.manager.replication_filter:
class: Drupal\replication\Plugin\ReplicationFilterManager
parent: default_plugin_manager

#Factories
replication.changes_factory:
class: Drupal\replication\ChangesFactory
arguments: ['@multiversion.entity_index.sequence', '@entity.manager', '@serializer']
arguments: ['@multiversion.entity_index.sequence', '@entity.manager', '@serializer', '@plugin.manager.replication_filter']
replication.revisiondiff_factory:
class: Drupal\replication\RevisionDiffFactory
arguments: ['@multiversion.entity_index.rev']
Expand Down Expand Up @@ -94,4 +99,4 @@ services:
replication.normalizer.comment_item:
class: Drupal\replication\Normalizer\CommentItemNormalizer
tags:
- { name: normalizer, priority: 10 }
- { name: normalizer, priority: 10 }
48 changes: 48 additions & 0 deletions src/Annotation/ReplicationFilter.php
@@ -0,0 +1,48 @@
<?php

namespace Drupal\replication\Annotation;

use Drupal\Component\Annotation\Plugin;

/**
* Defines a ReplicationFilter annotation object.
*
* Plugin Namespace: Plugin\ReplicationFilter
*
* For a working example, see
* \Drupal\replication\Plugin\ReplicationFilter\PublishedFilter
*
* @see \Drupal\replication\Plugin\ReplicationFilterInterface
* @see \Drupal\replication\Plugin\ReplicationFilterManager
* @see plugin_api
*
* @Annotation
*/
class ReplicationFilter extends Plugin {

/**
* The plugin ID.
*
* @var string
*/
public $id;

/**
* The human-readable name of the ReplicationFilter plugin.
*
* @var \Drupal\Core\Annotation\Translation
*
* @ingroup plugin_translatable
*/
public $label;

/**
* A short description of the ReplicationFilter plugin.
*
* @var \Drupal\Core\Annotation\Translation
*
* @ingroup plugin_translatable
*/
public $description;

}
85 changes: 73 additions & 12 deletions src/Changes/Changes.php
@@ -1,27 +1,25 @@
<?php

/**
* @file
* Contains \Drupal\replication\Changes\Changes.
*/

namespace Drupal\replication\Changes;

use Drupal\Core\DependencyInjection\DependencySerializationTrait;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\multiversion\Entity\Index\SequenceIndexInterface;
use Drupal\multiversion\Entity\WorkspaceInterface;
use Drupal\replication\Plugin\ReplicationFilterManagerInterface;
// @todo where is the ParameterBagInterface???
use Symfony\Component\HttpFoundation\ParameterBag;
use Symfony\Component\Serializer\SerializerInterface;
use Drupal\Core\DependencyInjection\DependencySerializationTrait;

/**
* @todo {@link https://www.drupal.org/node/2282295 Implement remaining feed
* query types.}
* {@inheritdoc}
*/
class Changes implements ChangesInterface {
use DependencySerializationTrait;

/**
* @var string
* The workspace to generate the changeset from.
*/
protected $workspaceId;

Expand All @@ -35,13 +33,32 @@ class Changes implements ChangesInterface {
*/
protected $serializer;

/**
* @var \Drupal\replication\Plugin\ReplicationFilterManagerInterface
*/
protected $filterManager;

/**
* @var string
* The id of the filter plugin to use during replication.
*/
protected $filterName;

/**
* @var ParameterBag
* The parameters passed to the filter function.
*/
protected $parameters;

/**
* @var boolean
* Whether to include entities in the changeset.
*/
protected $includeDocs = FALSE;

/**
* @var int
* The sequence ID to start including changes from. Result includes $lastSeq.
*/
protected $lastSeq = 0;

Expand All @@ -50,19 +67,38 @@ class Changes implements ChangesInterface {
* @param \Drupal\multiversion\Entity\WorkspaceInterface $workspace
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* @param \Symfony\Component\Serializer\SerializerInterface $serializer
* @param \Drupal\replication\Plugin\ReplicationFilterManagerInterface $filter_manager
*/
public function __construct(SequenceIndexInterface $sequence_index, WorkspaceInterface $workspace, EntityTypeManagerInterface $entity_type_manager, SerializerInterface $serializer) {
public function __construct(SequenceIndexInterface $sequence_index, WorkspaceInterface $workspace, EntityTypeManagerInterface $entity_type_manager, SerializerInterface $serializer, ReplicationFilterManagerInterface $filter_manager) {
$this->sequenceIndex = $sequence_index;
$this->workspaceId = $workspace->id();
$this->entityTypeManager = $entity_type_manager;
$this->serializer = $serializer;
$this->filterManager = $filter_manager;
}

/**
* {@inheritdoc}
*/
public function filter($filter_name) {
$this->filterName = $filter_name;
return $this;
}

/**
* {@inheritdoc}
*/
public function parameters(ParameterBag $parameters) {
$this->parameters = $parameters;
return $this;
}

/**
* {@inheritdoc}
*/
public function includeDocs($include_docs) {
$this->includeDocs = $include_docs;
return $this;
}

/**
Expand All @@ -81,13 +117,39 @@ public function getNormal() {
->useWorkspace($this->workspaceId)
->getRange($this->lastSeq, NULL);

// Setup filter plugin.
$parameters = ($this->parameters instanceof ParameterBag) ? $this->parameters : new ParameterBag();
$filter = NULL;
if (is_string($this->filterName) && $this->filterName) {
$filter = $this->filterManager->createInstance($this->filterName);
}
// If UUIDs are sent as a parameter, but no filter is set, automatically
// select the "uuid" filter.
elseif ($parameters->has('uuids')) {
$filter = $this->filterManager->createInstance('uuid');
}

// Format the result array.
$changes = array();
foreach ($sequences as $sequence) {
if (!empty($sequence['local']) || !empty($sequence['is_stub'])) {
continue;
}

// Get the document.
$revision = NULL;
if ($this->includeDocs == TRUE || $filter !== NULL) {
/** @var \Drupal\multiversion\Entity\Storage\ContentEntityStorageInterface $storage */
$storage = $this->entityTypeManager->getStorage($sequence['entity_type_id']);
$storage->useWorkspace($this->workspaceId);
$revision = $storage->loadRevision($sequence['revision_id']);
}

// Filter the document.
if ($filter !== NULL && !$filter->filter($revision, $parameters)) {
continue;
}

$uuid = $sequence['entity_uuid'];
$changes[$uuid] = array(
'changes' => array(
Expand All @@ -99,10 +161,9 @@ public function getNormal() {
if ($sequence['deleted']) {
$changes[$uuid]['deleted'] = TRUE;
}

// Include the document.
if ($this->includeDocs == TRUE) {
/** @var \Drupal\multiversion\Entity\Storage\ContentEntityStorageInterface $storage */
$storage = $this->entityTypeManager->getStorage($sequence['entity_type_id']);
$revision = $storage->loadRevision($sequence['revision_id']);
$changes[$uuid]['doc'] = $this->serializer->normalize($revision);
}
}
Expand Down
50 changes: 41 additions & 9 deletions src/Changes/ChangesInterface.php
@@ -1,29 +1,61 @@
<?php

/**
* @file
* Contains \Drupal\replication\Changes\ChangesInterface.
*/

namespace Drupal\replication\Changes;

use Drupal\multiversion\Entity\Index\SequenceIndexInterface;
use Drupal\multiversion\Entity\WorkspaceInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\ParameterBag;

/**
* Define and build a changeset for a Workspace.
*
* @todo {@link https://www.drupal.org/node/2282295 Implement remaining feed
* query types.}
* @todo break this class into a value object and a service object: one that
* defines the parameters for getting the changeset and the other for executing
* the code to build the changeset
*/
interface ChangesInterface {

/**
* @param boolean $include_docs
* Set the id of the filter plugin to use to refine the changeset.
*
* @param string $filter_name
* The plugin id of a Drupal\replication\Plugin\ReplicationFilterInterface.
*
* @return \Drupal\replication\Changes\ChangesInterface
* Returns $this.
*/
public function filter($filter_name);

/**
* Set the parameters for the filter plugin.
*
* @param ParameterBag $parameters
* The parameters passed to the filter function.
*
* @return \Drupal\replication\Changes\ChangesInterface
* Returns $this.
*/
public function parameters(ParameterBag $parameters);

/**
* Set the flag for including entities in the changeset.
*
* @param bool $include_docs
* Whether to include entities in the changeset.
*
* @return \Drupal\replication\Changes\ChangesInterface
* Returns $this.
*/
public function includeDocs($include_docs);

/**
* Sets from what sequence number to check for changes.
*
* @param int $seq
* The sequence ID to start including changes from. Result includes $seq.
*
* @return \Drupal\replication\Changes\ChangesInterface
* Returns $this.
*/
public function lastSeq($seq);

Expand Down
13 changes: 11 additions & 2 deletions src/ChangesFactory.php
Expand Up @@ -6,6 +6,7 @@
use Drupal\multiversion\Entity\Index\SequenceIndexInterface;
use Drupal\multiversion\Entity\WorkspaceInterface;
use Drupal\replication\Changes\Changes;
use Drupal\replication\Plugin\ReplicationFilterManagerInterface;
use Symfony\Component\Serializer\SerializerInterface;

class ChangesFactory implements ChangesFactoryInterface {
Expand All @@ -25,6 +26,11 @@ class ChangesFactory implements ChangesFactoryInterface {
*/
protected $serializer;

/**
* @var \Drupal\replication\Plugin\ReplicationFilterManagerInterface
*/
protected $filterManager;

/**
* @var \Drupal\replication\Changes\Changes[]
*/
Expand All @@ -34,11 +40,13 @@ class ChangesFactory implements ChangesFactoryInterface {
* @param \Drupal\multiversion\Entity\Index\SequenceIndexInterface $sequence_index
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* @param \Symfony\Component\Serializer\SerializerInterface $serializer
* @param \Drupal\replication\Plugin\ReplicationFilterManagerInterface $filter_manager
*/
public function __construct(SequenceIndexInterface $sequence_index, EntityTypeManagerInterface $entity_type_manager, SerializerInterface $serializer) {
public function __construct(SequenceIndexInterface $sequence_index, EntityTypeManagerInterface $entity_type_manager, SerializerInterface $serializer, ReplicationFilterManagerInterface $filter_manager) {
$this->sequenceIndex = $sequence_index;
$this->entityTypeManager = $entity_type_manager;
$this->serializer = $serializer;
$this->filterManager = $filter_manager;
}

/**
Expand All @@ -50,7 +58,8 @@ public function get(WorkspaceInterface $workspace) {
$this->sequenceIndex,
$workspace,
$this->entityTypeManager,
$this->serializer
$this->serializer,
$this->filterManager
);
}
return $this->instances[$workspace->id()];
Expand Down
38 changes: 38 additions & 0 deletions src/Plugin/ReplicationFilter/EntityTypeFilter.php
@@ -0,0 +1,38 @@
<?php

namespace Drupal\replication\Plugin\ReplicationFilter;

use Drupal\Core\Entity\EntityInterface;
use Drupal\replication\Plugin\ReplicationFilter\ReplicationFilterBase;
use Symfony\Component\HttpFoundation\ParameterBag;

/**
* Provides a filter based on entity type.
*
* Supported parameters:
* entity_type: a comma delimited list of entity type id's to include
*
* @ReplicationFilter(
* id = "entity_type",
* label = @Translation("Filter By Entity Type"),
* description = @Translation("Replicate only entities that match a given type.")
* )
*/
class EntityTypeFilter extends ReplicationFilterBase {

/**
* {@inheritdoc}
*/
public function filter(EntityInterface $entity, ParameterBag $parameters) {
if ($parameters->has('entity_type')) {
$types = $parameters->get('entity_type');
}
else {
$types = '';
}
$types = explode(',', $types);
$types = array_filter(array_map('trim', $types));
return in_array($entity->bundle(), $types);
}

}