mirror of
https://github.com/code-rhapsodie/ezdataflow-bundle.git
synced 2026-03-24 06:32:06 +01:00
Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0c13878f79 | ||
|
|
8b29a92aab | ||
|
|
c824c0ecbb | ||
|
|
760aea3948 | ||
|
|
e1213d4a74 | ||
|
|
5f3775cb6b | ||
|
|
ec42d6f765 | ||
|
|
deab8e8073 | ||
|
|
ca37b2438d | ||
|
|
d166f3aea8 | ||
|
|
9ed5fd3c2b | ||
|
|
f98fecdca9 |
24
CHANGELOG.md
Normal file
24
CHANGELOG.md
Normal file
@@ -0,0 +1,24 @@
|
||||
# Version 2.2.0
|
||||
* added `NotModifiedContentFilter` and a bunch of `FieldComparator` classes
|
||||
|
||||
# version 2.1.0
|
||||
* contentWriter return created content
|
||||
|
||||
# version 2.0.1
|
||||
|
||||
* Enclosure js code into anonymous function
|
||||
|
||||
# version 2.0.0
|
||||
|
||||
* Update to use Dataflow v2.0+
|
||||
* Add compiler pass to change the Dataflow DBAL connection factory
|
||||
* Use the DBAL connection from siteaccess
|
||||
* Add `mode` argument on `ContentStructureFactory::transform()` function
|
||||
* Add `CodeRhapsodie\EzDataflowBundle\Factory\ContentStructureFactoryInterface`
|
||||
|
||||
# version 1.0.0
|
||||
|
||||
* Initial version to use Dataflow v1.0+ into eZ Platform
|
||||
* Add Admin UI
|
||||
* Add content writer
|
||||
* Add content structure
|
||||
91
README.md
91
README.md
@@ -6,6 +6,8 @@ EzDataflow bundle is intended to manage content imports from external data sourc
|
||||
|
||||
> Note: before using this bundle, please read the [Code Rhapsodie Dataflow bundle documentation](https://github.com/code-rhapsodie/dataflow-bundle/blob/master/README.md).
|
||||
|
||||
> Command line notice: When you use Dataflow commands, **use `--siteaccess` instead of `--connection`** expect for `code-rhapsodie:dataflow:dump-schema` command.
|
||||
|
||||
## User Interface (UI)
|
||||
|
||||
The UI lets you create workflow processes from any defined `DataflowTypes`, and set options to each.
|
||||
@@ -24,6 +26,8 @@ $ composer require code-rhapsodie/ezdataflow-bundle
|
||||
|
||||
### Step 2: Enable the bundle
|
||||
|
||||
> Note: The loading order between the Dataflow bundle and Ez Dataflow bundle is important. Dataflow must be loaded first.
|
||||
|
||||
#### Symfony 4 (new tree)
|
||||
|
||||
For Symfony 4, add those two lines in the `config/bundles.php` file:
|
||||
@@ -174,7 +178,7 @@ class MyDataflowType extends AbstractDataflowType
|
||||
/**
|
||||
* @var ContentStructureFactory
|
||||
*/
|
||||
private contentStructureFactory;
|
||||
private $contentStructureFactory;
|
||||
|
||||
public function __construct(ContentWriter $contentWriter, ContentStructureFactory $contentStructureFactory)
|
||||
{
|
||||
@@ -198,7 +202,8 @@ class MyDataflowType extends AbstractDataflowType
|
||||
$remoteId,
|
||||
'eng-GB',
|
||||
'article2',
|
||||
54 //Parent location id
|
||||
54, //Parent location id
|
||||
ContentStructureFactoryInterface::MODE_INSERT_OR_UPDATE //Optional value. Other choice : ContentStructureFactoryInterface::MODE_INSERT_ONLY or ContentStructureFactoryInterface::MODE_UPDATE_ONLY
|
||||
);
|
||||
});
|
||||
$builder->addWriter($this->contentWriter);
|
||||
@@ -208,6 +213,83 @@ class MyDataflowType extends AbstractDataflowType
|
||||
|
||||
This example uses `ContentStructureFactory` to check if the content exists and returns the adequate `ContentStrucure` to pass to the content writer.
|
||||
|
||||
## Use the NotModifiedContentFilter
|
||||
|
||||
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.
|
||||
|
||||
```php
|
||||
// In your DataflowType
|
||||
public function __construct(NotModifiedContentFilter $notModifiedContentFilter)
|
||||
{
|
||||
$this->notModifiedContentFilter = $notModifiedContentFilter;
|
||||
}
|
||||
|
||||
//[...]
|
||||
protected function buildDataflow(DataflowBuilder $builder, array $options): void
|
||||
{
|
||||
//[...]
|
||||
$builder->addStep($this->notModifiedContentFilter);
|
||||
//[...]
|
||||
}
|
||||
```
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
### Supported field types
|
||||
- ezstring
|
||||
- ezauthor
|
||||
- ezboolean
|
||||
- ezcountry
|
||||
- ezdate
|
||||
- ezdatetime
|
||||
- ezemail
|
||||
- ezfloat
|
||||
- ezisbn
|
||||
- ezobjectrelation
|
||||
- ezobjectrelationlist
|
||||
- ezkeyword
|
||||
- ezselection
|
||||
- eztext
|
||||
- eztime
|
||||
- eztags
|
||||
- novaseometas
|
||||
- ezurl
|
||||
- ezmatrix
|
||||
- ezgmaplocation
|
||||
- ezrichtext
|
||||
|
||||
### Add custom field comparator
|
||||
|
||||
If you want to add support for a field type, simply create your own comparator.
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
use CodeRhapsodie\EzDataflowBundle\Core\FieldComparator\AbstractFieldComparator;
|
||||
use eZ\Publish\Core\FieldType\Value;
|
||||
//[...]
|
||||
|
||||
class MyFieldComparator extends AbstractFieldComparator
|
||||
{
|
||||
//[...]
|
||||
protected function compareValues(Value $currentValue, Value $newValue): bool
|
||||
{
|
||||
// Return true if values are identical, false if values are different.
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
```yaml
|
||||
# Service declaration
|
||||
App\FieldComparator\MyFieldComparator:
|
||||
parent: 'CodeRhapsodie\EzDataflowBundle\Core\FieldComparator\AbstractFieldComparator'
|
||||
tags:
|
||||
- { name: 'coderhapsodie.ezdataflow.field_comparator', fieldType: 'my_field_type_identifier' }
|
||||
```
|
||||
|
||||
# Admin UI
|
||||
|
||||
## Access to the eZ Dataflow UI
|
||||
@@ -297,6 +379,10 @@ Go to the eZ Dataflow admin UI and click on the "Oneshot" tab. Click on the "+"
|
||||
|
||||
Finally, click on the "Create" button.
|
||||
|
||||
# Rights
|
||||
|
||||
If a non-administrator user needs read-only access to the dataflow interface, add the `Setup / Administrate` and `eZ Dataflow / View` policies in one of their roles.
|
||||
|
||||
# Issues and feature requests
|
||||
|
||||
Please report issues and request features at https://github.com/code-rhapsodie/ezdataflow-bundle/issues.
|
||||
@@ -310,4 +396,3 @@ already.
|
||||
# License
|
||||
|
||||
This package is licensed under the [MIT license](LICENSE).
|
||||
|
||||
|
||||
15
UPGRADE.md
Normal file
15
UPGRADE.md
Normal file
@@ -0,0 +1,15 @@
|
||||
# From v1.0 to v2.0
|
||||
|
||||
When you use Dataflow commands, use `--siteaccess` instead of `--connection` except for `code-rhapsodie:dataflow:dump-schema`.
|
||||
|
||||
[BC] The return of `CodeRhapsodie\EzDataflowBundle\Gateway\JobGateway::findForScheduled`
|
||||
and `CodeRhapsodie\EzDataflowBundle\Gateway\ScheduledDataflowGateway::findAllOrderedByLabel` has been changed.
|
||||
The iterable contains an associative array instead of an object.
|
||||
|
||||
[BC] In classes `CodeRhapsodie\EzDataflowBundle\Gateway\JobGateway` and
|
||||
`CodeRhapsodie\EzDataflowBundle\Gateway\ScheduledDataflowGateway`, all methods return `Doctrine\ORM\Query` object has
|
||||
changed to return now a `Doctrine\DBAL\Query\QueryBuilder`
|
||||
|
||||
[BC] The return type of `CodeRhapsodie\EzDataflowBundle\Factory\ContentStructureFactory::transform` has been changed
|
||||
from `CodeRhapsodie\EzDataflowBundle\Model\ContentStructure` to `mixed`. In fact only `false` or
|
||||
`CodeRhapsodie\EzDataflowBundle\Model\ContentStructure` object will be returned.
|
||||
@@ -41,13 +41,14 @@
|
||||
}
|
||||
},
|
||||
"require": {
|
||||
"code-rhapsodie/dataflow-bundle": "^1.0 || dev-master",
|
||||
"php": "^7.1",
|
||||
"code-rhapsodie/dataflow-bundle": "^2.1 || dev-master",
|
||||
"ezsystems/ezplatform-admin-ui": "^1.0",
|
||||
"ezsystems/ezpublish-kernel": "^7.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^7||^8",
|
||||
"doctrine/orm": "^2.4.5"
|
||||
"doctrine/dbal": "^2.0"
|
||||
},
|
||||
"minimum-stability": "dev",
|
||||
"prefer-stable": true,
|
||||
@@ -56,7 +57,8 @@
|
||||
},
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.x-dev"
|
||||
"dev-master": "2.x-dev",
|
||||
"dev-v1.x": "1.x-dev"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
10
phpunit.xml
10
phpunit.xml
@@ -4,7 +4,7 @@
|
||||
<phpunit
|
||||
backupGlobals="false"
|
||||
backupStaticAttributes="false"
|
||||
bootstrap="Tests/bootstrap.php"
|
||||
bootstrap="tests/bootstrap.php"
|
||||
convertErrorsToExceptions="true"
|
||||
convertNoticesToExceptions="true"
|
||||
convertWarningsToExceptions="true"
|
||||
@@ -14,16 +14,16 @@
|
||||
<ini name="error_reporting" value="-1" />
|
||||
</php>
|
||||
<testsuites>
|
||||
<testsuite name="Port tests suite">
|
||||
<directory suffix="Test.php">./Tests</directory>
|
||||
<testsuite name="EzDataflow tests suite">
|
||||
<directory suffix="Test.php">./tests</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
|
||||
<filter>
|
||||
<whitelist>
|
||||
<directory>./</directory>
|
||||
<directory>./src/</directory>
|
||||
<exclude>
|
||||
<directory>Tests/</directory>
|
||||
<directory>tests/</directory>
|
||||
<directory>vendor/</directory>
|
||||
</exclude>
|
||||
</whitelist>
|
||||
|
||||
@@ -5,6 +5,7 @@ declare(strict_types=1);
|
||||
namespace CodeRhapsodie\EzDataflowBundle;
|
||||
|
||||
use CodeRhapsodie\EzDataflowBundle\DependencyInjection\CodeRhapsodieEzDataflowExtension;
|
||||
use CodeRhapsodie\EzDataflowBundle\DependencyInjection\Compiler\FieldComparatorCompilerPass;
|
||||
use CodeRhapsodie\EzDataflowBundle\Security\PolicyProvider;
|
||||
use eZ\Bundle\EzPublishCoreBundle\DependencyInjection\EzPublishCoreExtension;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
@@ -23,6 +24,8 @@ class CodeRhapsodieEzDataflowBundle extends Bundle
|
||||
{
|
||||
parent::build($container);
|
||||
|
||||
$container->addCompilerPass(new FieldComparatorCompilerPass());
|
||||
|
||||
/** @var EzPublishCoreExtension $eZExtension */
|
||||
$eZExtension = $container->getExtension('ezpublish');
|
||||
$eZExtension->addPolicyProvider(new PolicyProvider());
|
||||
|
||||
@@ -10,11 +10,11 @@ use CodeRhapsodie\EzDataflowBundle\Gateway\JobGateway;
|
||||
use CodeRhapsodie\EzDataflowBundle\Gateway\ScheduledDataflowGateway;
|
||||
use CodeRhapsodie\DataflowBundle\Entity\Job;
|
||||
use CodeRhapsodie\DataflowBundle\Entity\ScheduledDataflow;
|
||||
use Doctrine\ORM\Query;
|
||||
use Doctrine\DBAL\Query\QueryBuilder;
|
||||
use eZ\Publish\Core\MVC\Symfony\Security\Authorization\Attribute;
|
||||
use EzSystems\EzPlatformAdminUi\Notification\NotificationHandlerInterface;
|
||||
use EzSystems\EzPlatformAdminUiBundle\Controller\Controller;
|
||||
use Pagerfanta\Adapter\DoctrineORMAdapter;
|
||||
use Pagerfanta\Adapter\DoctrineDbalAdapter;
|
||||
use Pagerfanta\Pagerfanta;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
@@ -51,7 +51,7 @@ class DashboardController extends Controller
|
||||
return $this->render('@ezdesign/ezdataflow/Dashboard/main.html.twig');
|
||||
}
|
||||
|
||||
public function repeating(): Response
|
||||
public function repeating(Request $request): Response
|
||||
{
|
||||
$this->denyAccessUnlessGranted(new Attribute('ezdataflow', 'view'));
|
||||
|
||||
@@ -62,11 +62,27 @@ class DashboardController extends Controller
|
||||
]);
|
||||
|
||||
return $this->render('@ezdesign/ezdataflow/Dashboard/repeating.html.twig', [
|
||||
'items' => $this->scheduledDataflowGateway->findAllOrderedByLabel(),
|
||||
'pager' => $this->getPager($this->scheduledDataflowGateway->getListQueryForAdmin(), $request),
|
||||
'form' => $form->createView(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Route("/repeating", name="coderhapsodie.ezdataflow.repeating")
|
||||
*
|
||||
* @param Request $request
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function getRepeatingPage(Request $request): Response
|
||||
{
|
||||
$this->denyAccessUnlessGranted(new Attribute('ezdataflow', 'view'));
|
||||
|
||||
return $this->render('@ezdesign/ezdataflow/Dashboard/repeating.html.twig', [
|
||||
'pager' => $this->getPager($this->scheduledDataflowGateway->getListQueryForAdmin(), $request),
|
||||
]);
|
||||
}
|
||||
|
||||
public function oneshot(Request $request): Response
|
||||
{
|
||||
$this->denyAccessUnlessGranted(new Attribute('ezdataflow', 'view'));
|
||||
@@ -142,9 +158,12 @@ class DashboardController extends Controller
|
||||
]);
|
||||
}
|
||||
|
||||
private function getPager(Query $query, Request $request): Pagerfanta
|
||||
private function getPager(QueryBuilder $query, Request $request): Pagerfanta
|
||||
{
|
||||
$pager = new Pagerfanta(new DoctrineORMAdapter($query));
|
||||
$pager = new Pagerfanta(new DoctrineDbalAdapter($query, function ($queryBuilder) {
|
||||
return $queryBuilder->select('COUNT(DISTINCT id) AS total_results')
|
||||
->setMaxResults(1);
|
||||
}));
|
||||
$pager->setMaxPerPage(20);
|
||||
$pager->setCurrentPage($request->query->get('page', 1));
|
||||
|
||||
|
||||
@@ -10,11 +10,12 @@ use CodeRhapsodie\EzDataflowBundle\Gateway\JobGateway;
|
||||
use eZ\Publish\Core\MVC\Symfony\Security\Authorization\Attribute;
|
||||
use EzSystems\EzPlatformAdminUi\Notification\NotificationHandlerInterface;
|
||||
use EzSystems\EzPlatformAdminUiBundle\Controller\Controller;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
||||
use Symfony\Component\Translation\TranslatorInterface;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
|
||||
/**
|
||||
* @Route("/ezdataflow/job")
|
||||
@@ -82,7 +83,8 @@ class JobController extends Controller
|
||||
}
|
||||
|
||||
return new JsonResponse([
|
||||
'redirect' => $this->generateUrl('coderhapsodie.ezdataflow.main', ['_fragment' => 'oneshot']),
|
||||
'redirect' => $this->generateUrl('coderhapsodie.ezdataflow.main', ['_fragment' => 'oneshot'],
|
||||
UrlGeneratorInterface::ABSOLUTE_URL),
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
@@ -13,9 +13,6 @@ class DefaultFieldValueCreator implements FieldValueCreatorInterface
|
||||
/** @var FieldTypeService */
|
||||
private $fieldTypeService;
|
||||
|
||||
/** @var FieldType[] */
|
||||
private $fieldTypes = [];
|
||||
|
||||
public function __construct(FieldTypeService $fieldTypeService)
|
||||
{
|
||||
$this->fieldTypeService = $fieldTypeService;
|
||||
@@ -28,22 +25,6 @@ class DefaultFieldValueCreator implements FieldValueCreatorInterface
|
||||
|
||||
public function createValue(string $fieldTypeIdentifier, $hash): Value
|
||||
{
|
||||
return $this->getFieldType($fieldTypeIdentifier)->fromHash($hash);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $fieldTypeIdentifier
|
||||
*
|
||||
* @return FieldType
|
||||
*
|
||||
* @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException
|
||||
*/
|
||||
private function getFieldType(string $fieldTypeIdentifier): FieldType
|
||||
{
|
||||
if (!isset($this->fieldTypes[$fieldTypeIdentifier])) {
|
||||
$this->fieldTypes[$fieldTypeIdentifier] = $this->fieldTypeService->getFieldType($fieldTypeIdentifier);
|
||||
}
|
||||
|
||||
return $this->fieldTypes[$fieldTypeIdentifier];
|
||||
return $this->fieldTypeService->getFieldType($fieldTypeIdentifier)->fromHash($hash);
|
||||
}
|
||||
}
|
||||
|
||||
32
src/Core/FieldComparator/AbstractFieldComparator.php
Normal file
32
src/Core/FieldComparator/AbstractFieldComparator.php
Normal file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CodeRhapsodie\EzDataflowBundle\Core\FieldComparator;
|
||||
|
||||
use eZ\Publish\API\Repository\FieldTypeService;
|
||||
use eZ\Publish\API\Repository\Values\Content\Field;
|
||||
use eZ\Publish\Core\FieldType\Value;
|
||||
|
||||
abstract class AbstractFieldComparator implements FieldComparatorInterface
|
||||
{
|
||||
/** @var FieldTypeService */
|
||||
private $fieldTypeService;
|
||||
|
||||
public function __construct(FieldTypeService $fieldTypeService)
|
||||
{
|
||||
$this->fieldTypeService = $fieldTypeService;
|
||||
}
|
||||
|
||||
public function compare(Field $field, $hash): bool
|
||||
{
|
||||
$newValue = $this->fieldTypeService->getFieldType($field->fieldTypeIdentifier)->fromHash($hash);
|
||||
|
||||
return $this->compareValues($field->value, $newValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if values are equals, false otherwise
|
||||
*/
|
||||
abstract protected function compareValues(Value $currentValue, Value $newValue): bool;
|
||||
}
|
||||
36
src/Core/FieldComparator/DelegatorFieldComparator.php
Normal file
36
src/Core/FieldComparator/DelegatorFieldComparator.php
Normal file
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CodeRhapsodie\EzDataflowBundle\Core\FieldComparator;
|
||||
|
||||
use eZ\Publish\API\Repository\Values\Content\Field;
|
||||
|
||||
class DelegatorFieldComparator implements FieldComparatorInterface
|
||||
{
|
||||
/** @var FieldComparatorInterface[] */
|
||||
private $delegates;
|
||||
|
||||
/**
|
||||
* FieldComparator constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->delegates = [];
|
||||
}
|
||||
|
||||
public function compare(Field $field, $hash): bool
|
||||
{
|
||||
if (isset($this->delegates[$field->fieldTypeIdentifier])) {
|
||||
return $this->delegates[$field->fieldTypeIdentifier]->compare($field, $hash);
|
||||
}
|
||||
|
||||
// No comparator to handle this field type, we assume the value is different.
|
||||
return false;
|
||||
}
|
||||
|
||||
public function registerDelegateFieldComparator(FieldComparatorInterface $typedFieldComparator, string $fieldTypeIdentifier): void
|
||||
{
|
||||
$this->delegates[$fieldTypeIdentifier] = $typedFieldComparator;
|
||||
}
|
||||
}
|
||||
15
src/Core/FieldComparator/FieldComparatorInterface.php
Normal file
15
src/Core/FieldComparator/FieldComparatorInterface.php
Normal file
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CodeRhapsodie\EzDataflowBundle\Core\FieldComparator;
|
||||
|
||||
use eZ\Publish\API\Repository\Values\Content\Field;
|
||||
|
||||
interface FieldComparatorInterface
|
||||
{
|
||||
/**
|
||||
* @return bool true if identical, false otherwise
|
||||
*/
|
||||
public function compare(Field $field, $hash): bool;
|
||||
}
|
||||
18
src/Core/FieldComparator/MapLocationFieldComparator.php
Normal file
18
src/Core/FieldComparator/MapLocationFieldComparator.php
Normal file
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CodeRhapsodie\EzDataflowBundle\Core\FieldComparator;
|
||||
|
||||
use eZ\Publish\Core\FieldType\Value;
|
||||
|
||||
class MapLocationFieldComparator extends AbstractFieldComparator
|
||||
{
|
||||
protected function compareValues(Value $currentValue, Value $newValue): bool
|
||||
{
|
||||
return (string) $currentValue === (string) $newValue
|
||||
&& (float) $currentValue->longitude === (float) $newValue->longitude
|
||||
&& (float) $currentValue->latitude === (float) $newValue->latitude
|
||||
;
|
||||
}
|
||||
}
|
||||
29
src/Core/FieldComparator/MatrixFieldComparator.php
Normal file
29
src/Core/FieldComparator/MatrixFieldComparator.php
Normal file
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CodeRhapsodie\EzDataflowBundle\Core\FieldComparator;
|
||||
|
||||
use eZ\Publish\Core\FieldType\Value;
|
||||
|
||||
class MatrixFieldComparator extends AbstractFieldComparator
|
||||
{
|
||||
protected function compareValues(Value $currentValue, Value $newValue): bool
|
||||
{
|
||||
if (count($currentValue->rows) !== count($newValue->rows)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ($newValue->rows as $index => $row) {
|
||||
if (count($currentValue->rows[$index]->getCells()) !== count($row->getCells())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!empty(array_diff_assoc($currentValue->rows[$index]->getCells(), $row->getCells()))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
26
src/Core/FieldComparator/NovaSEOMetasFieldComparator.php
Normal file
26
src/Core/FieldComparator/NovaSEOMetasFieldComparator.php
Normal file
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CodeRhapsodie\EzDataflowBundle\Core\FieldComparator;
|
||||
|
||||
use eZ\Publish\Core\FieldType\Value;
|
||||
|
||||
class NovaSEOMetasFieldComparator extends AbstractFieldComparator
|
||||
{
|
||||
protected function compareValues(Value $currentValue, Value $newValue): bool
|
||||
{
|
||||
$map = [];
|
||||
foreach ($currentValue->metas as $meta) {
|
||||
$map[$meta->getName()] = $meta->getContent();
|
||||
}
|
||||
|
||||
foreach ($newValue->metas as $meta) {
|
||||
if (!isset($map[$meta->getName()]) || $map[$meta->getName()] !== $meta->getContent()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return count($currentValue->metas) === count($newValue->metas);
|
||||
}
|
||||
}
|
||||
15
src/Core/FieldComparator/SimpleFieldComparator.php
Normal file
15
src/Core/FieldComparator/SimpleFieldComparator.php
Normal file
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CodeRhapsodie\EzDataflowBundle\Core\FieldComparator;
|
||||
|
||||
use eZ\Publish\Core\FieldType\Value;
|
||||
|
||||
class SimpleFieldComparator extends AbstractFieldComparator
|
||||
{
|
||||
protected function compareValues(Value $currentValue, Value $newValue): bool
|
||||
{
|
||||
return (string) $currentValue === (string) $newValue;
|
||||
}
|
||||
}
|
||||
15
src/Core/FieldComparator/UrlFieldComparator.php
Normal file
15
src/Core/FieldComparator/UrlFieldComparator.php
Normal file
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CodeRhapsodie\EzDataflowBundle\Core\FieldComparator;
|
||||
|
||||
use eZ\Publish\Core\FieldType\Value;
|
||||
|
||||
class UrlFieldComparator extends AbstractFieldComparator
|
||||
{
|
||||
protected function compareValues(Value $currentValue, Value $newValue): bool
|
||||
{
|
||||
return $currentValue->link === $newValue->link && $currentValue->text === $newValue->text;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CodeRhapsodie\EzDataflowBundle\DependencyInjection\Compiler;
|
||||
|
||||
use CodeRhapsodie\EzDataflowBundle\Core\FieldComparator\DelegatorFieldComparator;
|
||||
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
|
||||
class FieldComparatorCompilerPass implements CompilerPassInterface
|
||||
{
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
if (!$container->has(DelegatorFieldComparator::class)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$delegatorDef = $container->findDefinition(DelegatorFieldComparator::class);
|
||||
|
||||
foreach ($container->findTaggedServiceIds('coderhapsodie.ezdataflow.field_comparator') as $id => $tags) {
|
||||
foreach ($tags as $attributes) {
|
||||
if (!isset($attributes['fieldType'])) {
|
||||
throw new \InvalidArgumentException(sprintf('Service "%s" must define the "fieldType" attribute on "coderhapsodie.ezdataflow.field_comparator" tags.', $id));
|
||||
}
|
||||
|
||||
$delegatorDef->addMethodCall(
|
||||
'registerDelegateFieldComparator',
|
||||
[new Reference($id), $attributes['fieldType']]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,7 @@ use CodeRhapsodie\EzDataflowBundle\Model\ContentUpdateStructure;
|
||||
use eZ\Publish\API\Repository\ContentService;
|
||||
use eZ\Publish\API\Repository\Exceptions\NotFoundException;
|
||||
|
||||
class ContentStructureFactory
|
||||
final class ContentStructureFactory implements ContentStructureFactoryInterface
|
||||
{
|
||||
/**
|
||||
* @var ContentService
|
||||
@@ -28,27 +28,35 @@ class ContentStructureFactory
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @param string $remoteId
|
||||
* @param string $language
|
||||
* @param string $contentType
|
||||
* @param mixed $parentLocations
|
||||
* @param array $data
|
||||
* @param string $remoteId
|
||||
* @param string $language
|
||||
* @param string $contentType
|
||||
* @param mixed $parentLocations
|
||||
* @param int $mode One of the constant ContentStructureFactoryInterface::MODE_*
|
||||
*
|
||||
* @return ContentStructure
|
||||
* @return false|ContentStructure
|
||||
*
|
||||
* @throws \CodeRhapsodie\EzDataflowBundle\Exception\InvalidArgumentTypeException
|
||||
* @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException
|
||||
*/
|
||||
public function transform(array $data, string $remoteId, string $language, string $contentType, $parentLocations): ContentStructure
|
||||
public function transform(array $data, string $remoteId, string $language, string $contentType, $parentLocations, int $mode = ContentStructureFactoryInterface::MODE_INSERT_OR_UPDATE)
|
||||
{
|
||||
try {
|
||||
$content = $this->contentService->loadContentByRemoteId($remoteId);
|
||||
if ($mode === static::MODE_INSERT_ONLY) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ContentUpdateStructure::createForContentId($content->id, $language, $data);
|
||||
} catch (NotFoundException $e) {
|
||||
// The content doesn't exist yet, so it will be created.
|
||||
}
|
||||
|
||||
if ($mode === static::MODE_UPDATE_ONLY) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return new ContentCreateStructure(
|
||||
$contentType,
|
||||
$language,
|
||||
|
||||
24
src/Factory/ContentStructureFactoryInterface.php
Normal file
24
src/Factory/ContentStructureFactoryInterface.php
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CodeRhapsodie\EzDataflowBundle\Factory;
|
||||
|
||||
interface ContentStructureFactoryInterface
|
||||
{
|
||||
public const MODE_INSERT_OR_UPDATE = 1;
|
||||
public const MODE_INSERT_ONLY = 2;
|
||||
public const MODE_UPDATE_ONLY = 3;
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @param string $remoteId
|
||||
* @param string $language
|
||||
* @param string $contentType
|
||||
* @param int|string $parentLocations Int for location id or string for remote location id
|
||||
* @param int $mode ContentStructureFactoryInterface
|
||||
*
|
||||
* @return false|\CodeRhapsodie\EzDataflowBundle\Model\ContentStructure
|
||||
*/
|
||||
public function transform(array $data, string $remoteId, string $language, string $contentType, $parentLocations, int $mode = ContentStructureFactoryInterface::MODE_INSERT_OR_UPDATE);
|
||||
}
|
||||
51
src/Filter/NotModifiedContentFilter.php
Normal file
51
src/Filter/NotModifiedContentFilter.php
Normal file
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CodeRhapsodie\EzDataflowBundle\Filter;
|
||||
|
||||
use CodeRhapsodie\EzDataflowBundle\Core\FieldComparator\FieldComparatorInterface;
|
||||
use CodeRhapsodie\EzDataflowBundle\Model\ContentUpdateStructure;
|
||||
use eZ\Publish\API\Repository\ContentService;
|
||||
|
||||
/**
|
||||
* Filters ContentUpdateStructure that would not result in any actual changes in the content.
|
||||
*/
|
||||
class NotModifiedContentFilter
|
||||
{
|
||||
/** @var ContentService */
|
||||
private $contentService;
|
||||
|
||||
/** @var FieldComparatorInterface */
|
||||
private $comparator;
|
||||
|
||||
public function __construct(ContentService $contentService, FieldComparatorInterface $comparator)
|
||||
{
|
||||
$this->contentService = $contentService;
|
||||
$this->comparator = $comparator;
|
||||
}
|
||||
|
||||
public function __invoke($data)
|
||||
{
|
||||
if (!$data instanceof ContentUpdateStructure) {
|
||||
return $data;
|
||||
}
|
||||
|
||||
if ($data->getId()) {
|
||||
$content = $this->contentService->loadContent($data->getId(), [$data->getLanguageCode()]);
|
||||
} else {
|
||||
$content = $this->contentService->loadContentByRemoteId($data->getRemoteId(), [$data->getLanguageCode()]);
|
||||
}
|
||||
|
||||
foreach ($data->getFields() as $identifier => $hash) {
|
||||
$field = $content->getField($identifier, $data->getLanguageCode());
|
||||
if ($field === null || !$this->comparator->compare($field, $hash)) {
|
||||
// At least one field is different, continue the dataflow.
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
|
||||
// All fields are identical, filter this item out.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -6,68 +6,49 @@ namespace CodeRhapsodie\EzDataflowBundle\Gateway;
|
||||
|
||||
use CodeRhapsodie\DataflowBundle\Entity\Job;
|
||||
use CodeRhapsodie\DataflowBundle\Repository\JobRepository;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\Query;
|
||||
use Doctrine\DBAL\Query\QueryBuilder;
|
||||
|
||||
class JobGateway
|
||||
final class JobGateway
|
||||
{
|
||||
/** @var EntityManagerInterface */
|
||||
private $em;
|
||||
/** @var JobRepository */
|
||||
private $jobRepository;
|
||||
|
||||
public function __construct(EntityManagerInterface $em, JobRepository $jobRepository)
|
||||
public function __construct(JobRepository $jobRepository)
|
||||
{
|
||||
$this->em = $em;
|
||||
$this->jobRepository = $jobRepository;
|
||||
}
|
||||
|
||||
public function find(int $id): Job
|
||||
public function find(int $id): ?Job
|
||||
{
|
||||
return $this->jobRepository->find($id);
|
||||
}
|
||||
|
||||
public function findForScheduled(int $id): iterable
|
||||
public function getOneshotListQueryForAdmin(): QueryBuilder
|
||||
{
|
||||
return $this->jobRepository->findBy(['scheduledDataflow' => $id], ['requestedDate' => 'desc'], 20);
|
||||
return $this->jobRepository->createQueryBuilder('i')
|
||||
->andWhere('i.scheduled_dataflow_id IS NULL')
|
||||
->addOrderBy('i.requested_date', 'DESC');
|
||||
}
|
||||
|
||||
public function getOneshotListQueryForAdmin(): Query
|
||||
public function getListQueryForAdmin(): QueryBuilder
|
||||
{
|
||||
$query = $this->jobRepository->createQueryBuilder('i')
|
||||
->andWhere('i.scheduledDataflow IS NULL')
|
||||
->addOrderBy('i.requestedDate', 'DESC');
|
||||
|
||||
return $query->getQuery();
|
||||
return $this->jobRepository->createQueryBuilder('w')
|
||||
->addOrderBy('w.requested_date', 'DESC');
|
||||
}
|
||||
|
||||
public function getListQueryForAdmin(): Query
|
||||
public function getListQueryForScheduleAdmin(int $id): QueryBuilder
|
||||
{
|
||||
$query = $this->jobRepository->createQueryBuilder('w')
|
||||
->addOrderBy('w.requestedDate', 'DESC');
|
||||
|
||||
return $query->getQuery();
|
||||
}
|
||||
|
||||
public function getListQueryForScheduleAdmin(int $id): Query
|
||||
{
|
||||
$query = $this->jobRepository->createQueryBuilder('w')
|
||||
->where('w.scheduledDataflow = :schedule_id')
|
||||
return $this->jobRepository->createQueryBuilder('w')
|
||||
->where('w.scheduled_dataflow_id = :schedule_id')
|
||||
->setParameter('schedule_id', $id)
|
||||
->addOrderBy('w.requestedDate', 'DESC');
|
||||
|
||||
return $query->getQuery();
|
||||
->addOrderBy('w.requested_date', 'DESC');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Job $job
|
||||
*
|
||||
* @throws \Doctrine\ORM\ORMException
|
||||
* @throws \Doctrine\ORM\OptimisticLockException
|
||||
*/
|
||||
public function save(Job $job)
|
||||
{
|
||||
$this->em->persist($job);
|
||||
$this->em->flush();
|
||||
$this->jobRepository->save($job);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,54 +6,44 @@ namespace CodeRhapsodie\EzDataflowBundle\Gateway;
|
||||
|
||||
use CodeRhapsodie\DataflowBundle\Entity\ScheduledDataflow;
|
||||
use CodeRhapsodie\DataflowBundle\Repository\ScheduledDataflowRepository;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\DBAL\Query\QueryBuilder;
|
||||
|
||||
class ScheduledDataflowGateway
|
||||
final class ScheduledDataflowGateway
|
||||
{
|
||||
/** @var EntityManagerInterface */
|
||||
private $em;
|
||||
/** @var ScheduledDataflowRepository */
|
||||
private $scheduledDataflowRepository;
|
||||
|
||||
public function __construct(EntityManagerInterface $em, ScheduledDataflowRepository $scheduledDataflowRepository)
|
||||
public function __construct(ScheduledDataflowRepository $scheduledDataflowRepository)
|
||||
{
|
||||
$this->em = $em;
|
||||
$this->scheduledDataflowRepository = $scheduledDataflowRepository;
|
||||
}
|
||||
|
||||
public function find(int $id): ScheduledDataflow
|
||||
public function find(int $id): ?ScheduledDataflow
|
||||
{
|
||||
return $this->scheduledDataflowRepository->find($id);
|
||||
}
|
||||
|
||||
public function findAllOrderedByLabel(): iterable
|
||||
public function getListQueryForAdmin(): QueryBuilder
|
||||
{
|
||||
return $this->scheduledDataflowRepository->findBy([], ['label' => 'asc']);
|
||||
return $this->scheduledDataflowRepository->createQueryBuilder('s')
|
||||
->addOrderBy('s.label', 'ASC');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ScheduledDataflow $scheduledDataflow
|
||||
*
|
||||
* @throws \Doctrine\ORM\ORMException
|
||||
* @throws \Doctrine\ORM\OptimisticLockException
|
||||
*/
|
||||
public function save(ScheduledDataflow $scheduledDataflow)
|
||||
{
|
||||
$this->em->persist($scheduledDataflow);
|
||||
$this->em->flush();
|
||||
$this->scheduledDataflowRepository->save($scheduledDataflow);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $id
|
||||
*
|
||||
* @throws \Doctrine\ORM\ORMException
|
||||
* @throws \Doctrine\ORM\OptimisticLockException
|
||||
* @throws \Throwable
|
||||
*/
|
||||
public function delete(int $id): void
|
||||
{
|
||||
$workflow = $this->find($id);
|
||||
|
||||
$this->em->remove($workflow);
|
||||
$this->em->flush();
|
||||
$this->scheduledDataflowRepository->delete($id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
imports:
|
||||
- { resource: services/comparators.yaml }
|
||||
|
||||
services:
|
||||
_defaults:
|
||||
public: false
|
||||
|
||||
coderhapsodie.dataflow.connection: "@ezpublish.persistence.connection"
|
||||
|
||||
CodeRhapsodie\EzDataflowBundle\Controller\DashboardController:
|
||||
public: true
|
||||
arguments:
|
||||
@@ -77,6 +82,8 @@ services:
|
||||
CodeRhapsodie\EzDataflowBundle\EventSubscriber\MenuSubscriber:
|
||||
tags: ['kernel.event_subscriber']
|
||||
|
||||
CodeRhapsodie\EzDataflowBundle\Factory\ContentStructureFactoryInterface: '@CodeRhapsodie\EzDataflowBundle\Factory\ContentStructureFactory'
|
||||
|
||||
CodeRhapsodie\EzDataflowBundle\Factory\ContentStructureFactory:
|
||||
arguments:
|
||||
$contentService: '@eZ\Publish\API\Repository\ContentService'
|
||||
@@ -97,12 +104,10 @@ services:
|
||||
|
||||
CodeRhapsodie\EzDataflowBundle\Gateway\ScheduledDataflowGateway:
|
||||
arguments:
|
||||
$em: '@doctrine.orm.default_entity_manager'
|
||||
$scheduledDataflowRepository: '@CodeRhapsodie\DataflowBundle\Repository\ScheduledDataflowRepository'
|
||||
|
||||
CodeRhapsodie\EzDataflowBundle\Gateway\JobGateway:
|
||||
arguments:
|
||||
$em: '@doctrine.orm.default_entity_manager'
|
||||
$jobRepository: '@CodeRhapsodie\DataflowBundle\Repository\JobRepository'
|
||||
|
||||
CodeRhapsodie\EzDataflowBundle\Tab\RepeatingTab:
|
||||
@@ -122,3 +127,16 @@ services:
|
||||
public: false
|
||||
tags:
|
||||
- {name: ezplatform.tab, group: coderhapsodie-ezdataflow}
|
||||
|
||||
CodeRhapsodie\EzDataflowBundle\Filter\NotModifiedContentFilter:
|
||||
arguments:
|
||||
$contentService: '@eZ\Publish\API\Repository\ContentService'
|
||||
$comparator: '@CodeRhapsodie\EzDataflowBundle\Core\FieldComparator\FieldComparatorInterface'
|
||||
|
||||
CodeRhapsodie\EzDataflowBundle\Core\FieldComparator\FieldComparatorInterface: '@CodeRhapsodie\EzDataflowBundle\Core\FieldComparator\DelegatorFieldComparator'
|
||||
CodeRhapsodie\EzDataflowBundle\Core\FieldComparator\DelegatorFieldComparator:
|
||||
|
||||
CodeRhapsodie\EzDataflowBundle\Core\FieldComparator\AbstractFieldComparator:
|
||||
arguments:
|
||||
$fieldTypeService: '@eZ\Publish\API\Repository\FieldTypeService'
|
||||
abstract: true
|
||||
|
||||
42
src/Resources/config/services/comparators.yaml
Normal file
42
src/Resources/config/services/comparators.yaml
Normal file
@@ -0,0 +1,42 @@
|
||||
services:
|
||||
CodeRhapsodie\EzDataflowBundle\Core\FieldComparator\SimpleFieldComparator:
|
||||
parent: 'CodeRhapsodie\EzDataflowBundle\Core\FieldComparator\AbstractFieldComparator'
|
||||
tags:
|
||||
- { name: 'coderhapsodie.ezdataflow.field_comparator', fieldType: 'ezauthor' }
|
||||
- { name: 'coderhapsodie.ezdataflow.field_comparator', fieldType: 'ezboolean' }
|
||||
- { name: 'coderhapsodie.ezdataflow.field_comparator', fieldType: 'ezcountry' }
|
||||
- { name: 'coderhapsodie.ezdataflow.field_comparator', fieldType: 'ezdate' }
|
||||
- { name: 'coderhapsodie.ezdataflow.field_comparator', fieldType: 'ezdatetime' }
|
||||
- { name: 'coderhapsodie.ezdataflow.field_comparator', fieldType: 'ezemail' }
|
||||
- { name: 'coderhapsodie.ezdataflow.field_comparator', fieldType: 'ezfloat' }
|
||||
- { name: 'coderhapsodie.ezdataflow.field_comparator', fieldType: 'ezinteger' }
|
||||
- { name: 'coderhapsodie.ezdataflow.field_comparator', fieldType: 'ezisbn' }
|
||||
- { name: 'coderhapsodie.ezdataflow.field_comparator', fieldType: 'ezkeyword' }
|
||||
- { name: 'coderhapsodie.ezdataflow.field_comparator', fieldType: 'ezobjectrelation' }
|
||||
- { name: 'coderhapsodie.ezdataflow.field_comparator', fieldType: 'ezobjectrelationlist' }
|
||||
- { name: 'coderhapsodie.ezdataflow.field_comparator', fieldType: 'ezrichtext' }
|
||||
- { name: 'coderhapsodie.ezdataflow.field_comparator', fieldType: 'ezselection' }
|
||||
- { name: 'coderhapsodie.ezdataflow.field_comparator', fieldType: 'eztext' }
|
||||
- { name: 'coderhapsodie.ezdataflow.field_comparator', fieldType: 'ezstring' }
|
||||
- { name: 'coderhapsodie.ezdataflow.field_comparator', fieldType: 'eztime' }
|
||||
- { name: 'coderhapsodie.ezdataflow.field_comparator', fieldType: 'eztags' }
|
||||
|
||||
CodeRhapsodie\EzDataflowBundle\Core\FieldComparator\UrlFieldComparator:
|
||||
parent: 'CodeRhapsodie\EzDataflowBundle\Core\FieldComparator\AbstractFieldComparator'
|
||||
tags:
|
||||
- { name: 'coderhapsodie.ezdataflow.field_comparator', fieldType: 'ezurl' }
|
||||
|
||||
CodeRhapsodie\EzDataflowBundle\Core\FieldComparator\NovaSEOMetasFieldComparator:
|
||||
parent: 'CodeRhapsodie\EzDataflowBundle\Core\FieldComparator\AbstractFieldComparator'
|
||||
tags:
|
||||
- { name: 'coderhapsodie.ezdataflow.field_comparator', fieldType: 'novaseometas' }
|
||||
|
||||
CodeRhapsodie\EzDataflowBundle\Core\FieldComparator\MatrixFieldComparator:
|
||||
parent: 'CodeRhapsodie\EzDataflowBundle\Core\FieldComparator\AbstractFieldComparator'
|
||||
tags:
|
||||
- { name: 'coderhapsodie.ezdataflow.field_comparator', fieldType: 'ezmatrix' }
|
||||
|
||||
CodeRhapsodie\EzDataflowBundle\Core\FieldComparator\MapLocationFieldComparator:
|
||||
parent: 'CodeRhapsodie\EzDataflowBundle\Core\FieldComparator\AbstractFieldComparator'
|
||||
tags:
|
||||
- { name: 'coderhapsodie.ezdataflow.field_comparator', fieldType: 'ezgmaplocation' }
|
||||
@@ -74,3 +74,4 @@ coderhapsodie.ezdataflow.workflow.edit.submit: Save
|
||||
coderhapsodie.dataflow.update.next: 'Next execution'
|
||||
coderhapsodie.ezdataflow.workflow.edit.success: 'Dataflow schedule successfully updated.'
|
||||
coderhapsodie.ezdataflow.workflow.edit.error: 'An error occurred during the dataflow schedule update: "%message%".'
|
||||
coderhapsodie.ezdataflow.notfound: 'Requested data is not found'
|
||||
|
||||
@@ -49,15 +49,15 @@ coderhapsodie.ezdataflow.workflow.history.title: 'Historique des exécutions'
|
||||
coderhapsodie.ezdataflow.workflow.list.delete: Supprimer
|
||||
coderhapsodie.ezdataflow.workflow.delete: 'Êtes-vous sûr de vouloir supprimer ce dataflow ?'
|
||||
coderhapsodie.ezdataflow.workflow.create.success: 'La programmation du dataflow a bien été ajoutée.'
|
||||
coderhapsodie.ezdataflow.workflow.create.error: 'Une erreur est survenue lors de l''ajout de la programamtion du dataflow : "%message%".'
|
||||
coderhapsodie.ezdataflow.workflow.delete.success: 'La programmation du dataflow a bien été supprimé.'
|
||||
coderhapsodie.ezdataflow.workflow.create.error: 'Une erreur est survenue lors de l''ajout de la programmation du dataflow : "%message%".'
|
||||
coderhapsodie.ezdataflow.workflow.delete.success: 'La programmation du dataflow a bien été supprimée.'
|
||||
coderhapsodie.ezdataflow.workflow.delete.error: 'Une erreur est survenue lors de la suppression de la programmation du dataflow : "%message%".'
|
||||
coderhapsodie.ezdataflow.workflow.oneshot.new.title: 'Nouvelle exécution ponctuelle'
|
||||
coderhapsodie.ezdataflow.job.create.success: 'Votre exécution a bien été ajoutée.'
|
||||
coderhapsodie.ezdataflow.job.create.error: 'Une erreur est survenue lors de l''ajout de l''exécution : "%message%".'
|
||||
coderhapsodie.dataflow.label: 'Nom de la programamtion du dataflow'
|
||||
coderhapsodie.dataflow.label: 'Nom de la programmation du dataflow'
|
||||
coderhapsodie.dataflow.oneshot.label: 'Nom de l''exécution ponctuelle du dataflow'
|
||||
coderhapsodie.dataflow.dataflowType: 'Dataflow a exécuter'
|
||||
coderhapsodie.dataflow.dataflowType: 'Dataflow à exécuter'
|
||||
coderhapsodie.dataflow.options: 'Options passées au dataflow (YAML)'
|
||||
coderhapsodie.dataflow.options.title: 'Entrez les options comme un tableau clé/valeur YAML'
|
||||
coderhapsodie.dataflow.options.placeholder: "option1: valeur1\noption2: valeur2\n"
|
||||
@@ -70,5 +70,6 @@ coderhapsodie.dataflow.create.enabled: 'Activé ?'
|
||||
coderhapsodie.ezdataflow.workflow.repeating.edit.title: "Édition de la programmation d'un dataflow"
|
||||
coderhapsodie.ezdataflow.workflow.edit.submit: Sauvegarder
|
||||
coderhapsodie.dataflow.update.next: 'Prochaine exécution'
|
||||
coderhapsodie.ezdataflow.workflow.edit.success: 'La programmation du dataflow a été mis à jour avec succès.'
|
||||
coderhapsodie.ezdataflow.workflow.edit.success: 'La programmation du dataflow a été mise à jour avec succès.'
|
||||
coderhapsodie.ezdataflow.workflow.edit.error: 'Une erreur est survenue lors de la modification de la programmation du dataflow : "%message%".'
|
||||
coderhapsodie.ezdataflow.notfound: 'Les données demandées sont introuvables'
|
||||
|
||||
@@ -24,7 +24,8 @@
|
||||
<h3 class="modal-title">{{ 'coderhapsodie.ezdataflow.workflow.history.title'|trans }}</h3>
|
||||
<button type="button" class="close" aria-label="Close">
|
||||
<svg class="ez-icon ez-icon--medium" aria-hidden="true">
|
||||
<use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/bundles/ezplatformadminui/img/ez-icons.svg#discard"></use>
|
||||
<use xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xlink:href="/bundles/ezplatformadminui/img/ez-icons.svg#discard"></use>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
@@ -34,35 +35,40 @@
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$('#ez-modal--history-details').modal({keyboard: false, show: false});
|
||||
$('.history-details-aware').delegate('.modal-history-details', 'click', function(e) {
|
||||
e.preventDefault();
|
||||
$('#modal_content-details').html('');
|
||||
$('#ez-modal--history-details').modal('show');
|
||||
$.ajax(this.href, {
|
||||
success: function(result) {
|
||||
$('#modal_content-details').html(result);
|
||||
}
|
||||
|
||||
(function ($) {
|
||||
$(document).ready(function ($) {
|
||||
$('#ez-modal--history-details').modal({keyboard: false, show: false});
|
||||
$('.history-details-aware').delegate('.modal-history-details', 'click', function (e) {
|
||||
e.preventDefault();
|
||||
$('#modal_content-details').html('');
|
||||
$('#ez-modal--history-details').modal('show');
|
||||
$.ajax(this.href, {
|
||||
success: function (result) {
|
||||
$('#modal_content-details').html(result);
|
||||
}
|
||||
});
|
||||
});
|
||||
$('#ez-modal--history-details .close').click(function () {
|
||||
$('#ez-modal--history-details').modal('hide');
|
||||
});
|
||||
$(document).ready(function () {
|
||||
if (window.location.hash && window.location.hash === '#oneshot') {
|
||||
$('#ez-tab-list-coderhapsodie-ezdataflow li a').removeClass('active');
|
||||
$('#ez-tab-list-content-coderhapsodie-ezdataflow .tab-pane').removeClass('active');
|
||||
|
||||
$('#ez-tab-list-coderhapsodie-ezdataflow li a:eq(1)').addClass('active');
|
||||
$('#ez-tab-list-content-coderhapsodie-ezdataflow .tab-pane:eq(1)').addClass('active');
|
||||
}
|
||||
if (window.location.hash && window.location.hash === '#history') {
|
||||
$('#ez-tab-list-coderhapsodie-ezdataflow li a').removeClass('active');
|
||||
$('#ez-tab-list-content-coderhapsodie-ezdataflow .tab-pane').removeClass('active');
|
||||
|
||||
$('#ez-tab-list-coderhapsodie-ezdataflow li a:eq(2)').addClass('active');
|
||||
$('#ez-tab-list-content-coderhapsodie-ezdataflow .tab-pane:eq(2)').addClass('active');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
$('#ez-modal--history-details .close').click(function () {
|
||||
$('#ez-modal--history-details').modal('hide');
|
||||
});
|
||||
$(document).ready(function () {
|
||||
if (window.location.hash && window.location.hash === '#oneshot') {
|
||||
$('#ez-tab-list-coderhapsodie-ezdataflow li a').removeClass('active');
|
||||
$('#ez-tab-list-content-coderhapsodie-ezdataflow .tab-pane').removeClass('active');
|
||||
|
||||
$('#ez-tab-list-coderhapsodie-ezdataflow li a:eq(1)').addClass('active');
|
||||
$('#ez-tab-list-content-coderhapsodie-ezdataflow .tab-pane:eq(1)').addClass('active');
|
||||
}
|
||||
if (window.location.hash && window.location.hash === '#history') {
|
||||
$('#ez-tab-list-coderhapsodie-ezdataflow li a').removeClass('active');
|
||||
$('#ez-tab-list-content-coderhapsodie-ezdataflow .tab-pane').removeClass('active');
|
||||
|
||||
$('#ez-tab-list-coderhapsodie-ezdataflow li a:eq(2)').addClass('active');
|
||||
$('#ez-tab-list-content-coderhapsodie-ezdataflow .tab-pane:eq(2)').addClass('active');
|
||||
}
|
||||
});
|
||||
})(jQuery);
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
{% form_theme form 'bootstrap_3_layout.html.twig' %}
|
||||
|
||||
<h2>{{ 'coderhapsodie.ezdataflow.oneshot.title'|trans }}</h2>
|
||||
|
||||
<div class="ez-table-header">
|
||||
<div class="ez-table-header__headline">{{ 'coderhapsodie.ezdataflow.oneshot.list.title'|trans }}</div>
|
||||
<div>
|
||||
<button type="button" class="btn btn-primary btn-modal-launcher" data-toggle="modal" data-target="#ez-modal--new-oneshot">
|
||||
<button type="button" class="btn btn-primary btn-modal-launcher" data-toggle="modal"
|
||||
data-target="#ez-modal--new-oneshot">
|
||||
<svg class="ez-icon ez-icon--medium ez-icon--light ez-icon-create">
|
||||
<use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/bundles/ezplatformadminui/img/ez-icons.svg#create"></use>
|
||||
<use xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xlink:href="/bundles/ezplatformadminui/img/ez-icons.svg#create"></use>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
@@ -16,6 +16,7 @@
|
||||
{{ include('@ezdesign/ezdataflow/parts/tab/job_list.html.twig', {identifier: 'ezdataflow_oneshot_history', paginate_route: 'coderhapsodie.ezdataflow.oneshot'}) }}
|
||||
|
||||
{% if form is defined %}
|
||||
{% form_theme form 'bootstrap_3_layout.html.twig' %}
|
||||
<div class="modal fade ez-modal show" id="ez-modal--new-oneshot" tabindex="-1" role="dialog" aria-modal="true">
|
||||
<div class="modal-dialog" role="document">
|
||||
{{ include('@ezdesign/ezdataflow/parts/schedule_form.html.twig', {mode: 'oneshot'}) }}
|
||||
@@ -23,27 +24,35 @@
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$('#ez-modal--new-oneshot').on('submit', 'form', function (e) {
|
||||
e.preventDefault();
|
||||
url = $(this).attr('action');
|
||||
data = new FormData(this);
|
||||
$.ajax({
|
||||
'type': 'POST',
|
||||
'url': url,
|
||||
'data': data,
|
||||
processData: false,
|
||||
contentType: false,
|
||||
success: function (result) {
|
||||
if (result.redirect) {
|
||||
window.location = result.redirect;
|
||||
return;
|
||||
}
|
||||
|
||||
let obj = $(result.form).find('.modal-body');
|
||||
$('#ez-modal--new-oneshot .modal-body').html($(obj).html());
|
||||
}
|
||||
(function ($) {
|
||||
$(document).ready(function ($) {
|
||||
$('#ez-modal--new-oneshot').on('submit', 'form', function (e) {
|
||||
e.preventDefault();
|
||||
url = $(this).attr('action');
|
||||
data = new FormData(this);
|
||||
$.ajax({
|
||||
'type': 'POST',
|
||||
'url': url,
|
||||
'data': data,
|
||||
processData: false,
|
||||
contentType: false,
|
||||
success: function (result) {
|
||||
if (result.redirect) {
|
||||
if (window.location.href === result.redirect) {
|
||||
document.location.reload();
|
||||
}
|
||||
window.location = result.redirect;
|
||||
return;
|
||||
}
|
||||
|
||||
let obj = $(result.form).find('.modal-body');
|
||||
$('#ez-modal--new-oneshot .modal-body').html($(obj).html());
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
})(jQuery);
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
{% form_theme form 'bootstrap_3_layout.html.twig' %}
|
||||
|
||||
<h2>{{ 'coderhapsodie.ezdataflow.repeating.title'|trans }}</h2>
|
||||
|
||||
<div class="ez-table-header">
|
||||
@@ -15,162 +13,172 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{ include('@ezdesign/ezdataflow/parts/tab/schedule_list.html.twig') }}
|
||||
{{ include('@ezdesign/ezdataflow/parts/tab/schedule_list.html.twig', {identifier: 'ezdataflow_schedule_results', paginate_route: 'coderhapsodie.ezdataflow.repeating'}) }}
|
||||
|
||||
<div class="modal fade ez-modal show" id="ez-modal--new-scheduled" tabindex="-1" role="dialog" aria-modal="true">
|
||||
<div class="modal-dialog" role="document">
|
||||
{{ include('@ezdesign/ezdataflow/parts/schedule_form.html.twig') }}
|
||||
{% if form is defined %}
|
||||
{% form_theme form 'bootstrap_3_layout.html.twig' %}
|
||||
<div class="modal fade ez-modal show" id="ez-modal--new-scheduled" tabindex="-1" role="dialog" aria-modal="true">
|
||||
<div class="modal-dialog" role="document">
|
||||
{{ include('@ezdesign/ezdataflow/parts/schedule_form.html.twig') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal -->
|
||||
<div class="modal fade ez-modal ez-modal--delete-workflow show" id="ez-modal--delete-workflow" tabindex="-1"
|
||||
role="dialog">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<svg class="ez-icon ez-icon--medium" aria-hidden="true">
|
||||
<use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="../../ez-icons.svg#discard"></use>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p class="font-weight-bold" id="delete-modal--workflow-name"></p>
|
||||
<p class="ez-modal-body__main">{{ 'coderhapsodie.ezdataflow.workflow.delete'|trans }}</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-dark"
|
||||
data-dismiss="modal">{{ 'coderhapsodie.ezdataflow.workflow.new.cancel'|trans }}</button>
|
||||
<button type="button" class="btn btn-danger font-weight-bold"
|
||||
id="ez-modal--delete-workflow-confirm">{{ 'coderhapsodie.ezdataflow.workflow.list.delete'|trans }}</button>
|
||||
<!-- Modal -->
|
||||
<div class="modal fade ez-modal ez-modal--delete-workflow show" id="ez-modal--delete-workflow" tabindex="-1"
|
||||
role="dialog">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<svg class="ez-icon ez-icon--medium" aria-hidden="true">
|
||||
<use xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xlink:href="../../ez-icons.svg#discard"></use>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p class="font-weight-bold" id="delete-modal--workflow-name"></p>
|
||||
<p class="ez-modal-body__main">{{ 'coderhapsodie.ezdataflow.workflow.delete'|trans }}</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-dark"
|
||||
data-dismiss="modal">{{ 'coderhapsodie.ezdataflow.workflow.new.cancel'|trans }}</button>
|
||||
<button type="button" class="btn btn-danger font-weight-bold"
|
||||
id="ez-modal--delete-workflow-confirm">{{ 'coderhapsodie.ezdataflow.workflow.list.delete'|trans }}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal fade ez-modal show" id="ez-modal--history" tabindex="-1" role="dialog" aria-modal="true">
|
||||
<div class="modal-dialog" role="document" style="max-width: 80%">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h3 class="modal-title">{{ 'coderhapsodie.ezdataflow.workflow.history.title'|trans }}</h3>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<svg class="ez-icon ez-icon--medium" aria-hidden="true">
|
||||
<use xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xlink:href="/bundles/ezplatformadminui/img/ez-icons.svg#discard"></use>
|
||||
</svg>
|
||||
</button>
|
||||
<div class="modal fade ez-modal show" id="ez-modal--history" tabindex="-1" role="dialog" aria-modal="true">
|
||||
<div class="modal-dialog" role="document" style="max-width: 80%">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h3 class="modal-title">{{ 'coderhapsodie.ezdataflow.workflow.history.title'|trans }}</h3>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<svg class="ez-icon ez-icon--medium" aria-hidden="true">
|
||||
<use xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xlink:href="/bundles/ezplatformadminui/img/ez-icons.svg#discard"></use>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body history-details-aware" id="modal_content"></div>
|
||||
</div>
|
||||
<div class="modal-body history-details-aware" id="modal_content"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal fade ez-modal show" id="ez-modal--edit-scheduled" tabindex="-1" role="dialog" aria-modal="true">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div id="schedule_edit"></div>
|
||||
<div class="modal fade ez-modal show" id="ez-modal--edit-scheduled" tabindex="-1" role="dialog" aria-modal="true">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div id="schedule_edit"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$('#ez-modal--history').modal({keyboard: false, show: false});
|
||||
$('.modal-history').each(function (index, elem) {
|
||||
$(elem).click(function (e) {
|
||||
e.preventDefault();
|
||||
$('#modal_content').html('');
|
||||
$('#ez-modal--history').modal('show');
|
||||
$.ajax(elem.href, {
|
||||
success: function (result) {
|
||||
$('#modal_content').html(result);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
$('#ez-modal--history .close').click(function () {
|
||||
$('#ez-modal--history').modal('hide');
|
||||
});
|
||||
<script>
|
||||
(function ($) {
|
||||
$(document).ready(function ($) {
|
||||
$('#ez-modal--history').modal({keyboard: false, show: false});
|
||||
$('.modal-history').each(function (index, elem) {
|
||||
$(elem).click(function (e) {
|
||||
e.preventDefault();
|
||||
$('#modal_content').html('');
|
||||
$('#ez-modal--history').modal('show');
|
||||
$.ajax(elem.href, {
|
||||
success: function (result) {
|
||||
$('#modal_content').html(result);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
$('#ez-modal--history .close').click(function () {
|
||||
$('#ez-modal--history').modal('hide');
|
||||
});
|
||||
|
||||
$('#ez-modal--delete-workflow').modal({keyboard: true, show: false});
|
||||
$('.modal-delete').each(function (index, elem) {
|
||||
$(elem).click(function (e) {
|
||||
e.preventDefault();
|
||||
$('#delete-modal--workflow-name').html($(elem).data('name'));
|
||||
$('#ez-modal--delete-workflow').modal('show');
|
||||
$('#ez-modal--delete-workflow-confirm').data('target', $(elem).data('path'));
|
||||
});
|
||||
});
|
||||
$('#ez-modal--delete-workflow-confirm').click(function () {
|
||||
let target = $(this).data('target');
|
||||
if (target && target !== '') {
|
||||
$.ajax(target, {
|
||||
method: 'POST',
|
||||
complete: function () {
|
||||
$('#ez-modal--delete-workflow').modal('hide');
|
||||
window.location.reload();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
$('#ez-modal--edit-scheduled').modal({keyboard: true, show: false});
|
||||
$('.modal-edit').each(function (index, elem) {
|
||||
$(elem).click(function (e) {
|
||||
e.preventDefault();
|
||||
$('#schedule_edit').html('');
|
||||
$('#ez-modal--edit-scheduled').modal('show');
|
||||
$.ajax(elem.href, {
|
||||
success: function (result) {
|
||||
if (result.redirect) {
|
||||
window.location = result.redirect;
|
||||
return;
|
||||
$('#ez-modal--delete-workflow').modal({keyboard: true, show: false});
|
||||
$('.modal-delete').each(function (index, elem) {
|
||||
$(elem).click(function (e) {
|
||||
e.preventDefault();
|
||||
$('#delete-modal--workflow-name').html($(elem).data('name'));
|
||||
$('#ez-modal--delete-workflow').modal('show');
|
||||
$('#ez-modal--delete-workflow-confirm').data('target', $(elem).data('path'));
|
||||
});
|
||||
});
|
||||
$('#ez-modal--delete-workflow-confirm').click(function () {
|
||||
let target = $(this).data('target');
|
||||
if (target && target !== '') {
|
||||
$.ajax(target, {
|
||||
method: 'POST',
|
||||
complete: function () {
|
||||
$('#ez-modal--delete-workflow').modal('hide');
|
||||
window.location.reload();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
$('#schedule_edit').html(result.form);
|
||||
}
|
||||
$('#ez-modal--edit-scheduled').modal({keyboard: true, show: false});
|
||||
$('.modal-edit').each(function (index, elem) {
|
||||
$(elem).click(function (e) {
|
||||
e.preventDefault();
|
||||
$('#schedule_edit').html('');
|
||||
$('#ez-modal--edit-scheduled').modal('show');
|
||||
$.ajax(elem.href, {
|
||||
success: function (result) {
|
||||
if (result.redirect) {
|
||||
if (window.location.href === result.redirect) {
|
||||
document.location.reload();
|
||||
}
|
||||
window.location = result.redirect;
|
||||
return;
|
||||
}
|
||||
|
||||
$('#schedule_edit').html(result.form);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
$('#ez-modal--edit-scheduled').on('submit', 'form', function (e) {
|
||||
e.preventDefault();
|
||||
url = $(this).attr('action');
|
||||
data = new FormData(this);
|
||||
$.ajax({
|
||||
'type': 'POST',
|
||||
'url': url,
|
||||
'data': data,
|
||||
processData: false,
|
||||
contentType: false,
|
||||
success: function (result) {
|
||||
if (result.redirect) {
|
||||
window.location = result.redirect;
|
||||
return;
|
||||
}
|
||||
|
||||
$('#schedule_edit').html(result.form);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$('#ez-modal--new-scheduled form').on('submit', function (e) {
|
||||
e.preventDefault();
|
||||
url = $(this).attr('action');
|
||||
data = new FormData(this);
|
||||
$.ajax({
|
||||
'type': 'POST',
|
||||
'url': url,
|
||||
'data': data,
|
||||
processData: false,
|
||||
contentType: false,
|
||||
success: function (result) {
|
||||
if (result.redirect) {
|
||||
window.location = result.redirect;
|
||||
return;
|
||||
}
|
||||
let obj = $(result.form).find('.modal-body');
|
||||
$('#ez-modal--new-scheduled .modal-body').html($(obj).html());
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
$('#ez-modal--edit-scheduled').on('submit', 'form', function (e) {
|
||||
e.preventDefault();
|
||||
url = $(this).attr('action');
|
||||
data = new FormData(this);
|
||||
$.ajax({
|
||||
'type': 'POST',
|
||||
'url': url,
|
||||
'data': data,
|
||||
processData: false,
|
||||
contentType: false,
|
||||
success: function (result) {
|
||||
if (result.redirect) {
|
||||
window.location = result.redirect;
|
||||
return;
|
||||
}
|
||||
|
||||
$('#schedule_edit').html(result.form);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$('#ez-modal--new-scheduled form').on('submit', function (e) {
|
||||
e.preventDefault();
|
||||
url = $(this).attr('action');
|
||||
data = new FormData(this);
|
||||
$.ajax({
|
||||
'type': 'POST',
|
||||
'url': url,
|
||||
'data': data,
|
||||
processData: false,
|
||||
contentType: false,
|
||||
success: function (result) {
|
||||
if (result.redirect) {
|
||||
window.location = result.redirect;
|
||||
return;
|
||||
}
|
||||
let obj = $(result.form).find('.modal-body');
|
||||
$('#ez-modal--new-scheduled .modal-body').html($(obj).html());
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
</script>
|
||||
})(jQuery);
|
||||
</script>
|
||||
{% endif %}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
{% import '@ezdesign/ezdataflow/macros.twig' as macros %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div class="container ez-main-container">
|
||||
{% if item is not null %}
|
||||
<h2>{{ 'coderhapsodie.ezdataflow.history.job.title'|trans }} n°{{ item.id }}</h2>
|
||||
|
||||
<table class="table ez-table ez-table--list">
|
||||
@@ -51,5 +53,8 @@
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
{% else %}
|
||||
<p class="ez-table-no-content">{{ 'coderhapsodie.ezdataflow.notfound'|trans }}</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
|
||||
<div id="loading_{{ id }}" class="text-center d-none">
|
||||
<svg class="ez-icon ez-icon--extra-large">
|
||||
<use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/bundles/ezplatformadminui/img/ez-icons.svg#spinner"></use>
|
||||
<use xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xlink:href="/bundles/ezplatformadminui/img/ez-icons.svg#spinner"></use>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
@@ -26,15 +27,18 @@
|
||||
{% for job in pager.currentPageResults %}
|
||||
<tr>
|
||||
<td>{{ job.label }}</td>
|
||||
<td>{{ job.requestedDate|date('d/m/Y H:i:s') }}</td>
|
||||
<td>{{ job.requested_date|date('d/m/Y H:i:s') }}</td>
|
||||
<td>{{ job.count|default('-') }}</td>
|
||||
<td>{{ job.startTime ? job.startTime|date('d/m/Y H:i:s') : '-' }}</td>
|
||||
<td>{{ job.endTime ? job.endTime|date('d/m/Y H:i:s') : '-' }}</td>
|
||||
<td>{{ job.start_time ? job.start_time|date('d/m/Y H:i:s') : '-' }}</td>
|
||||
<td>{{ job.end_time ? job.end_time|date('d/m/Y H:i:s') : '-' }}</td>
|
||||
<td>{{ macros.translateStatus(job.status) }}</td>
|
||||
<td class="ez-table__cell ez-table__cell--has-action-btns text-right">
|
||||
<a href="{{ path('coderhapsodie.ezdataflow.job.details', {id: job.id}) }}" class="btn btn-icon mx-2 modal-history-details" title="{{ 'coderhapsodie.ezdataflow.history.list.view'|trans }}">
|
||||
<a href="{{ path('coderhapsodie.ezdataflow.job.details', {id: job.id}) }}"
|
||||
class="btn btn-icon mx-2 modal-history-details"
|
||||
title="{{ 'coderhapsodie.ezdataflow.history.list.view'|trans }}">
|
||||
<svg class="ez-icon ez-icon--small-medium">
|
||||
<use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/bundles/ezplatformadminui/img/ez-icons.svg#about-info"></use>
|
||||
<use xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xlink:href="/bundles/ezplatformadminui/img/ez-icons.svg#about-info"></use>
|
||||
</svg>
|
||||
</a>
|
||||
</td>
|
||||
@@ -54,14 +58,19 @@
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// Manage ajax pagination
|
||||
$('#{{ id }}').delegate('.ez-pagination a', 'click', function (e) {
|
||||
e.preventDefault();
|
||||
$('#loading_{{ id }}').removeClass('d-none');
|
||||
$('#{{ id }}')
|
||||
.html('')
|
||||
.load(this.href + ' #{{ id }}>*', null, function () {
|
||||
$('#loading_{{ id }}').addClass('d-none');
|
||||
|
||||
(function ($) {
|
||||
$(document).ready(function ($) {
|
||||
// Manage ajax pagination
|
||||
$('#{{ id }}').delegate('.ez-pagination a', 'click', function (e) {
|
||||
e.preventDefault();
|
||||
$('#loading_{{ id }}').removeClass('d-none');
|
||||
$('#{{ id }}')
|
||||
.html('')
|
||||
.load(this.href + ' #{{ id }}>*', null, function () {
|
||||
$('#loading_{{ id }}').addClass('d-none');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
})(jQuery);
|
||||
</script>
|
||||
|
||||
@@ -1,55 +1,106 @@
|
||||
{% if items|length %}
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{ 'coderhapsodie.ezdataflow.workflow.list.name'|trans }}</th>
|
||||
<th>{{ 'coderhapsodie.ezdataflow.workflow.list.frequency'|trans }}</th>
|
||||
<th>{{ 'coderhapsodie.ezdataflow.workflow.list.next_execution'|trans }}</th>
|
||||
<th>{{ 'coderhapsodie.ezdataflow.workflow.list.enabled'|trans }}</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for item in items %}
|
||||
{% set id = identifier|default('ezdataflow_schedule_results') %}
|
||||
|
||||
<div id="loading_{{ id }}" class="text-center d-none">
|
||||
<svg class="ez-icon ez-icon--extra-large">
|
||||
<use xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xlink:href="/bundles/ezplatformadminui/img/ez-icons.svg#spinner"></use>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<div id="{{ id }}" class="history-details-aware">
|
||||
{% if pager.currentPageResults|length %}
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<td>{{ item.label }}</td>
|
||||
<td>{{ item.frequency }}</td>
|
||||
<td>{{ item.next|date('d/m/Y H:i:s') }}</td>
|
||||
<td>{{ ('coderhapsodie.ezdataflow.' ~ (item.enabled ? 'yes' : 'no'))|trans }}</td>
|
||||
<td class="ez-table__cell ez-table__cell--has-action-btns text-right">
|
||||
<a href="{{ path('coderhapsodie.ezdataflow.history.workflow', {id: item.id}) }}" class="btn btn-icon mx-2 modal-history" title="{{ 'coderhapsodie.ezdataflow.workflow.list.history'|trans }}">
|
||||
<svg class="ez-icon ez-icon--small-medium">
|
||||
<use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/bundles/ezplatformadminui/img/ez-icons.svg#history"></use>
|
||||
</svg>
|
||||
</a>
|
||||
<a href="{{ path('coderhapsodie.ezdataflow.workflow.edit', {id: item.id}) }}" type="button" class="btn btn-icon mx-2 modal-edit" title="{{ 'coderhapsodie.ezdataflow.workflow.list.edit'|trans }}">
|
||||
<svg class="ez-icon ez-icon--small-medium ez-icon-edit">
|
||||
<use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/bundles/ezplatformadminui/img/ez-icons.svg#edit"></use>
|
||||
</svg>
|
||||
</a>
|
||||
{% if item.enabled %}
|
||||
<a href="{{ path('coderhapsodie.ezdataflow.workflow.disable', {id: item.id}) }}" class="btn btn-icon mx-2" title="{{ 'coderhapsodie.ezdataflow.workflow.list.disable'|trans }}">
|
||||
<svg class="ez-icon ez-icon--small-medium" style="fill: #f7d000;">
|
||||
<use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/bundles/ezplatformadminui/img/ez-icons.svg#logout"></use>
|
||||
</svg>
|
||||
</a>
|
||||
{% else %}
|
||||
<a href="{{ path('coderhapsodie.ezdataflow.workflow.enable', {id: item.id}) }}" class="btn btn-icon mx-2" title="{{ 'coderhapsodie.ezdataflow.workflow.list.enable'|trans }}">
|
||||
<svg class="ez-icon ez-icon--small-medium" style="fill: #00825c;">
|
||||
<use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/bundles/ezplatformadminui/img/ez-icons.svg#approved"></use>
|
||||
</svg>
|
||||
</a>
|
||||
{% endif %}
|
||||
<button type="button" class="btn btn-icon mx-2 ez-btn--content-trash modal-delete" data-name="{{ item.label }}" data-path="{{ path('coderhapsodie.ezdataflow.workflow.delete', {id: item.id}) }}" title="{{ 'coderhapsodie.ezdataflow.workflow.list.delete'|trans }}">
|
||||
<svg class="ez-icon ez-icon--small-medium ez-icon-trash">
|
||||
<use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/bundles/ezplatformadminui/img/ez-icons.svg#trash"></use>
|
||||
</svg>
|
||||
</button>
|
||||
</td>
|
||||
<th>{{ 'coderhapsodie.ezdataflow.workflow.list.name'|trans }}</th>
|
||||
<th>{{ 'coderhapsodie.ezdataflow.workflow.list.frequency'|trans }}</th>
|
||||
<th>{{ 'coderhapsodie.ezdataflow.workflow.list.next_execution'|trans }}</th>
|
||||
<th>{{ 'coderhapsodie.ezdataflow.workflow.list.enabled'|trans }}</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% else %}
|
||||
<p class="ez-table-no-content">{{ 'coderhapsodie.ezdataflow.workflow.list.empty'|trans }}</p>
|
||||
{% endif %}
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for item in pager.currentPageResults %}
|
||||
<tr>
|
||||
<td>{{ item.label }}</td>
|
||||
<td>{{ item.frequency }}</td>
|
||||
<td>{{ item.next|date('d/m/Y H:i:s') }}</td>
|
||||
<td>{{ ('coderhapsodie.ezdataflow.' ~ (item.enabled ? 'yes' : 'no'))|trans }}</td>
|
||||
<td class="ez-table__cell ez-table__cell--has-action-btns text-right">
|
||||
<a href="{{ path('coderhapsodie.ezdataflow.history.workflow', {id: item.id}) }}"
|
||||
class="btn btn-icon mx-2 modal-history"
|
||||
title="{{ 'coderhapsodie.ezdataflow.workflow.list.history'|trans }}">
|
||||
<svg class="ez-icon ez-icon--small-medium">
|
||||
<use xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xlink:href="/bundles/ezplatformadminui/img/ez-icons.svg#history"></use>
|
||||
</svg>
|
||||
</a>
|
||||
<a href="{{ path('coderhapsodie.ezdataflow.workflow.edit', {id: item.id}) }}" type="button"
|
||||
class="btn btn-icon mx-2 modal-edit"
|
||||
title="{{ 'coderhapsodie.ezdataflow.workflow.list.edit'|trans }}">
|
||||
<svg class="ez-icon ez-icon--small-medium ez-icon-edit">
|
||||
<use xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xlink:href="/bundles/ezplatformadminui/img/ez-icons.svg#edit"></use>
|
||||
</svg>
|
||||
</a>
|
||||
{% if item.enabled %}
|
||||
<a href="{{ path('coderhapsodie.ezdataflow.workflow.disable', {id: item.id}) }}"
|
||||
class="btn btn-icon mx-2"
|
||||
title="{{ 'coderhapsodie.ezdataflow.workflow.list.disable'|trans }}">
|
||||
<svg class="ez-icon ez-icon--small-medium" style="fill: #f7d000;">
|
||||
<use xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xlink:href="/bundles/ezplatformadminui/img/ez-icons.svg#logout"></use>
|
||||
</svg>
|
||||
</a>
|
||||
{% else %}
|
||||
<a href="{{ path('coderhapsodie.ezdataflow.workflow.enable', {id: item.id}) }}"
|
||||
class="btn btn-icon mx-2"
|
||||
title="{{ 'coderhapsodie.ezdataflow.workflow.list.enable'|trans }}">
|
||||
<svg class="ez-icon ez-icon--small-medium" style="fill: #00825c;">
|
||||
<use xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xlink:href="/bundles/ezplatformadminui/img/ez-icons.svg#approved"></use>
|
||||
</svg>
|
||||
</a>
|
||||
{% endif %}
|
||||
<button type="button" class="btn btn-icon mx-2 ez-btn--content-trash modal-delete"
|
||||
data-name="{{ item.label }}"
|
||||
data-path="{{ path('coderhapsodie.ezdataflow.workflow.delete', {id: item.id}) }}"
|
||||
title="{{ 'coderhapsodie.ezdataflow.workflow.list.delete'|trans }}">
|
||||
<svg class="ez-icon ez-icon--small-medium ez-icon-trash">
|
||||
<use xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xlink:href="/bundles/ezplatformadminui/img/ez-icons.svg#trash"></use>
|
||||
</svg>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% else %}
|
||||
<p class="ez-table-no-content">{{ 'coderhapsodie.ezdataflow.workflow.list.empty'|trans }}</p>
|
||||
{% endif %}
|
||||
|
||||
{% if pager.haveToPaginate %}
|
||||
<div class="ez-pagination justify-content-center align-items-center ez-pagination__spacing">
|
||||
{{ pagerfanta(pager, 'ez', {routeName: paginate_route, routeParams: paginate_params|default({})}) }}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<script>
|
||||
|
||||
(function ($) {
|
||||
$(document).ready(function ($) {
|
||||
// Manage ajax pagination
|
||||
$('#{{ id }}').delegate('.ez-pagination a', 'click', function (e) {
|
||||
e.preventDefault();
|
||||
$('#loading_{{ id }}').removeClass('d-none');
|
||||
$('#{{ id }}')
|
||||
.html('')
|
||||
.load(this.href + ' #{{ id }}>*', null, function () {
|
||||
$('#loading_{{ id }}').addClass('d-none');
|
||||
});
|
||||
});
|
||||
});
|
||||
})(jQuery);
|
||||
</script>
|
||||
|
||||
@@ -4,14 +4,14 @@ declare(strict_types=1);
|
||||
|
||||
namespace CodeRhapsodie\EzDataflowBundle\Writer;
|
||||
|
||||
use CodeRhapsodie\DataflowBundle\DataflowType\Writer\DelegateWriterInterface;
|
||||
use CodeRhapsodie\EzDataflowBundle\Core\Content\ContentCreatorInterface;
|
||||
use CodeRhapsodie\EzDataflowBundle\Core\Content\ContentUpdaterInterface;
|
||||
use CodeRhapsodie\EzDataflowBundle\Model\ContentCreateStructure;
|
||||
use CodeRhapsodie\EzDataflowBundle\Model\ContentStructure;
|
||||
use CodeRhapsodie\EzDataflowBundle\Model\ContentUpdateStructure;
|
||||
use CodeRhapsodie\DataflowBundle\DataflowType\Writer\WriterInterface;
|
||||
|
||||
class ContentWriter extends RepositoryWriter implements WriterInterface
|
||||
class ContentWriter extends RepositoryWriter implements DelegateWriterInterface
|
||||
{
|
||||
/** @var ContentCreatorInterface */
|
||||
private $creator;
|
||||
@@ -35,11 +35,19 @@ class ContentWriter extends RepositoryWriter implements WriterInterface
|
||||
}
|
||||
|
||||
if ($item instanceof ContentCreateStructure) {
|
||||
$this->creator->createFromStructure($item);
|
||||
return $this->creator->createFromStructure($item);
|
||||
}
|
||||
|
||||
if ($item instanceof ContentUpdateStructure) {
|
||||
$this->updater->updateFromStructure($item);
|
||||
return $this->updater->updateFromStructure($item);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function supports($item): bool
|
||||
{
|
||||
return $item instanceof ContentStructure;
|
||||
}
|
||||
}
|
||||
|
||||
49
tests/Core/FieldComparator/DelegatorFieldComparatorTest.php
Normal file
49
tests/Core/FieldComparator/DelegatorFieldComparatorTest.php
Normal file
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace CodeRhapsodie\EzDataflowBundle\Tests\Core\FieldComparator;
|
||||
|
||||
use CodeRhapsodie\EzDataflowBundle\Core\FieldComparator\DelegatorFieldComparator;
|
||||
use CodeRhapsodie\EzDataflowBundle\Core\FieldComparator\FieldComparatorInterface;
|
||||
use eZ\Publish\API\Repository\Values\Content\Field;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class DelegatorFieldComparatorTest extends TestCase
|
||||
{
|
||||
/** @var DelegatorFieldComparator */
|
||||
private $delegatorFieldComparator;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$type1FieldComparatorMock = $this->createMock(FieldComparatorInterface::class);
|
||||
$type1FieldComparatorMock->method('compare')->willReturnCallback(function (Field $field, $hash) {
|
||||
return $hash === 'rightValue1';
|
||||
});
|
||||
$type2FieldComparatorMock = $this->createMock(FieldComparatorInterface::class);
|
||||
$type2FieldComparatorMock->method('compare')->willReturnCallback(function (Field $field, $hash) {
|
||||
return $hash === 'rightValue2';
|
||||
});
|
||||
$this->delegatorFieldComparator = new DelegatorFieldComparator();
|
||||
$this->delegatorFieldComparator->registerDelegateFieldComparator($type1FieldComparatorMock, 'type1');
|
||||
$this->delegatorFieldComparator->registerDelegateFieldComparator($type2FieldComparatorMock, 'type2');
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider fieldProvider
|
||||
*/
|
||||
public function testField(string $type, bool $expected, $hash)
|
||||
{
|
||||
$field = new Field(['fieldTypeIdentifier' => $type]);
|
||||
$return = $this->delegatorFieldComparator->compare($field, $hash);
|
||||
|
||||
$this->assertSame($expected, $return);
|
||||
}
|
||||
|
||||
public function fieldProvider(): iterable
|
||||
{
|
||||
yield ['type1', true, 'rightValue1'];
|
||||
yield ['type1', false, 'wrongValue'];
|
||||
yield ['type2', true, 'rightValue2'];
|
||||
yield ['type2', false, 'wrongValue'];
|
||||
yield ['otherType', false, 'rightValue1'];
|
||||
}
|
||||
}
|
||||
138
tests/Filter/NotModifiedContentFilterTest.php
Normal file
138
tests/Filter/NotModifiedContentFilterTest.php
Normal file
@@ -0,0 +1,138 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CodeRhapsodie\EzDataflowBundle\Tests\Filter;
|
||||
|
||||
use CodeRhapsodie\EzDataflowBundle\Core\FieldComparator\FieldComparatorInterface;
|
||||
use CodeRhapsodie\EzDataflowBundle\Filter\NotModifiedContentFilter;
|
||||
use CodeRhapsodie\EzDataflowBundle\Model\ContentUpdateStructure;
|
||||
use eZ\Publish\API\Repository\ContentService;
|
||||
use eZ\Publish\API\Repository\Values\Content\Field;
|
||||
use eZ\Publish\Core\Repository\Values\Content\Content;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class NotModifiedContentFilterTest extends TestCase
|
||||
{
|
||||
/** @var ContentService|MockObject */
|
||||
private $contentServiceMock;
|
||||
|
||||
/** @var FieldComparatorInterface|MockObject */
|
||||
private $comparatorMock;
|
||||
|
||||
/** @var NotModifiedContentFilter */
|
||||
private $notModifiedContentFilter;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->contentServiceMock = $this->createMock(ContentService::class);
|
||||
$this->comparatorMock = $this->createMock(FieldComparatorInterface::class);
|
||||
$this->notModifiedContentFilter = new NotModifiedContentFilter($this->contentServiceMock, $this->comparatorMock);
|
||||
}
|
||||
|
||||
public function testNotContentUpdateStructure()
|
||||
{
|
||||
$data = 'notAStruct';
|
||||
$returnValue = ($this->notModifiedContentFilter)($data);
|
||||
|
||||
$this->assertSame($data, $returnValue);
|
||||
}
|
||||
|
||||
public function testIdenticalContent()
|
||||
{
|
||||
$id = 10;
|
||||
$field1 = 'field1';
|
||||
$value1 = 'value1';
|
||||
$field2 = 'field2';
|
||||
$value2 = 'value2';
|
||||
$contentField1 = new Field();
|
||||
$contentField2 = new Field();
|
||||
$data = ContentUpdateStructure::createForContentId($id, 'lang', [
|
||||
$field1 => $value1,
|
||||
$field2 => $value2,
|
||||
]);
|
||||
$content = $this->createMock(Content::class);
|
||||
|
||||
$content
|
||||
->expects($this->exactly(2))
|
||||
->method('getField')
|
||||
->withConsecutive([$field1], [$field2])
|
||||
->willReturnOnConsecutiveCalls($contentField1, $contentField2)
|
||||
;
|
||||
$this->contentServiceMock
|
||||
->expects($this->once())
|
||||
->method('loadContent')
|
||||
->with($id)
|
||||
->willReturn($content)
|
||||
;
|
||||
$this->comparatorMock
|
||||
->expects($this->exactly(2))
|
||||
->method('compare')
|
||||
->withConsecutive([$contentField1, $value1], [$contentField2, $value2])
|
||||
->willReturn(true)
|
||||
;
|
||||
|
||||
$return = ($this->notModifiedContentFilter)($data);
|
||||
|
||||
$this->assertFalse($return);
|
||||
}
|
||||
|
||||
public function testDifferentContent()
|
||||
{
|
||||
$id = 10;
|
||||
$field1 = 'field1';
|
||||
$value1 = 'value1';
|
||||
$field2 = 'field2';
|
||||
$value2 = 'value2';
|
||||
$field3 = 'field3';
|
||||
$value3 = 'value3';
|
||||
$contentField1 = new Field();
|
||||
$contentField2 = new Field();
|
||||
$data = ContentUpdateStructure::createForContentId($id, 'lang', [
|
||||
$field1 => $value1,
|
||||
$field2 => $value2,
|
||||
$field3 => $value3,
|
||||
]);
|
||||
$content = $this->createMock(Content::class);
|
||||
|
||||
$content
|
||||
->expects($this->exactly(2))
|
||||
->method('getField')
|
||||
->withConsecutive([$field1], [$field2])
|
||||
->willReturnOnConsecutiveCalls($contentField1, $contentField2)
|
||||
;
|
||||
$this->contentServiceMock
|
||||
->expects($this->once())
|
||||
->method('loadContent')
|
||||
->with($id)
|
||||
->willReturn($content)
|
||||
;
|
||||
$this->comparatorMock
|
||||
->expects($this->exactly(2))
|
||||
->method('compare')
|
||||
->withConsecutive([$contentField1, $value1], [$contentField2, $value2])
|
||||
->willReturnOnConsecutiveCalls(true, false)
|
||||
;
|
||||
|
||||
$return = ($this->notModifiedContentFilter)($data);
|
||||
|
||||
$this->assertSame($data, $return);
|
||||
}
|
||||
|
||||
public function testLoadEmptyByRemoteId()
|
||||
{
|
||||
$remoteId = 'abc';
|
||||
$data = ContentUpdateStructure::createForContentRemoteId($remoteId, 'lang', []);
|
||||
|
||||
$this->contentServiceMock
|
||||
->expects($this->once())
|
||||
->method('loadContentByRemoteId')
|
||||
->with($remoteId)
|
||||
->willReturn(new Content())
|
||||
;
|
||||
$return = ($this->notModifiedContentFilter)($data);
|
||||
|
||||
$this->assertFalse($return);
|
||||
}
|
||||
}
|
||||
11
tests/bootstrap.php
Normal file
11
tests/bootstrap.php
Normal file
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
// Skip autoloading if already done by phpunit alias (including from meta repo if this is vendor)
|
||||
if (defined('PHPUNIT_COMPOSER_INSTALL')) {
|
||||
return;
|
||||
}
|
||||
$autoloadFile = __DIR__ . '/../vendor/autoload.php';
|
||||
if (!file_exists($autoloadFile)) {
|
||||
throw new RuntimeException('Install dependencies to run test suite.');
|
||||
}
|
||||
require_once $autoloadFile;
|
||||
Reference in New Issue
Block a user