Skip to content

Commit 0c13878

Browse files
authored
Added content fields comparison to ignore updates that would result in no change (#26)
1 parent 8b29a92 commit 0c13878

21 files changed

Lines changed: 629 additions & 9 deletions

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
# Version 2.2.0
2+
* added `NotModifiedContentFilter` and a bunch of `FieldComparator` classes
3+
14
# version 2.1.0
25
* contentWriter return created content
36

README.md

Lines changed: 78 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ class MyDataflowType extends AbstractDataflowType
178178
/**
179179
* @var ContentStructureFactory
180180
*/
181-
private contentStructureFactory;
181+
private $contentStructureFactory;
182182
183183
public function __construct(ContentWriter $contentWriter, ContentStructureFactory $contentStructureFactory)
184184
{
@@ -213,6 +213,83 @@ class MyDataflowType extends AbstractDataflowType
213213

214214
This example uses `ContentStructureFactory` to check if the content exists and returns the adequate `ContentStrucure` to pass to the content writer.
215215

216+
## Use the NotModifiedContentFilter
217+
218+
When updating contents, you might want to ignore contents where the update would not result in any actual changes in fields values. In that case, you can add the `NotModifiedContentFilter` as one of your steps.
219+
220+
```php
221+
// In your DataflowType
222+
public function __construct(NotModifiedContentFilter $notModifiedContentFilter)
223+
{
224+
$this->notModifiedContentFilter = $notModifiedContentFilter;
225+
}
226+
227+
//[...]
228+
protected function buildDataflow(DataflowBuilder $builder, array $options): void
229+
{
230+
//[...]
231+
$builder->addStep($this->notModifiedContentFilter);
232+
//[...]
233+
}
234+
```
235+
236+
This filter compares each field value in the `ContentUpdateStructure` received to the fields values in the existing content object. If all values are identical, this filter will return `false`, otherwise, the `ContentUpdateStructure` will be returned as is.
237+
238+
Not all field types are supported by this filter. Il a field type is not supported, values will be assumed different. If your dataflow is dealing with content types containing unsupported field types, it is better to simply not use the `NotModifiedContentFilter` to prevent unnecessary overhead.
239+
240+
### Supported field types
241+
- ezstring
242+
- ezauthor
243+
- ezboolean
244+
- ezcountry
245+
- ezdate
246+
- ezdatetime
247+
- ezemail
248+
- ezfloat
249+
- ezisbn
250+
- ezobjectrelation
251+
- ezobjectrelationlist
252+
- ezkeyword
253+
- ezselection
254+
- eztext
255+
- eztime
256+
- eztags
257+
- novaseometas
258+
- ezurl
259+
- ezmatrix
260+
- ezgmaplocation
261+
- ezrichtext
262+
263+
### Add custom field comparator
264+
265+
If you want to add support for a field type, simply create your own comparator.
266+
267+
```php
268+
<?php
269+
270+
use CodeRhapsodie\EzDataflowBundle\Core\FieldComparator\AbstractFieldComparator;
271+
use eZ\Publish\Core\FieldType\Value;
272+
//[...]
273+
274+
class MyFieldComparator extends AbstractFieldComparator
275+
{
276+
//[...]
277+
protected function compareValues(Value $currentValue, Value $newValue): bool
278+
{
279+
// Return true if values are identical, false if values are different.
280+
}
281+
}
282+
283+
```
284+
285+
```yaml
286+
# Service declaration
287+
App\FieldComparator\MyFieldComparator:
288+
parent: 'CodeRhapsodie\EzDataflowBundle\Core\FieldComparator\AbstractFieldComparator'
289+
tags:
290+
- { name: 'coderhapsodie.ezdataflow.field_comparator', fieldType: 'my_field_type_identifier' }
291+
```
292+
216293
# Admin UI
217294

218295
## Access to the eZ Dataflow UI

composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@
4141
}
4242
},
4343
"require": {
44-
"code-rhapsodie/dataflow-bundle": "^2.0 || dev-master",
44+
"php": "^7.1",
45+
"code-rhapsodie/dataflow-bundle": "^2.1 || dev-master",
4546
"ezsystems/ezplatform-admin-ui": "^1.0",
4647
"ezsystems/ezpublish-kernel": "^7.0"
4748
},

phpunit.xml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<phpunit
55
backupGlobals="false"
66
backupStaticAttributes="false"
7-
bootstrap="Tests/bootstrap.php"
7+
bootstrap="tests/bootstrap.php"
88
convertErrorsToExceptions="true"
99
convertNoticesToExceptions="true"
1010
convertWarningsToExceptions="true"
@@ -14,16 +14,16 @@
1414
<ini name="error_reporting" value="-1" />
1515
</php>
1616
<testsuites>
17-
<testsuite name="Port tests suite">
18-
<directory suffix="Test.php">./Tests</directory>
17+
<testsuite name="EzDataflow tests suite">
18+
<directory suffix="Test.php">./tests</directory>
1919
</testsuite>
2020
</testsuites>
2121

2222
<filter>
2323
<whitelist>
24-
<directory>./</directory>
24+
<directory>./src/</directory>
2525
<exclude>
26-
<directory>Tests/</directory>
26+
<directory>tests/</directory>
2727
<directory>vendor/</directory>
2828
</exclude>
2929
</whitelist>

