1 Commits

Author SHA1 Message Date
jb cr
2c8c2112a1 add make by mention 2025-04-01 16:53:50 +02:00
82 changed files with 220 additions and 694 deletions

View File

@@ -1,23 +1,3 @@
# Version 6.1.0
* Add `ibexa_product_specification` comparator
* Add `attributes` in `ProductCreateStructure` and `ProductUpdateStructure`
# Version 6.0.1
* Fix taxonomy comparator
# Version 6.0.0
* Ibexa 5.0+ support
* Comparators for Ibexa Commerce / Experience field types
# Version 5.2.1
* Fixed datepicker in oneshot modal
# Version 5.2.0
* Added Dashboard tab
# Version 5.1.1
* Add branding label
# Version 5.1.0
* Added possibility to create one shot job from scheduled job

View File

@@ -13,7 +13,7 @@ Ibexa Dataflow bundle is intended to manage content imports from external data s
| Ibexa Dataflow Version | Ibexa Content Version | Status |
|------------------------|-----------------------|-------------------------------|
| 6.x | 5.x | :white_check_mark: Maintained |
| 5.x | 4.x | :white_check_mark: Maintained |
## User Interface (UI)
@@ -232,32 +232,27 @@ the `NotModifiedContentFilter` to prevent unnecessary overhead.
### Supported field types
- ibexa_author
- ibexa_boolean
- ibexa_country
- ibexa_datetime
- ibexa_date
- ibexa_email
- ibexa_float
- ibexa_integer
- ibexa_isbn
- ibexa_keyword
- ibexa_object_relation
- ibexa_object_relation_list
- ibexa_richtext
- ibexa_selection
- ibexa_text
- ibexa_string
- ibexa_time
- ezstring
- ezauthor
- ezboolean
- ezcountry
- ezdate
- ezdatetime
- ezemail
- ezfloat
- ezisbn
- ezobjectrelation
- ezobjectrelationlist
- ezkeyword
- ezselection
- eztext
- eztime
- eztags
- ibexa_url
- novaseometas
- ibexa_matrix
- ibexa_gmap_location
- ibexa_taxonomy_entry_assignment
- ibexa_address
- ibexa_customer_group
- ibexa_product_specification
- ezurl
- ezmatrix
- ezgmaplocation
- ezrichtext
### Add custom field comparator

View File

@@ -44,17 +44,16 @@
}
},
"require": {
"php": "^8.3",
"php": "^8.1",
"ext-json": "*",
"code-rhapsodie/dataflow-bundle": "^5.0",
"guzzlehttp/promises": "^2.2",
"code-rhapsodie/dataflow-bundle": "^3.0||^4.0",
"http-interop/http-factory-guzzle": "^1.2",
"ibexa/admin-ui": "^5.0",
"ibexa/core": "^5.0"
"ibexa/admin-ui": "^4.6",
"ibexa/core": "^4.6"
},
"require-dev": {
"doctrine/dbal": "^3.0",
"phpunit/phpunit": "^12.0",
"doctrine/dbal": "^2.0|^3.0",
"phpunit/phpunit": "^7||^8||^9",
"rector/rector": "^2.0"
},
"minimum-stability": "dev",
@@ -69,8 +68,7 @@
"extra": {
"branch-alias": {
"dev-v4.x": "4.x-dev",
"dev-v5.x": "5.x-dev",
"dev-v6.x": "6.x-dev"
"dev-v5.x": "5.x-dev"
}
}
}

View File

@@ -10,9 +10,9 @@ return RectorConfig::configure()
__DIR__ . '/src',
__DIR__ . '/tests',
])
->withPhpVersion(PhpVersion::PHP_83)
->withPhpVersion(PhpVersion::PHP_81)
// uncomment to reach your current PHP version
->withPhpSets(php83: true)
->withPhpSets(php81: true)
->withTypeCoverageLevel(0)
->withDeadCodeLevel(0)
->withCodeQualityLevel(0)

View File

@@ -9,23 +9,21 @@ use CodeRhapsodie\IbexaDataflowBundle\DependencyInjection\Compiler\FieldComparat
use CodeRhapsodie\IbexaDataflowBundle\Security\PolicyProvider;
use Ibexa\Bundle\Core\DependencyInjection\IbexaCoreExtension;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Extension\ExtensionInterface;
use Symfony\Component\HttpKernel\Bundle\Bundle;
class CodeRhapsodieIbexaDataflowBundle extends Bundle
{
public const string VERSION = '6.0.0';
public const string PRODUCT_NAME = 'ibexadataflow';
public const VERSION = '5.1.0';
public const PRODUCT_NAME = 'ibexadataflow';
protected string $name = 'CodeRhapsodieIbexaDataflowBundle';
protected $name = 'CodeRhapsodieIbexaDataflowBundle';
#[\Override]
public function getContainerExtension(): ?ExtensionInterface
public function getContainerExtension()
{
return new CodeRhapsodieIbexaDataflowExtension();
}
public function build(ContainerBuilder $container): void
public function build(ContainerBuilder $container)
{
parent::build($container);
@@ -36,3 +34,4 @@ class CodeRhapsodieIbexaDataflowBundle extends Bundle
$ibexaExtension->addPolicyProvider(new PolicyProvider());
}
}
class_alias(CodeRhapsodieIbexaDataflowBundle::class, 'CodeRhapsodie\EzDataflowBundle\CodeRhapsodieIbexaDataflowBundle');

View File

@@ -6,8 +6,6 @@ namespace CodeRhapsodie\IbexaDataflowBundle\Controller;
use CodeRhapsodie\DataflowBundle\Entity\Job;
use CodeRhapsodie\DataflowBundle\Entity\ScheduledDataflow;
use CodeRhapsodie\DataflowBundle\ExceptionsHandler\ExceptionHandlerInterface;
use CodeRhapsodie\DataflowBundle\ExceptionsHandler\NullExceptionHandler;
use CodeRhapsodie\IbexaDataflowBundle\CodeRhapsodieIbexaDataflowBundle;
use CodeRhapsodie\IbexaDataflowBundle\Form\CreateOneshotType;
use CodeRhapsodie\IbexaDataflowBundle\Form\CreateScheduledType;
@@ -15,7 +13,6 @@ use CodeRhapsodie\IbexaDataflowBundle\Form\UpdateScheduledType;
use CodeRhapsodie\IbexaDataflowBundle\Gateway\ExceptionJSONDecoderAdapter;
use CodeRhapsodie\IbexaDataflowBundle\Gateway\JobGateway;
use CodeRhapsodie\IbexaDataflowBundle\Gateway\ScheduledDataflowGateway;
use CodeRhapsodie\IbexaDataflowBundle\Gateway\TransformingAdapter;
use Doctrine\DBAL\Query\QueryBuilder;
use Ibexa\Contracts\AdminUi\Controller\Controller;
use Ibexa\Contracts\Core\Ibexa;
@@ -24,16 +21,12 @@ use Pagerfanta\Doctrine\DBAL\QueryAdapter;
use Pagerfanta\Pagerfanta;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Routing\Annotation\Route;
#[Route(path: '/ibexa_dataflow')]
class DashboardController extends Controller
{
public function __construct(
private readonly JobGateway $jobGateway,
private readonly ScheduledDataflowGateway $scheduledDataflowGateway,
private readonly ExceptionHandlerInterface $exceptionHandler
)
public function __construct(private readonly JobGateway $jobGateway, private readonly ScheduledDataflowGateway $scheduledDataflowGateway)
{
}
@@ -95,7 +88,7 @@ class DashboardController extends Controller
]);
return $this->render('@ibexadesign/ibexa_dataflow/Dashboard/oneshot.html.twig', [
'pager' => $this->getPager($this->jobGateway->getOneshotListQueryForAdmin(), $request, Job::class),
'pager' => $this->getPager($this->jobGateway->getOneshotListQueryForAdmin(), $request),
'form' => $form->createView(),
]);
}
@@ -106,7 +99,7 @@ class DashboardController extends Controller
$this->denyAccessUnlessGranted(new Attribute('ibexa_dataflow', 'view'));
return $this->render('@ibexadesign/ibexa_dataflow/Dashboard/oneshot.html.twig', [
'pager' => $this->getPager($this->jobGateway->getOneshotListQueryForAdmin(), $request, Job::class),
'pager' => $this->getPager($this->jobGateway->getOneshotListQueryForAdmin(), $request),
]);
}
@@ -117,7 +110,7 @@ class DashboardController extends Controller
$filter = (int) $request->query->get('filter', JobGateway::FILTER_NONE);
return $this->render('@ibexadesign/ibexa_dataflow/Dashboard/history.html.twig', [
'pager' => $this->getPager($this->jobGateway->getListQueryForAdmin($filter), $request, Job::class),
'pager' => $this->getPager($this->jobGateway->getListQueryForAdmin($filter), $request),
'filter' => $filter,
]);
}
@@ -129,41 +122,22 @@ class DashboardController extends Controller
return $this->render('@ibexadesign/ibexa_dataflow/Dashboard/schedule_history.html.twig', [
'id' => $id,
'pager' => $this->getPager($this->jobGateway->getListQueryForScheduleAdmin($id), $request, Job::class),
'pager' => $this->getPager($this->jobGateway->getListQueryForScheduleAdmin($id), $request),
]);
}
private function getPager(QueryBuilder $query, Request $request, string $class = null): Pagerfanta
private function getPager(QueryBuilder $query, Request $request): Pagerfanta
{
$adatapter = new ExceptionJSONDecoderAdapter(
new QueryAdapter($query, fn($queryBuilder) => $queryBuilder->select('COUNT(DISTINCT id) AS total_results')
->resetQueryPart('orderBy')
->setMaxResults(1))
$pager = new Pagerfanta(
new ExceptionJSONDecoderAdapter(
new QueryAdapter($query, fn ($queryBuilder) => $queryBuilder->select('COUNT(DISTINCT id) AS total_results')
->resetQueryPart('orderBy')
->setMaxResults(1))
)
);
if ($class === Job::class && !$this->exceptionHandler instanceof NullExceptionHandler) {
$adatapter = new TransformingAdapter($adatapter, function (array $value) {
$exceptions = $this->exceptionHandler->find((int)$value['id']);
$value['exceptions'] = $exceptions;
$value['total_results'] = \count($exceptions);
return $value;
});
}
$pager = new Pagerfanta($adatapter);
$pager->setMaxPerPage(20);
$pager->setCurrentPage($request->query->getInt('page', 1));
$pager->setCurrentPage($request->query->get('page', 1));
return $pager;
}
public function dashboard(): Response
{
$this->denyAccessUnlessGranted(new Attribute('ibexa_dataflow', 'view'));
return $this->render('@ibexadesign/ibexa_dataflow/Dashboard/dashboard.html.twig', [
'jobs' => $this->jobGateway->getListPendindOrRunning(),
]);
}
}

