15 Commits

Author SHA1 Message Date
Jérémy J
176517f9c6 Updated CHANGELOG 2024-12-17 11:50:52 +01:00
Jérémy J
9507a39720 Added error count columns to job tables 2024-12-17 11:48:27 +01:00
Jérémy J
131045afe8 Fix NotModifiedContentFilter when creating new translation 2024-02-05 15:55:55 +01:00
jeremycr
0a47f788dc Allow Dataflow 4 (#43) 2023-07-27 09:51:45 +02:00
Jérémy
2274bbf5e5 Changelog for 3.2.0 2023-04-11 09:47:36 +02:00
jeremycr
4a0070dc04 Improvements on datetime handling + #38 + #39 (#41) 2023-04-11 09:39:57 +02:00
jeremycr
7ca493e3e8 Allow LocationCreateStruct objects inside the $locations argument of ContentCreateStructure to have more control over the created locations. (#40) 2023-01-13 16:41:37 +01:00
jbcr
473968791b bump PHP version (#37)
* bump PHP version

* update PHPUnit config
2022-01-25 16:58:20 +01:00
jbcr
dd655543ce fail-fast: false 2022-01-25 09:12:06 +01:00
jbcr
d49d23b4fe change composer command 2022-01-25 09:06:00 +01:00
jbcr
7ab5b5cbd1 remove redunded action and comment 2022-01-25 09:04:02 +01:00
jbcr
df1fcd5132 remove PHP 7.1 and PHP 7.2 2022-01-25 09:01:50 +01:00
jbcr
35d3788a59 app PHP Lint 2022-01-25 08:59:15 +01:00
jbcr
c36fef9220 Add test in action 2022-01-25 08:53:40 +01:00
jbcr
b4186ed3ce WIP: Add compatibilty to eZ Platform 3 (#20)
* update require to platform 3

* update admin to admin ui 2.0beta3

* some eZ Platform 3 change (#32)

* bump eZ required version

* enable autowire and autoconfigure on controller

* use contracts dependency for translation interface instead of Component

* change requirements

* add change log

Co-authored-by: Jean-Baptiste Nahan <814683+macintoshplus@users.noreply.github.com>
2021-06-25 14:52:13 +02:00
48 changed files with 444 additions and 284 deletions

55
.github/workflows/php.yml vendored Normal file
View File

@@ -0,0 +1,55 @@
name: PHP Composer
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
build:
strategy:
fail-fast: false
matrix:
php-version: [7.3, 7.4, 8.0, 8.1]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Setup PHP ${{ matrix.php-version }}
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php-version }}
extensions: xdebug
- name: PHP Version
run: php -v
- name: PHP Lint
run: find . -type f -name '*.php' -exec php -l {} \; | (! grep -v "No syntax errors detected" )
- name: Validate composer.json and composer.lock
run: composer validate --strict
- name: Cache Composer packages
id: composer-cache
uses: actions/cache@v2
with:
path: vendor
key: ${{ runner.os }}-php${{ matrix.php-version }}-${{ hashFiles('**/composer.lock') }}
restore-keys: |
${{ runner.os }}-php${{ matrix.php-version }}-
- name: Install dependencies
run: composer update --prefer-dist --no-progress --no-scripts
- name: PHPUnit
run: php -d xdebug.mode=coverage vendor/bin/phpunit --log-junit junit.xml
- name: Publish Unit Test Results
uses: EnricoMi/publish-unit-test-result-action@v1
if: always()
with:
files: junit.xml

1
.gitignore vendored
View File

@@ -3,3 +3,4 @@ composer.lock
.phpunit.result.cache
.php_cs.cache
.php_cs
.php-cs-fixer.cache

View File

@@ -2,7 +2,7 @@
$finder = PhpCsFixer\Finder::create()->in(__DIR__.'/src');
return PhpCsFixer\Config::create()
return (new PhpCsFixer\Config())
->setRules([
'@Symfony' => true,
'declare_strict_types' => true,

View File

@@ -1,3 +1,36 @@
# Version 3.4.0
* Added error count columns to job tables
# Version 3.3.2
* Fix NotModifiedContentFilter when creating new translation
# Version 3.3.1
* Allow Dataflow 4
# Version 3.2.0
* Fixed History page pagination is hidden by footer on Ibexa 3.3 #38
* Added filter on history page to filter out jobs with 0 items
* Date and times will now be displayed using the user defined timezone, and stored using php timezone
# Version 3.1.0
* Allow `LocationCreateStruct` objects inside the `$locations` argument of `ContentCreateStructure` to have more control over the created locations.
# Version 3.0.1
* Bump minimum PHP version to PHP 7.3 like code-rhapsodie/dataflow-bundle dependency.
* Allow PHP 8.x.
* Add GitHub Action to run tests.
# Version 3.0.0
* Add compatibility with Ibexa Content 3.3
* Add compatibility with Symfony 5.x
# Version 2.3.0
* Added a button to display exceptions / log in a modal

View File

@@ -41,19 +41,24 @@
}
},
"require": {
"php": "^7.1",
"code-rhapsodie/dataflow-bundle": "^2.1 || dev-master",
"ezsystems/ezplatform-admin-ui": "^1.0",
"ezsystems/ezpublish-kernel": "^7.0"
"php": "^7.3||^8.0",
"ext-json": "*",
"code-rhapsodie/dataflow-bundle": "^3.0||^4.0",
"ezsystems/ezplatform-admin-ui": "^2.3",
"ezsystems/ezplatform-kernel": "^1.3",
"http-interop/http-factory-guzzle": "^1.2"
},
"require-dev": {
"phpunit/phpunit": "^7||^8",
"phpunit/phpunit": "^7||^8||^9",
"doctrine/dbal": "^2.0"
},
"minimum-stability": "dev",
"prefer-stable": true,
"config": {
"sort-packages": true
"sort-packages": true,
"allow-plugins": {
"php-http/discovery": true
}
},
"extra": {
"branch-alias": {

View File

@@ -1,32 +1,21 @@
<?xml version = '1.0' encoding = 'UTF-8'?>
<?xml version="1.0" encoding="UTF-8"?>
<!-- http://www.phpunit.de/manual/current/en/appendixes.configuration.html -->
<phpunit
backupGlobals="false"
backupStaticAttributes="false"
bootstrap="tests/bootstrap.php"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
colors="false"
>
<php>
<ini name="error_reporting" value="-1" />
</php>
<testsuites>
<testsuite name="EzDataflow tests suite">
<directory suffix="Test.php">./tests</directory>
</testsuite>
</testsuites>
<filter>
<whitelist>
<directory>./src/</directory>
<exclude>
<directory>tests/</directory>
<directory>vendor/</directory>
</exclude>
</whitelist>
</filter>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" backupGlobals="false" backupStaticAttributes="false" bootstrap="tests/bootstrap.php" convertErrorsToExceptions="true" convertNoticesToExceptions="true" convertWarningsToExceptions="true" colors="false" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd">
<coverage>
<include>
<directory>./src/</directory>
</include>
<exclude>
<directory>tests/</directory>
<directory>vendor/</directory>
</exclude>
</coverage>
<php>
<ini name="error_reporting" value="-1"/>
</php>
<testsuites>
<testsuite name="EzDataflow tests suite">
<directory suffix="Test.php">./tests</directory>
</testsuite>
</testsuites>
</phpunit>

View File

@@ -4,15 +4,15 @@ declare(strict_types=1);
namespace CodeRhapsodie\EzDataflowBundle\Controller;
use CodeRhapsodie\EzDataflowBundle\Form\CreateOneshotType;
use CodeRhapsodie\EzDataflowBundle\Form\CreateScheduledType;
use CodeRhapsodie\EzDataflowBundle\Gateway\JobGateway;
use CodeRhapsodie\EzDataflowBundle\Gateway\ScheduledDataflowGateway;
use CodeRhapsodie\DataflowBundle\Entity\Job;
use CodeRhapsodie\DataflowBundle\Entity\ScheduledDataflow;
use CodeRhapsodie\EzDataflowBundle\Form\CreateOneshotType;
use CodeRhapsodie\EzDataflowBundle\Form\CreateScheduledType;
use CodeRhapsodie\EzDataflowBundle\Gateway\ExceptionJSONDecoderAdapter;
use CodeRhapsodie\EzDataflowBundle\Gateway\JobGateway;
use CodeRhapsodie\EzDataflowBundle\Gateway\ScheduledDataflowGateway;
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\DoctrineDbalAdapter;
use Pagerfanta\Pagerfanta;
@@ -27,22 +27,17 @@ class DashboardController extends Controller
{
/** @var JobGateway */
private $jobGateway;
/** @var NotificationHandlerInterface */
private $notificationHandler;
/** @var ScheduledDataflowGateway */
private $scheduledDataflowGateway;
public function __construct(JobGateway $jobGateway, NotificationHandlerInterface $notificationHandler, ScheduledDataflowGateway $scheduledDataflowGateway)
public function __construct(JobGateway $jobGateway, ScheduledDataflowGateway $scheduledDataflowGateway)
{
$this->jobGateway = $jobGateway;
$this->notificationHandler = $notificationHandler;
$this->scheduledDataflowGateway = $scheduledDataflowGateway;
}
/**
* @Route("/", name="coderhapsodie.ezdataflow.main")
*
* @return Response
*/
public function main(): Response
{
@@ -69,10 +64,6 @@ class DashboardController extends Controller
/**
* @Route("/repeating", name="coderhapsodie.ezdataflow.repeating")
*
* @param Request $request
*
* @return Response
*/
public function getRepeatingPage(Request $request): Response
{
@@ -101,10 +92,6 @@ class DashboardController extends Controller
/**
* @Route("/oneshot", name="coderhapsodie.ezdataflow.oneshot")
*
* @param Request $request
*
* @return Response
*/
public function getOneshotPage(Request $request): Response
{
@@ -118,35 +105,30 @@ class DashboardController extends Controller
public function history(Request $request): Response
{
$this->denyAccessUnlessGranted(new Attribute('ezdataflow', 'view'));
$filter = (int) $request->query->get('filter', JobGateway::FILTER_NONE);
return $this->render('@ezdesign/ezdataflow/Dashboard/history.html.twig', [
'pager' => $this->getPager($this->jobGateway->getListQueryForAdmin(), $request),
'pager' => $this->getPager($this->jobGateway->getListQueryForAdmin($filter), $request),
'filter' => $filter,
]);
}
/**
* @Route("/history", name="coderhapsodie.ezdataflow.history")
*
* @param Request $request
*
* @return Response
*/
public function getHistoryPage(Request $request): Response
{
$this->denyAccessUnlessGranted(new Attribute('ezdataflow', 'view'));
$filter = (int) $request->query->get('filter', JobGateway::FILTER_NONE);
return $this->render('@ezdesign/ezdataflow/Dashboard/history.html.twig', [
'pager' => $this->getPager($this->jobGateway->getListQueryForAdmin(), $request),
'pager' => $this->getPager($this->jobGateway->getListQueryForAdmin($filter), $request),
'filter' => $filter,
]);
}
/**
* @Route("/history/schedule/{id}", name="coderhapsodie.ezdataflow.history.workflow")
*
* @param Request $request
* @param int $id
*
* @return Response
*/
public function getHistoryForScheduled(Request $request, int $id): Response
{
@@ -160,10 +142,15 @@ class DashboardController extends Controller
private function getPager(QueryBuilder $query, Request $request): Pagerfanta
{
$pager = new Pagerfanta(new DoctrineDbalAdapter($query, function ($queryBuilder) {
return $queryBuilder->select('COUNT(DISTINCT id) AS total_results')
->setMaxResults(1);
}));
$pager = new Pagerfanta(
new ExceptionJSONDecoderAdapter(
new DoctrineDbalAdapter($query, function ($queryBuilder) {
return $queryBuilder->select('COUNT(DISTINCT id) AS total_results')
->resetQueryPart('orderBy')
->setMaxResults(1);
})
)
);
$pager->setMaxPerPage(20);
$pager->setCurrentPage($request->query->get('page', 1));

View File

@@ -15,7 +15,7 @@ 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\Contracts\Translation\TranslatorInterface;
/**
* @Route("/ezdataflow/job")
@@ -26,7 +26,7 @@ class JobController extends Controller
private $jobGateway;
/** @var NotificationHandlerInterface */
private $notificationHandler;
/** @var TranslatorInterface */
/** @var Symfony\Component\Translation\TranslatorInterface|Symfony\Contracts\Translation\TranslatorInterface */
private $translator;
public function __construct(
@@ -41,10 +41,6 @@ class JobController extends Controller
/**
* @Route("/details/{id}", name="coderhapsodie.ezdataflow.job.details")
*
* @param int $id
*
* @return Response
*/
public function displayDetails(int $id): Response
{
@@ -57,10 +53,6 @@ class JobController extends Controller
/**
* @Route("/details/log/{id}", name="coderhapsodie.ezdataflow.job.log")
*
* @param int $id
*
* @return Response
*/
public function displayLog(int $id): Response
{
@@ -77,10 +69,6 @@ class JobController extends Controller
/**
* @Route("/create", name="coderhapsodie.ezdataflow.job.create", methods={"POST"})
*
* @param Request $request
*
* @return Response
*/
public function create(Request $request): Response
{

View File

@@ -4,11 +4,11 @@ declare(strict_types=1);
namespace CodeRhapsodie\EzDataflowBundle\Controller;
use CodeRhapsodie\DataflowBundle\Entity\ScheduledDataflow;
use CodeRhapsodie\EzDataflowBundle\Form\CreateScheduledType;
use CodeRhapsodie\EzDataflowBundle\Form\UpdateScheduledType;
use CodeRhapsodie\EzDataflowBundle\Gateway\ScheduledDataflowGateway;
use CodeRhapsodie\EzDataflowBundle\Gateway\JobGateway;
use CodeRhapsodie\DataflowBundle\Entity\ScheduledDataflow;
use CodeRhapsodie\EzDataflowBundle\Gateway\ScheduledDataflowGateway;
use eZ\Publish\Core\MVC\Symfony\Security\Authorization\Attribute;
use EzSystems\EzPlatformAdminUi\Notification\NotificationHandlerInterface;
use EzSystems\EzPlatformAdminUiBundle\Controller\Controller;
@@ -16,7 +16,7 @@ use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Translation\TranslatorInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
/**
* @Route("/ezdataflow/scheduled_workflow")
@@ -32,8 +32,12 @@ class ScheduledDataflowController extends Controller
/** @var TranslatorInterface */
private $translator;
public function __construct(JobGateway $jobGateway, NotificationHandlerInterface $notificationHandler, ScheduledDataflowGateway $scheduledDataflowGateway, TranslatorInterface $translator)
{
public function __construct(
JobGateway $jobGateway,
NotificationHandlerInterface $notificationHandler,
ScheduledDataflowGateway $scheduledDataflowGateway,
TranslatorInterface $translator
) {
$this->jobGateway = $jobGateway;
$this->notificationHandler = $notificationHandler;
$this->scheduledDataflowGateway = $scheduledDataflowGateway;
@@ -42,10 +46,6 @@ class ScheduledDataflowController extends Controller
/**
* @Route("/create", name="coderhapsodie.ezdataflow.workflow.create", methods={"POST"})
*
* @param Request $request
*
* @return Response
*/
public function create(Request $request): Response
{
@@ -58,12 +58,12 @@ class ScheduledDataflowController extends Controller
if ($form->isSubmitted() && $form->isValid()) {
/** @var ScheduledDataflow $newWorkflow */
$newWorkflow = $form->getData();
try {
$this->scheduledDataflowGateway->save($newWorkflow);
$this->notificationHandler->success($this->translator->trans('coderhapsodie.ezdataflow.workflow.create.success'));
} catch (\Exception $e) {
$this->notificationHandler->error($this->translator->trans('coderhapsodie.ezdataflow.workflow.create.error', ['message' => $e->getMessage()]));
$this->notificationHandler->error($this->translator->trans('coderhapsodie.ezdataflow.workflow.create.error',
['message' => $e->getMessage()]));
}
return new JsonResponse(['redirect' => $this->generateUrl('coderhapsodie.ezdataflow.main')]);
@@ -79,10 +79,6 @@ class ScheduledDataflowController extends Controller
/**
* @Route("/{id}/delete", name="coderhapsodie.ezdataflow.workflow.delete", methods={"post"})
*
* @param int $id
*
* @return Response
*/
public function delete(int $id): Response
{
@@ -94,7 +90,8 @@ class ScheduledDataflowController extends Controller
return new JsonResponse(['code' => 200]);
} catch (\Exception $e) {
$this->notificationHandler->error($this->translator->trans('coderhapsodie.ezdataflow.workflow.delete.error', ['message' => $e->getMessage()]));
$this->notificationHandler->error($this->translator->trans('coderhapsodie.ezdataflow.workflow.delete.error',
['message' => $e->getMessage()]));
return new JsonResponse(['code' => $e->getCode()]);
}
@@ -102,11 +99,6 @@ class ScheduledDataflowController extends Controller
/**
* @Route("/{id}/edit", name="coderhapsodie.ezdataflow.workflow.edit")
*
* @param Request $request
* @param int $id
*
* @return Response
*/
public function edit(Request $request, int $id): Response
{
@@ -123,7 +115,8 @@ class ScheduledDataflowController extends Controller
$this->scheduledDataflowGateway->save($editDataflow);
$this->notificationHandler->success($this->translator->trans('coderhapsodie.ezdataflow.workflow.edit.success'));
} catch (\Exception $e) {
$this->notificationHandler->error($this->translator->trans('coderhapsodie.ezdataflow.workflow.edit.error', ['message' => $e->getMessage()]));
$this->notificationHandler->error($this->translator->trans('coderhapsodie.ezdataflow.workflow.edit.error',
['message' => $e->getMessage()]));
}
return new JsonResponse(['redirect' => $this->generateUrl('coderhapsodie.ezdataflow.main')]);
@@ -139,10 +132,6 @@ class ScheduledDataflowController extends Controller
/**
* @Route("/{id}/enable", name="coderhapsodie.ezdataflow.workflow.enable")
*
* @param int $id
*
* @return Response
*/
public function enableDataflow(int $id): Response
{
@@ -153,22 +142,6 @@ class ScheduledDataflowController extends Controller
return $this->redirectToRoute('coderhapsodie.ezdataflow.main');
}
/**
* @Route("/{id}/disable", name="coderhapsodie.ezdataflow.workflow.disable")
*
* @param int $id
*
* @return Response
*/
public function disableDataflow(int $id): Response
{
$this->denyAccessUnlessGranted(new Attribute('ezdataflow', 'edit'));
$this->changeDataflowStatus($id, false);
return $this->redirectToRoute('coderhapsodie.ezdataflow.main');
}
private function changeDataflowStatus(int $id, bool $status)
{
try {
@@ -182,4 +155,16 @@ class ScheduledDataflowController extends Controller
$this->notificationHandler->error(sprintf('An error occured : "%s".', $e->getMessage()));
}
}
/**
* @Route("/{id}/disable", name="coderhapsodie.ezdataflow.workflow.disable")
*/
public function disableDataflow(int $id): Response
{
$this->denyAccessUnlessGranted(new Attribute('ezdataflow', 'edit'));
$this->changeDataflowStatus($id, false);
return $this->redirectToRoute('coderhapsodie.ezdataflow.main');
}
}

View File

@@ -35,10 +35,6 @@ class ContentCreator implements ContentCreatorInterface
}
/**
* @param ContentCreateStructure $structure
*
* @return Content
*
* @throws \eZ\Publish\API\Repository\Exceptions\BadStateException
* @throws \eZ\Publish\API\Repository\Exceptions\ContentFieldValidationException
* @throws \eZ\Publish\API\Repository\Exceptions\ContentValidationException
@@ -58,17 +54,21 @@ class ContentCreator implements ContentCreatorInterface
}
/**
* @param array $locations
*
* @return LocationCreateStruct[]
*/
private function getLocationCreateStructs(array $locations): array
{
$locationCreateStructs = [];
foreach ($locations as $locationOrIdOrRemoteId) {
foreach ($locations as $locationOrIdOrRemoteIdOrStruct) {
if ($locationOrIdOrRemoteIdOrStruct instanceof LocationCreateStruct) {
$locationCreateStructs[] = $locationOrIdOrRemoteIdOrStruct;
continue;
}
$locationCreateStructs[] = new LocationCreateStruct([
'parentLocationId' => $this->matcher->matchLocation($locationOrIdOrRemoteId)->id,
'parentLocationId' => $this->matcher->matchLocation($locationOrIdOrRemoteIdOrStruct)->id,
]);
}

View File

@@ -30,10 +30,6 @@ class ContentUpdater implements ContentUpdaterInterface
}
/**
* @param ContentUpdateStructure $structure
*
* @return Content
*
* @throws NoMatchFoundException
* @throws \eZ\Publish\API\Repository\Exceptions\BadStateException
* @throws \eZ\Publish\API\Repository\Exceptions\ContentFieldValidationException

View File

@@ -17,8 +17,6 @@ class ContentStructFieldFiller implements ContentStructFieldFillerInterface
/**
* ContentStructFieldFiller constructor.
*
* @param iterable $fieldValueCreators
*/
public function __construct(iterable $fieldValueCreators)
{
@@ -47,10 +45,7 @@ class ContentStructFieldFiller implements ContentStructFieldFillerInterface
}
/**
* @param string $fieldTypeIdentifier
* @param mixed $hash
*
* @return Value
* @param mixed $hash
*
* @throws UnsupportedFieldTypeException
*/

View File

@@ -9,10 +9,5 @@ use eZ\Publish\API\Repository\Values\ContentType\ContentType;
interface ContentStructFieldFillerInterface
{
/**
* @param ContentType $contentType
* @param ContentStruct $contentStruct
* @param array $fieldHashes
*/
public function fillFields(ContentType $contentType, ContentStruct $contentStruct, array $fieldHashes): void;
}

View File

@@ -4,7 +4,6 @@ declare(strict_types=1);
namespace CodeRhapsodie\EzDataflowBundle\Core\Field;
use eZ\Publish\API\Repository\FieldType;
use eZ\Publish\API\Repository\FieldTypeService;
use eZ\Publish\Core\FieldType\Value;

View File

@@ -8,18 +8,10 @@ use eZ\Publish\Core\FieldType\Value;
interface FieldValueCreatorInterface
{
/**
* @param string $fieldTypeIdentifier
*
* @return bool
*/
public function supports(string $fieldTypeIdentifier): bool;
/**
* @param string $fieldTypeIdentifier
* @param mixed $hash
*
* @return Value
* @param mixed $hash
*/
public function createValue(string $fieldTypeIdentifier, $hash): Value;
}

View File

@@ -26,7 +26,7 @@ abstract class AbstractFieldComparator implements FieldComparatorInterface
}
/**
* Returns true if values are equals, false otherwise
* Returns true if values are equals, false otherwise.
*/
abstract protected function compareValues(Value $currentValue, Value $newValue): bool;
}

View File

@@ -9,8 +9,6 @@ class InvalidArgumentTypeException extends \Exception
/**
* @param string|array $expectedTypes
* @param mixed $received
*
* @return InvalidArgumentTypeException
*/
public static function create($expectedTypes, $received): self
{

View File

@@ -6,12 +6,6 @@ namespace CodeRhapsodie\EzDataflowBundle\Exception;
class UnknownFieldException extends \Exception
{
/**
* @param string $fieldIdentifier
* @param string $contentTypeIdentifier
*
* @return UnknownFieldException
*/
public static function create(string $fieldIdentifier, string $contentTypeIdentifier): self
{
return new self(sprintf(

View File

@@ -19,8 +19,6 @@ final class ContentStructureFactory implements ContentStructureFactoryInterface
/**
* ContentStructureFactory constructor.
*
* @param ContentService $contentService
*/
public function __construct(ContentService $contentService)
{
@@ -28,12 +26,8 @@ final class ContentStructureFactory implements ContentStructureFactoryInterface
}
/**
* @param array $data
* @param string $remoteId
* @param string $language
* @param string $contentType
* @param mixed $parentLocations
* @param int $mode One of the constant ContentStructureFactoryInterface::MODE_*
* @param mixed $parentLocations
* @param int $mode One of the constant ContentStructureFactoryInterface::MODE_*
*
* @return false|ContentStructure
*

View File

@@ -11,10 +11,6 @@ interface ContentStructureFactoryInterface
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
*

View File

@@ -7,6 +7,7 @@ namespace CodeRhapsodie\EzDataflowBundle\Filter;
use CodeRhapsodie\EzDataflowBundle\Core\FieldComparator\FieldComparatorInterface;
use CodeRhapsodie\EzDataflowBundle\Model\ContentUpdateStructure;
use eZ\Publish\API\Repository\ContentService;
use eZ\Publish\API\Repository\Exceptions\NotFoundException;
use Psr\Log\LoggerAwareTrait;
/**
@@ -22,7 +23,6 @@ class NotModifiedContentFilter
/** @var FieldComparatorInterface */
private $comparator;
public function __construct(ContentService $contentService, FieldComparatorInterface $comparator)
{
$this->contentService = $contentService;
@@ -38,12 +38,17 @@ class NotModifiedContentFilter
if ($data->getId()) {
$content = $this->contentService->loadContent($data->getId(), [$data->getLanguageCode()]);
} else {
$content = $this->contentService->loadContentByRemoteId($data->getRemoteId(), [$data->getLanguageCode()]);
try {
$content = $this->contentService->loadContentByRemoteId($data->getRemoteId(), [$data->getLanguageCode()]);
} catch (NotFoundException $e) {
// New translation
return $data;
}
}
foreach ($data->getFields() as $identifier => $hash) {
$field = $content->getField($identifier, $data->getLanguageCode());
if ($field === null || !$this->comparator->compare($field, $hash)) {
if (null === $field || !$this->comparator->compare($field, $hash)) {
// At least one field is different, continue the dataflow.
return $data;
}
@@ -51,12 +56,13 @@ class NotModifiedContentFilter
// All fields are identical, filter this item out.
$this->log('info', 'Not modified content skipped', ['id' => $data->getId(), 'remote_id' => $data->getRemoteId()]);
return false;
}
private function log(string $level, string $message, array $context = [])
{
if ($this->logger === null) {
if (null === $this->logger) {
return;
}
$this->logger->log($level, $message, $context);

View File

@@ -6,7 +6,6 @@ namespace CodeRhapsodie\EzDataflowBundle\Form;
use CodeRhapsodie\DataflowBundle\Entity\Job;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\DateTimeType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
@@ -30,7 +29,7 @@ class CreateOneshotType extends AbstractType
'placeholder' => 'coderhapsodie.dataflow.options.placeholder',
],
])
->add('requestedDate', DateTimeType::class, [
->add('requestedDate', UserTimezoneAwareDateTimeType::class, [
'label' => 'coderhapsodie.dataflow.requestedDate',
'years' => range(date('Y'), date('Y') + 5),
])

View File

@@ -7,7 +7,6 @@ namespace CodeRhapsodie\EzDataflowBundle\Form;
use CodeRhapsodie\DataflowBundle\Entity\ScheduledDataflow;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\DateTimeType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
@@ -38,7 +37,7 @@ class CreateScheduledType extends AbstractType
],
'label' => 'coderhapsodie.dataflow.frequency',
])
->add('next', DateTimeType::class, [
->add('next', UserTimezoneAwareDateTimeType::class, [
'years' => range(date('Y'), date('Y') + 5),
'label' => 'coderhapsodie.dataflow.create.next',
])

View File

@@ -6,7 +6,6 @@ namespace CodeRhapsodie\EzDataflowBundle\Form;
use CodeRhapsodie\DataflowBundle\Entity\ScheduledDataflow;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\DateTimeType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
@@ -32,7 +31,7 @@ class UpdateScheduledType extends AbstractType
],
'label' => 'coderhapsodie.dataflow.frequency',
])
->add('next', DateTimeType::class, [
->add('next', UserTimezoneAwareDateTimeType::class, [
'years' => range(date('Y'), date('Y') + 5),
'label' => 'coderhapsodie.dataflow.update.next',
])

View File

@@ -0,0 +1,51 @@
<?php
declare(strict_types=1);
namespace CodeRhapsodie\EzDataflowBundle\Form;
use eZ\Publish\API\Repository\Exceptions\NotFoundException;
use eZ\Publish\API\Repository\UserPreferenceService;
use Symfony\Component\Form\DataTransformerInterface;
class UserTimezoneAwareDateTimeTransformer implements DataTransformerInterface
{
/** @var UserPreferenceService */
private $userPreferenceService;
public function __construct(UserPreferenceService $userPreferenceService)
{
$this->userPreferenceService = $userPreferenceService;
}
public function transform($value)
{
if (!$value instanceof \DateTimeInterface) {
return $value;
}
return (new \DateTime('now', $this->userTimezone()))->setTimestamp($value->getTimestamp());
}
public function reverseTransform($value)
{
if (!$value instanceof \DateTimeInterface) {
return $value;
}
$dateTimeWithUserTimeZone = new \DateTime($value->format('Y-m-d H:i:s'), $this->userTimezone());
return (new \DateTime())->setTimestamp($dateTimeWithUserTimeZone->getTimestamp());
}
private function userTimezone(): \DateTimeZone
{
try {
$tz = $this->userPreferenceService->getUserPreference('timezone')->value ?? 'UTC';
} catch (NotFoundException $e) {
$tz = 'UTC';
}
return new \DateTimeZone($tz);
}
}

View File

@@ -0,0 +1,31 @@
<?php
declare(strict_types=1);
namespace CodeRhapsodie\EzDataflowBundle\Form;
use eZ\Publish\API\Repository\UserPreferenceService;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\DateTimeType;
use Symfony\Component\Form\FormBuilderInterface;
class UserTimezoneAwareDateTimeType extends AbstractType
{
/** @var UserPreferenceService */
private $userPreferenceService;
public function __construct(UserPreferenceService $userPreferenceService)
{
$this->userPreferenceService = $userPreferenceService;
}
public function getParent()
{
return DateTimeType::class;
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->addModelTransformer(new UserTimezoneAwareDateTimeTransformer($this->userPreferenceService));
}
}

View File

@@ -0,0 +1,35 @@
<?php
declare(strict_types=1);
namespace CodeRhapsodie\EzDataflowBundle\Gateway;
use Pagerfanta\Adapter\AdapterInterface;
class ExceptionJSONDecoderAdapter implements AdapterInterface
{
/** @var AdapterInterface */
private $adapter;
public function __construct(AdapterInterface $adapter)
{
$this->adapter = $adapter;
}
public function getNbResults()
{
return $this->adapter->getNbResults();
}
public function getSlice($offset, $length)
{
$slice = $this->adapter->getSlice($offset, $length);
array_walk($slice, static function (&$value) {
if (isset($value['exceptions'])) {
$value['exceptions'] = json_decode($value['exceptions'], true, 512, JSON_THROW_ON_ERROR);
}
});
return $slice;
}
}

View File

@@ -10,6 +10,9 @@ use Doctrine\DBAL\Query\QueryBuilder;
final class JobGateway
{
public const FILTER_NONE = 0;
public const FILTER_NON_EMPTY = 1;
/** @var JobRepository */
private $jobRepository;
@@ -30,10 +33,17 @@ final class JobGateway
->addOrderBy('i.requested_date', 'DESC');
}
public function getListQueryForAdmin(): QueryBuilder
public function getListQueryForAdmin(int $filter): QueryBuilder
{
return $this->jobRepository->createQueryBuilder('w')
->addOrderBy('w.requested_date', 'DESC');
$qb = $this->jobRepository->createQueryBuilder('w')
->addOrderBy('w.requested_date', 'DESC')
;
if (self::FILTER_NON_EMPTY === $filter) {
$qb->andWhere('w.count > 0');
}
return $qb;
}
public function getListQueryForScheduleAdmin(int $id): QueryBuilder
@@ -44,9 +54,6 @@ final class JobGateway
->addOrderBy('w.requested_date', 'DESC');
}
/**
* @param Job $job
*/
public function save(Job $job)
{
$this->jobRepository->save($job);

View File

@@ -29,17 +29,12 @@ final class ScheduledDataflowGateway
->addOrderBy('s.label', 'ASC');
}
/**
* @param ScheduledDataflow $scheduledDataflow
*/
public function save(ScheduledDataflow $scheduledDataflow)
{
$this->scheduledDataflowRepository->save($scheduledDataflow);
}
/**
* @param int $id
*
* @throws \Throwable
*/
public function delete(int $id): void

View File

@@ -22,8 +22,6 @@ class LocationMatcher implements LocationMatcherInterface
/**
* @param mixed $valueToMatch
*
* @return Location
*
* @throws NoMatchFoundException
* @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException
*/

View File

@@ -10,8 +10,6 @@ interface LocationMatcherInterface
{
/**
* @param mixed $valueToMatch
*
* @return Location
*/
public function matchLocation($valueToMatch): Location;
}

View File

@@ -6,6 +6,7 @@ namespace CodeRhapsodie\EzDataflowBundle\Model;
use CodeRhapsodie\EzDataflowBundle\Exception\InvalidArgumentTypeException;
use eZ\Publish\API\Repository\Values\Content\Location;
use eZ\Publish\API\Repository\Values\Content\LocationCreateStruct;
class ContentCreateStructure extends ContentStructure
{
@@ -18,17 +19,14 @@ class ContentCreateStructure extends ContentStructure
/**
* ContentCreateStructure constructor.
*
* @param string $contentTypeIdentifier
* @param string $languageCode
* @param array $locations
* A location can be any of the following:
* <ul>
* <li>an integer, the id of the Location object</li>
* <li>a string, the remote id of the Location object</li>
* <li>a Location object</li>
* </ul>
* @param array $fields
* @param string|null $remoteId
* @param array $locations
* A location can be any of the following:
* <ul>
* <li>an integer, the id of the Location object</li>
* <li>a string, the remote id of the Location object</li>
* <li>a Location object</li>
* <li>a LocationCreateStruct object</li>
* </ul>
*
* @throws InvalidArgumentTypeException
*/
@@ -41,35 +39,28 @@ class ContentCreateStructure extends ContentStructure
$this->remoteId = $remoteId;
}
/**
* @return string
*/
public function getContentTypeIdentifier(): string
{
return $this->contentTypeIdentifier;
}
/**
* @return array
*/
public function getLocations(): array
{
return $this->locations;
}
/**
* @param array $locations
*
* @throws InvalidArgumentTypeException
*/
private function setLocations(array $locations)
{
foreach ($locations as $locationOrIdOrRemoteId) {
if (!is_int($locationOrIdOrRemoteId)
&& !is_string($locationOrIdOrRemoteId)
&& !$locationOrIdOrRemoteId instanceof Location
foreach ($locations as $locationOrIdOrRemoteIdOrStruct) {
if (!is_int($locationOrIdOrRemoteIdOrStruct)
&& !is_string($locationOrIdOrRemoteIdOrStruct)
&& !$locationOrIdOrRemoteIdOrStruct instanceof Location
&& !$locationOrIdOrRemoteIdOrStruct instanceof LocationCreateStruct
) {
throw InvalidArgumentTypeException::create(['int', 'string', Location::class], $locationOrIdOrRemoteId);
throw InvalidArgumentTypeException::create(['int', 'string', Location::class, LocationCreateStruct::class], $locationOrIdOrRemoteIdOrStruct);
}
}

View File

@@ -15,25 +15,16 @@ abstract class ContentStructure
/** @var array */
protected $fields;
/**
* @return string|null
*/
public function getRemoteId(): ?string
{
return $this->remoteId;
}
/**
* @return string
*/
public function getLanguageCode(): string
{
return $this->languageCode;
}
/**
* @return array
*/
public function getFields(): array
{
return $this->fields;

View File

@@ -15,13 +15,6 @@ class ContentUpdateStructure extends ContentStructure
$this->fields = $fields;
}
/**
* @param int $id
* @param string $languageCode
* @param array $fields
*
* @return ContentUpdateStructure
*/
public static function createForContentId(int $id, string $languageCode, array $fields): self
{
$struct = new self($languageCode, $fields);
@@ -30,13 +23,6 @@ class ContentUpdateStructure extends ContentStructure
return $struct;
}
/**
* @param string $remoteId
* @param string $languageCode
* @param array $fields
*
* @return ContentUpdateStructure
*/
public static function createForContentRemoteId(string $remoteId, string $languageCode, array $fields): self
{
$struct = new self($languageCode, $fields);
@@ -45,9 +31,6 @@ class ContentUpdateStructure extends ContentStructure
return $struct;
}
/**
* @return int|null
*/
public function getId(): ?int
{
return $this->id;

View File

@@ -9,25 +9,39 @@ services:
CodeRhapsodie\EzDataflowBundle\Controller\DashboardController:
public: true
tags:
- { name: controller.service_arguments }
arguments:
$jobGateway: '@CodeRhapsodie\EzDataflowBundle\Gateway\JobGateway'
$notificationHandler: '@EzSystems\EzPlatformAdminUi\Notification\NotificationHandlerInterface'
$scheduledDataflowGateway: '@CodeRhapsodie\EzDataflowBundle\Gateway\ScheduledDataflowGateway'
calls:
- ['setContainer', ['@service_container']]
- ['performAccessCheck', []]
CodeRhapsodie\EzDataflowBundle\Controller\ScheduledDataflowController:
public: true
tags:
- { name: controller.service_arguments }
arguments:
$jobGateway: '@CodeRhapsodie\EzDataflowBundle\Gateway\JobGateway'
$notificationHandler: '@EzSystems\EzPlatformAdminUi\Notification\NotificationHandlerInterface'
$scheduledDataflowGateway: '@CodeRhapsodie\EzDataflowBundle\Gateway\ScheduledDataflowGateway'
$translator: '@translator'
calls:
- [ 'setContainer', [ '@service_container' ] ]
- [ 'performAccessCheck', [ ] ]
CodeRhapsodie\EzDataflowBundle\Controller\JobController:
public: true
tags:
- { name: controller.service_arguments }
arguments:
$jobGateway: '@CodeRhapsodie\EzDataflowBundle\Gateway\JobGateway'
$notificationHandler: '@EzSystems\EzPlatformAdminUi\Notification\NotificationHandlerInterface'
$translator: '@translator'
calls:
- [ 'setContainer', [ '@service_container' ] ]
- [ 'performAccessCheck', [ ] ]
CodeRhapsodie\EzDataflowBundle\Writer\RepositoryWriter:
abstract: true
@@ -102,6 +116,11 @@ services:
CodeRhapsodie\EzDataflowBundle\Form\CreateOneshotType:
tags: ['form.type']
CodeRhapsodie\EzDataflowBundle\Form\UserTimezoneAwareDateTimeType:
arguments:
$userPreferenceService: '@eZ\Publish\API\Repository\UserPreferenceService'
tags: ['form.type']
CodeRhapsodie\EzDataflowBundle\Gateway\ScheduledDataflowGateway:
arguments:
$scheduledDataflowRepository: '@CodeRhapsodie\DataflowBundle\Repository\ScheduledDataflowRepository'
@@ -113,21 +132,28 @@ services:
CodeRhapsodie\EzDataflowBundle\Tab\RepeatingTab:
parent: EzSystems\EzPlatformAdminUi\Tab\AbstractTab
public: false
arguments:
$httpKernelRuntime: '@twig.runtime.httpkernel'
tags:
- {name: ezplatform.tab, group: coderhapsodie-ezdataflow}
CodeRhapsodie\EzDataflowBundle\Tab\OneshotTab:
parent: EzSystems\EzPlatformAdminUi\Tab\AbstractTab
public: false
arguments:
$httpKernelRuntime: '@twig.runtime.httpkernel'
tags:
- {name: ezplatform.tab, group: coderhapsodie-ezdataflow}
CodeRhapsodie\EzDataflowBundle\Tab\HistoryTab:
parent: EzSystems\EzPlatformAdminUi\Tab\AbstractTab
public: false
arguments:
$httpKernelRuntime: '@twig.runtime.httpkernel'
tags:
- {name: ezplatform.tab, group: coderhapsodie-ezdataflow}
CodeRhapsodie\EzDataflowBundle\Filter\NotModifiedContentFilter:
arguments:
$contentService: '@eZ\Publish\API\Repository\ContentService'
@@ -140,3 +166,14 @@ services:
arguments:
$fieldTypeService: '@eZ\Publish\API\Repository\FieldTypeService'
abstract: true
_cr.admin_tabs.ezdataflow_group:
parent: EzSystems\EzPlatformAdminUi\Component\TabsComponent
autowire: true
autoconfigure: false
public: false
arguments:
$template: '@@ezdesign/ezdataflow/parts/tab/ezdataflow.html.twig'
$groupIdentifier: 'coderhapsodie-ezdataflow'
tags:
- { name: ezplatform.admin_ui.component, group: 'coderhapsodie-ezdataflow' }

View File

@@ -20,11 +20,16 @@ coderhapsodie.ezdataflow.history.title: History
coderhapsodie.ezdataflow.history.list.title: 'Executions list'
coderhapsodie.ezdataflow.history.list.name: Name
coderhapsodie.ezdataflow.history.list.request: 'Requested on'
coderhapsodie.ezdataflow.history.list.count: 'Items count'
coderhapsodie.ezdataflow.history.list.count: 'Number of successes'
coderhapsodie.ezdataflow.history.list.errors: 'Number of errors'
coderhapsodie.ezdataflow.history.list.start: 'Started on'
coderhapsodie.ezdataflow.history.list.end: 'Finished on'
coderhapsodie.ezdataflow.history.list.view: 'View details'
coderhapsodie.ezdataflow.history.list.status: Status
coderhapsodie.ezdataflow.history.filter.label: Filter results
coderhapsodie.ezdataflow.history.filter.none: All results
coderhapsodie.ezdataflow.history.filter.non_empty_only: Only non empty
coderhapsodie.ezdataflow.history.filter.with_error_only: Only with errors
coderhapsodie.ezdataflow.job.status.pending: Pending
coderhapsodie.ezdataflow.job.status.running: Running
coderhapsodie.ezdataflow.job.status.complete: Completed

View File

@@ -20,7 +20,8 @@ coderhapsodie.ezdataflow.history.title: Historique
coderhapsodie.ezdataflow.history.list.title: 'Liste des exécutions'
coderhapsodie.ezdataflow.history.list.name: Nom
coderhapsodie.ezdataflow.history.list.request: 'Demandé le'
coderhapsodie.ezdataflow.history.list.count: 'Nombre d''objets'
coderhapsodie.ezdataflow.history.list.count: 'Nombre de succès'
coderhapsodie.ezdataflow.history.list.errors: 'Nombre d''erreurs'
coderhapsodie.ezdataflow.history.list.start: 'Commencé le'
coderhapsodie.ezdataflow.history.list.end: 'Terminé le'
coderhapsodie.ezdataflow.history.list.view: 'Voir le détail'

View File

@@ -2,6 +2,34 @@
<div class="ez-table-header">
<div class="ez-table-header__headline">{{ 'coderhapsodie.ezdataflow.history.list.title'|trans }}</div>
<div class="ez-table-header__tools">
<label for="ezdataflow_history_filter">{{ 'coderhapsodie.ezdataflow.history.filter.label'|trans }}</label>
<select id="ezdataflow_history_filter" name="filter">
<option value="0" {{ filter == 0 ? 'selected="selected"' }}>{{ 'coderhapsodie.ezdataflow.history.filter.none'|trans }}</option>
<option value="1" {{ filter == 1 ? 'selected="selected"' }}>{{ 'coderhapsodie.ezdataflow.history.filter.non_empty_only'|trans }}</option>
</select>
</div>
</div>
{% include '@ezdesign/ezdataflow/parts/tab/job_list.html.twig' with {identifier: 'ezdataflow_history_results', paginate_route: 'coderhapsodie.ezdataflow.history'} %}
{% include '@ezdesign/ezdataflow/parts/tab/job_list.html.twig' with {
identifier: 'ezdataflow_history_results',
paginate_route: 'coderhapsodie.ezdataflow.history',
paginate_params: {'filter': filter}
} %}
<script>
(function ($) {
$(document).ready(function ($) {
// Manage ajax pagination
$('#ezdataflow_history_filter').change(function (e) {
e.preventDefault();
$('#loading_ezdataflow_history_results').removeClass('d-none');
$('#ezdataflow_history_results')
.html('')
.load('{{ path('coderhapsodie.ezdataflow.history') }}?filter=' + this.value + ' #ezdataflow_history_results>*', null, function () {
$('#loading_ezdataflow_history_results').addClass('d-none');
});
});
});
})(jQuery);
</script>

View File

@@ -1,21 +1,23 @@
{% extends "@ezdesign/layout.html.twig" %}
{% extends ["@ezdesign/layout.html.twig", "@ezdesign/ui/layout.html.twig"] %}
{% block body_class %}ez-has-full-width-footer{% endblock %}
{% block breadcrumbs %}
{% include '@ezdesign/parts/breadcrumbs.html.twig' with { items: [
{% include ['@ezdesign/parts/breadcrumbs.html.twig', '@ezdesign/ui/breadcrumbs.html.twig'] with { items: [
{ value: 'breadcrumb.admin'|trans(domain='messages')|desc('Admin') },
{ value: 'coderhapsodie.ezdataflow'|trans|desc('EzDataflow') }
]} %}
{% endblock %}
{% block page_title %}
{% include '@ezdesign/parts/page_title.html.twig' with {
{% include ['@ezdesign/parts/page_title.html.twig', '@ezdesign/ui/page_title.html.twig'] with {
title: 'coderhapsodie.ezdataflow'|trans|desc('EzDataflow'),
iconName: 'workflow'
} %}
{% endblock %}
{% block content %}
{{ ez_platform_tabs('coderhapsodie-ezdataflow', {}, '@ezdesign/ezdataflow/parts/tab/ezdataflow.html.twig') }}
{{ ez_render_component_group('coderhapsodie-ezdataflow', {'filter': app.request.query.get('filter', 0)}, '@ezdesign/ezdataflow/parts/tab/ezdataflow.html.twig') }}
<div class="modal fade ez-modal show" id="ez-modal--history-details" tabindex="-1" role="dialog" aria-modal="true">
<div class="modal-dialog" role="document" style="max-width: 90%">

View File

@@ -40,9 +40,10 @@
success: function (result) {
if (result.redirect) {
if (window.location.href === result.redirect) {
document.location.reload();
window.location.reload();
}
window.location = result.redirect;
window.location.reload();
return;
}

View File

@@ -125,9 +125,10 @@
success: function (result) {
if (result.redirect) {
if (window.location.href === result.redirect) {
document.location.reload();
window.location.reload();
}
window.location = result.redirect;
window.location.reload();
return;
}

View File

@@ -20,7 +20,7 @@
</tr>
<tr>
<td>{{ 'coderhapsodie.ezdataflow.history.details.request'|trans }}</td>
<td>{{ item.requestedDate|date('d/m/Y H:i:s') }}</td>
<td>{{ date(item.requestedDate)|ez_short_datetime }}</td>
</tr>
<tr>
<td>{{ 'coderhapsodie.ezdataflow.history.details.status'|trans }}</td>
@@ -28,11 +28,11 @@
</tr>
<tr>
<td>{{ 'coderhapsodie.ezdataflow.history.details.start'|trans }}</td>
<td>{{ item.startTime|date('d/m/Y H:i:s') }}</td>
<td>{{ item.startTime ? date(item.startTime)|ez_short_datetime : '—' }}</td>
</tr>
<tr>
<td>{{ 'coderhapsodie.ezdataflow.history.details.end'|trans }}</td>
<td>{{ item.endTime|date('d/m/Y H:i:s') }}</td>
<td>{{ item.endTime ? date(item.endTime)|ez_short_datetime : '—' }}</td>
</tr>
<tr>
<td>{{ 'coderhapsodie.ezdataflow.history.details.count'|trans }}</td>

View File

@@ -17,6 +17,7 @@
<th>{{ 'coderhapsodie.ezdataflow.history.list.name'|trans }}</th>
<th>{{ 'coderhapsodie.ezdataflow.history.list.request'|trans }}</th>
<th>{{ 'coderhapsodie.ezdataflow.history.list.count'|trans }}</th>
<th>{{ 'coderhapsodie.ezdataflow.history.list.errors'|trans }}</th>
<th>{{ 'coderhapsodie.ezdataflow.history.list.start'|trans }}</th>
<th>{{ 'coderhapsodie.ezdataflow.history.list.end'|trans }}</th>
<th>{{ 'coderhapsodie.ezdataflow.history.list.status'|trans }}</th>
@@ -27,10 +28,11 @@
{% for job in pager.currentPageResults %}
<tr>
<td>{{ job.label }}</td>
<td>{{ job.requested_date|date('d/m/Y H:i:s') }}</td>
<td>{{ job.count|default('-') }}</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>{{ date(job.requested_date)|ez_short_datetime }}</td>
<td>{{ job.count|default('') }}</td>
<td>{{ job.exceptions|length }}</td>
<td>{{ job.start_time ? date(job.start_time)|ez_short_datetime : '' }}</td>
<td>{{ job.end_time ? date(job.end_time)|ez_short_datetime : '—' }}</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}) }}"
@@ -66,7 +68,6 @@
</div>
<script>
(function ($) {
$(document).ready(function ($) {
// Manage ajax pagination

View File

@@ -24,7 +24,7 @@
<tr>
<td>{{ item.label }}</td>
<td>{{ item.frequency }}</td>
<td>{{ item.next|date('d/m/Y H:i:s') }}</td>
<td>{{ date(item.next)|ez_short_datetime }}</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}) }}"

View File

@@ -16,7 +16,7 @@ class HistoryTab extends AbstractControllerBasedTab implements OrderedTabInterfa
*/
public function getControllerReference(array $parameters): ControllerReference
{
return new ControllerReference(DashboardController::class.'::history');
return new ControllerReference(DashboardController::class.'::history', [], $parameters);
}
/**

View File

@@ -9,9 +9,6 @@ trait UserSwitcherAwareTrait
/** @var UserSwitcherInterface */
protected $userSwitcher;
/**
* @param UserSwitcherInterface $userSwitcher
*/
public function setUserSwitcher(UserSwitcherInterface $userSwitcher): void
{
$this->userSwitcher = $userSwitcher;

View File

@@ -10,7 +10,6 @@ use CodeRhapsodie\EzDataflowBundle\Core\Content\ContentUpdaterInterface;
use CodeRhapsodie\EzDataflowBundle\Model\ContentCreateStructure;
use CodeRhapsodie\EzDataflowBundle\Model\ContentStructure;
use CodeRhapsodie\EzDataflowBundle\Model\ContentUpdateStructure;
use Psr\Log\LoggerAwareTrait;
class ContentWriter extends RepositoryWriter implements DelegateWriterInterface
@@ -35,20 +34,23 @@ class ContentWriter extends RepositoryWriter implements DelegateWriterInterface
public function write($item)
{
if (!$item instanceof ContentStructure) {
$this->log('warning', "Data is not a ContentStucture");
$this->log('warning', 'Data is not a ContentStucture');
return;
}
if ($item instanceof ContentCreateStructure) {
$this->log('info', 'Save content', [
'content_type' => $item->getContentTypeIdentifier(),
'content_location' => $item->getLocations()
'content_location' => $item->getLocations(),
]);
return $this->creator->createFromStructure($item);
}
if ($item instanceof ContentUpdateStructure) {
$this->log('info', 'Update content', ['id' => $item->getId(), 'remote_id' => $item->getRemoteId()]);
return $this->updater->updateFromStructure($item);
}
}
@@ -63,7 +65,7 @@ class ContentWriter extends RepositoryWriter implements DelegateWriterInterface
private function log(string $level, string $message, array $context = [])
{
if ($this->logger === null) {
if (null === $this->logger) {
return;
}
$this->logger->log($level, $message, $context);

View File

@@ -4,9 +4,9 @@ declare(strict_types=1);
namespace CodeRhapsodie\EzDataflowBundle\Writer;
use CodeRhapsodie\DataflowBundle\DataflowType\Writer\WriterInterface;
use CodeRhapsodie\EzDataflowBundle\UserSwitcher\UserSwitcherAwareInterface;
use CodeRhapsodie\EzDataflowBundle\UserSwitcher\UserSwitcherAwareTrait;
use CodeRhapsodie\DataflowBundle\DataflowType\Writer\WriterInterface;
abstract class RepositoryWriter implements WriterInterface, UserSwitcherAwareInterface
{