src/CodeRhapsodieEzDataflowBundle.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
namespace CodeRhapsodie\EzDataflowBundle;
66

77
use CodeRhapsodie\EzDataflowBundle\DependencyInjection\CodeRhapsodieEzDataflowExtension;
8+
use CodeRhapsodie\EzDataflowBundle\DependencyInjection\Compiler\FieldComparatorCompilerPass;
89
use CodeRhapsodie\EzDataflowBundle\Security\PolicyProvider;
910
use eZ\Bundle\EzPublishCoreBundle\DependencyInjection\EzPublishCoreExtension;
1011
use Symfony\Component\DependencyInjection\ContainerBuilder;
@@ -23,6 +24,8 @@ public function build(ContainerBuilder $container)
2324
{
2425
parent::build($container);
2526

27+
$container->addCompilerPass(new FieldComparatorCompilerPass());
28+
2629
/** @var EzPublishCoreExtension $eZExtension */
2730
$eZExtension = $container->getExtension('ezpublish');
2831
$eZExtension->addPolicyProvider(new PolicyProvider());
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace CodeRhapsodie\EzDataflowBundle\Core\FieldComparator;
6+
7+
use eZ\Publish\API\Repository\FieldTypeService;
8+
use eZ\Publish\API\Repository\Values\Content\Field;
9+
use eZ\Publish\Core\FieldType\Value;
10+
11+
abstract class AbstractFieldComparator implements FieldComparatorInterface
12+
{
13+
/** @var FieldTypeService */
14+
private $fieldTypeService;
15+
16+
public function __construct(FieldTypeService $fieldTypeService)
17+
{
18+
$this->fieldTypeService = $fieldTypeService;
19+
}
20+
21+
public function compare(Field $field, $hash): bool
22+
{
23+
$newValue = $this->fieldTypeService->getFieldType($field->fieldTypeIdentifier)->fromHash($hash);
24+
25+
return $this->compareValues($field->value, $newValue);
26+
}
27+
28+
/**
29+
* Returns true if values are equals, false otherwise
30+
*/
31+
abstract protected function compareValues(Value $currentValue, Value $newValue): bool;
32+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace CodeRhapsodie\EzDataflowBundle\Core\FieldComparator;
6+
7+
use eZ\Publish\API\Repository\Values\Content\Field;
8+
9+
class DelegatorFieldComparator implements FieldComparatorInterface
10+
{
11+
/** @var FieldComparatorInterface[] */
12+
private $delegates;
13+
14+
/**
15+
* FieldComparator constructor.
16+
*/
17+
public function __construct()
18+
{
19+
$this->delegates = [];
20+
}
21+
22+
public function compare(Field $field, $hash): bool
23+
{
24+
if (isset($this->delegates[$field->fieldTypeIdentifier])) {
25+
return $this->delegates[$field->fieldTypeIdentifier]->compare($field, $hash);
26+
}
27+
28+
// No comparator to handle this field type, we assume the value is different.
29+
return false;
30+
}
31+
32+
public function registerDelegateFieldComparator(FieldComparatorInterface $typedFieldComparator, string $fieldTypeIdentifier): void
33+
{
34+
$this->delegates[$fieldTypeIdentifier] = $typedFieldComparator;
35+
}
36+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace CodeRhapsodie\EzDataflowBundle\Core\FieldComparator;
6+
7+
use eZ\Publish\API\Repository\Values\Content\Field;
8+
9+
interface FieldComparatorInterface
10+
{
11+
/**
12+
* @return bool true if identical, false otherwise
13+
*/
14+
public function compare(Field $field, $hash): bool;
15+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace CodeRhapsodie\EzDataflowBundle\Core\FieldComparator;
6+
7+
use eZ\Publish\Core\FieldType\Value;
8+
9+
class MapLocationFieldComparator extends AbstractFieldComparator
10+
{
11+
protected function compareValues(Value $currentValue, Value $newValue): bool
12+
{
13+
return (string) $currentValue === (string) $newValue
14+
&& (float) $currentValue->longitude === (float) $newValue->longitude
15+
&& (float) $currentValue->latitude === (float) $newValue->latitude
16+
;
17+
}
18+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace CodeRhapsodie\EzDataflowBundle\Core\FieldComparator;
6+
7+
use eZ\Publish\Core\FieldType\Value;
8+
9+
class MatrixFieldComparator extends AbstractFieldComparator
10+
{
11+
protected function compareValues(Value $currentValue, Value $newValue): bool
12+
{
13+
if (count($currentValue->rows) !== count($newValue->rows)) {
14+
return false;
15+
}
16+
17+
foreach ($newValue->rows as $index => $row) {
18+
if (count($currentValue->rows[$index]->getCells()) !== count($row->getCells())) {
19+
return false;
20+
}
21+
22+
if (!empty(array_diff_assoc($currentValue->rows[$index]->getCells(), $row->getCells()))) {
23+
return false;
24+
}
25+
}
26+
27+
return true;
28+
}
29+
}

0 commit comments

Comments
 (0)