View File

@@ -15,7 +15,7 @@ use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Contracts\Translation\TranslatorInterface;

View File

@@ -14,7 +14,7 @@ use Ibexa\Core\MVC\Symfony\Security\Authorization\Attribute;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Contracts\Translation\TranslatorInterface;
#[Route(path: '/ibexa_dataflow/scheduled_workflow')]
@@ -44,7 +44,7 @@ class ScheduledDataflowController extends Controller
['message' => $e->getMessage()]));
}
return new JsonResponse(['redirect' => $this->generateUrl('coderhapsodie.ibexa_dataflow.main', ['_fragment' => 'ibexa-tab-coderhapsodie-ibexa_dataflow-code-rhapsodie-ibexa_dataflow-repeating'])]);
return new JsonResponse(['redirect' => $this->generateUrl('coderhapsodie.ibexa_dataflow.main')]);
}
return new JsonResponse([
@@ -68,7 +68,7 @@ class ScheduledDataflowController extends Controller
['message' => $e->getMessage()]));
}
return $this->redirectToRoute('coderhapsodie.ibexa_dataflow.main', ['_fragment' => 'ibexa-tab-coderhapsodie-ibexa_dataflow-code-rhapsodie-ibexa_dataflow-repeating']);
return $this->redirectToRoute('coderhapsodie.ibexa_dataflow.main');
}
#[Route(path: '/{id}/edit', name: 'coderhapsodie.ibexa_dataflow.workflow.edit')]
@@ -91,7 +91,7 @@ class ScheduledDataflowController extends Controller
['message' => $e->getMessage()]));
}
return new JsonResponse(['redirect' => $this->generateUrl('coderhapsodie.ibexa_dataflow.main', ['_fragment' => 'ibexa-tab-coderhapsodie-ibexa_dataflow-code-rhapsodie-ibexa_dataflow-repeating'])]);
return new JsonResponse(['redirect' => $this->generateUrl('coderhapsodie.ibexa_dataflow.main')]);
}
return new JsonResponse([
@@ -109,7 +109,7 @@ class ScheduledDataflowController extends Controller
$this->changeDataflowStatus($id, true);
return $this->redirectToRoute('coderhapsodie.ibexa_dataflow.main', ['_fragment' => 'ibexa-tab-coderhapsodie-ibexa_dataflow-code-rhapsodie-ibexa_dataflow-repeating']);
return $this->redirectToRoute('coderhapsodie.ibexa_dataflow.main');
}
private function changeDataflowStatus(int $id, bool $status)
@@ -133,6 +133,6 @@ class ScheduledDataflowController extends Controller
$this->changeDataflowStatus($id, false);
return $this->redirectToRoute('coderhapsodie.ibexa_dataflow.main', ['_fragment' => 'ibexa-tab-coderhapsodie-ibexa_dataflow-code-rhapsodie-ibexa_dataflow-repeating']);
return $this->redirectToRoute('coderhapsodie.ibexa_dataflow.main');
}
}

View File

@@ -9,13 +9,12 @@ use CodeRhapsodie\IbexaDataflowBundle\Matcher\LocationMatcherInterface;
use CodeRhapsodie\IbexaDataflowBundle\Model\ContentCreateStructure;
use Ibexa\Contracts\Core\Repository\ContentService;
use Ibexa\Contracts\Core\Repository\ContentTypeService;
use Ibexa\Contracts\Core\Repository\Repository;
use Ibexa\Contracts\Core\Repository\Values\Content\Content;
use Ibexa\Contracts\Core\Repository\Values\Content\LocationCreateStruct;
readonly class ContentCreator implements ContentCreatorInterface
class ContentCreator implements ContentCreatorInterface
{
public function __construct(private ContentService $contentService, private ContentTypeService $contentTypeService, private ContentStructFieldFillerInterface $filler, private LocationMatcherInterface $matcher, private Repository $repository)
public function __construct(private readonly ContentService $contentService, private readonly ContentTypeService $contentTypeService, private readonly ContentStructFieldFillerInterface $filler, private readonly LocationMatcherInterface $matcher)
{
}
@@ -33,20 +32,9 @@ readonly class ContentCreator implements ContentCreatorInterface
$contentCreateStruct = $this->contentService->newContentCreateStruct($contentType, $structure->getLanguageCode());
$contentCreateStruct->remoteId = $structure->getRemoteId();
$this->filler->fillFields($contentType, $contentCreateStruct, $structure->getFields());
$content = $this->contentService->createContent($contentCreateStruct, $this->getLocationCreateStructs($structure->getLocations()));
$this->repository->beginTransaction();
try {
$content = $this->contentService->createContent($contentCreateStruct, $this->getLocationCreateStructs($structure->getLocations()));
$content = $this->contentService->publishVersion($content->versionInfo);
$this->repository->commit();
return $content;
} catch (\Exception $exception) {
$this->repository->rollback();
throw $exception;
}
return $this->contentService->publishVersion($content->versionInfo);
}
/**
@@ -71,3 +59,4 @@ readonly class ContentCreator implements ContentCreatorInterface
return $locationCreateStructs;
}
}
class_alias(ContentCreator::class, 'CodeRhapsodie\EzDataflowBundle\Core\Content\ContentCreator');

View File

@@ -11,3 +11,4 @@ interface ContentCreatorInterface
{
public function createFromStructure(ContentCreateStructure $structure): Content;
}
class_alias(ContentCreatorInterface::class, 'CodeRhapsodie\EzDataflowBundle\Core\Content\ContentCreatorInterface');

View File

@@ -9,12 +9,11 @@ use CodeRhapsodie\IbexaDataflowBundle\Exception\NoMatchFoundException;
use CodeRhapsodie\IbexaDataflowBundle\Model\ContentUpdateStructure;
use Ibexa\Contracts\Core\Repository\ContentService;
use Ibexa\Contracts\Core\Repository\ContentTypeService;
use Ibexa\Contracts\Core\Repository\Repository;
use Ibexa\Contracts\Core\Repository\Values\Content\Content;
readonly class ContentUpdater implements ContentUpdaterInterface
class ContentUpdater implements ContentUpdaterInterface
{
public function __construct(private ContentService $contentService, private ContentTypeService $contentTypeService, private ContentStructFieldFillerInterface $filler, private Repository $repository)
public function __construct(private readonly ContentService $contentService, private readonly ContentTypeService $contentTypeService, private readonly ContentStructFieldFillerInterface $filler)
{
}
@@ -45,18 +44,10 @@ readonly class ContentUpdater implements ContentUpdaterInterface
$structure->getFields()
);
$this->repository->beginTransaction();
try {
$draft = $this->contentService->createContentDraft($content->contentInfo);
$this->contentService->updateContent($draft->versionInfo, $contentUpdateStruct);
$content = $this->contentService->publishVersion($draft->versionInfo);
$draft = $this->contentService->createContentDraft($content->contentInfo);
$this->contentService->updateContent($draft->versionInfo, $contentUpdateStruct);
$this->repository->commit();
return $content;
} catch (\Exception $e) {
$this->repository->rollback();
throw $e;
}
return $this->contentService->publishVersion($draft->versionInfo);
}
}
class_alias(ContentUpdater::class, 'CodeRhapsodie\EzDataflowBundle\Core\Content\ContentUpdater');

View File

@@ -11,3 +11,4 @@ interface ContentUpdaterInterface
{
public function updateFromStructure(ContentUpdateStructure $structure): Content;
}
class_alias(ContentUpdaterInterface::class, 'CodeRhapsodie\EzDataflowBundle\Core\Content\ContentUpdaterInterface');

View File

@@ -59,3 +59,4 @@ class ContentStructFieldFiller implements ContentStructFieldFillerInterface
throw UnsupportedFieldTypeException::create($fieldTypeIdentifier);
}
}
class_alias(ContentStructFieldFiller::class, 'CodeRhapsodie\EzDataflowBundle\Core\Field\ContentStructFieldFiller');

View File

@@ -11,3 +11,4 @@ interface ContentStructFieldFillerInterface
{
public function fillFields(ContentType $contentType, ContentStruct $contentStruct, array $fieldHashes): void;
}
class_alias(ContentStructFieldFillerInterface::class, 'CodeRhapsodie\EzDataflowBundle\Core\Field\ContentStructFieldFillerInterface');

View File

@@ -23,3 +23,4 @@ class DefaultFieldValueCreator implements FieldValueCreatorInterface
return $this->fieldTypeService->getFieldType($fieldTypeIdentifier)->fromHash($hash);
}
}
class_alias(DefaultFieldValueCreator::class, 'CodeRhapsodie\EzDataflowBundle\Core\Field\DefaultFieldValueCreator');

View File

@@ -15,3 +15,4 @@ interface FieldValueCreatorInterface
*/
public function createValue(string $fieldTypeIdentifier, $hash): Value;
}
class_alias(FieldValueCreatorInterface::class, 'CodeRhapsodie\EzDataflowBundle\Core\Field\FieldValueCreatorInterface');

View File

@@ -26,3 +26,4 @@ abstract class AbstractFieldComparator implements FieldComparatorInterface
*/
abstract protected function compareValues(Value $currentValue, Value $newValue): bool;
}
class_alias(AbstractFieldComparator::class, 'CodeRhapsodie\EzDataflowBundle\Core\FieldComparator\AbstractFieldComparator');

View File

@@ -1,18 +0,0 @@
<?php
namespace CodeRhapsodie\IbexaDataflowBundle\Core\FieldComparator;
use Ibexa\Contracts\Core\FieldType\Value;
class BillingAddressComparator extends AbstractFieldComparator
{
/**
* @param \Ibexa\FieldTypeAddress\FieldType\Value $currentValue
* @param \Ibexa\FieldTypeAddress\FieldType\Value $newValue
*/
protected function compareValues(Value $currentValue, Value $newValue): bool
{
return empty(array_diff_assoc($currentValue->fields, $newValue->fields)) && $currentValue->name === $newValue->name && $currentValue->country === $newValue->country;
}
}

View File

@@ -1,18 +0,0 @@
<?php
namespace CodeRhapsodie\IbexaDataflowBundle\Core\FieldComparator;
use Ibexa\Contracts\Core\FieldType\Value;
class CustomerGroupComparator extends AbstractFieldComparator
{
/**
* @param \Ibexa\ProductCatalog\FieldType\CustomerGroup\Value $currentValue
* @param \Ibexa\ProductCatalog\FieldType\CustomerGroup\Value $newValue
*/
protected function compareValues(Value $currentValue, Value $newValue): bool
{
return $currentValue->getCustomerGroup()->getIdentifier() === $newValue->getCustomerGroup()->getIdentifier();
}
}

View File

@@ -34,3 +34,4 @@ class DelegatorFieldComparator implements FieldComparatorInterface
$this->delegates[$fieldTypeIdentifier] = $typedFieldComparator;
}
}
class_alias(DelegatorFieldComparator::class, 'CodeRhapsodie\EzDataflowBundle\Core\FieldComparator\DelegatorFieldComparator');

View File

@@ -13,3 +13,4 @@ interface FieldComparatorInterface
*/
public function compare(Field $field, $hash): bool;
}
class_alias(FieldComparatorInterface::class, 'CodeRhapsodie\EzDataflowBundle\Core\FieldComparator\FieldComparatorInterface');

View File

@@ -16,3 +16,4 @@ class MapLocationFieldComparator extends AbstractFieldComparator
;
}
}
class_alias(MapLocationFieldComparator::class, 'CodeRhapsodie\EzDataflowBundle\Core\FieldComparator\MapLocationFieldComparator');

View File

@@ -27,3 +27,4 @@ class MatrixFieldComparator extends AbstractFieldComparator
return true;
}
}
class_alias(MatrixFieldComparator::class, 'CodeRhapsodie\EzDataflowBundle\Core\FieldComparator\MatrixFieldComparator');

View File

@@ -24,3 +24,4 @@ class NovaSEOMetasFieldComparator extends AbstractFieldComparator
return count($currentValue->metas) === count($newValue->metas);
}
}
class_alias(NovaSEOMetasFieldComparator::class, 'CodeRhapsodie\EzDataflowBundle\Core\FieldComparator\NovaSEOMetasFieldComparator');

View File

@@ -1,25 +0,0 @@
<?php
declare(strict_types=1);
namespace CodeRhapsodie\IbexaDataflowBundle\Core\FieldComparator;
use Ibexa\Contracts\Core\FieldType\Value;
class ProductSpecificationComparator extends AbstractFieldComparator
{
protected function compareValues(Value $currentValue, Value $newValue): bool
{
$currentAttributes = $currentValue->getAttributes();
$newAttributes = $newValue->getAttributes();
if ($newValue->isCodeChanged() || $currentValue->isVirtual() !== $newValue->isVirtual() || \count($currentAttributes) !== \count($newAttributes)) {
return false;
}
sort($currentAttributes);
sort($newAttributes);
return $currentAttributes === $newAttributes;
}
}

View File

@@ -13,3 +13,4 @@ class SimpleFieldComparator extends AbstractFieldComparator
return (string) $currentValue === (string) $newValue;
}
}
class_alias(SimpleFieldComparator::class, 'CodeRhapsodie\EzDataflowBundle\Core\FieldComparator\SimpleFieldComparator');

View File

@@ -1,44 +0,0 @@
<?php
namespace CodeRhapsodie\IbexaDataflowBundle\Core\FieldComparator;
use CodeRhapsodie\IbexaDataflowBundle\Core\FieldComparator\AbstractFieldComparator;
use Ibexa\Contracts\Core\FieldType\Value;
use Ibexa\Contracts\Taxonomy\Value\TaxonomyEntry;
class TaxonomyEntryAssignmentComparator extends AbstractFieldComparator
{
/**
* @param \Ibexa\Taxonomy\FieldType\TaxonomyEntryAssignment\Value $currentValue
* @param \Ibexa\Taxonomy\FieldType\TaxonomyEntryAssignment\Value $newValue
*/
protected function compareValues(Value $currentValue, Value $newValue): bool
{
return $currentValue->getTaxonomy() === $newValue->getTaxonomy() && $this->compareEntries($currentValue->getTaxonomyEntries(), $newValue->getTaxonomyEntries());
}
/**
* @param array<TaxonomyEntry> $currentEntries
* @param array<TaxonomyEntry> $newEntries
*/
private function compareEntries(array $currentEntries, array $newEntries): bool
{
$currentEntriesId = array_map(function (TaxonomyEntry $currentEntry) {
return $currentEntry->id;
}, $currentEntries);
$newEntriesId = array_map(function (TaxonomyEntry $newEntry) {
return $newEntry->id;
}, $newEntries);
if (\count($currentEntriesId) !== \count($newEntriesId)) {
return false;
}
sort($currentEntriesId);
sort($newEntriesId);
return $currentEntriesId === $newEntriesId;
}
}

View File

@@ -13,3 +13,4 @@ class UrlFieldComparator extends AbstractFieldComparator
return $currentValue->link === $newValue->link && $currentValue->text === $newValue->text;
}
}
class_alias(UrlFieldComparator::class, 'CodeRhapsodie\EzDataflowBundle\Core\FieldComparator\UrlFieldComparator');

View File

@@ -12,7 +12,7 @@ use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
class CodeRhapsodieIbexaDataflowExtension extends Extension
{
public function load(array $configs, ContainerBuilder $container): void
public function load(array $configs, ContainerBuilder $container)
{
$configuration = new Configuration();
$config = $this->processConfiguration($configuration, $configs);

View File

@@ -11,7 +11,7 @@ use Symfony\Component\DependencyInjection\Reference;
class FieldComparatorCompilerPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container): void
public function process(ContainerBuilder $container)
{
if (!$container->has(DelegatorFieldComparator::class)) {
return;

View File

@@ -12,7 +12,7 @@ class Configuration implements ConfigurationInterface
/**
* {@inheritdoc}
*/
public function getConfigTreeBuilder(): TreeBuilder
public function getConfigTreeBuilder()
{
$treeBuilder = new TreeBuilder('code_rhapsodie_ibexa_dataflow');

View File

@@ -13,12 +13,12 @@ class MenuSubscriber implements EventSubscriberInterface
/**
* {@inheritdoc}
*/
public static function getSubscribedEvents(): array
public static function getSubscribedEvents()
{
return [ConfigureMenuEvent::MAIN_MENU => 'onConfigureMenu'];
}
public function onConfigureMenu(ConfigureMenuEvent $event): void
public function onConfigureMenu(ConfigureMenuEvent $event)
{
/** @var \Knp\Menu\ItemInterface $menu */
$menu = $event->getMenu();

View File

@@ -30,3 +30,4 @@ class InvalidArgumentTypeException extends \Exception
));
}
}
class_alias(InvalidArgumentTypeException::class, 'CodeRhapsodie\EzDataflowBundle\Exception\InvalidArgumentTypeException');

View File

@@ -7,3 +7,4 @@ namespace CodeRhapsodie\IbexaDataflowBundle\Exception;
class NoMatchFoundException extends \Exception
{
}
class_alias(NoMatchFoundException::class, 'CodeRhapsodie\EzDataflowBundle\Exception\NoMatchFoundException');

View File

@@ -15,3 +15,4 @@ class UnknownFieldException extends \Exception
));
}
}
class_alias(UnknownFieldException::class, 'CodeRhapsodie\EzDataflowBundle\Exception\UnknownFieldException');

View File

@@ -14,3 +14,4 @@ class UnsupportedFieldTypeException extends \Exception
));
}
}
class_alias(UnsupportedFieldTypeException::class, 'CodeRhapsodie\EzDataflowBundle\Exception\UnsupportedFieldTypeException');

View File

@@ -9,9 +9,12 @@ use CodeRhapsodie\IbexaDataflowBundle\Model\ContentUpdateStructure;
use Ibexa\Contracts\Core\Repository\ContentService;
use Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException;
final readonly class ContentStructureFactory implements ContentStructureFactoryInterface
final class ContentStructureFactory implements ContentStructureFactoryInterface
{
public function __construct(private ContentService $contentService)
/**
* ContentStructureFactory constructor.
*/
public function __construct(private readonly ContentService $contentService)
{
}
@@ -50,3 +53,4 @@ final readonly class ContentStructureFactory implements ContentStructureFactoryI
);
}
}
class_alias(ContentStructureFactory::class, 'CodeRhapsodie\EzDataflowBundle\Factory\ContentStructureFactory');

View File

@@ -18,3 +18,4 @@ interface ContentStructureFactoryInterface
*/
public function transform(array $data, string $remoteId, string $language, string $contentType, $parentLocations, int $mode = ContentStructureFactoryInterface::MODE_INSERT_OR_UPDATE);
}
class_alias(ContentStructureFactoryInterface::class, 'CodeRhapsodie\EzDataflowBundle\Factory\ContentStructureFactoryInterface');

View File

@@ -52,7 +52,7 @@ class NotModifiedContentFilter
return false;
}
private function log(string $level, string $message, array $context = []): void
private function log(string $level, string $message, array $context = [])
{
if (null === $this->logger) {
return;
@@ -60,3 +60,4 @@ class NotModifiedContentFilter
$this->logger->log($level, $message, $context);
}
}
class_alias(NotModifiedContentFilter::class, 'CodeRhapsodie\EzDataflowBundle\Filter\NotModifiedContentFilter');

View File

@@ -1,46 +0,0 @@
<?php
declare(strict_types=1);
namespace CodeRhapsodie\IbexaDataflowBundle\Filter;
use CodeRhapsodie\IbexaDataflowBundle\Model\ContentUpdateStructure;
use CodeRhapsodie\IbexaDataflowBundle\Model\ProductUpdateStructure;
use Doctrine\DBAL\Connection;
readonly class NotModifiedProductFilter
{
public function __construct(private NotModifiedContentFilter $notModifiedContentFilter, private Connection $connection)
{
}
public function __invoke(mixed $data)
{
if (!$data instanceof ProductUpdateStructure) {
return $data;
}
$contentId = $this->connection->executeQuery('SELECT content_id FROM ibexa_product_specification where code = :code', ['code' => $data->getCode()])
->fetchFirstColumn();
if (empty($contentId)) {
return $data;
}
$result = $this->notModifiedContentFilter->__invoke(ContentUpdateStructure::createForContentId($contentId[0], $data->getLanguageCode(), $data->getFields()));
if ($result === false) {
$data->setUpdateContent(false);
}
$stockData = $this->connection->executeQuery('SELECT stock FROM ibexa_product_specification_availability WHERE product_code = :code', ['code' => $data->getCode()])->fetchFirstColumn();
if (!empty($stockData) && ($data->getStock() === $stockData[0] || ($data->getStock() === 0 && $stockData[0] === null))) {
$data->setUpdateStock(false);
}
return $data;
}
}

View File

@@ -12,7 +12,7 @@ use Symfony\Component\OptionsResolver\OptionsResolver;
class CreateOneshotType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('label', TextType::class, [
@@ -35,10 +35,11 @@ class CreateOneshotType extends AbstractType
;
}
public function configureOptions(OptionsResolver $resolver): void
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Job::class,
]);
}
}
class_alias(CreateOneshotType::class, 'CodeRhapsodie\EzDataflowBundle\Form\CreateOneshotType');

View File

@@ -13,7 +13,7 @@ use Symfony\Component\OptionsResolver\OptionsResolver;
class CreateScheduledType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('label', TextType::class, [
@@ -47,10 +47,11 @@ class CreateScheduledType extends AbstractType
;
}
public function configureOptions(OptionsResolver $resolver): void
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => ScheduledDataflow::class,
]);
}
}
class_alias(CreateScheduledType::class, 'CodeRhapsodie\EzDataflowBundle\Form\CreateScheduledType');

View File

@@ -15,13 +15,12 @@ class DataflowTypeChoiceType extends AbstractType
{
}
#[\Override]
public function getParent(): string
public function getParent()
{
return ChoiceType::class;
}
public function configureOptions(OptionsResolver $resolver): void
public function configureOptions(OptionsResolver $resolver)
{
$choices = [];
foreach ($this->registry->listDataflowTypes() as $fqcn => $dataflowType) {
@@ -33,3 +32,4 @@ class DataflowTypeChoiceType extends AbstractType
]);
}
}
class_alias(DataflowTypeChoiceType::class, 'CodeRhapsodie\EzDataflowBundle\Form\DataflowTypeChoiceType');

View File

@@ -12,15 +12,14 @@ use Symfony\Component\Form\Extension\Core\Type\TextType;
*/
class FrequencyType extends AbstractType
{
#[\Override]
public function getParent(): string
public function getParent()
{
return TextType::class;
}
#[\Override]
public function getBlockPrefix(): string
public function getBlockPrefix()
{
return 'coderhapsodie_port_frequency';
}
}
class_alias(FrequencyType::class, 'CodeRhapsodie\EzDataflowBundle\Form\FrequencyType');

View File

@@ -12,7 +12,7 @@ use Symfony\Component\OptionsResolver\OptionsResolver;
class UpdateScheduledType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('label', TextType::class, [
@@ -37,10 +37,11 @@ class UpdateScheduledType extends AbstractType
;
}
public function configureOptions(OptionsResolver $resolver): void
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => ScheduledDataflow::class,
]);
}
}
class_alias(UpdateScheduledType::class, 'CodeRhapsodie\EzDataflowBundle\Form\UpdateScheduledType');

View File

@@ -14,7 +14,7 @@ class UserTimezoneAwareDateTimeTransformer implements DataTransformerInterface
{
}
public function transform($value): mixed
public function transform($value)
{
if (!$value instanceof \DateTimeInterface) {
return $value;
@@ -23,7 +23,7 @@ class UserTimezoneAwareDateTimeTransformer implements DataTransformerInterface
return (new \DateTime('now', $this->userTimezone()))->setTimestamp($value->getTimestamp());
}
public function reverseTransform($value): mixed
public function reverseTransform($value)
{
if (!$value instanceof \DateTimeInterface) {
return $value;
@@ -45,3 +45,4 @@ class UserTimezoneAwareDateTimeTransformer implements DataTransformerInterface
return new \DateTimeZone($tz);
}
}
class_alias(UserTimezoneAwareDateTimeTransformer::class, 'CodeRhapsodie\EzDataflowBundle\Form\UserTimezoneAwareDateTimeTransformer');

View File

@@ -15,14 +15,14 @@ class UserTimezoneAwareDateTimeType extends AbstractType
{
}
#[\Override]
public function getParent(): string
public function getParent()
{
return DateTimePickerType::class;
}
public function buildForm(FormBuilderInterface $builder, array $options): void
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->addModelTransformer(new UserTimezoneAwareDateTimeTransformer($this->userPreferenceService));
}
}
class_alias(UserTimezoneAwareDateTimeType::class, 'CodeRhapsodie\EzDataflowBundle\Form\UserTimezoneAwareDateTimeType');

View File

@@ -17,13 +17,12 @@ use Symfony\Component\Yaml\Yaml;
*/
class YamlType extends AbstractType
{
#[\Override]
public function getParent(): string
public function getParent()
{
return TextareaType::class;
}
public function buildForm(FormBuilderInterface $builder, array $options): void
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->addModelTransformer(new CallbackTransformer(
function ($optionsAsArray) {
@@ -52,9 +51,9 @@ class YamlType extends AbstractType
));
}
#[\Override]
public function getBlockPrefix(): string
public function getBlockPrefix()
{
return 'coderhapsodie_port_yaml';
}
}
class_alias(YamlType::class, 'CodeRhapsodie\EzDataflowBundle\Form\YamlType');

View File

@@ -12,12 +12,12 @@ class ExceptionJSONDecoderAdapter implements AdapterInterface
{
}
public function getNbResults(): int
public function getNbResults()
{
return $this->adapter->getNbResults();
}
public function getSlice($offset, $length): iterable
public function getSlice($offset, $length)
{
$slice = $this->adapter->getSlice($offset, $length);
array_walk($slice, static function (&$value): void {

View File

@@ -5,22 +5,21 @@ declare(strict_types=1);
namespace CodeRhapsodie\IbexaDataflowBundle\Gateway;
use CodeRhapsodie\DataflowBundle\Entity\Job;
use CodeRhapsodie\DataflowBundle\Gateway\JobGateway as JobGatewayDataflow;
use CodeRhapsodie\DataflowBundle\Repository\JobRepository;
use Doctrine\DBAL\Query\QueryBuilder;
final readonly class JobGateway
final class JobGateway
{
public const int FILTER_NONE = 0;
public const int FILTER_NON_EMPTY = 1;
public const FILTER_NONE = 0;
public const FILTER_NON_EMPTY = 1;
public function __construct(private JobRepository $jobRepository, private JobGatewayDataflow $jobGateway)
public function __construct(private readonly JobRepository $jobRepository)
{
}
public function find(int $id): ?Job
{
return $this->jobGateway->find($id);
return $this->jobRepository->find($id);
}
public function getOneshotListQueryForAdmin(): QueryBuilder
@@ -53,14 +52,7 @@ final readonly class JobGateway
public function save(Job $job)
{
$this->jobGateway->save($job);
}
public function getListPendindOrRunning(): array
{
$qb = $this->jobRepository->createQueryBuilder('w');
return $qb->andWhere($qb->expr()->in('w.status', [Job::STATUS_RUNNING, Job::STATUS_PENDING, Job::STATUS_QUEUED]))
->orderBy('w.requested_date', 'ASC')
->fetchAllAssociative();
$this->jobRepository->save($job);
}
}
class_alias(JobGateway::class, 'CodeRhapsodie\EzDataflowBundle\Gateway\JobGateway');

View File

@@ -8,9 +8,9 @@ use CodeRhapsodie\DataflowBundle\Entity\ScheduledDataflow;
use CodeRhapsodie\DataflowBundle\Repository\ScheduledDataflowRepository;
use Doctrine\DBAL\Query\QueryBuilder;
final readonly class ScheduledDataflowGateway
final class ScheduledDataflowGateway
{
public function __construct(private ScheduledDataflowRepository $scheduledDataflowRepository)
public function __construct(private readonly ScheduledDataflowRepository $scheduledDataflowRepository)
{
}
@@ -38,3 +38,4 @@ final readonly class ScheduledDataflowGateway
$this->scheduledDataflowRepository->delete($id);
}
}
class_alias(ScheduledDataflowGateway::class, 'CodeRhapsodie\EzDataflowBundle\Gateway\ScheduledDataflowGateway');

View File

@@ -1,65 +0,0 @@
<?php declare(strict_types=1);
namespace CodeRhapsodie\IbexaDataflowBundle\Gateway;
use Pagerfanta\Adapter\AdapterInterface;
/**
* Adapter which transforms the result of other adapter.
*
* @template T
* @template Transformed
*
* @implements AdapterInterface<Transformed>
*/
class TransformingAdapter implements AdapterInterface
{
/**
* @var AdapterInterface<T>
*/
private AdapterInterface $adapter;
/**
* @var callable
*
* @phpstan-var callable(T, array-key): Transformed
*/
private $transformer;
/**
* @param AdapterInterface<T> $adapter
*
* @phpstan-param callable(T, array-key): Transformed $transformer
*/
public function __construct(AdapterInterface $adapter, callable $transformer)
{
$this->adapter = $adapter;
$this->transformer = $transformer;
}
/**
* @phpstan-return int<0, max>
*/
public function getNbResults(): int
{
return $this->adapter->getNbResults();
}
/**
* @phpstan-param int<0, max> $offset
* @phpstan-param int<0, max> $length
*
* @return iterable<array-key, Transformed>
*/
public function getSlice(int $offset, int $length): iterable
{
$transformer = $this->transformer;
$data = [];
foreach ($this->adapter->getSlice($offset, $length) as $key => $item) {
$data[] = $transformer($item, $key);
}
return $data;
}
}

View File

@@ -42,3 +42,4 @@ class LocationMatcher implements LocationMatcherInterface
throw new NoMatchFoundException('No location matched provided value');
}
}
class_alias(LocationMatcher::class, 'CodeRhapsodie\EzDataflowBundle\Matcher\LocationMatcher');

View File

@@ -13,3 +13,4 @@ interface LocationMatcherInterface
*/
public function matchLocation($valueToMatch): Location;
}
class_alias(LocationMatcherInterface::class, 'CodeRhapsodie\EzDataflowBundle\Matcher\LocationMatcherInterface');

View File

@@ -10,7 +10,11 @@ use Ibexa\Contracts\Core\Repository\Values\Content\LocationCreateStruct;
class ContentCreateStructure extends ContentStructure
{
protected array $locations;
/** @var string */
protected $contentTypeIdentifier;
/** @var array */
protected $locations;
/**
* ContentCreateStructure constructor.
@@ -26,8 +30,9 @@ class ContentCreateStructure extends ContentStructure
*
* @throws \CodeRhapsodie\IbexaDataflowBundle\Exception\InvalidArgumentTypeException
*/
public function __construct(protected string $contentTypeIdentifier, string $languageCode, array $locations, array $fields, ?string $remoteId = null)
public function __construct(string $contentTypeIdentifier, string $languageCode, array $locations, array $fields, ?string $remoteId = null)
{
$this->contentTypeIdentifier = $contentTypeIdentifier;
$this->languageCode = $languageCode;
$this->setLocations($locations);
$this->fields = $fields;
@@ -47,7 +52,7 @@ class ContentCreateStructure extends ContentStructure
/**
* @throws \CodeRhapsodie\IbexaDataflowBundle\Exception\InvalidArgumentTypeException
*/
private function setLocations(array $locations): void
private function setLocations(array $locations)
{
foreach ($locations as $locationOrIdOrRemoteIdOrStruct) {
if (!is_int($locationOrIdOrRemoteIdOrStruct)
@@ -62,3 +67,4 @@ class ContentCreateStructure extends ContentStructure
$this->locations = $locations;
}
}
class_alias(ContentCreateStructure::class, 'CodeRhapsodie\EzDataflowBundle\Model\ContentCreateStructure');

View File

@@ -6,11 +6,14 @@ namespace CodeRhapsodie\IbexaDataflowBundle\Model;
abstract class ContentStructure
{
protected ?string $remoteId = null;
/** @var string|null */
protected $remoteId;
protected string $languageCode;
/** @var string */
protected $languageCode;
protected array $fields;
/** @var array */
protected $fields;
public function getRemoteId(): ?string
{
@@ -27,3 +30,4 @@ abstract class ContentStructure
return $this->fields;
}
}
class_alias(ContentStructure::class, 'CodeRhapsodie\EzDataflowBundle\Model\ContentStructure');

View File

@@ -6,7 +6,8 @@ namespace CodeRhapsodie\IbexaDataflowBundle\Model;
class ContentUpdateStructure extends ContentStructure
{
protected ?int $id = null;
/** @var int|null */
protected $id;
private function __construct(string $languageCode, array $fields)
{
@@ -35,3 +36,4 @@ class ContentUpdateStructure extends ContentStructure
return $this->id;
}
}
class_alias(ContentUpdateStructure::class, 'CodeRhapsodie\EzDataflowBundle\Model\ContentUpdateStructure');

View File

@@ -1,17 +0,0 @@
<?php
declare(strict_types=1);
namespace CodeRhapsodie\IbexaDataflowBundle\Model;
class ProductCreateStructure extends ProductStructure
{
public function __construct(string $code, array $fields, string $languageCode, int $stock = 0, array $attributes = [])
{
$this->code = $code;
$this->fields = $fields;
$this->languageCode = $languageCode;
$this->stock = $stock;
$this->attributes = $attributes;
}
}

View File

@@ -1,42 +0,0 @@
<?php
namespace CodeRhapsodie\IbexaDataflowBundle\Model;
abstract class ProductStructure
{
protected string $code;
protected array $fields;
protected string $languageCode;
protected int $stock;
protected array $attributes;
public function getCode(): string
{
return $this->code;
}
public function getFields(): array
{
return $this->fields;
}
public function getLanguageCode(): string
{
return $this->languageCode;
}
public function getStock(): int
{
return $this->stock;
}
public function getAttributes(): array
{
return $this->attributes;
}
}

View File

@@ -1,41 +0,0 @@
<?php
declare(strict_types=1);
namespace CodeRhapsodie\IbexaDataflowBundle\Model;
class ProductUpdateStructure extends ProductStructure
{
protected bool $updateContent = true;
protected bool $updateStock = true;
public function __construct(string $code, array $fields, string $languageCode, int $stock = 0, array $attributes = [])
{
$this->code = $code;
$this->fields = $fields;
$this->languageCode = $languageCode;
$this->stock = $stock;
$this->attributes = $attributes;
}
public function isUpdateContent(): bool
{
return $this->updateContent;
}
public function isUpdateStock(): bool
{
return $this->updateStock;
}
public function setUpdateContent(bool $updateContent): void
{
$this->updateContent = $updateContent;
}
public function setUpdateStock(bool $updateStock): void
{
$this->updateStock = $updateStock;
}
}

View File

@@ -1,4 +1,3 @@
coderhapsodie.ibexa_dataflow.controllers:
resource: '../../Controller/'
type: attribute
type: annotation

View File

@@ -4,32 +4,44 @@ imports:
services:
_defaults:
public: false
autowire: true
autoconfigure: true
coderhapsodie.dataflow.connection: "@ibexa.persistence.connection"
CodeRhapsodie\IbexaDataflowBundle\Controller\DashboardController:
public: true
tags:
- { name: controller.service_arguments }
arguments:
$jobGateway: '@CodeRhapsodie\IbexaDataflowBundle\Gateway\JobGateway'
$scheduledDataflowGateway: '@CodeRhapsodie\IbexaDataflowBundle\Gateway\ScheduledDataflowGateway'
$exceptionHandler: '@CodeRhapsodie\DataflowBundle\ExceptionsHandler\ExceptionHandlerInterface'
calls:
- ['setContainer', ['@service_container']]
- ['performAccessCheck', []]
CodeRhapsodie\IbexaDataflowBundle\Controller\ScheduledDataflowController:
public: true
tags:
- { name: controller.service_arguments }
arguments:
$notificationHandler: '@Ibexa\Contracts\AdminUi\Notification\NotificationHandlerInterface'
$scheduledDataflowGateway: '@CodeRhapsodie\IbexaDataflowBundle\Gateway\ScheduledDataflowGateway'
$translator: '@translator'
calls:
- [ 'setContainer', [ '@service_container' ] ]
- [ 'performAccessCheck', [ ] ]
CodeRhapsodie\IbexaDataflowBundle\Controller\JobController:
public: true
tags:
- { name: controller.service_arguments }
arguments:
$jobGateway: '@CodeRhapsodie\IbexaDataflowBundle\Gateway\JobGateway'
$notificationHandler: '@Ibexa\Contracts\AdminUi\Notification\NotificationHandlerInterface'
$translator: '@translator'
$scheduledDataflowGateway: '@CodeRhapsodie\IbexaDataflowBundle\Gateway\ScheduledDataflowGateway'
calls:
- [ 'setContainer', [ '@service_container' ] ]
- [ 'performAccessCheck', [ ] ]
CodeRhapsodie\IbexaDataflowBundle\Writer\RepositoryWriter:
abstract: true
@@ -64,12 +76,11 @@ services:
$contentService: '@Ibexa\Contracts\Core\Repository\ContentService'
$contentTypeService: '@Ibexa\Contracts\Core\Repository\ContentTypeService'
$filler: '@CodeRhapsodie\IbexaDataflowBundle\Core\Field\ContentStructFieldFillerInterface'
$repository: '@Ibexa\Core\Event\Repository'
CodeRhapsodie\IbexaDataflowBundle\Core\Field\ContentStructFieldFillerInterface: '@CodeRhapsodie\IbexaDataflowBundle\Core\Field\ContentStructFieldFiller'
CodeRhapsodie\IbexaDataflowBundle\Core\Field\ContentStructFieldFiller:
arguments:
$fieldValueCreators: !tagged_iterator 'coderhapsodie.ibexa_dataflow.field_value_creator'
$fieldValueCreators: !tagged 'coderhapsodie.ibexa_dataflow.field_value_creator'
CodeRhapsodie\IbexaDataflowBundle\Matcher\LocationMatcherInterface: '@CodeRhapsodie\IbexaDataflowBundle\Matcher\LocationMatcher'
CodeRhapsodie\IbexaDataflowBundle\Matcher\LocationMatcher:
@@ -117,15 +128,6 @@ services:
CodeRhapsodie\IbexaDataflowBundle\Gateway\JobGateway:
arguments:
$jobRepository: '@CodeRhapsodie\DataflowBundle\Repository\JobRepository'
$jobGateway: '@CodeRhapsodie\DataflowBundle\Gateway\JobGateway'
CodeRhapsodie\IbexaDataflowBundle\Tab\DashboardTab:
parent: Ibexa\Contracts\AdminUi\Tab\AbstractTab
public: false
arguments:
$httpKernelRuntime: '@twig.runtime.httpkernel'
tags:
- { name: ibexa.admin_ui.tab, group: coderhapsodie-ibexa_dataflow }
CodeRhapsodie\IbexaDataflowBundle\Tab\RepeatingTab:
parent: Ibexa\Contracts\AdminUi\Tab\AbstractTab
@@ -157,11 +159,6 @@ services:
$contentService: '@Ibexa\Contracts\Core\Repository\ContentService'
$comparator: '@CodeRhapsodie\IbexaDataflowBundle\Core\FieldComparator\FieldComparatorInterface'
CodeRhapsodie\IbexaDataflowBundle\Filter\NotModifiedProductFilter:
arguments:
$notModifiedContentFilter: '@CodeRhapsodie\IbexaDataflowBundle\Filter\NotModifiedContentFilter'
$connection: '@ibexa.persistence.connection'
CodeRhapsodie\IbexaDataflowBundle\Core\FieldComparator\FieldComparatorInterface: '@CodeRhapsodie\IbexaDataflowBundle\Core\FieldComparator\DelegatorFieldComparator'
CodeRhapsodie\IbexaDataflowBundle\Core\FieldComparator\DelegatorFieldComparator:

View File

@@ -2,29 +2,29 @@ services:
CodeRhapsodie\IbexaDataflowBundle\Core\FieldComparator\SimpleFieldComparator:
parent: 'CodeRhapsodie\IbexaDataflowBundle\Core\FieldComparator\AbstractFieldComparator'
tags:
- { name: 'coderhapsodie.ibexa_dataflow.field_comparator', fieldType: 'ibexa_author' }
- { name: 'coderhapsodie.ibexa_dataflow.field_comparator', fieldType: 'ibexa_boolean' }
- { name: 'coderhapsodie.ibexa_dataflow.field_comparator', fieldType: 'ibexa_country' }
- { name: 'coderhapsodie.ibexa_dataflow.field_comparator', fieldType: 'ibexa_datetime' }
- { name: 'coderhapsodie.ibexa_dataflow.field_comparator', fieldType: 'ibexa_date' }
- { name: 'coderhapsodie.ibexa_dataflow.field_comparator', fieldType: 'ibexa_email' }
- { name: 'coderhapsodie.ibexa_dataflow.field_comparator', fieldType: 'ibexa_float' }
- { name: 'coderhapsodie.ibexa_dataflow.field_comparator', fieldType: 'ibexa_integer' }
- { name: 'coderhapsodie.ibexa_dataflow.field_comparator', fieldType: 'ibexa_isbn' }
- { name: 'coderhapsodie.ibexa_dataflow.field_comparator', fieldType: 'ibexa_keyword' }
- { name: 'coderhapsodie.ibexa_dataflow.field_comparator', fieldType: 'ibexa_object_relation' }
- { name: 'coderhapsodie.ibexa_dataflow.field_comparator', fieldType: 'ibexa_object_relation_list' }
- { name: 'coderhapsodie.ibexa_dataflow.field_comparator', fieldType: 'ibexa_richtext' }
- { name: 'coderhapsodie.ibexa_dataflow.field_comparator', fieldType: 'ibexa_selection' }
- { name: 'coderhapsodie.ibexa_dataflow.field_comparator', fieldType: 'ibexa_text' }
- { name: 'coderhapsodie.ibexa_dataflow.field_comparator', fieldType: 'ibexa_string' }
- { name: 'coderhapsodie.ibexa_dataflow.field_comparator', fieldType: 'ibexa_time' }
- { name: 'coderhapsodie.ibexa_dataflow.field_comparator', fieldType: 'ezauthor' }
- { name: 'coderhapsodie.ibexa_dataflow.field_comparator', fieldType: 'ezboolean' }
- { name: 'coderhapsodie.ibexa_dataflow.field_comparator', fieldType: 'ezcountry' }
- { name: 'coderhapsodie.ibexa_dataflow.field_comparator', fieldType: 'ezdate' }
- { name: 'coderhapsodie.ibexa_dataflow.field_comparator', fieldType: 'ezdatetime' }
- { name: 'coderhapsodie.ibexa_dataflow.field_comparator', fieldType: 'ezemail' }
- { name: 'coderhapsodie.ibexa_dataflow.field_comparator', fieldType: 'ezfloat' }
- { name: 'coderhapsodie.ibexa_dataflow.field_comparator', fieldType: 'ezinteger' }
- { name: 'coderhapsodie.ibexa_dataflow.field_comparator', fieldType: 'ezisbn' }
- { name: 'coderhapsodie.ibexa_dataflow.field_comparator', fieldType: 'ezkeyword' }
- { name: 'coderhapsodie.ibexa_dataflow.field_comparator', fieldType: 'ezobjectrelation' }
- { name: 'coderhapsodie.ibexa_dataflow.field_comparator', fieldType: 'ezobjectrelationlist' }
- { name: 'coderhapsodie.ibexa_dataflow.field_comparator', fieldType: 'ezrichtext' }
- { name: 'coderhapsodie.ibexa_dataflow.field_comparator', fieldType: 'ezselection' }
- { name: 'coderhapsodie.ibexa_dataflow.field_comparator', fieldType: 'eztext' }
- { name: 'coderhapsodie.ibexa_dataflow.field_comparator', fieldType: 'ezstring' }
- { name: 'coderhapsodie.ibexa_dataflow.field_comparator', fieldType: 'eztime' }
- { name: 'coderhapsodie.ibexa_dataflow.field_comparator', fieldType: 'eztags' }
CodeRhapsodie\IbexaDataflowBundle\Core\FieldComparator\UrlFieldComparator:
parent: 'CodeRhapsodie\IbexaDataflowBundle\Core\FieldComparator\AbstractFieldComparator'
tags:
- { name: 'coderhapsodie.ibexa_dataflow.field_comparator', fieldType: 'ibexa_url' }
- { name: 'coderhapsodie.ibexa_dataflow.field_comparator', fieldType: 'ezurl' }
CodeRhapsodie\IbexaDataflowBundle\Core\FieldComparator\NovaSEOMetasFieldComparator:
parent: 'CodeRhapsodie\IbexaDataflowBundle\Core\FieldComparator\AbstractFieldComparator'
@@ -34,29 +34,9 @@ services:
CodeRhapsodie\IbexaDataflowBundle\Core\FieldComparator\MatrixFieldComparator:
parent: 'CodeRhapsodie\IbexaDataflowBundle\Core\FieldComparator\AbstractFieldComparator'
tags:
- { name: 'coderhapsodie.ibexa_dataflow.field_comparator', fieldType: 'ibexa_matrix' }
- { name: 'coderhapsodie.ibexa_dataflow.field_comparator', fieldType: 'ezmatrix' }
CodeRhapsodie\IbexaDataflowBundle\Core\FieldComparator\MapLocationFieldComparator:
parent: 'CodeRhapsodie\IbexaDataflowBundle\Core\FieldComparator\AbstractFieldComparator'
tags:
- { name: 'coderhapsodie.ibexa_dataflow.field_comparator', fieldType: 'ibexa_gmap_location' }
CodeRhapsodie\IbexaDataflowBundle\Core\FieldComparator\TaxonomyEntryAssignmentComparator:
parent: 'CodeRhapsodie\IbexaDataflowBundle\Core\FieldComparator\AbstractFieldComparator'
tags:
- { name: 'coderhapsodie.ibexa_dataflow.field_comparator', fieldType: 'ibexa_taxonomy_entry_assignment' }
CodeRhapsodie\IbexaDataflowBundle\Core\FieldComparator\BillingAddressComparator:
parent: 'CodeRhapsodie\IbexaDataflowBundle\Core\FieldComparator\AbstractFieldComparator'
tags:
- { name: 'coderhapsodie.ibexa_dataflow.field_comparator', fieldType: 'ibexa_address' }
CodeRhapsodie\IbexaDataflowBundle\Core\FieldComparator\CustomerGroupComparator:
parent: 'CodeRhapsodie\IbexaDataflowBundle\Core\FieldComparator\AbstractFieldComparator'
tags:
- { name: 'coderhapsodie.ibexa_dataflow.field_comparator', fieldType: 'ibexa_customer_group' }
CodeRhapsodie\IbexaDataflowBundle\Core\FieldComparator\ProductSpecificationComparator:
parent: 'CodeRhapsodie\IbexaDataflowBundle\Core\FieldComparator\AbstractFieldComparator'
tags:
- { name: 'coderhapsodie.ibexa_dataflow.field_comparator', fieldType: 'ibexa_product_specification' }
- { name: 'coderhapsodie.ibexa_dataflow.field_comparator', fieldType: 'ezgmaplocation' }

View File

@@ -85,5 +85,3 @@ coderhapsodie.ibexa_dataflow.workflow.edit.error: 'An error occurred during the
coderhapsodie.ibexa_dataflow.notfound: 'Requested data is not found'
coderhapsodie.ibexa_dataflow.powered_by: 'Powered by'
coderhapsodie.ibexa_dataflow.made_by: 'Made by'
coderhapsodie.ibexa_dataflow.dashboard: Dashboard
coderhapsodie.ibexa_dataflow.dashboard.title: Running or waiting tasks

View File

@@ -83,5 +83,3 @@ coderhapsodie.ibexa_dataflow.workflow.edit.error: 'Une erreur est survenue lors
coderhapsodie.ibexa_dataflow.notfound: 'Les données demandées sont introuvables'
coderhapsodie.ibexa_dataflow.powered_by: 'Propulsé par'
coderhapsodie.ibexa_dataflow.made_by: 'Fabriqué par'
coderhapsodie.ibexa_dataflow.dashboard: Dashboard
coderhapsodie.ibexa_dataflow.dashboard.title: Tâches en cours ou en attente

View File

@@ -1,5 +0,0 @@
{%- block content -%}
{% include '@ibexadesign/ibexa_dataflow/parts/tab/dashboard_list.html.twig' with {
identifier: 'ibexa_dataflow_schedule_dashboard_results',
} %}
{%- endblock -%}

View File

@@ -16,7 +16,7 @@
{% endblock %}
{% block content %}
{{ ibexa_twig_component_group('coderhapsodie-ibexa_dataflow', {'filter': app.request.query.get('filter', 0)}) }}
{{ ibexa_render_component_group('coderhapsodie-ibexa_dataflow', {'filter': app.request.query.get('filter', 0)}) }}
{% embed '@ibexadesign/ui/component/modal/modal.html.twig' with {
id: 'modal-history-details',

View File

@@ -61,7 +61,7 @@
const oneShotModal = document.getElementById('modal-new-oneshot');
oneShotModal.querySelector('#create_oneshot_label').value = '';
oneShotModal.querySelector('#create_oneshot_options').value = '';
oneShotModal.querySelector('#create_oneshot_requestedDate').closest('.ibexa-picker').querySelector('.ibexa-date-time-picker').ibexaInstance.flatpickrInstance.setDate(new Date(), true);
oneShotModal.querySelector('.flatpickr.flatpickr-input').parentNode.parentNode.ibexaInstance.flatpickrInstance.setDate(new Date(), true);
});
}
});

View File

@@ -17,10 +17,10 @@
} %}
{% block body_content %}
{{ form_start(update_form) }}
<div class="form-fields">
{{ form_widget(update_form) }}
</div>
<button id="modal-edit-submit" type="submit" hidden />
<div class="form-fields">
{{ form_widget(update_form) }}
</div>
<button id="modal-edit-submit" type="submit" hidden />
{{ form_end(update_form) }}
{% endblock %}
{% block footer_content %}
@@ -66,10 +66,6 @@
})
.then((r) => r.json())
.then((result) => {
if (result.redirect && window.location.pathname+window.location.hash === result.redirect) {
location.reload();
return;
}
if (result.redirect) {
window.location = result.redirect;
return;
@@ -100,7 +96,7 @@
editModal.querySelector('#update_scheduled_label').value = node.querySelector('#update_scheduled_label').value;
editModal.querySelector('#update_scheduled_options').value = node.querySelector('#update_scheduled_options').value;
editModal.querySelector('#update_scheduled_frequency').value = node.querySelector('#update_scheduled_frequency').value;
editModal.querySelector('#update_scheduled_next').closest('.ibexa-picker').querySelector('.ibexa-date-time-picker').ibexaInstance.flatpickrInstance.setDate(
editModal.querySelector('#update_scheduled_next').parentNode.parentNode.ibexaInstance.flatpickrInstance.setDate(
new Date(node.querySelector('#update_scheduled_next').value * 1000),
true
);

View File

@@ -36,11 +36,11 @@
</tr>
<tr>
<td>{{ 'coderhapsodie.ibexa_dataflow.history.details.count'|trans }}</td>
<td>{{ item.count ? item.count|format_number(locale: app.request.locale) : '—' }}</td>
<td>{{ item.count }}</td>
</tr>
<tr>
<td>{{ 'coderhapsodie.ibexa_dataflow.history.details.errors'|trans }}</td>
<td>{{ item.exceptions|length|format_number(locale: app.request.locale) }}</td>
<td>{{ item.exceptions|length }}</td>
</tr>
<tr>
<td>{{ 'coderhapsodie.ibexa_dataflow.history.details.type'|trans }}</td>

View File

@@ -1,7 +1,6 @@
{% extends '@ibexadesign/ui/form_fields.html.twig' %}
{%- block checkbox_widget -%}
{{ block('form_label') }}
{{ block('toggle_widget') }}
{%- endblock -%}

View File

@@ -1,42 +0,0 @@
{% set id = identifier|default('ibexa_dataflow_history_results') %}
{% import '@ibexadesign/ibexa_dataflow/macros.twig' as macros %}
<div id="loading_{{ id }}" class="text-center" hidden>
<svg class="ez-icon ez-icon--extra-large">
<use xmlns:xlink="http://www.w3.org/1999/xlink"
xlink:href="{{ ibexa_icon_path('spinner') }}"></use>
</svg>
</div>
<div id="{{ id }}" data-loader="loading_{{ id }}" class="history-details-aware">
{% set body_rows = [] %}
{% for job in jobs %}
{% set body_row_cols = [] %}
{% set body_row_cols = body_row_cols|merge([
{content: job.label},
{content: date(job.requested_date)|ibexa_short_datetime},
{content: job.start_time ? date(job.start_time)|ibexa_short_datetime : '—'},
{content: macros.translateStatus(job.status)},
]) %}
{% set body_rows = body_rows|merge([{ cols: body_row_cols }]) %}
{% endfor %}
{% embed '@ibexadesign/ui/component/table/table.html.twig' with {
headline: 'coderhapsodie.ibexa_dataflow.dashboard.title'|trans,
head_cols: [
{ content: 'coderhapsodie.ibexa_dataflow.history.list.name'|trans },
{ content: 'coderhapsodie.ibexa_dataflow.history.list.request'|trans },
{ content: 'coderhapsodie.ibexa_dataflow.history.list.start'|trans },
{ content: 'coderhapsodie.ibexa_dataflow.history.list.status'|trans },
{ },
],
body_rows,
empty_table_info_text: 'coderhapsodie.ibexa_dataflow.history.list.empty'|trans,
} %}
{% endembed %}
</div>

View File

@@ -18,8 +18,8 @@
{% set body_row_cols = body_row_cols|merge([
{content: job.label},
{content: date(job.requested_date)|ibexa_short_datetime},
{content: job.count is not null ? job.count|format_number(locale: app.request.locale) : '—'},
{content: job.exceptions|length|format_number(locale: app.request.locale)},
{content: job.count|default('—')},
{content: job.exceptions|length},
{content: job.start_time ? date(job.start_time)|ibexa_short_datetime : '—'},
{content: job.end_time ? date(job.end_time)|ibexa_short_datetime : '—'},
{content: macros.translateStatus(job.status)},

View File

@@ -148,7 +148,7 @@
oneShotModal.querySelector('#create_oneshot_label').value = node.querySelector('#create_oneshot_label').value;
oneShotModal.querySelector('#create_oneshot_options').value = node.querySelector('#create_oneshot_options').value;
oneShotModal.querySelector('.ibexa-dropdown').ibexaInstance.selectOption(node.querySelector('#create_oneshot_dataflowType').value)
oneShotModal.querySelector('#create_oneshot_requestedDate').closest('.ibexa-picker').querySelector('.ibexa-date-time-picker').ibexaInstance.flatpickrInstance.setDate(new Date(), true);
oneShotModal.querySelector('.flatpickr.flatpickr-input').parentNode.parentNode.ibexaInstance.flatpickrInstance.setDate(new Date(), true);
})
.then(() => {
bootstrap.Tab.getOrCreateInstance(document.querySelector('#ibexa-tab-label-coderhapsodie-ibexa_dataflow-code-rhapsodie-ibexa_dataflow-oneshot')).show()

View File

@@ -12,7 +12,7 @@ class PolicyProvider extends YamlPolicyProvider implements PolicyProviderInterfa
/**
* {@inheritdoc}
*/
protected function getFiles(): array
protected function getFiles()
{
return [__DIR__.'/../Resources/config/policies.yaml'];
}

View File

@@ -1,45 +0,0 @@
<?php
declare(strict_types=1);
namespace CodeRhapsodie\IbexaDataflowBundle\Tab;
use CodeRhapsodie\IbexaDataflowBundle\Controller\DashboardController;
use Ibexa\Contracts\AdminUi\Tab\AbstractControllerBasedTab;
use Ibexa\Contracts\AdminUi\Tab\OrderedTabInterface;
use Symfony\Component\HttpKernel\Controller\ControllerReference;
class DashboardTab extends AbstractControllerBasedTab implements OrderedTabInterface
{
/**
* {@inheritdoc}
*/
public function getControllerReference(array $parameters): ControllerReference
{
return new ControllerReference(DashboardController::class.'::dashboard');
}
/**
* {@inheritdoc}
*/
public function getOrder(): int
{
return 0;
}
/**
* {@inheritdoc}
*/
public function getIdentifier(): string
{
return 'code-rhapsodie-ibexa_dataflow-dashboard';
}
/**
* {@inheritdoc}
*/
public function getName(): string
{
return $this->translator->trans('coderhapsodie.ibexa_dataflow.dashboard');
}
}

View File

@@ -10,7 +10,7 @@ use Ibexa\Contracts\Core\Repository\UserService;
class UserSwitcher implements UserSwitcherInterface
{
/** @var \Ibexa\Contracts\Core\Repository\Values\User\UserReference[] */
private array $userStack;
private $userStack;
/**
* @param string|int $adminLoginOrId
@@ -46,3 +46,4 @@ class UserSwitcher implements UserSwitcherInterface
$this->permissionResolver->setCurrentUserReference(array_pop($this->userStack));
}
}
class_alias(UserSwitcher::class, 'CodeRhapsodie\EzDataflowBundle\UserSwitcher\UserSwitcher');

View File

@@ -8,3 +8,4 @@ interface UserSwitcherAwareInterface
{
public function setUserSwitcher(UserSwitcherInterface $userSwitcher): void;
}
class_alias(UserSwitcherAwareInterface::class, 'CodeRhapsodie\EzDataflowBundle\UserSwitcher\UserSwitcherAwareInterface');

View File

@@ -6,10 +6,13 @@ namespace CodeRhapsodie\IbexaDataflowBundle\UserSwitcher;
trait UserSwitcherAwareTrait
{
protected UserSwitcherInterface $userSwitcher;
/** @var UserSwitcherInterface */
protected $userSwitcher;
public function setUserSwitcher(UserSwitcherInterface $userSwitcher): void
{
$this->userSwitcher = $userSwitcher;
}
}
class_alias(UserSwitcherAwareTrait::class, 'CodeRhapsodie\EzDataflowBundle\UserSwitcher\UserSwitcherAwareTrait');

View File

@@ -12,3 +12,4 @@ interface UserSwitcherInterface
public function switchBack(): void;
}
class_alias(UserSwitcherInterface::class, 'CodeRhapsodie\EzDataflowBundle\UserSwitcher\UserSwitcherInterface');

View File

@@ -55,7 +55,7 @@ class ContentWriter extends RepositoryWriter implements DelegateWriterInterface
return $item instanceof ContentStructure;
}
private function log(string $level, string $message, array $context = []): void
private function log(string $level, string $message, array $context = [])
{
if (null === $this->logger) {
return;
@@ -63,3 +63,4 @@ class ContentWriter extends RepositoryWriter implements DelegateWriterInterface
$this->logger->log($level, $message, $context);
}
}
class_alias(ContentWriter::class, 'CodeRhapsodie\EzDataflowBundle\Writer\ContentWriter');

View File

@@ -12,13 +12,14 @@ abstract class RepositoryWriter implements WriterInterface, UserSwitcherAwareInt
{
use UserSwitcherAwareTrait;
public function prepare(): void
public function prepare()
{
$this->userSwitcher->switchToAdmin();
}
public function finish(): void
public function finish()
{
$this->userSwitcher->switchBack();
}
}
class_alias(RepositoryWriter::class, 'CodeRhapsodie\EzDataflowBundle\Writer\RepositoryWriter');