├── .gitignore ├── Resources ├── public │ ├── less │ │ ├── index.less │ │ └── custom.less │ ├── templates │ │ └── form │ │ │ └── common │ │ │ └── fields │ │ │ ├── export-mapping.html │ │ │ ├── import-mapping.html │ │ │ └── lua-script.html │ └── js │ │ └── form │ │ └── common │ │ └── fields │ │ ├── lua-script.js │ │ ├── import-mapping.js │ │ └── export-mapping.js ├── translations │ ├── validators.en.yml │ ├── validators.fr.yml │ ├── messages.en.yml │ ├── messages.fr.yml │ ├── jsmessages.en.yml │ └── jsmessages.fr.yml ├── config │ ├── routing.yml │ ├── entities.yml │ ├── controllers.yml │ ├── validators.yml │ ├── subscribers.yml │ ├── custom_entities.yml │ ├── validation.yml │ ├── providers.yml │ ├── normalizers.yml │ ├── helpers.yml │ ├── requirejs.yml │ ├── archiving.yml │ ├── doctrine │ │ ├── LuaUpdater.orm.yml │ │ ├── ExportMapping.orm.yml │ │ └── ImportMapping.orm.yml │ ├── form_extensions │ │ ├── luaUpdater │ │ │ ├── create.yml │ │ │ ├── index.yml │ │ │ └── edit.yml │ │ ├── exportMapping │ │ │ ├── create.yml │ │ │ ├── index.yml │ │ │ └── edit.yml │ │ ├── importMapping │ │ │ ├── create.yml │ │ │ ├── index.yml │ │ │ └── edit.yml │ │ ├── menu.yml │ │ ├── csv_advanced_product_export_show.yml │ │ ├── csv_advanced_product_model_export_show.yml │ │ ├── csv_advanced_product_import_show.yml │ │ └── csv_advanced_product_model_import_show.yml │ ├── repositories.yml │ ├── readers.yml │ ├── acl.yml │ ├── job_defaults.yml │ ├── job_constraints.yml │ ├── datagrid │ │ ├── lua_updater.yml │ │ ├── export_mapping.yml │ │ └── import_mapping.yml │ ├── steps.yml │ ├── jobs.yml │ └── writers.yml ├── views │ └── notification.html.twig └── bin │ └── split-csv-files.sh ├── Reader ├── MultiFilesReaderInterface.php └── File │ └── Csv │ └── ProductModelAdvancedReader.php ├── Doctrine └── ORM │ └── Repository │ ├── LuaUpdaterRepository.php │ ├── ExportMappingRepository.php │ ├── ImportMappingRepository.php │ └── AttributeOptionRepository.php ├── Writer └── File │ ├── Csv │ └── ProductModelAdvancedWriter.php │ └── ProductColumnSorterByMapping.php ├── ClickAndMortarAdvancedCsvConnectorBundle.php ├── Validator ├── Constraints │ └── LuaScriptConstraint.php └── LuaScriptValidator.php ├── composer.json ├── EventSubscriber └── LoadClassMetadataSubscriber.php ├── Normalizer └── Standard │ ├── LuaUpdaterNormalizer.php │ ├── ExportMappingNormalizer.php │ └── ImportMappingNormalizer.php ├── DependencyInjection └── ClickAndMortarAdvancedCsvConnectorExtension.php ├── Job └── JobParameters │ ├── DefaultValuesProvider │ ├── ProductCsvAdvancedExport.php │ └── ProductCsvAdvancedImport.php │ └── ConstraintCollectionProvider │ ├── ProductCsvAdvancedImport.php │ └── ProductCsvAdvancedExport.php ├── Controller └── LuaUpdaterController.php ├── Entity ├── LuaUpdater.php ├── ExportMapping.php └── ImportMapping.php ├── Archiver ├── AdvancedFileReaderArchiver.php └── AdvancedCsvInvalidItemWriter.php ├── Helper └── ExportHelper.php ├── README.md └── Step └── MailNotification.php /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | *~ 3 | *.swp 4 | *.swo -------------------------------------------------------------------------------- /Resources/public/less/index.less: -------------------------------------------------------------------------------- 1 | @import "./public/bundles/clickandmortaradvancedcsvconnector/less/lib/tabulator_bootstrap4.less"; 2 | @import "./public/bundles/clickandmortaradvancedcsvconnector/less/custom.less"; -------------------------------------------------------------------------------- /Resources/translations/validators.en.yml: -------------------------------------------------------------------------------- 1 | candm_advanced_csv_connector: 2 | lua_updater: 3 | validation: 4 | lua_script: 5 | empty: LUA script can not be empty 6 | error: Invalid LUA script -------------------------------------------------------------------------------- /Resources/config/routing.yml: -------------------------------------------------------------------------------- 1 | candm_advanced_csv_connector_api_luaUpdater_test: 2 | path: /lupdateUpdater/test 3 | defaults: { _controller: candm_advanced_csv_connector.controller.lua_updater:testAction, _format: json } 4 | methods: [POST] -------------------------------------------------------------------------------- /Resources/translations/validators.fr.yml: -------------------------------------------------------------------------------- 1 | candm_advanced_csv_connector: 2 | lua_updater: 3 | validation: 4 | lua_script: 5 | empty: Le script LUA ne doit pas être vide 6 | error: Le script LUA n'est pas correct -------------------------------------------------------------------------------- /Resources/public/templates/form/common/fields/export-mapping.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | <%- _.__('candm_advanced_csv_connector.exportMapping.actions.add_row') %> 5 |
6 |
-------------------------------------------------------------------------------- /Resources/public/templates/form/common/fields/import-mapping.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | <%- _.__('candm_advanced_csv_connector.importMapping.actions.add_row') %> 5 |
6 |
-------------------------------------------------------------------------------- /Resources/config/entities.yml: -------------------------------------------------------------------------------- 1 | parameters: 2 | pim_custom_entity.entity.importMapping.class: ClickAndMortar\AdvancedCsvConnectorBundle\Entity\ImportMapping 3 | pim_custom_entity.entity.exportMapping.class: ClickAndMortar\AdvancedCsvConnectorBundle\Entity\ExportMapping 4 | pim_custom_entity.entity.luaUpdater.class: ClickAndMortar\AdvancedCsvConnectorBundle\Entity\LuaUpdater -------------------------------------------------------------------------------- /Resources/config/controllers.yml: -------------------------------------------------------------------------------- 1 | parameters: 2 | candm_advanced_csv_connector.controller.lua_updater.class: ClickAndMortar\AdvancedCsvConnectorBundle\Controller\LuaUpdaterController 3 | 4 | services: 5 | _defaults: { public: true } 6 | 7 | candm_advanced_csv_connector.controller.lua_updater: 8 | class: '%candm_advanced_csv_connector.controller.lua_updater.class%' 9 | arguments: 10 | - '@translator' -------------------------------------------------------------------------------- /Reader/MultiFilesReaderInterface.php: -------------------------------------------------------------------------------- 1 | 11 | * @package ClickAndMortar\AdvancedCsvConnectorBundle\Doctrine\ORM\Repository 12 | */ 13 | class LuaUpdaterRepository extends CustomEntityRepository 14 | { 15 | } 16 | -------------------------------------------------------------------------------- /Doctrine/ORM/Repository/ExportMappingRepository.php: -------------------------------------------------------------------------------- 1 | 11 | * @package ClickAndMortar\AdvancedCsvConnectorBundle\Doctrine\ORM\Repository 12 | */ 13 | class ExportMappingRepository extends CustomEntityRepository 14 | { 15 | } 16 | -------------------------------------------------------------------------------- /Doctrine/ORM/Repository/ImportMappingRepository.php: -------------------------------------------------------------------------------- 1 | 11 | * @package ClickAndMortar\AdvancedCsvConnectorBundle\Doctrine\ORM\Repository 12 | */ 13 | class ImportMappingRepository extends CustomEntityRepository 14 | { 15 | } 16 | -------------------------------------------------------------------------------- /Resources/config/custom_entities.yml: -------------------------------------------------------------------------------- 1 | custom_entities: 2 | importMapping: 3 | entity_class: ClickAndMortar\AdvancedCsvConnectorBundle\Entity\ImportMapping 4 | options: 5 | edit_form_extension: pim-importMapping-edit-form 6 | 7 | exportMapping: 8 | entity_class: ClickAndMortar\AdvancedCsvConnectorBundle\Entity\ExportMapping 9 | options: 10 | edit_form_extension: pim-exportMapping-edit-form 11 | 12 | luaUpdater: 13 | entity_class: ClickAndMortar\AdvancedCsvConnectorBundle\Entity\LuaUpdater 14 | options: 15 | edit_form_extension: pim-luaUpdater-edit-form -------------------------------------------------------------------------------- /Writer/File/Csv/ProductModelAdvancedWriter.php: -------------------------------------------------------------------------------- 1 | 10 | * @package ClickAndMortar\AdvancedCsvConnectorBundle\Writer\File\Csv 11 | */ 12 | class ProductModelAdvancedWriter extends ProductAdvancedWriter 13 | { 14 | /** 15 | * {@inheritdoc} 16 | */ 17 | protected function getItemIdentifier(array $productModel): string 18 | { 19 | return $productModel['code']; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Resources/config/validation.yml: -------------------------------------------------------------------------------- 1 | ClickAndMortar\AdvancedCsvConnectorBundle\Entity\ImportMapping: 2 | properties: 3 | label: 4 | - NotBlank: ~ 5 | code: 6 | - NotBlank: ~ 7 | 8 | ClickAndMortar\AdvancedCsvConnectorBundle\Entity\ExportMapping: 9 | properties: 10 | label: 11 | - NotBlank: ~ 12 | code: 13 | - NotBlank: ~ 14 | 15 | ClickAndMortar\AdvancedCsvConnectorBundle\Entity\LuaUpdater: 16 | constraints: 17 | - ClickAndMortar\AdvancedCsvConnectorBundle\Validator\Constraints\LuaScriptConstraint: ~ 18 | properties: 19 | label: 20 | - NotBlank: ~ 21 | code: 22 | - NotBlank: ~ -------------------------------------------------------------------------------- /Resources/config/providers.yml: -------------------------------------------------------------------------------- 1 | services: 2 | candm_advanced_csv_connector.provider.form.job_instance: 3 | class: 'Akeneo\Platform\Bundle\ImportExportBundle\Provider\Form\JobInstanceFormProvider' 4 | arguments: 5 | - 6 | csv_advanced_product_import: pim-job-instance-csv-advanced-product-import 7 | csv_advanced_product_model_import: pim-job-instance-csv-advanced-product-model-import 8 | csv_advanced_product_export: pim-job-instance-csv-advanced-product-export 9 | csv_advanced_product_model_export: pim-job-instance-csv-advanced-product-model-export 10 | tags: 11 | - { name: pim_enrich.provider.form } -------------------------------------------------------------------------------- /ClickAndMortarAdvancedCsvConnectorBundle.php: -------------------------------------------------------------------------------- 1 | 12 | * @package ClickAndMortar\AdvancedCsvConnectorBundle 13 | */ 14 | class ClickAndMortarAdvancedCsvConnectorBundle extends Bundle 15 | { 16 | /** 17 | * Build. 18 | * 19 | * @param ContainerBuilder $container 20 | */ 21 | public function build(ContainerBuilder $container) 22 | { 23 | parent::build($container); 24 | } 25 | } -------------------------------------------------------------------------------- /Validator/Constraints/LuaScriptConstraint.php: -------------------------------------------------------------------------------- 1 | 11 | * @package ClickAndMortar\AdvancedCsvConnectorBundle\Validator\Constraints 12 | */ 13 | class LuaScriptConstraint extends Constraint 14 | { 15 | /** 16 | * {@inheritdoc} 17 | */ 18 | public function getTargets() 19 | { 20 | return self::CLASS_CONSTRAINT; 21 | } 22 | 23 | /** 24 | * {@inheritdoc} 25 | */ 26 | public function validatedBy() 27 | { 28 | return 'candm_advanced_csv_connector.validator.lua_script'; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Resources/config/normalizers.yml: -------------------------------------------------------------------------------- 1 | # Normalizers 2 | services: 3 | pim_custom_entity.normalizer.standard.importMapping: 4 | public: false 5 | class: ClickAndMortar\AdvancedCsvConnectorBundle\Normalizer\Standard\ImportMappingNormalizer 6 | tags: 7 | - { name: pim_serializer.normalizer, priority: 200 } 8 | 9 | pim_custom_entity.normalizer.standard.exportMapping: 10 | public: false 11 | class: ClickAndMortar\AdvancedCsvConnectorBundle\Normalizer\Standard\ExportMappingNormalizer 12 | tags: 13 | - { name: pim_serializer.normalizer, priority: 200 } 14 | 15 | pim_custom_entity.normalizer.standard.luaUpdater: 16 | public: false 17 | class: ClickAndMortar\AdvancedCsvConnectorBundle\Normalizer\Standard\LuaUpdaterNormalizer 18 | tags: 19 | - { name: pim_serializer.normalizer, priority: 200 } -------------------------------------------------------------------------------- /Resources/public/templates/form/common/fields/lua-script.html: -------------------------------------------------------------------------------- 1 |
2 | 8 |
9 |
10 |
11 | 12 |
13 |
14 | <%- _.__('candm_advanced_csv_connector.luaUpdater.custom.test_action') %> 15 |
16 |
17 |
-------------------------------------------------------------------------------- /Resources/config/helpers.yml: -------------------------------------------------------------------------------- 1 | parameters: 2 | candm_advanced_csv_connector.helper.import.class: ClickAndMortar\AdvancedCsvConnectorBundle\Helper\ImportHelper 3 | candm_advanced_csv_connector.helper.export.class: ClickAndMortar\AdvancedCsvConnectorBundle\Helper\ExportHelper 4 | 5 | services: 6 | candm_advanced_csv_connector.helper.import: 7 | class: '%candm_advanced_csv_connector.helper.import.class%' 8 | arguments: 9 | - '@logger' 10 | - '@doctrine.orm.entity_manager' 11 | - '%kernel.project_dir%' 12 | - '@pim_catalog.repository.attribute' 13 | - '@translator' 14 | 15 | candm_advanced_csv_connector.helper.export: 16 | class: '%candm_advanced_csv_connector.helper.export.class%' 17 | arguments: 18 | - '@doctrine.orm.entity_manager' 19 | - '@pim_catalog.repository.attribute_option' -------------------------------------------------------------------------------- /Resources/views/notification.html.twig: -------------------------------------------------------------------------------- 1 | 2 | 3 | {% for stepName, messagesByType in messagesByStepAndType %} 4 |

{{ ('batch_jobs.mail_notification.step_title') | trans }} : {{ stepName }}

5 | {% for messageType, messages in messagesByType %} 6 | {{ ('batch_jobs.mail_notification.types.' ~ messageType) | trans }} 7 | 16 | {% endfor %} 17 | {% endfor %} 18 | 19 | 20 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "clickandmortar/advanced-csv-connector-bundle", 3 | "description": "Advanced CSV Connector for Akeneo", 4 | "type": "symfony-bundle", 5 | "license": "MIT", 6 | "authors": [ 7 | { 8 | "name": "Simon CARRE", 9 | "email": "simon.carre@clickandmortar.fr" 10 | } 11 | ], 12 | "require": { 13 | "akeneo/pim-community-dev": "^7.0.0", 14 | "akeneo-labs/custom-entity-bundle": "7.0.*" 15 | }, 16 | "repositories": [ 17 | { 18 | "type": "vcs", 19 | "url": "git@github.com:ClickAndMortar/AdvancedEnrichBundle.git" 20 | }, 21 | { 22 | "type": "vcs", 23 | "url": "https://github.com/ClickAndMortar/CustomEntityBundle" 24 | } 25 | ], 26 | "autoload": { 27 | "psr-4": { 28 | "ClickAndMortar\\AdvancedCsvConnectorBundle\\": "" 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Resources/config/requirejs.yml: -------------------------------------------------------------------------------- 1 | config: 2 | paths: 3 | tabulator: clickandmortaradvancedcsvconnector/js/lib/tabulator 4 | 5 | # Mapping fields 6 | pim/form/common/fields/import-mapping: clickandmortaradvancedcsvconnector/js/form/common/fields/import-mapping 7 | pim/template/form/common/fields/import-mapping: clickandmortaradvancedcsvconnector/templates/form/common/fields/import-mapping.html 8 | pim/form/common/fields/export-mapping: clickandmortaradvancedcsvconnector/js/form/common/fields/export-mapping 9 | pim/template/form/common/fields/export-mapping: clickandmortaradvancedcsvconnector/templates/form/common/fields/export-mapping.html 10 | 11 | # LUA script field 12 | pim/form/common/fields/lua-script: clickandmortaradvancedcsvconnector/js/form/common/fields/lua-script 13 | pim/template/form/common/fields/lua-script: clickandmortaradvancedcsvconnector/templates/form/common/fields/lua-script.html -------------------------------------------------------------------------------- /Resources/config/archiving.yml: -------------------------------------------------------------------------------- 1 | parameters: 2 | pim_connector.archiver.file_reader_archiver.class: ClickAndMortar\AdvancedCsvConnectorBundle\Archiver\AdvancedFileReaderArchiver 3 | candm_advanced_csv_connector.archiver.invalid_item_csv_writer.class: ClickAndMortar\AdvancedCsvConnectorBundle\Archiver\AdvancedCsvInvalidItemWriter 4 | 5 | services: 6 | candm_advanced_csv_connector.archiver.invalid_item_csv_writer: 7 | class: '%candm_advanced_csv_connector.archiver.invalid_item_csv_writer.class%' 8 | arguments: 9 | - '@pim_connector.event_listener.invalid_items_collector' 10 | - '@pim_connector.writer.file.invalid_items_csv' 11 | - '@pim_connector.reader.file.csv_iterator_factory' 12 | - '@oneup_flysystem.archivist_filesystem' 13 | - '@pim_connector.job.job_parameters.default_values_provider.product_csv_export' 14 | - 'advanced_csv' 15 | tags: 16 | - { name: pim_connector.archiver } -------------------------------------------------------------------------------- /Resources/config/doctrine/LuaUpdater.orm.yml: -------------------------------------------------------------------------------- 1 | ClickAndMortar\AdvancedCsvConnectorBundle\Entity\LuaUpdater: 2 | repositoryClass: ClickAndMortar\AdvancedCsvConnectorBundle\Doctrine\ORM\Repository\LuaUpdaterRepository 3 | type: entity 4 | table: candm_reference_data_luaupdater 5 | changeTrackingPolicy: DEFERRED_EXPLICIT 6 | fields: 7 | id: 8 | type: integer 9 | id: true 10 | generator: 11 | strategy: AUTO 12 | label: 13 | type: string 14 | length: 255 15 | code: 16 | type: string 17 | length: 255 18 | unique: true 19 | script: 20 | type: text 21 | nullable: true 22 | sortOrder: 23 | type: integer 24 | created: 25 | type: datetime 26 | gedmo: 27 | timestampable: 28 | on: create 29 | updated: 30 | type: datetime 31 | gedmo: 32 | timestampable: 33 | on: update 34 | lifecycleCallbacks: { } -------------------------------------------------------------------------------- /Reader/File/Csv/ProductModelAdvancedReader.php: -------------------------------------------------------------------------------- 1 | 9 | * @package ClickAndMortar\AdvancedCsvConnectorBundle\Reader\File\Csv 10 | */ 11 | class ProductModelAdvancedReader extends ProductAdvancedReader 12 | { 13 | /** 14 | * @return array 15 | */ 16 | protected function getArrayConverterOptions(): array 17 | { 18 | $jobParameters = $this->stepExecution->getJobParameters(); 19 | 20 | return [ 21 | // for the array converters 22 | 'mapping' => [ 23 | $jobParameters->get('familyVariantColumn') => 'family_variant', 24 | $jobParameters->get('categoriesColumn') => 'categories', 25 | ], 26 | 'with_associations' => false, 27 | 28 | // for the delocalization 29 | 'decimal_separator' => $jobParameters->get('decimalSeparator'), 30 | 'date_format' => $jobParameters->get('dateFormat'), 31 | ]; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /EventSubscriber/LoadClassMetadataSubscriber.php: -------------------------------------------------------------------------------- 1 | getClassMetadata(); 33 | if ($classMetadata->getName() !== 'Akeneo\Pim\Structure\Component\Model\AttributeOption') { 34 | return; 35 | } 36 | 37 | $classMetadata->customRepositoryClassName = 'ClickAndMortar\AdvancedCsvConnectorBundle\Doctrine\ORM\Repository\AttributeOptionRepository'; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Resources/config/doctrine/ExportMapping.orm.yml: -------------------------------------------------------------------------------- 1 | ClickAndMortar\AdvancedCsvConnectorBundle\Entity\ExportMapping: 2 | repositoryClass: ClickAndMortar\AdvancedCsvConnectorBundle\Doctrine\ORM\Repository\ExportMappingRepository 3 | type: entity 4 | table: candm_reference_data_exportmapping 5 | changeTrackingPolicy: DEFERRED_EXPLICIT 6 | fields: 7 | id: 8 | type: integer 9 | id: true 10 | generator: 11 | strategy: AUTO 12 | label: 13 | type: string 14 | length: 255 15 | code: 16 | type: string 17 | length: 255 18 | unique: true 19 | mappingAsJson: 20 | type: text 21 | nullable: true 22 | completeCallback: 23 | type: string 24 | length: 255 25 | nullable: true 26 | sortOrder: 27 | type: integer 28 | created: 29 | type: datetime 30 | gedmo: 31 | timestampable: 32 | on: create 33 | updated: 34 | type: datetime 35 | gedmo: 36 | timestampable: 37 | on: update 38 | lifecycleCallbacks: { } -------------------------------------------------------------------------------- /Resources/config/form_extensions/luaUpdater/create.yml: -------------------------------------------------------------------------------- 1 | extensions: 2 | pim-luaUpdater-create-modal: 3 | module: custom_entity/form/creation/modal 4 | config: 5 | labels: 6 | title: pim_custom_entity.create_popin.title 7 | subTitle: candm_advanced_csv_connector.menu.item.reference_data.luaUpdater 8 | picture: illustrations/User.svg 9 | successMessage: pim_custom_entity.message.created 10 | editRoute: pim_customentity_rest_get 11 | postUrl: 12 | route: pim_customentity_rest_create 13 | parameters: 14 | customEntityName: luaUpdater 15 | 16 | pim-luaUpdater-create-label: 17 | module: pim/form/common/creation/field 18 | parent: pim-luaUpdater-create-modal 19 | targetZone: fields 20 | position: 10 21 | config: 22 | identifier: label 23 | label: pim_custom_entity.form.field.label.label 24 | 25 | pim-luaUpdater-create-code: 26 | module: pim/form/common/creation/field 27 | parent: pim-luaUpdater-create-modal 28 | targetZone: fields 29 | position: 20 30 | config: 31 | identifier: code 32 | label: pim_custom_entity.form.field.label.code -------------------------------------------------------------------------------- /Resources/config/form_extensions/exportMapping/create.yml: -------------------------------------------------------------------------------- 1 | extensions: 2 | pim-exportMapping-create-modal: 3 | module: custom_entity/form/creation/modal 4 | config: 5 | labels: 6 | title: pim_custom_entity.create_popin.title 7 | subTitle: candm_advanced_csv_connector.menu.item.reference_data.exportMapping 8 | picture: illustrations/User.svg 9 | successMessage: pim_custom_entity.message.created 10 | editRoute: pim_customentity_rest_get 11 | postUrl: 12 | route: pim_customentity_rest_create 13 | parameters: 14 | customEntityName: exportMapping 15 | 16 | pim-exportMapping-create-label: 17 | module: pim/form/common/creation/field 18 | parent: pim-exportMapping-create-modal 19 | targetZone: fields 20 | position: 10 21 | config: 22 | identifier: label 23 | label: pim_custom_entity.form.field.label.label 24 | 25 | pim-exportMapping-create-code: 26 | module: pim/form/common/creation/field 27 | parent: pim-exportMapping-create-modal 28 | targetZone: fields 29 | position: 20 30 | config: 31 | identifier: code 32 | label: pim_custom_entity.form.field.label.code -------------------------------------------------------------------------------- /Resources/config/form_extensions/importMapping/create.yml: -------------------------------------------------------------------------------- 1 | extensions: 2 | pim-importMapping-create-modal: 3 | module: custom_entity/form/creation/modal 4 | config: 5 | labels: 6 | title: pim_custom_entity.create_popin.title 7 | subTitle: candm_advanced_csv_connector.menu.item.reference_data.importMapping 8 | picture: illustrations/User.svg 9 | successMessage: pim_custom_entity.message.created 10 | editRoute: pim_customentity_rest_get 11 | postUrl: 12 | route: pim_customentity_rest_create 13 | parameters: 14 | customEntityName: importMapping 15 | 16 | pim-importMapping-create-label: 17 | module: pim/form/common/creation/field 18 | parent: pim-importMapping-create-modal 19 | targetZone: fields 20 | position: 10 21 | config: 22 | identifier: label 23 | label: pim_custom_entity.form.field.label.label 24 | 25 | pim-importMapping-create-code: 26 | module: pim/form/common/creation/field 27 | parent: pim-importMapping-create-modal 28 | targetZone: fields 29 | position: 20 30 | config: 31 | identifier: code 32 | label: pim_custom_entity.form.field.label.code -------------------------------------------------------------------------------- /Resources/config/form_extensions/menu.yml: -------------------------------------------------------------------------------- 1 | extensions: 2 | candm_advanced_csv_connector-menu-reference_data-item-importMapping: 3 | module: pim/menu/item 4 | parent: pim-menu-reference_data-navigation-block 5 | position: 10 6 | config: 7 | title: candm_advanced_csv_connector.menu.item.reference_data.importMapping 8 | to: pim_customentity_index 9 | routeParams: 10 | customEntityName: importMapping 11 | 12 | candm_advanced_csv_connector-menu-reference_data-item-exportMapping: 13 | module: pim/menu/item 14 | parent: pim-menu-reference_data-navigation-block 15 | position: 20 16 | config: 17 | title: candm_advanced_csv_connector.menu.item.reference_data.exportMapping 18 | to: pim_customentity_index 19 | routeParams: 20 | customEntityName: exportMapping 21 | 22 | candm_advanced_csv_connector-menu-reference_data-item-luaUpdater: 23 | module: pim/menu/item 24 | parent: pim-menu-reference_data-navigation-block 25 | position: 30 26 | config: 27 | title: candm_advanced_csv_connector.menu.item.reference_data.luaUpdater 28 | to: pim_customentity_index 29 | routeParams: 30 | customEntityName: luaUpdater -------------------------------------------------------------------------------- /Normalizer/Standard/LuaUpdaterNormalizer.php: -------------------------------------------------------------------------------- 1 | 12 | * @package ClickAndMortar\AdvancedCsvConnectorBundle\Normalizer\Standard 13 | */ 14 | class LuaUpdaterNormalizer implements NormalizerInterface 15 | { 16 | /** 17 | * @var string[] 18 | */ 19 | protected $supportedFormats = ['standard']; 20 | 21 | /** 22 | * @param LuaUpdater $entity 23 | * @param null $format 24 | * @param array $context 25 | * 26 | * @return array 27 | */ 28 | public function normalize($entity, $format = null, array $context = []) 29 | { 30 | $mapping = [ 31 | 'id' => $entity->getId(), 32 | 'label' => $entity->getLabel(), 33 | 'code' => $entity->getCode(), 34 | 'script' => $entity->getScript(), 35 | ]; 36 | 37 | return $mapping; 38 | } 39 | 40 | /** 41 | * @param mixed $data 42 | * @param null $format 43 | * 44 | * @return bool 45 | */ 46 | public function supportsNormalization($data, $format = null) 47 | { 48 | return $data instanceof LuaUpdater && in_array($format, $this->supportedFormats); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /DependencyInjection/ClickAndMortarAdvancedCsvConnectorExtension.php: -------------------------------------------------------------------------------- 1 | 14 | * @package ClickAndMortar\AdvancedCsvConnectorBundle\DependencyInjection 15 | */ 16 | class ClickAndMortarAdvancedCsvConnectorExtension extends Extension 17 | { 18 | public function load(array $configs, ContainerBuilder $container) 19 | { 20 | $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config')); 21 | $loader->load('jobs.yml'); 22 | $loader->load('steps.yml'); 23 | $loader->load('readers.yml'); 24 | $loader->load('writers.yml'); 25 | $loader->load('job_constraints.yml'); 26 | $loader->load('job_defaults.yml'); 27 | $loader->load('providers.yml'); 28 | $loader->load('archiving.yml'); 29 | $loader->load('helpers.yml'); 30 | $loader->load('subscribers.yml'); 31 | $loader->load('normalizers.yml'); 32 | $loader->load('entities.yml'); 33 | $loader->load('repositories.yml'); 34 | $loader->load('validators.yml'); 35 | $loader->load('controllers.yml'); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Writer/File/ProductColumnSorterByMapping.php: -------------------------------------------------------------------------------- 1 | 11 | * @package ClickAndMortar\AdvancedCsvConnectorBundle\Writer\File 12 | */ 13 | class ProductColumnSorterByMapping extends ProductColumnSorter 14 | { 15 | /** 16 | * Columns order context key 17 | * 18 | * @var string 19 | */ 20 | const CONTEXT_KEY_COLUMNS_ORDER = 'columnsOrder'; 21 | 22 | /** 23 | * {@inheritdoc} 24 | */ 25 | public function sort(array $columns, array $context = []) 26 | { 27 | // Get order from context if possible 28 | if (isset($context[self::CONTEXT_KEY_COLUMNS_ORDER])) { 29 | $sortedColumns = []; 30 | foreach ($context[self::CONTEXT_KEY_COLUMNS_ORDER] as $columnName) { 31 | if (in_array($columnName, $columns)) { 32 | $sortedColumns[] = $columnName; 33 | } 34 | } 35 | 36 | // Add other columns 37 | $otherColumns = array_diff($columns, $sortedColumns); 38 | if (!empty($otherColumns)) { 39 | $sortedColumns = array_merge($sortedColumns, $otherColumns); 40 | } 41 | 42 | return $sortedColumns; 43 | } 44 | 45 | // Else keep classic case 46 | return parent::sort($columns, $context); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Normalizer/Standard/ExportMappingNormalizer.php: -------------------------------------------------------------------------------- 1 | 12 | * @package ClickAndMortar\AdvancedCsvConnectorBundle\Normalizer\Standard 13 | */ 14 | class ExportMappingNormalizer implements NormalizerInterface 15 | { 16 | /** 17 | * @var string[] 18 | */ 19 | protected $supportedFormats = ['standard']; 20 | 21 | /** 22 | * @param ImportMapping $entity 23 | * @param null $format 24 | * @param array $context 25 | * 26 | * @return array 27 | */ 28 | public function normalize($entity, $format = null, array $context = []) 29 | { 30 | $mapping = [ 31 | 'id' => $entity->getId(), 32 | 'label' => $entity->getLabel(), 33 | 'code' => $entity->getCode(), 34 | 'mappingAsJson' => $entity->getMappingAsJson(), 35 | 'completeCallback' => $entity->getCompleteCallback(), 36 | ]; 37 | 38 | return $mapping; 39 | } 40 | 41 | /** 42 | * @param mixed $data 43 | * @param null $format 44 | * 45 | * @return bool 46 | */ 47 | public function supportsNormalization($data, $format = null) 48 | { 49 | return $data instanceof ExportMapping && in_array($format, $this->supportedFormats); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Resources/config/doctrine/ImportMapping.orm.yml: -------------------------------------------------------------------------------- 1 | ClickAndMortar\AdvancedCsvConnectorBundle\Entity\ImportMapping: 2 | repositoryClass: ClickAndMortar\AdvancedCsvConnectorBundle\Doctrine\ORM\Repository\ImportMappingRepository 3 | type: entity 4 | table: candm_reference_data_importmapping 5 | changeTrackingPolicy: DEFERRED_EXPLICIT 6 | fields: 7 | id: 8 | type: integer 9 | id: true 10 | generator: 11 | strategy: AUTO 12 | label: 13 | type: string 14 | length: 255 15 | code: 16 | type: string 17 | length: 255 18 | unique: true 19 | mappingAsJson: 20 | type: text 21 | nullable: true 22 | completeCallback: 23 | type: string 24 | length: 255 25 | nullable: true 26 | initializeCallback: 27 | type: string 28 | length: 255 29 | nullable: true 30 | flushCallback: 31 | type: string 32 | length: 255 33 | nullable: true 34 | itemsLimit: 35 | type: integer 36 | nullable: true 37 | onlyUpdate: 38 | type: boolean 39 | options: 40 | default: false 41 | sortOrder: 42 | type: integer 43 | created: 44 | type: datetime 45 | gedmo: 46 | timestampable: 47 | on: create 48 | updated: 49 | type: datetime 50 | gedmo: 51 | timestampable: 52 | on: update 53 | lifecycleCallbacks: { } 54 | -------------------------------------------------------------------------------- /Resources/config/repositories.yml: -------------------------------------------------------------------------------- 1 | parameters: 2 | candm_advanced_csv_connector.repository.attribute_option.class: ClickAndMortar\AdvancedCsvConnectorBundle\Doctrine\ORM\Repository\AttributeOptionRepository 3 | candm_advanced_csv_connector.repository.import_mapping.class: ClickAndMortar\AdvancedCsvConnectorBundle\Doctrine\ORM\Repository\ImportMappingRepository 4 | candm_advanced_csv_connector.repository.export_mapping.class: ClickAndMortar\AdvancedCsvConnectorBundle\Doctrine\ORM\Repository\ExportMappingRepository 5 | candm_advanced_csv_connector.repository.lua_updater.class: ClickAndMortar\AdvancedCsvConnectorBundle\Doctrine\ORM\Repository\LuaUpdaterRepository 6 | 7 | services: 8 | candm_advanced_csv_connector.repository.import_mapping: 9 | class: '%candm_advanced_csv_connector.repository.import_mapping.class%' 10 | factory: ['@doctrine.orm.entity_manager', 'getRepository'] 11 | arguments: ['%pim_custom_entity.entity.importMapping.class%'] 12 | tags: 13 | - { name: 'pim_repository' } 14 | 15 | candm_advanced_csv_connector.repository.export_mapping: 16 | class: '%candm_advanced_csv_connector.repository.export_mapping.class%' 17 | factory: ['@doctrine.orm.entity_manager', 'getRepository'] 18 | arguments: ['%pim_custom_entity.entity.exportMapping.class%'] 19 | tags: 20 | - { name: 'pim_repository' } 21 | 22 | candm_advanced_csv_connector.repository.lua_updater: 23 | class: '%candm_advanced_csv_connector.repository.lua_updater.class%' 24 | factory: ['@doctrine.orm.entity_manager', 'getRepository'] 25 | arguments: ['%pim_custom_entity.entity.luaUpdater.class%'] 26 | tags: 27 | - { name: 'pim_repository' } -------------------------------------------------------------------------------- /Doctrine/ORM/Repository/AttributeOptionRepository.php: -------------------------------------------------------------------------------- 1 | createQueryBuilder('o') 21 | ->leftJoin('o.attribute', 'a') 22 | ->where('a.code = :attribute_code') 23 | ->andWhere('o.code IN (:option_codes)') 24 | ->setParameters(array( 25 | 'attribute_code' => $attributeCode, 26 | 'option_codes' => $optionCode 27 | )) 28 | ->getQuery() 29 | ->getResult(); 30 | } 31 | 32 | /** 33 | * @param $attributeCode 34 | * @param $attributeValue 35 | * 36 | * @return array 37 | */ 38 | public function findOptionByValue($attributeCode, $attributeValue) 39 | { 40 | return $this->createQueryBuilder('o') 41 | ->innerJoin('o.attribute', 'a') 42 | ->innerJoin('o.optionValues', 'v') 43 | ->where('a.code = :attribute_code') 44 | ->andWhere('v.value = :attribute_value') 45 | ->setParameters([ 46 | 'attribute_code' => $attributeCode, 47 | 'attribute_value' => $attributeValue 48 | ]) 49 | ->getQuery() 50 | ->getResult(); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /Resources/config/readers.yml: -------------------------------------------------------------------------------- 1 | parameters: 2 | candm_advanced_csv_connector.reader.file.csv_advanced_product.class: ClickAndMortar\AdvancedCsvConnectorBundle\Reader\File\Csv\ProductAdvancedReader 3 | candm_advanced_csv_connector.reader.file.csv_advanced_product_model.class: ClickAndMortar\AdvancedCsvConnectorBundle\Reader\File\Csv\ProductModelAdvancedReader 4 | 5 | services: 6 | candm_advanced_csv_connector.reader.file.csv_advanced_product: 7 | class: '%candm_advanced_csv_connector.reader.file.csv_advanced_product.class%' 8 | arguments: 9 | - '@pim_connector.reader.file.csv_iterator_factory' 10 | - '@pim_connector.array_converter.flat_to_standard.product_delocalized' 11 | - '@pim_connector.reader.file.media_path_transformer' 12 | - '@candm_advanced_csv_connector.helper.import' 13 | - '@pim_catalog.repository.product' 14 | - '@candm_advanced_csv_connector.repository.import_mapping' 15 | - '@candm_advanced_csv_connector.repository.lua_updater' 16 | - [] 17 | 18 | candm_advanced_csv_connector.reader.file.csv_advanced_product_model: 19 | class: '%candm_advanced_csv_connector.reader.file.csv_advanced_product_model.class%' 20 | arguments: 21 | - '@pim_connector.reader.file.csv_iterator_factory' 22 | - '@pim_connector.array_converter.flat_to_standard.product_model_delocalized' 23 | - '@pim_connector.reader.file.media_path_transformer' 24 | - '@candm_advanced_csv_connector.helper.import' 25 | - '@pim_catalog.repository.product_model' 26 | - '@candm_advanced_csv_connector.repository.import_mapping' 27 | - '@candm_advanced_csv_connector.repository.lua_updater' 28 | - [] -------------------------------------------------------------------------------- /Validator/LuaScriptValidator.php: -------------------------------------------------------------------------------- 1 | 14 | * @package ClickAndMortar\AdvancedCsvConnectorBundle\Validator 15 | */ 16 | class LuaScriptValidator extends ConstraintValidator 17 | { 18 | /** 19 | * Test attribute value 20 | * 21 | * @var string 22 | */ 23 | const ATTRIBUTE_VALUE_TEST = '1'; 24 | 25 | /** 26 | * @param LuaUpdater $luaUpdater 27 | * @param Constraint $constraint 28 | */ 29 | public function validate($luaUpdater, Constraint $constraint) 30 | { 31 | $luaScript = $luaUpdater->getScript(); 32 | 33 | // Check if script is empty 34 | if (empty($luaScript)) { 35 | $this->context->addViolation( 36 | 'candm_advanced_csv_connector.lua_updater.validation.lua_script.empty' 37 | ); 38 | } 39 | 40 | // Check script validity 41 | $lua = new \Lua(); 42 | $lua->assign('attributeValue', self::ATTRIBUTE_VALUE_TEST); 43 | $value = $lua->eval(sprintf( 44 | "%s\n%s", 45 | ProductAdvancedReader::LUA_SCRIPT_PREFIX, 46 | $luaScript 47 | )); 48 | if ($value === false) { 49 | $this->context->addViolation( 50 | 'candm_advanced_csv_connector.lua_updater.validation.lua_script.error' 51 | ); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /Job/JobParameters/DefaultValuesProvider/ProductCsvAdvancedExport.php: -------------------------------------------------------------------------------- 1 | 12 | * @package ClickAndMortar\AdvancedCsvConnectorBundle\Job\JobParameters\DefaultValuesProvider 13 | */ 14 | class ProductCsvAdvancedExport implements DefaultValuesProviderInterface 15 | { 16 | /** 17 | * @var DefaultValuesProviderInterface 18 | */ 19 | protected $baseDefaultValuesProvider; 20 | 21 | /** 22 | * @var array 23 | */ 24 | protected $supportedJobNames; 25 | 26 | /** 27 | * @param DefaultValuesProviderInterface $baseDefaultValuesProvider 28 | * @param array $supportedJobNames 29 | */ 30 | public function __construct(DefaultValuesProviderInterface $baseDefaultValuesProvider, array $supportedJobNames) 31 | { 32 | $this->baseDefaultValuesProvider = $baseDefaultValuesProvider; 33 | $this->supportedJobNames = $supportedJobNames; 34 | } 35 | 36 | /** 37 | * {@inheritdoc} 38 | */ 39 | public function getDefaultValues() 40 | { 41 | return array_merge($this->baseDefaultValuesProvider->getDefaultValues(), [ 42 | 'encoding' => null, 43 | 'mapping' => null, 44 | 'forceXlsx' => false 45 | ]); 46 | } 47 | 48 | /** 49 | * {@inheritdoc} 50 | */ 51 | public function supports(JobInterface $job) 52 | { 53 | return in_array($job->getName(), $this->supportedJobNames); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Normalizer/Standard/ImportMappingNormalizer.php: -------------------------------------------------------------------------------- 1 | 12 | * @package ClickAndMortar\AdvancedCsvConnectorBundle\Normalizer\Standard 13 | */ 14 | class ImportMappingNormalizer implements NormalizerInterface 15 | { 16 | /** 17 | * @var string[] 18 | */ 19 | protected $supportedFormats = ['standard']; 20 | 21 | /** 22 | * @param ImportMapping $entity 23 | * @param null $format 24 | * @param array $context 25 | * 26 | * @return array 27 | */ 28 | public function normalize($entity, $format = null, array $context = []) 29 | { 30 | $mapping = [ 31 | 'id' => $entity->getId(), 32 | 'label' => $entity->getLabel(), 33 | 'code' => $entity->getCode(), 34 | 'mappingAsJson' => $entity->getMappingAsJson(), 35 | 'completeCallback' => $entity->getCompleteCallback(), 36 | 'initializeCallback' => $entity->getInitializeCallback(), 37 | 'flushCallback' => $entity->getFlushCallback(), 38 | 'itemsLimit' => $entity->getItemsLimit(), 39 | 'onlyUpdate' => $entity->getOnlyUpdate(), 40 | ]; 41 | 42 | return $mapping; 43 | } 44 | 45 | /** 46 | * @param mixed $data 47 | * @param null $format 48 | * 49 | * @return bool 50 | */ 51 | public function supportsNormalization($data, $format = null) 52 | { 53 | return $data instanceof ImportMapping && in_array($format, $this->supportedFormats); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Job/JobParameters/DefaultValuesProvider/ProductCsvAdvancedImport.php: -------------------------------------------------------------------------------- 1 | 12 | * @package Solaris\Bundle\RestConnectorBundle\Job\JobParameters\DefaultValuesProvider 13 | */ 14 | class ProductCsvAdvancedImport implements DefaultValuesProviderInterface 15 | { 16 | /** 17 | * @var DefaultValuesProviderInterface 18 | */ 19 | protected $baseDefaultValuesProvider; 20 | 21 | /** 22 | * @var array 23 | */ 24 | protected $supportedJobNames; 25 | 26 | /** 27 | * @param DefaultValuesProviderInterface $baseDefaultValuesProvider 28 | * @param array $supportedJobNames 29 | */ 30 | public function __construct(DefaultValuesProviderInterface $baseDefaultValuesProvider, array $supportedJobNames) 31 | { 32 | $this->baseDefaultValuesProvider = $baseDefaultValuesProvider; 33 | $this->supportedJobNames = $supportedJobNames; 34 | } 35 | 36 | /** 37 | * {@inheritdoc} 38 | */ 39 | public function getDefaultValues() 40 | { 41 | return array_merge($this->baseDefaultValuesProvider->getDefaultValues(), [ 42 | 'mapping' => null, 43 | 'emailRecipients' => '', 44 | 'invalid_items_file_format' => 'advanced_csv', 45 | 'successNotification' => false, 46 | 'fromEncoding' => '', 47 | ]); 48 | } 49 | 50 | /** 51 | * {@inheritdoc} 52 | */ 53 | public function supports(JobInterface $job) 54 | { 55 | return in_array($job->getName(), $this->supportedJobNames); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Controller/LuaUpdaterController.php: -------------------------------------------------------------------------------- 1 | 14 | * @package ClickAndMortar\AdvancedCsvConnectorBundle\Controller 15 | */ 16 | class LuaUpdaterController 17 | { 18 | /** 19 | * @var TranslatorInterface 20 | */ 21 | protected $translator; 22 | 23 | /** 24 | * LuaUpdaterController constructor. 25 | * 26 | * @param TranslatorInterface $translator 27 | */ 28 | public function __construct(TranslatorInterface $translator) 29 | { 30 | $this->translator = $translator; 31 | } 32 | 33 | /** 34 | * Test a given script 35 | * 36 | * @param Request $request 37 | * 38 | * @throws BadRequestHttpException 39 | * 40 | * @return JsonResponse 41 | */ 42 | public function testAction(Request $request): JsonResponse 43 | { 44 | // Check if script is not empty 45 | $script = $request->get('script'); 46 | if (empty($script)) { 47 | return new JsonResponse([ 48 | 'message' => $this->translator->trans('luaUpdater.validation.empty_script'), 49 | ], 400); 50 | } 51 | 52 | // Check if test value is not empty 53 | $testValue = $request->get('testValue'); 54 | if (empty($testValue)) { 55 | return new JsonResponse([ 56 | 'message' => $this->translator->trans('luaUpdater.validation.empty_test_value'), 57 | ], 400); 58 | } 59 | 60 | $lua = new \Lua(); 61 | $lua->assign('attributeValue', $testValue); 62 | $value = $lua->eval(sprintf( 63 | "%s\n%s", 64 | ProductAdvancedReader::LUA_SCRIPT_PREFIX, 65 | $script 66 | )); 67 | 68 | return new JsonResponse(['value' => $value]); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /Job/JobParameters/ConstraintCollectionProvider/ProductCsvAdvancedImport.php: -------------------------------------------------------------------------------- 1 | 15 | * @package ClickAndMortar\AdvancedCsvConnectorBundle\Job\JobParameters\ConstraintCollectionProvider 16 | */ 17 | class ProductCsvAdvancedImport implements ConstraintCollectionProviderInterface 18 | { 19 | /** 20 | * @var ConstraintCollectionProviderInterface 21 | */ 22 | protected $baseConstraintCollectionProvider; 23 | 24 | /** 25 | * @var array 26 | */ 27 | protected $supportedJobNames; 28 | 29 | /** 30 | * @param ConstraintCollectionProviderInterface $baseConstraintCollectionProvider 31 | * @param array $supportedJobNames 32 | */ 33 | public function __construct(ConstraintCollectionProviderInterface $baseConstraintCollectionProvider, array $supportedJobNames) 34 | { 35 | $this->baseConstraintCollectionProvider = $baseConstraintCollectionProvider; 36 | $this->supportedJobNames = $supportedJobNames; 37 | } 38 | 39 | /** 40 | * {@inheritdoc} 41 | */ 42 | public function getConstraintCollection() 43 | { 44 | $constraintFields = array_merge($this->baseConstraintCollectionProvider->getConstraintCollection()->fields, [ 45 | 'mapping' => [ 46 | new NotBlank(), 47 | ], 48 | 'emailRecipients' => [], 49 | 'successNotification' => [], 50 | 'fromEncoding' => [] 51 | ]); 52 | 53 | return new Collection(['fields' => $constraintFields]); 54 | } 55 | 56 | /** 57 | * {@inheritdoc} 58 | */ 59 | public function supports(JobInterface $job) 60 | { 61 | return in_array($job->getName(), $this->supportedJobNames); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /Job/JobParameters/ConstraintCollectionProvider/ProductCsvAdvancedExport.php: -------------------------------------------------------------------------------- 1 | 15 | * @package ClickAndMortar\AdvancedCsvConnectorBundle\Job\JobParameters\ConstraintCollectionProvider 16 | */ 17 | class ProductCsvAdvancedExport implements ConstraintCollectionProviderInterface 18 | { 19 | /** 20 | * @var ConstraintCollectionProviderInterface 21 | */ 22 | protected $baseConstraintCollectionProvider; 23 | 24 | /** 25 | * @var array 26 | */ 27 | protected $supportedJobNames; 28 | 29 | /** 30 | * @param ConstraintCollectionProviderInterface $baseConstraintCollectionProvider 31 | * @param array $supportedJobNames 32 | */ 33 | public function __construct(ConstraintCollectionProviderInterface $baseConstraintCollectionProvider, array $supportedJobNames) 34 | { 35 | $this->baseConstraintCollectionProvider = $baseConstraintCollectionProvider; 36 | $this->supportedJobNames = $supportedJobNames; 37 | } 38 | 39 | /** 40 | * {@inheritdoc} 41 | */ 42 | public function getConstraintCollection() 43 | { 44 | $constraintFields = array_merge($this->baseConstraintCollectionProvider->getConstraintCollection()->fields, [ 45 | 'encoding' => [ 46 | ], 47 | 'mapping' => [ 48 | new NotBlank(), 49 | ], 50 | 'forceXlsx' => [ 51 | new Type('bool') 52 | ] 53 | ]); 54 | 55 | return new Collection(['fields' => $constraintFields]); 56 | } 57 | 58 | /** 59 | * {@inheritdoc} 60 | */ 61 | public function supports(JobInterface $job) 62 | { 63 | return in_array($job->getName(), $this->supportedJobNames); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /Entity/LuaUpdater.php: -------------------------------------------------------------------------------- 1 | 11 | * @package ClickAndMortar\AdvancedCsvConnectorBundle\Entity 12 | */ 13 | class LuaUpdater extends AbstractCustomEntity 14 | { 15 | /** 16 | * Default script value for creation 17 | * 18 | * @return string 19 | */ 20 | const DEFAULT_SCRIPT_VALUE = 'return attributeValue;'; 21 | 22 | /** 23 | * Label 24 | * 25 | * @var string 26 | */ 27 | protected $label; 28 | 29 | /** 30 | * Script to update value 31 | * 32 | * @var string 33 | */ 34 | protected $script = self::DEFAULT_SCRIPT_VALUE; 35 | 36 | /** 37 | * Get label 38 | * 39 | * @return string 40 | */ 41 | public function getLabel() 42 | { 43 | return $this->label; 44 | } 45 | 46 | /** 47 | * Set label 48 | * 49 | * @param string $label 50 | * 51 | * @return Brand 52 | */ 53 | public function setLabel($label) 54 | { 55 | $this->label = $label; 56 | 57 | return $this; 58 | } 59 | 60 | /** 61 | * @return string 62 | */ 63 | public function getScript() 64 | { 65 | return $this->script; 66 | } 67 | 68 | /** 69 | * @param string $script 70 | * 71 | * @return LuaUpdater 72 | */ 73 | public function setScript($script) 74 | { 75 | $this->script = $script; 76 | 77 | return $this; 78 | } 79 | 80 | /** 81 | * {@inheritdoc} 82 | */ 83 | public static function getLabelProperty(): string 84 | { 85 | return 'label'; 86 | } 87 | 88 | /** 89 | * Returns the custom entity name used in the configuration 90 | * Used to map row actions on datagrid 91 | * 92 | * @return string 93 | */ 94 | public function getCustomEntityName(): string 95 | { 96 | return 'luaUpdater'; 97 | } 98 | 99 | /** 100 | * Get reference value 101 | * 102 | * @return string 103 | */ 104 | public function getReference(): string 105 | { 106 | return $this->getCode(); 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /Resources/translations/messages.en.yml: -------------------------------------------------------------------------------- 1 | # Custom 2 | batch_jobs: 3 | csv_advanced_product_import: 4 | import: 5 | errors: 6 | no_mapping: No mapping found. 7 | mapping_attributes_error: Incorrect mapping. Missing "attributes" key. 8 | mapping_no_attribute_code: Incorrect mapping. Missing "attributeCode" key. 9 | mapping_no_identifier: Incorrect mapping. Missing "identifier" key. 10 | warnings: 11 | new_product: Product "%identifier%" does not exist. It cannot be updated. 12 | csv_advanced_product_export: 13 | export: 14 | errors: 15 | no_mapping: No mapping found. 16 | mail_notification: 17 | subject: "Import report '%importLabel%' (%date%)" 18 | step_title: "Step name" 19 | types: 20 | default: "Warnings:" 21 | statistics: "Summary:" 22 | statistics: 23 | read: "Lines read : %readCount%" 24 | write: "Processed : %writeCount%" 25 | warning: "Warnings : %warningCount%" 26 | 27 | # Custom entity 28 | importMapping: 29 | this: 30 | edit: Edit import mapping 31 | show: Show import mapping 32 | delete: Delete import mapping 33 | 34 | exportMapping: 35 | this: 36 | edit: Edit export mapping 37 | show: Show export mapping 38 | delete: Delete export mapping 39 | 40 | luaUpdater: 41 | this: 42 | edit: Edit LUA script 43 | show: Show LUA script 44 | delete: Delete LUA script 45 | validation: 46 | empty_script: Your script is empty. 47 | empty_test_value: Your test value is empty. 48 | 49 | pim_custom_entity: 50 | form: 51 | field: 52 | label: 53 | label: Label 54 | code: Code 55 | 56 | candm_advanced_csv_connector: 57 | acl: 58 | importMapping: 59 | index: List import mappings 60 | create: Create an import mapping 61 | edit: Edit an import mapping 62 | delete: Delete an import mapping 63 | exportMapping: 64 | index: List export mappings 65 | create: Create an export mapping 66 | edit: Edit an export mapping 67 | delete: Delete an export mapping 68 | luaUpdater: 69 | index: List LUA scripts 70 | create: Create a LUA script 71 | edit: Edit a LUA script 72 | delete: Delete a LUA script 73 | -------------------------------------------------------------------------------- /Resources/config/acl.yml: -------------------------------------------------------------------------------- 1 | # Reference data 2 | ## Import Mapping 3 | candm_advanced_csv_connector_importMapping_index: 4 | type: action 5 | label: candm_advanced_csv_connector.acl.importMapping.index 6 | group_name: pim_custom_entity.acl_group.reference_data 7 | 8 | candm_advanced_csv_connector_importMapping_create: 9 | type: action 10 | label: candm_advanced_csv_connector.acl.importMapping.create 11 | group_name: pim_custom_entity.acl_group.reference_data 12 | 13 | candm_advanced_csv_connector_importMapping_edit: 14 | type: action 15 | label: candm_advanced_csv_connector.acl.importMapping.edit 16 | group_name: pim_custom_entity.acl_group.reference_data 17 | 18 | candm_advanced_csv_connector_importMapping_delete: 19 | type: action 20 | label: candm_advanced_csv_connector.acl.importMapping.delete 21 | group_name: pim_custom_entity.acl_group.reference_data 22 | 23 | ## Export Mapping 24 | candm_advanced_csv_connector_exportMapping_index: 25 | type: action 26 | label: candm_advanced_csv_connector.acl.exportMapping.index 27 | group_name: pim_custom_entity.acl_group.reference_data 28 | 29 | candm_advanced_csv_connector_exportMapping_create: 30 | type: action 31 | label: candm_advanced_csv_connector.acl.exportMapping.create 32 | group_name: pim_custom_entity.acl_group.reference_data 33 | 34 | candm_advanced_csv_connector_exportMapping_edit: 35 | type: action 36 | label: candm_advanced_csv_connector.acl.exportMapping.edit 37 | group_name: pim_custom_entity.acl_group.reference_data 38 | 39 | candm_advanced_csv_connector_exportMapping_delete: 40 | type: action 41 | label: candm_advanced_csv_connector.acl.exportMapping.delete 42 | group_name: pim_custom_entity.acl_group.reference_data 43 | 44 | ## Lua Updater 45 | candm_advanced_csv_connector_luaUpdater_index: 46 | type: action 47 | label: candm_advanced_csv_connector.acl.luaUpdater.index 48 | group_name: pim_custom_entity.acl_group.reference_data 49 | 50 | candm_advanced_csv_connector_luaUpdater_create: 51 | type: action 52 | label: candm_advanced_csv_connector.acl.luaUpdater.create 53 | group_name: pim_custom_entity.acl_group.reference_data 54 | 55 | candm_advanced_csv_connector_luaUpdater_edit: 56 | type: action 57 | label: candm_advanced_csv_connector.acl.luaUpdater.edit 58 | group_name: pim_custom_entity.acl_group.reference_data 59 | 60 | candm_advanced_csv_connector_luaUpdater_delete: 61 | type: action 62 | label: candm_advanced_csv_connector.acl.luaUpdater.delete 63 | group_name: pim_custom_entity.acl_group.reference_data -------------------------------------------------------------------------------- /Resources/config/form_extensions/csv_advanced_product_export_show.yml: -------------------------------------------------------------------------------- 1 | extensions: 2 | pim-job-instance-csv-advanced-product-export-show: 3 | module: pim/form/common/edit-form 4 | 5 | pim-job-instance-csv-advanced-product-export-show-main-image: 6 | module: pim/form/common/main-image 7 | parent: pim-job-instance-csv-advanced-product-export-show 8 | targetZone: main-image 9 | config: 10 | path: bundles/pimui/images/illustrations/ExportCSV.svg 11 | 12 | pim-job-instance-csv-advanced-product-export-show-user-navigation: 13 | module: pim/menu/user-navigation 14 | parent: pim-job-instance-csv-advanced-product-export-show 15 | targetZone: user-menu 16 | config: 17 | userAccount: pim_menu.user.user_account 18 | logout: pim_menu.user.logout 19 | 20 | pim-job-instance-csv-advanced-product-export-show-breadcrumbs: 21 | module: pim/job/common/breadcrumb/breadcrumb 22 | parent: pim-job-instance-csv-advanced-product-export-show 23 | targetZone: breadcrumbs 24 | 25 | pim-job-instance-csv-advanced-product-export-show-launch: 26 | module: pim/job/common/edit/launch 27 | parent: pim-job-instance-csv-advanced-product-export-show 28 | targetZone: meta 29 | position: 110 30 | config: 31 | label: pim_import_export.form.job_instance.button.export.title 32 | route: pim_enrich_job_instance_rest_export_launch 33 | identifier: 34 | path: code 35 | name: code 36 | 37 | pim-job-instance-csv-advanced-product-export-show-label: 38 | module: pim/job/common/edit/label 39 | parent: pim-job-instance-csv-advanced-product-export-show 40 | targetZone: title 41 | position: 100 42 | 43 | pim-job-instance-csv-advanced-product-export-show-edit: 44 | module: pim/job/common/edit-button 45 | parent: pim-job-instance-csv-advanced-product-export-show 46 | targetZone: buttons 47 | position: 100 48 | aclResourceId: pim_importexport_export_profile_edit 49 | config: 50 | label: pim_common.edit 51 | route: pim_importexport_export_profile_edit 52 | buttonClass: AknButton AknButton--action 53 | identifier: 54 | path: code 55 | name: code 56 | 57 | pim-job-instance-csv-advanced-product-export-show-last-executions: 58 | module: akeneojob/controller/job-instance 59 | parent: pim-job-instance-csv-advanced-product-export-show 60 | position: 100 61 | targetZone: content 62 | -------------------------------------------------------------------------------- /Resources/public/js/form/common/fields/lua-script.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | define([ 4 | 'jquery', 5 | 'underscore', 6 | 'routing', 7 | 'pim/form/common/fields/field', 8 | 'pim/template/form/common/fields/lua-script' 9 | ], 10 | function ( 11 | $, 12 | _, 13 | Routing, 14 | BaseField, 15 | template 16 | ) { 17 | return BaseField.extend({ 18 | template: _.template(template), 19 | events: { 20 | 'keyup textarea': function (event) { 21 | this.errors = []; 22 | this.updateModel(this.getFieldValue(event.target)); 23 | }, 24 | 'click .AknButton--apply': function (event) { 25 | var $messageContainer = $('.lua-message-container'); 26 | var data = { 27 | 'script': this.getModelValue(), 28 | 'testValue': $('.AknTextField--testValue').val() 29 | }; 30 | 31 | $.ajax({ 32 | method: 'POST', 33 | url: Routing.generate('candm_advanced_csv_connector_api_luaUpdater_test'), 34 | contentType: 'application/json', 35 | data: JSON.stringify(data), 36 | success: function (response) { 37 | $messageContainer.empty(); 38 | if (_.has(response, 'value')) { 39 | $messageContainer.append('
' + response.value + '
'); 40 | } 41 | }, 42 | error: function (response) { 43 | $messageContainer.empty(); 44 | if (_.has(response.responseJSON, 'message')) { 45 | $messageContainer.append('
' + response.responseJSON.message + '
'); 46 | } 47 | } 48 | }); 49 | } 50 | }, 51 | 52 | /** 53 | * {@inheritdoc} 54 | */ 55 | renderInput: function (templateContext) { 56 | return this.template(_.extend(templateContext, { 57 | value: this.getModelValue() 58 | })); 59 | }, 60 | 61 | /** 62 | * {@inheritdoc} 63 | */ 64 | getFieldValue: function (field) { 65 | return $(field).val(); 66 | }, 67 | }); 68 | }); 69 | -------------------------------------------------------------------------------- /Resources/config/form_extensions/csv_advanced_product_model_export_show.yml: -------------------------------------------------------------------------------- 1 | extensions: 2 | pim-job-instance-csv-advanced-product-model-export-show: 3 | module: pim/form/common/edit-form 4 | 5 | pim-job-instance-csv-advanced-product-model-export-show-main-image: 6 | module: pim/form/common/main-image 7 | parent: pim-job-instance-csv-advanced-product-model-export-show 8 | targetZone: main-image 9 | config: 10 | path: bundles/pimui/images/illustrations/ExportCSV.svg 11 | 12 | pim-job-instance-csv-advanced-product-model-export-show-user-navigation: 13 | module: pim/menu/user-navigation 14 | parent: pim-job-instance-csv-advanced-product-model-export-show 15 | targetZone: user-menu 16 | config: 17 | userAccount: pim_menu.user.user_account 18 | logout: pim_menu.user.logout 19 | 20 | pim-job-instance-csv-advanced-product-model-export-show-breadcrumbs: 21 | module: pim/job/common/breadcrumb/breadcrumb 22 | parent: pim-job-instance-csv-advanced-product-model-export-show 23 | targetZone: breadcrumbs 24 | 25 | pim-job-instance-csv-advanced-product-model-export-show-launch: 26 | module: pim/job/common/edit/launch 27 | parent: pim-job-instance-csv-advanced-product-model-export-show 28 | targetZone: meta 29 | position: 110 30 | config: 31 | label: pim_import_export.form.job_instance.button.export.title 32 | route: pim_enrich_job_instance_rest_export_launch 33 | identifier: 34 | path: code 35 | name: code 36 | 37 | pim-job-instance-csv-advanced-product-model-export-show-label: 38 | module: pim/job/common/edit/label 39 | parent: pim-job-instance-csv-advanced-product-model-export-show 40 | targetZone: title 41 | position: 100 42 | 43 | pim-job-instance-csv-advanced-product-model-export-show-edit: 44 | module: pim/job/common/edit-button 45 | parent: pim-job-instance-csv-advanced-product-model-export-show 46 | targetZone: buttons 47 | position: 100 48 | aclResourceId: pim_importexport_export_profile_edit 49 | config: 50 | label: pim_common.edit 51 | route: pim_importexport_export_profile_edit 52 | buttonClass: AknButton AknButton--action 53 | identifier: 54 | path: code 55 | name: code 56 | 57 | pim-job-instance-csv-advanced-product-model-export-show-last-executions: 58 | module: akeneojob/controller/job-instance 59 | parent: pim-job-instance-csv-advanced-product-model-export-show 60 | position: 100 61 | targetZone: content -------------------------------------------------------------------------------- /Resources/config/job_defaults.yml: -------------------------------------------------------------------------------- 1 | parameters: 2 | candm_advanced_csv_connector.job.job_parameters.default_values_provider.product_csv_advanced_import.class: ClickAndMortar\AdvancedCsvConnectorBundle\Job\JobParameters\DefaultValuesProvider\ProductCsvAdvancedImport 3 | candm_advanced_csv_connector.job.job_parameters.default_values_provider.product_csv_advanced_export.class: ClickAndMortar\AdvancedCsvConnectorBundle\Job\JobParameters\DefaultValuesProvider\ProductCsvAdvancedExport 4 | 5 | services: 6 | candm_advanced_csv_connector.job.job_parameters.default_values_provider.product_csv_advanced_import: 7 | class: '%candm_advanced_csv_connector.job.job_parameters.default_values_provider.product_csv_advanced_import.class%' 8 | arguments: 9 | - '@pim_connector.job.job_parameters.default_values_provider.product_csv_import' 10 | - 11 | - '%candm_advanced_csv_connector.job_name.csv_advanced_product_import%' 12 | tags: 13 | - { name: akeneo_batch.job.job_parameters.default_values_provider } 14 | 15 | candm_advanced_csv_connector.job.job_parameters.default_values_provider.product_model_csv_import: 16 | class: '%candm_advanced_csv_connector.job.job_parameters.default_values_provider.product_csv_advanced_import.class%' 17 | arguments: 18 | - '@pim_connector.job.job_parameters.default_values_provider.product_model_csv_import' 19 | - 20 | - '%candm_advanced_csv_connector.job_name.csv_advanced_product_model_import%' 21 | tags: 22 | - { name: akeneo_batch.job.job_parameters.default_values_provider } 23 | 24 | candm_advanced_csv_connector.job.job_parameters.default_values_provider.product_csv_advanced_export: 25 | class: '%candm_advanced_csv_connector.job.job_parameters.default_values_provider.product_csv_advanced_export.class%' 26 | arguments: 27 | - '@pim_connector.job.job_parameters.default_values_provider.product_csv_export' 28 | - 29 | - '%candm_advanced_csv_connector.job_name.csv_advanced_product_export%' 30 | tags: 31 | - { name: akeneo_batch.job.job_parameters.default_values_provider } 32 | 33 | candm_advanced_csv_connector.job.job_parameters.default_values_provider.product_model_csv_advanced_export: 34 | class: '%candm_advanced_csv_connector.job.job_parameters.default_values_provider.product_csv_advanced_export.class%' 35 | arguments: 36 | - '@pim_connector.job.job_parameters.default_values_provider.product_model_csv_export' 37 | - 38 | - '%candm_advanced_csv_connector.job_name.csv_advanced_product_model_export%' 39 | tags: 40 | - { name: akeneo_batch.job.job_parameters.default_values_provider } 41 | -------------------------------------------------------------------------------- /Resources/translations/messages.fr.yml: -------------------------------------------------------------------------------- 1 | # Custom 2 | batch_jobs: 3 | csv_advanced_product_import: 4 | import: 5 | errors: 6 | no_mapping: Aucun mapping trouvé. Merci de réessayer. 7 | mapping_attributes_error: Le mapping est incorrect. La clé "attributes" est manquante. 8 | mapping_no_attribute_code: Le mapping est incorrect. La clé "attributeCode" est manquante pour un attribut. 9 | mapping_no_identifier: Le mapping est incorrect. la clé "identifier" est manquante sur au moins un attribut. 10 | warnings: 11 | new_product: Le produit "%identifier%" n'existe pas, il ne peut pas être mis à jour. 12 | csv_advanced_product_export: 13 | export: 14 | errors: 15 | no_mapping: Aucun mapping trouvé. Merci de réessayer. 16 | mail_notification: 17 | subject: "Rapport de l'import '%importLabel%' (%date%)" 18 | step_title: "Nom de l'étape" 19 | types: 20 | default: "Liste des avertissements :" 21 | statistics: "Résumé :" 22 | statistics: 23 | read: "Lignes lues : %readCount%" 24 | write: "Traité(s) : %writeCount%" 25 | warning: "Avertissements : %warningCount%" 26 | 27 | # Custom entity 28 | importMapping: 29 | this: 30 | edit: Éditer le mapping d'import 31 | show: Afficher le mapping d'import 32 | delete: Supprimer le mapping d'import 33 | 34 | exportMapping: 35 | this: 36 | edit: Éditer le mapping d'export 37 | show: Afficher le mapping d'export 38 | delete: Supprimer le mapping d'export 39 | 40 | luaUpdater: 41 | this: 42 | edit: Éditer le script LUA 43 | show: Afficher le script LUA 44 | delete: Supprimer le script LUA 45 | validation: 46 | empty_script: Votre script est vide. 47 | empty_test_value: Votre valeur de test est vide. 48 | 49 | pim_custom_entity: 50 | form: 51 | field: 52 | label: 53 | label: Libellé 54 | code: Code 55 | 56 | candm_advanced_csv_connector: 57 | acl: 58 | importMapping: 59 | index: Lister les mappings d'import 60 | create: Créer un mapping d'import 61 | edit: Éditer un mapping d'import 62 | delete: Supprimer un mapping d'import 63 | exportMapping: 64 | index: Lister les mappings d'export 65 | create: Créer un mapping d'export 66 | edit: Éditer un mapping d'export 67 | delete: Supprimer un mapping d'export 68 | luaUpdater: 69 | index: Lister les scripts LUA 70 | create: Créer un script LUA 71 | edit: Éditer un script LUA 72 | delete: Supprimer un script LUA 73 | -------------------------------------------------------------------------------- /Resources/config/job_constraints.yml: -------------------------------------------------------------------------------- 1 | parameters: 2 | candm_advanced_csv_connector.job.job_parameters.constraint_collection_provider.product_csv_advanced_import.class: ClickAndMortar\AdvancedCsvConnectorBundle\Job\JobParameters\ConstraintCollectionProvider\ProductCsvAdvancedImport 3 | candm_advanced_csv_connector.job.job_parameters.constraint_collection_provider.product_csv_advanced_export.class: ClickAndMortar\AdvancedCsvConnectorBundle\Job\JobParameters\ConstraintCollectionProvider\ProductCsvAdvancedExport 4 | 5 | services: 6 | candm_advanced_csv_connector.job.job_parameters.constraint_collection_provider.product_csv_import: 7 | class: '%candm_advanced_csv_connector.job.job_parameters.constraint_collection_provider.product_csv_advanced_import.class%' 8 | arguments: 9 | - '@pim_connector.job.job_parameters.constraint_collection_provider.product_csv_import' 10 | - 11 | - '%candm_advanced_csv_connector.job_name.csv_advanced_product_import%' 12 | tags: 13 | - { name: akeneo_batch.job.job_parameters.constraint_collection_provider } 14 | 15 | candm_advanced_csv_connector.job.job_parameters.constraint_collection_provider.product_model_csv_import: 16 | class: '%candm_advanced_csv_connector.job.job_parameters.constraint_collection_provider.product_csv_advanced_import.class%' 17 | arguments: 18 | - '@pim_connector.job.job_parameters.constraint_collection_provider.product_model_csv_import' 19 | - 20 | - '%candm_advanced_csv_connector.job_name.csv_advanced_product_model_import%' 21 | tags: 22 | - { name: akeneo_batch.job.job_parameters.constraint_collection_provider } 23 | 24 | candm_advanced_csv_connector.job.job_parameters.constraint_collection_provider.product_csv_export: 25 | class: '%candm_advanced_csv_connector.job.job_parameters.constraint_collection_provider.product_csv_advanced_export.class%' 26 | arguments: 27 | - '@pim_connector.job.job_parameters.constraint_collection_provider.product_csv_export' 28 | - 29 | - '%candm_advanced_csv_connector.job_name.csv_advanced_product_export%' 30 | tags: 31 | - { name: akeneo_batch.job.job_parameters.constraint_collection_provider } 32 | 33 | candm_advanced_csv_connector.job.job_parameters.constraint_collection_provider.product_model_csv_export: 34 | class: '%candm_advanced_csv_connector.job.job_parameters.constraint_collection_provider.product_csv_advanced_export.class%' 35 | arguments: 36 | - '@pim_connector.job.job_parameters.constraint_collection_provider.product_model_csv_export' 37 | - 38 | - '%candm_advanced_csv_connector.job_name.csv_advanced_product_model_export%' 39 | tags: 40 | - { name: akeneo_batch.job.job_parameters.constraint_collection_provider } -------------------------------------------------------------------------------- /Archiver/AdvancedFileReaderArchiver.php: -------------------------------------------------------------------------------- 1 | 14 | * @package Pim\Component\Connector\Archiver 15 | */ 16 | class AdvancedFileReaderArchiver extends FileReaderArchiver 17 | { 18 | /** 19 | * Archive files used by job execution (input / output) 20 | * 21 | * @param JobExecution $jobExecution 22 | */ 23 | public function archive(JobExecution $jobExecution): void 24 | { 25 | $job = $this->jobRegistry->get($jobExecution->getJobInstance()->getJobName()); 26 | foreach ($job->getSteps() as $step) { 27 | if ( 28 | method_exists($step, 'getReader') 29 | && $step->getReader() instanceof MultiFilesReaderInterface 30 | ) { 31 | $reader = $step->getReader(); 32 | $filePaths = $reader->getFilePaths(); 33 | foreach ($filePaths as $filePath) { 34 | if (file_exists($filePath)) { 35 | $archivePath = strtr( 36 | $this->getRelativeArchivePath($jobExecution), 37 | [ 38 | '%filename%' => basename($filePath), 39 | ] 40 | ); 41 | 42 | if (is_readable($filePath)) { 43 | $fileResource = fopen($filePath, 'r'); 44 | $this->filesystem->writeStream($archivePath, $fileResource); 45 | 46 | if (is_resource($fileResource)) { 47 | fclose($fileResource); 48 | } 49 | } 50 | unlink($filePath); 51 | } 52 | } 53 | } 54 | } 55 | } 56 | 57 | /** 58 | * Check if the job execution is supported 59 | * 60 | * @param JobExecution $jobExecution 61 | * 62 | * @return bool 63 | */ 64 | public function supports(JobExecution $jobExecution): bool 65 | { 66 | $job = $this->jobRegistry->get($jobExecution->getJobInstance()->getJobName()); 67 | foreach ($job->getSteps() as $step) { 68 | if ( 69 | method_exists($step, 'getReader') 70 | && $step->getReader() instanceof MultiFilesReaderInterface 71 | ) { 72 | return true; 73 | } 74 | } 75 | 76 | return false; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /Resources/config/form_extensions/luaUpdater/index.yml: -------------------------------------------------------------------------------- 1 | extensions: 2 | pim-luaUpdater-index: 3 | module: pim/common/simple-view 4 | config: 5 | template: pim/template/common/default-template 6 | forwarded-events: 7 | grid_load:start: grid_load:start 8 | grid_load:complete: grid_load:complete 9 | 10 | pim-luaUpdater-index-grid-container: 11 | module: pim/common/simple-view 12 | parent: pim-luaUpdater-index 13 | targetZone: content 14 | config: 15 | template: pim/template/form/index/index 16 | 17 | pim-luaUpdater-index-user-navigation: 18 | module: pim/menu/user-navigation 19 | parent: pim-luaUpdater-index 20 | targetZone: user-menu 21 | config: 22 | userAccount: pim_menu.user.user_account 23 | logout: pim_menu.user.logout 24 | 25 | pim-luaUpdater-index-grid-title: 26 | module: pim/common/grid-title 27 | parent: pim-luaUpdater-index 28 | targetZone: title 29 | config: 30 | title: candm_advanced_csv_connector.luaUpdater.index_title 31 | 32 | pim-luaUpdater-index-breadcrumbs: 33 | module: pim/common/breadcrumbs 34 | parent: pim-luaUpdater-index 35 | targetZone: breadcrumbs 36 | config: 37 | tab: pim-menu-reference_data 38 | item: candm_advanced_csv_connector-menu-reference_data-item-luaUpdater 39 | 40 | pim-luaUpdater-index-grid-filters-list: 41 | module: oro/datafilter/filters-list 42 | parent: pim-luaUpdater-index-grid-container 43 | targetZone: filters 44 | 45 | pim-luaUpdater-index-grid-filters-manage: 46 | module: oro/datafilter/filters-button 47 | parent: pim-luaUpdater-index-grid-container 48 | targetZone: filters 49 | 50 | pim-luaUpdater-index-mass-actions: 51 | module: pim/grid/mass-actions 52 | parent: pim-luaUpdater-index 53 | targetZone: bottom-panel 54 | config: 55 | label: candm_advanced_csv_connector.luaUpdater.selected 56 | 57 | pim-luaUpdater-index-actions-panel: 58 | module: oro/datagrid/actions-panel 59 | parent: pim-luaUpdater-index-mass-actions 60 | targetZone: actions-panel 61 | 62 | pim-luaUpdater-index-pagination: 63 | module: oro/datagrid/pagination-input 64 | parent: pim-luaUpdater-index-grid-container 65 | targetZone: toolbar 66 | config: 67 | gridName: luaUpdater 68 | 69 | pim-luaUpdater-index-grid: 70 | module: pim/form/common/index/grid 71 | parent: pim-luaUpdater-index 72 | targetZone: content 73 | position: 1000 74 | config: 75 | alias: luaUpdater 76 | 77 | pim-luaUpdater-index-create-button: 78 | module: pim/form/common/index/create-button 79 | parent: pim-luaUpdater-index 80 | targetZone: buttons 81 | aclResourceId: pim_enrich_product_create 82 | config: 83 | title: pim_custom_entity.button.create 84 | modalForm: pim-luaUpdater-create-modal -------------------------------------------------------------------------------- /Resources/config/datagrid/lua_updater.yml: -------------------------------------------------------------------------------- 1 | datagrid: 2 | luaUpdater: 3 | options: 4 | entityHint: luaUpdater 5 | manageFilters: false 6 | source: 7 | type: pim_datasource_default 8 | entity: ClickAndMortar\AdvancedCsvConnectorBundle\Entity\LuaUpdater 9 | repository_method: createDatagridQueryBuilder 10 | columns: 11 | label: 12 | label: pim_custom_entity.form.field.label.label 13 | code: 14 | label: pim_custom_entity.form.field.label.code 15 | properties: 16 | id: ~ 17 | edit_link: 18 | type: url 19 | route: pim_customentity_rest_get 20 | params: 21 | - id 22 | - customEntityName 23 | delete_link: 24 | type: url 25 | route: pim_customentity_rest_delete 26 | params: 27 | - id 28 | - customEntityName 29 | actions: 30 | edit: 31 | type: navigate 32 | acl_resource: candm_advanced_csv_connector_luaUpdater_edit 33 | label: luaUpdater.this.edit 34 | icon: edit 35 | link: edit_link 36 | rowAction: true 37 | delete: 38 | type: delete 39 | acl_resource: candm_advanced_csv_connector_luaUpdater_delete 40 | label: luaUpdater.this.delete 41 | icon: trash 42 | link: delete_link 43 | filters: 44 | columns: 45 | label: 46 | type: string 47 | label: pim_custom_entity.form.field.label.label 48 | data_name: rd.label 49 | code: 50 | type: string 51 | label: pim_custom_entity.form.field.label.code 52 | data_name: rd.code 53 | sorters: 54 | columns: 55 | label: 56 | data_name: rd.label 57 | code: 58 | data_name: rd.code 59 | default: 60 | code: '%oro_datagrid.extension.orm_sorter.class%::DIRECTION_ASC' 61 | 62 | mass_actions: 63 | delete: 64 | type: delete 65 | label: pim.grid.mass_action.delete 66 | entity_name: brand 67 | acl_resource: ~ 68 | handler: mass_delete 69 | className: 'AknButton AknButton--important AknButtonList-item' 70 | messages: 71 | confirm_title: pim_datagrid.mass_action.delete.confirm_title 72 | confirm_content: pim_datagrid.mass_action.delete.confirm_content 73 | confirm_ok: OK 74 | success: pim_datagrid.mass_action.delete.success 75 | error: pim_datagrid.mass_action.delete.error 76 | empty_selection: pim_datagrid.mass_action.delete.empty_selection -------------------------------------------------------------------------------- /Resources/config/datagrid/export_mapping.yml: -------------------------------------------------------------------------------- 1 | datagrid: 2 | exportMapping: 3 | options: 4 | entityHint: exportMapping 5 | manageFilters: false 6 | source: 7 | type: pim_datasource_default 8 | entity: ClickAndMortar\AdvancedCsvConnectorBundle\Entity\ExportMapping 9 | repository_method: createDatagridQueryBuilder 10 | columns: 11 | label: 12 | label: pim_custom_entity.form.field.label.label 13 | code: 14 | label: pim_custom_entity.form.field.label.code 15 | properties: 16 | id: ~ 17 | edit_link: 18 | type: url 19 | route: pim_customentity_rest_get 20 | params: 21 | - id 22 | - customEntityName 23 | delete_link: 24 | type: url 25 | route: pim_customentity_rest_delete 26 | params: 27 | - id 28 | - customEntityName 29 | actions: 30 | edit: 31 | type: navigate 32 | acl_resource: candm_advanced_csv_connector_exportMapping_edit 33 | label: exportMapping.this.edit 34 | icon: edit 35 | link: edit_link 36 | rowAction: true 37 | delete: 38 | type: delete 39 | acl_resource: candm_advanced_csv_connector_exportMapping_delete 40 | label: exportMapping.this.delete 41 | icon: trash 42 | link: delete_link 43 | filters: 44 | columns: 45 | label: 46 | type: string 47 | label: pim_custom_entity.form.field.label.label 48 | data_name: rd.label 49 | code: 50 | type: string 51 | label: pim_custom_entity.form.field.label.code 52 | data_name: rd.code 53 | sorters: 54 | columns: 55 | label: 56 | data_name: rd.label 57 | code: 58 | data_name: rd.code 59 | default: 60 | code: '%oro_datagrid.extension.orm_sorter.class%::DIRECTION_ASC' 61 | 62 | mass_actions: 63 | delete: 64 | type: delete 65 | label: pim.grid.mass_action.delete 66 | entity_name: brand 67 | acl_resource: ~ 68 | handler: mass_delete 69 | className: 'AknButton AknButton--important AknButtonList-item' 70 | messages: 71 | confirm_title: pim_datagrid.mass_action.delete.confirm_title 72 | confirm_content: pim_datagrid.mass_action.delete.confirm_content 73 | confirm_ok: OK 74 | success: pim_datagrid.mass_action.delete.success 75 | error: pim_datagrid.mass_action.delete.error 76 | empty_selection: pim_datagrid.mass_action.delete.empty_selection -------------------------------------------------------------------------------- /Resources/config/datagrid/import_mapping.yml: -------------------------------------------------------------------------------- 1 | datagrid: 2 | importMapping: 3 | options: 4 | entityHint: importMapping 5 | manageFilters: false 6 | source: 7 | type: pim_datasource_default 8 | entity: ClickAndMortar\AdvancedCsvConnectorBundle\Entity\ImportMapping 9 | repository_method: createDatagridQueryBuilder 10 | columns: 11 | label: 12 | label: pim_custom_entity.form.field.label.label 13 | code: 14 | label: pim_custom_entity.form.field.label.code 15 | properties: 16 | id: ~ 17 | edit_link: 18 | type: url 19 | route: pim_customentity_rest_get 20 | params: 21 | - id 22 | - customEntityName 23 | delete_link: 24 | type: url 25 | route: pim_customentity_rest_delete 26 | params: 27 | - id 28 | - customEntityName 29 | actions: 30 | edit: 31 | type: navigate 32 | acl_resource: candm_advanced_csv_connector_importMapping_edit 33 | label: importMapping.this.edit 34 | icon: edit 35 | link: edit_link 36 | rowAction: true 37 | delete: 38 | type: delete 39 | acl_resource: candm_advanced_csv_connector_importMapping_delete 40 | label: importMapping.this.delete 41 | icon: trash 42 | link: delete_link 43 | filters: 44 | columns: 45 | label: 46 | type: string 47 | label: pim_custom_entity.form.field.label.label 48 | data_name: rd.label 49 | code: 50 | type: string 51 | label: pim_custom_entity.form.field.label.code 52 | data_name: rd.code 53 | sorters: 54 | columns: 55 | label: 56 | data_name: rd.label 57 | code: 58 | data_name: rd.code 59 | default: 60 | code: '%oro_datagrid.extension.orm_sorter.class%::DIRECTION_ASC' 61 | 62 | mass_actions: 63 | delete: 64 | type: delete 65 | label: pim.grid.mass_action.delete 66 | entity_name: brand 67 | acl_resource: ~ 68 | handler: mass_delete 69 | className: 'AknButton AknButton--important AknButtonList-item' 70 | messages: 71 | confirm_title: pim_datagrid.mass_action.delete.confirm_title 72 | confirm_content: pim_datagrid.mass_action.delete.confirm_content 73 | confirm_ok: OK 74 | success: pim_datagrid.mass_action.delete.success 75 | error: pim_datagrid.mass_action.delete.error 76 | empty_selection: pim_datagrid.mass_action.delete.empty_selection -------------------------------------------------------------------------------- /Resources/config/form_extensions/exportMapping/index.yml: -------------------------------------------------------------------------------- 1 | extensions: 2 | pim-exportMapping-index: 3 | module: pim/common/simple-view 4 | config: 5 | template: pim/template/common/default-template 6 | forwarded-events: 7 | grid_load:start: grid_load:start 8 | grid_load:complete: grid_load:complete 9 | 10 | pim-exportMapping-index-grid-container: 11 | module: pim/common/simple-view 12 | parent: pim-exportMapping-index 13 | targetZone: content 14 | config: 15 | template: pim/template/form/index/index 16 | 17 | pim-exportMapping-index-user-navigation: 18 | module: pim/menu/user-navigation 19 | parent: pim-exportMapping-index 20 | targetZone: user-menu 21 | config: 22 | userAccount: pim_menu.user.user_account 23 | logout: pim_menu.user.logout 24 | 25 | pim-exportMapping-index-grid-title: 26 | module: pim/common/grid-title 27 | parent: pim-exportMapping-index 28 | targetZone: title 29 | config: 30 | title: candm_advanced_csv_connector.exportMapping.index_title 31 | 32 | pim-exportMapping-index-breadcrumbs: 33 | module: pim/common/breadcrumbs 34 | parent: pim-exportMapping-index 35 | targetZone: breadcrumbs 36 | config: 37 | tab: pim-menu-reference_data 38 | item: candm_advanced_csv_connector-menu-reference_data-item-exportMapping 39 | 40 | pim-exportMapping-index-grid-filters-list: 41 | module: oro/datafilter/filters-list 42 | parent: pim-exportMapping-index-grid-container 43 | targetZone: filters 44 | 45 | pim-exportMapping-index-grid-filters-manage: 46 | module: oro/datafilter/filters-button 47 | parent: pim-exportMapping-index-grid-container 48 | targetZone: filters 49 | 50 | pim-exportMapping-index-mass-actions: 51 | module: pim/grid/mass-actions 52 | parent: pim-exportMapping-index 53 | targetZone: bottom-panel 54 | config: 55 | label: candm_advanced_csv_connector.exportMapping.selected 56 | 57 | pim-exportMapping-index-actions-panel: 58 | module: oro/datagrid/actions-panel 59 | parent: pim-exportMapping-index-mass-actions 60 | targetZone: actions-panel 61 | 62 | pim-exportMapping-index-pagination: 63 | module: oro/datagrid/pagination-input 64 | parent: pim-exportMapping-index-grid-container 65 | targetZone: toolbar 66 | config: 67 | gridName: exportMapping 68 | 69 | pim-exportMapping-index-grid: 70 | module: pim/form/common/index/grid 71 | parent: pim-exportMapping-index 72 | targetZone: content 73 | position: 1000 74 | config: 75 | alias: exportMapping 76 | 77 | pim-exportMapping-index-create-button: 78 | module: pim/form/common/index/create-button 79 | parent: pim-exportMapping-index 80 | targetZone: buttons 81 | aclResourceId: pim_enrich_product_create 82 | config: 83 | title: pim_custom_entity.button.create 84 | modalForm: pim-exportMapping-create-modal -------------------------------------------------------------------------------- /Resources/config/form_extensions/importMapping/index.yml: -------------------------------------------------------------------------------- 1 | extensions: 2 | pim-importMapping-index: 3 | module: pim/common/simple-view 4 | config: 5 | template: pim/template/common/default-template 6 | forwarded-events: 7 | grid_load:start: grid_load:start 8 | grid_load:complete: grid_load:complete 9 | 10 | pim-importMapping-index-grid-container: 11 | module: pim/common/simple-view 12 | parent: pim-importMapping-index 13 | targetZone: content 14 | config: 15 | template: pim/template/form/index/index 16 | 17 | pim-importMapping-index-user-navigation: 18 | module: pim/menu/user-navigation 19 | parent: pim-importMapping-index 20 | targetZone: user-menu 21 | config: 22 | userAccount: pim_menu.user.user_account 23 | logout: pim_menu.user.logout 24 | 25 | pim-importMapping-index-grid-title: 26 | module: pim/common/grid-title 27 | parent: pim-importMapping-index 28 | targetZone: title 29 | config: 30 | title: candm_advanced_csv_connector.importMapping.index_title 31 | 32 | pim-importMapping-index-breadcrumbs: 33 | module: pim/common/breadcrumbs 34 | parent: pim-importMapping-index 35 | targetZone: breadcrumbs 36 | config: 37 | tab: pim-menu-reference_data 38 | item: candm_advanced_csv_connector-menu-reference_data-item-importMapping 39 | 40 | pim-importMapping-index-grid-filters-list: 41 | module: oro/datafilter/filters-list 42 | parent: pim-importMapping-index-grid-container 43 | targetZone: filters 44 | 45 | pim-importMapping-index-grid-filters-manage: 46 | module: oro/datafilter/filters-button 47 | parent: pim-importMapping-index-grid-container 48 | targetZone: filters 49 | 50 | pim-importMapping-index-mass-actions: 51 | module: pim/grid/mass-actions 52 | parent: pim-importMapping-index 53 | targetZone: bottom-panel 54 | config: 55 | label: candm_advanced_csv_connector.importMapping.selected 56 | 57 | pim-importMapping-index-actions-panel: 58 | module: oro/datagrid/actions-panel 59 | parent: pim-importMapping-index-mass-actions 60 | targetZone: actions-panel 61 | 62 | pim-importMapping-index-pagination: 63 | module: oro/datagrid/pagination-input 64 | parent: pim-importMapping-index-grid-container 65 | targetZone: toolbar 66 | config: 67 | gridName: importMapping 68 | 69 | pim-importMapping-index-grid: 70 | module: pim/form/common/index/grid 71 | parent: pim-importMapping-index 72 | targetZone: content 73 | position: 1000 74 | config: 75 | alias: importMapping 76 | 77 | pim-importMapping-index-create-button: 78 | module: pim/form/common/index/create-button 79 | parent: pim-importMapping-index 80 | targetZone: buttons 81 | aclResourceId: pim_enrich_product_create 82 | config: 83 | title: pim_custom_entity.button.create 84 | modalForm: pim-importMapping-create-modal -------------------------------------------------------------------------------- /Helper/ExportHelper.php: -------------------------------------------------------------------------------- 1 | 13 | * @package ClickAndMortar\AdvancedCsvConnectorBundle\Helper 14 | */ 15 | class ExportHelper 16 | { 17 | /** 18 | * Multi select values separator 19 | * 20 | * @var string 21 | */ 22 | const MULTI_SELECT_SEPARATOR = ','; 23 | 24 | /** 25 | * Entity manager 26 | * 27 | * @var EntityManager 28 | */ 29 | protected $entityManager; 30 | 31 | /** 32 | * Attribute option repository 33 | * 34 | * @var AttributeOptionRepository 35 | */ 36 | protected $attributeOptionRepository; 37 | 38 | /** 39 | * ExportHelper constructor. 40 | * 41 | * @param EntityManager $entityManager 42 | */ 43 | public function __construct(EntityManager $entityManager, AttributeOptionRepository $attributeOptionRepository) 44 | { 45 | $this->entityManager = $entityManager; 46 | $this->attributeOptionRepository = $attributeOptionRepository; 47 | } 48 | 49 | /** 50 | * Get value from code in a list case 51 | * 52 | * @param string $attributeKey 53 | * @param string $attributeValue 54 | * @param string $locale 55 | * 56 | * @return string 57 | */ 58 | public function getValueFromCode($attributeKey, $attributeValue, $locale) 59 | { 60 | // Use loop if we have multi select attribute 61 | $labelAsArray = []; 62 | $attributeValues = explode(self::MULTI_SELECT_SEPARATOR, $attributeValue); 63 | foreach ($attributeValues as $attributeValue) { 64 | $option = $this->attributeOptionRepository->findOptionByCode($attributeKey, array($attributeValue)); 65 | if (empty($option) || empty($option[0])) { 66 | continue; 67 | } 68 | 69 | $option[0]->setLocale($locale)->getTranslation(); 70 | $labelAsArray[] = $option[0]->getOptionValue()->getLabel(); 71 | } 72 | 73 | return implode(self::MULTI_SELECT_SEPARATOR, $labelAsArray); 74 | } 75 | 76 | /** 77 | * Encode given $filePath with $encoding from UTF-8 78 | * 79 | * @param string $filePath 80 | * @param string $encoding 81 | * 82 | * @return void 83 | */ 84 | public function encodeFile($filePath, $encoding) 85 | { 86 | $tempFilePath = sprintf('%s.tmp', $filePath); 87 | $encodeFileCommand = sprintf( 88 | 'iconv -f UTF-8 -t %s//TRANSLIT %s > %s', 89 | $encoding, 90 | $filePath, 91 | $tempFilePath 92 | ); 93 | $encodeFileProcess = Process::fromShellCommandline($encodeFileCommand); 94 | $encodeFileProcess->mustRun(); 95 | 96 | if (file_exists($tempFilePath)) { 97 | unlink($filePath); 98 | rename($tempFilePath, $filePath); 99 | } 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /Resources/config/steps.yml: -------------------------------------------------------------------------------- 1 | parameters: 2 | pim_connector.step.product.import.bulk_size: 100 3 | candm_advanced_csv_connector.step.mail_notification.class: 'ClickAndMortar\AdvancedCsvConnectorBundle\Step\MailNotification' 4 | 5 | services: 6 | candm_advanced_csv_connector.step.csv_advanced_product.import: 7 | class: '%pim_connector.step.item_step.class%' 8 | arguments: 9 | - 'import' 10 | - '@event_dispatcher' 11 | - '@akeneo_batch.job_repository' 12 | - '@candm_advanced_csv_connector.reader.file.csv_advanced_product' 13 | - '@pim_connector.processor.denormalization.product' 14 | - '@pim_connector.writer.database.product' 15 | - '%pim_connector.step.product.import.bulk_size%' 16 | 17 | candm_advanced_csv_connector.step.csv_advanced_root_product_model.import: 18 | class: '%pim_connector.step.item_step.class%' 19 | arguments: 20 | - 'import_root_product_model' 21 | - '@event_dispatcher' 22 | - '@akeneo_batch.job_repository' 23 | - '@candm_advanced_csv_connector.reader.file.csv_advanced_product_model' 24 | - '@pim_connector.processor.denormalization.root_product_model' 25 | - '@pim_connector.writer.database.product_model' 26 | - '%pim_job_product_batch_size%' 27 | 28 | candm_advanced_csv_connector.step.csv_advanced_sub_product_model.import: 29 | class: '%pim_connector.step.item_step.class%' 30 | arguments: 31 | - 'import_sub_product_model' 32 | - '@event_dispatcher' 33 | - '@akeneo_batch.job_repository' 34 | - '@candm_advanced_csv_connector.reader.file.csv_advanced_product_model' 35 | - '@pim_connector.processor.denormalization.sub_product_model' 36 | - '@pim_connector.writer.database.product_model' 37 | - '%pim_job_product_batch_size%' 38 | 39 | candm_advanced_csv_connector.step.csv_advanced_product.export: 40 | class: '%pim_connector.step.item_step.class%' 41 | arguments: 42 | - 'export' 43 | - '@event_dispatcher' 44 | - '@akeneo_batch.job_repository' 45 | - '@pim_connector.reader.database.product' 46 | - '@pim_connector.processor.normalization.product' 47 | - '@candm_advanced_csv_connector.writer.file.csv_advanced_product' 48 | - '%pim_job_product_batch_size%' 49 | 50 | candm_advanced_csv_connector.step.csv_advanced_product_model.export: 51 | class: '%pim_connector.step.item_step.class%' 52 | arguments: 53 | - 'export' 54 | - '@event_dispatcher' 55 | - '@akeneo_batch.job_repository' 56 | - '@pim_connector.reader.database.product_model' 57 | - '@pim_connector.processor.normalization.product_model' 58 | - '@candm_advanced_csv_connector.writer.file.csv_advanced_product_model' 59 | - '%pim_job_product_batch_size%' 60 | 61 | candm_advanced_csv_connector.step.mail_notification: 62 | class: '%candm_advanced_csv_connector.step.mail_notification.class%' 63 | arguments: 64 | - 'notification' 65 | - '@event_dispatcher' 66 | - '@akeneo_batch.job_repository' 67 | - '@pim_notification.email.email_notifier' 68 | - '@twig' 69 | - '@translator' 70 | -------------------------------------------------------------------------------- /Resources/config/jobs.yml: -------------------------------------------------------------------------------- 1 | parameters: 2 | candm_advanced_csv_connector.connector_name.csv: 'Click And Mortar Advanced CSV Connector' 3 | candm_advanced_csv_connector.job_name.csv_advanced_product_import: 'csv_advanced_product_import' 4 | candm_advanced_csv_connector.job_name.csv_advanced_product_model_import: 'csv_advanced_product_model_import' 5 | candm_advanced_csv_connector.job_name.csv_advanced_product_export: 'csv_advanced_product_export' 6 | candm_advanced_csv_connector.job_name.csv_advanced_product_model_export: 'csv_advanced_product_model_export' 7 | 8 | services: 9 | candm_advanced_csv_connector.job.csv_advanced_product_import: 10 | class: '%pim_connector.job.simple_job.class%' 11 | arguments: 12 | - '%candm_advanced_csv_connector.job_name.csv_advanced_product_import%' 13 | - '@event_dispatcher' 14 | - '@akeneo_batch.job_repository' 15 | - 16 | - '@akeneo.job_automation.connector.step.download' 17 | - '@candm_advanced_csv_connector.step.csv_advanced_product.import' 18 | - '@candm_advanced_csv_connector.step.mail_notification' 19 | tags: 20 | - { name: akeneo_batch.job, connector: '%candm_advanced_csv_connector.connector_name.csv%', type: '%pim_connector.job.import_type%' } 21 | 22 | candm_advanced_csv_connector.job.csv_advanced_product_model_import: 23 | class: '%pim_connector.job.simple_job.class%' 24 | arguments: 25 | - '%candm_advanced_csv_connector.job_name.csv_advanced_product_model_import%' 26 | - '@event_dispatcher' 27 | - '@akeneo_batch.job_repository' 28 | - 29 | - '@akeneo.job_automation.connector.step.download' 30 | - '@candm_advanced_csv_connector.step.csv_advanced_root_product_model.import' 31 | - '@candm_advanced_csv_connector.step.csv_advanced_sub_product_model.import' 32 | - '@candm_advanced_csv_connector.step.mail_notification' 33 | tags: 34 | - { name: akeneo_batch.job, connector: '%candm_advanced_csv_connector.connector_name.csv%', type: '%pim_connector.job.import_type%' } 35 | 36 | candm_advanced_csv_connector.job.csv_advanced_product_export: 37 | class: '%pim_connector.job.simple_job.class%' 38 | arguments: 39 | - '%candm_advanced_csv_connector.job_name.csv_advanced_product_export%' 40 | - '@event_dispatcher' 41 | - '@akeneo_batch.job_repository' 42 | - 43 | - '@candm_advanced_csv_connector.step.csv_advanced_product.export' 44 | - '@akeneo.job_automation.connector.step.upload' 45 | tags: 46 | - { name: akeneo_batch.job, connector: '%candm_advanced_csv_connector.connector_name.csv%', type: '%pim_connector.job.export_type%' } 47 | 48 | candm_advanced_csv_connector.job.csv_advanced_product_model_export: 49 | class: '%pim_connector.job.simple_job.class%' 50 | arguments: 51 | - '%candm_advanced_csv_connector.job_name.csv_advanced_product_model_export%' 52 | - '@event_dispatcher' 53 | - '@akeneo_batch.job_repository' 54 | - 55 | - '@candm_advanced_csv_connector.step.csv_advanced_product_model.export' 56 | - '@akeneo.job_automation.connector.step.upload' 57 | tags: 58 | - { name: akeneo_batch.job, connector: '%candm_advanced_csv_connector.connector_name.csv%', type: '%pim_connector.job.export_type%' } 59 | -------------------------------------------------------------------------------- /Entity/ExportMapping.php: -------------------------------------------------------------------------------- 1 | 11 | * @package ClickAndMortar\AdvancedCsvConnectorBundle\Entity 12 | */ 13 | class ExportMapping extends AbstractCustomEntity 14 | { 15 | /** 16 | * Label 17 | * 18 | * @var string 19 | */ 20 | protected $label; 21 | 22 | /** 23 | * Mapping as JSON 24 | * 25 | * @var string 26 | */ 27 | protected $mappingAsJson; 28 | 29 | /** 30 | * Complete callback 31 | * 32 | * @var string 33 | */ 34 | protected $completeCallback; 35 | 36 | /** 37 | * Get label 38 | * 39 | * @return string 40 | */ 41 | public function getLabel() 42 | { 43 | return $this->label; 44 | } 45 | 46 | /** 47 | * Set label 48 | * 49 | * @param string $label 50 | * 51 | * @return Brand 52 | */ 53 | public function setLabel($label) 54 | { 55 | $this->label = $label; 56 | 57 | return $this; 58 | } 59 | 60 | /** 61 | * @return string 62 | */ 63 | public function getMappingAsJson() 64 | { 65 | return $this->mappingAsJson; 66 | } 67 | 68 | /** 69 | * @param string $mappingAsJson 70 | * 71 | * @return Mapping 72 | */ 73 | public function setMappingAsJson($mappingAsJson) 74 | { 75 | $this->mappingAsJson = $mappingAsJson; 76 | 77 | return $this; 78 | } 79 | 80 | /** 81 | * @return string 82 | */ 83 | public function getCompleteCallback() 84 | { 85 | return $this->completeCallback; 86 | } 87 | 88 | /** 89 | * @param string $completeCallback 90 | * 91 | * @return ImportMapping 92 | */ 93 | public function setCompleteCallback($completeCallback) 94 | { 95 | $this->completeCallback = $completeCallback; 96 | 97 | return $this; 98 | } 99 | 100 | /** 101 | * {@inheritdoc} 102 | */ 103 | public static function getLabelProperty(): string 104 | { 105 | return 'label'; 106 | } 107 | 108 | /** 109 | * Returns the custom entity name used in the configuration 110 | * Used to map row actions on datagrid 111 | * 112 | * @return string 113 | */ 114 | public function getCustomEntityName(): string 115 | { 116 | return 'exportMapping'; 117 | } 118 | 119 | /** 120 | * Get reference value 121 | * 122 | * @return string 123 | */ 124 | public function getReference() 125 | { 126 | return $this->getCode(); 127 | } 128 | 129 | /** 130 | * Get complete mapping 131 | * 132 | * @return string 133 | */ 134 | public function getMappingAsArray() 135 | { 136 | // Get columns mapping 137 | $columnsMapping = !empty($this->getMappingAsJson()) ? $this->getMappingAsJson() : '[]'; 138 | 139 | $mapping = [ 140 | 'columns' => json_decode($columnsMapping, true), 141 | ]; 142 | 143 | // And complete callback if necessary 144 | if (!empty($this->getCompleteCallback())) { 145 | $mapping['completeCallback'] = $this->getCompleteCallback(); 146 | } 147 | 148 | return $mapping; 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /Resources/config/writers.yml: -------------------------------------------------------------------------------- 1 | parameters: 2 | candm_advanced_csv_connector.writer.file.product.flat_item_buffer_flusher.class: Akeneo\Tool\Component\Connector\Writer\File\FlatItemBufferFlusher 3 | candm_advanced_csv_connector.writer.file.product.column_sorter_by_mapping.class: ClickAndMortar\AdvancedCsvConnectorBundle\Writer\File\ProductColumnSorterByMapping 4 | candm_advanced_csv_connector.writer.file.csv_advanced_product.class: ClickAndMortar\AdvancedCsvConnectorBundle\Writer\File\Csv\ProductAdvancedWriter 5 | candm_advanced_csv_connector.writer.file.csv_advanced_product_model.class: ClickAndMortar\AdvancedCsvConnectorBundle\Writer\File\Csv\ProductModelAdvancedWriter 6 | 7 | services: 8 | candm_advanced_csv_connector.writer.file.product.flat_item_buffer_flusher: 9 | class: '%candm_advanced_csv_connector.writer.file.product.flat_item_buffer_flusher.class%' 10 | arguments: 11 | - '@pim_connector.writer.file.product.column_presenter' 12 | - '@candm_advanced_csv_connector.writer.file.product.column_sorter_by_mapping' 13 | 14 | candm_advanced_csv_connector.writer.file.product.column_sorter_by_mapping: 15 | class: '%candm_advanced_csv_connector.writer.file.product.column_sorter_by_mapping.class%' 16 | arguments: 17 | - '@pim_connector.array_converter.flat_to_standard.product.field_splitter' 18 | - '@pim_catalog.repository.attribute' 19 | - '@pim_catalog.repository.association_type' 20 | - ['categories', 'enabled', 'family', 'parent', 'groups'] 21 | 22 | candm_advanced_csv_connector.writer.file.csv_advanced_product: 23 | class: '%candm_advanced_csv_connector.writer.file.csv_advanced_product.class%' 24 | arguments: 25 | - '@pim_connector.array_converter.standard_to_flat.product_localized' 26 | - '@pim_connector.factory.flat_item_buffer' 27 | - '@candm_advanced_csv_connector.writer.file.product.flat_item_buffer_flusher' 28 | - '@pim_catalog.repository.attribute' 29 | - '@pim_connector.writer.file.media_exporter_path_generator' 30 | - '@pim_enrich.connector.flat_translators.product_translator' 31 | - '@akeneo_file_storage.repository.file_info' 32 | - '@akeneo_file_storage.file_storage.filesystem_provider' 33 | - ['pim_catalog_file', 'pim_catalog_image'] 34 | - '@candm_advanced_csv_connector.helper.export' 35 | - '@doctrine.orm.entity_manager' 36 | - '@candm_advanced_csv_connector.repository.export_mapping' 37 | - '@service_container' 38 | - '@candm_advanced_csv_connector.repository.lua_updater' 39 | - 'fr_FR' 40 | - 'file_path' 41 | 42 | candm_advanced_csv_connector.writer.file.csv_advanced_product_model: 43 | class: '%candm_advanced_csv_connector.writer.file.csv_advanced_product_model.class%' 44 | arguments: 45 | - '@pim_connector.array_converter.standard_to_flat.product_model_localized' 46 | - '@pim_connector.factory.flat_item_buffer' 47 | - '@candm_advanced_csv_connector.writer.file.product.flat_item_buffer_flusher' 48 | - '@pim_catalog.repository.attribute' 49 | - '@pim_connector.writer.file.media_exporter_path_generator' 50 | - '@pim_enrich.connector.flat_translators.product_translator' 51 | - '@akeneo_file_storage.repository.file_info' 52 | - '@akeneo_file_storage.file_storage.filesystem_provider' 53 | - ['pim_catalog_file', 'pim_catalog_image'] 54 | - '@candm_advanced_csv_connector.helper.export' 55 | - '@doctrine.orm.entity_manager' 56 | - '@candm_advanced_csv_connector.repository.export_mapping' 57 | - '@service_container' 58 | - '@candm_advanced_csv_connector.repository.lua_updater' 59 | - 'fr_FR' 60 | - 'file_path' -------------------------------------------------------------------------------- /Archiver/AdvancedCsvInvalidItemWriter.php: -------------------------------------------------------------------------------- 1 | 16 | * @package ClickAndMortar\AdvancedCsvConnectorBundle\Archiver 17 | */ 18 | class AdvancedCsvInvalidItemWriter extends AbstractInvalidItemWriter 19 | { 20 | /** 21 | * {@inheritdoc} 22 | */ 23 | public function getName(): string 24 | { 25 | return 'invalid_advanced_csv'; 26 | } 27 | 28 | /** 29 | * {@inheritdoc} 30 | * 31 | * Re-parse imported files and write into a new one the invalid lines. 32 | */ 33 | public function archive(JobExecution $jobExecution): void 34 | { 35 | if (empty($this->collector->getInvalidItems())) { 36 | return; 37 | } 38 | 39 | $invalidItemPositions = new ArrayCollection(); 40 | foreach ($this->collector->getInvalidItems() as $invalidItem) { 41 | if ($invalidItem instanceof InvalidItemInterface) { 42 | $invalidItemPositions->add($invalidItem->getItemPosition()); 43 | } 44 | } 45 | 46 | $readJobParameters = $jobExecution->getJobParameters(); 47 | if ($readJobParameters->has('mapping')) { 48 | return; 49 | } 50 | $currentItemPosition = 0; 51 | $itemsToWrite = []; 52 | 53 | $fileIterator = $this->getInputFileIterator($readJobParameters); 54 | $this->setupWriter($jobExecution); 55 | 56 | while ($fileIterator->valid()) { 57 | $readItem = $fileIterator->current(); 58 | 59 | $currentItemPosition++; 60 | 61 | if ($invalidItemPositions->contains($currentItemPosition)) { 62 | $headers = $fileIterator->getHeaders(); 63 | $invalidItem = array_combine($headers, array_slice($readItem, 0, count($headers))); 64 | if (false !== $invalidItem) { 65 | $itemsToWrite[] = $invalidItem; 66 | } 67 | 68 | $invalidItemPositions->removeElement($currentItemPosition); 69 | } 70 | 71 | if (count($itemsToWrite) > 0 && 0 === count($itemsToWrite) % $this->batchSize) { 72 | $this->writer->write($itemsToWrite); 73 | $itemsToWrite = []; 74 | } 75 | 76 | if ($invalidItemPositions->isEmpty()) { 77 | break; 78 | } 79 | 80 | $fileIterator->next(); 81 | } 82 | 83 | if (count($itemsToWrite) > 0) { 84 | $this->writer->write($itemsToWrite); 85 | } 86 | 87 | $this->writer->flush(); 88 | } 89 | 90 | /** 91 | * {@inheritdoc} 92 | */ 93 | protected function getFilename(): string 94 | { 95 | return 'invalid_items.csv'; 96 | } 97 | 98 | /** 99 | * {@inheritdoc} 100 | */ 101 | protected function getInputFileIterator(JobParameters $jobParameters): FileIteratorInterface 102 | { 103 | $filePath = $jobParameters->get('storage')['file_path']; 104 | $delimiter = $jobParameters->get('delimiter'); 105 | $enclosure = $jobParameters->get('enclosure'); 106 | $fileIterator = $this->fileIteratorFactory->create($filePath, [ 107 | 'reader_options' => [ 108 | 'fieldDelimiter' => $delimiter, 109 | 'fieldEnclosure' => $enclosure, 110 | ] 111 | ]); 112 | $fileIterator->rewind(); 113 | $fileIterator->next(); 114 | 115 | return $fileIterator; 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /Resources/bin/split-csv-files.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Split large CSV files in chunks 3 | 4 | # Exit on errors 5 | set -e 6 | 7 | FILE_PATH=${1} 8 | LINES_PER_FILE=${2} 9 | TARGET_FOLDER=${3} 10 | PREFIX_FILES=${4} 11 | SEPARATOR=";" 12 | 13 | # Help menu 14 | print_help() { 15 | cat <<-HELP 16 | This script is used to split large CSV files in chunks. 17 | You need to provide the following arguments: 18 | 1) CSV file path. 19 | 2) Lines per each new file. 20 | 3) Target folder for new files. 21 | 4) Prefix for new generated files. 22 | 5) Separator (optional, default: ;). 23 | Usage: bash ${0##*/} --file_path=FILE_PATH --lines_per_file=LINES_PER_FILE --target_folder=TARGET_FOLDER --prefix=PREFIX_FILES [--separator=SEPARATOR] 24 | Example: bash ${0##*/} --file_path=/tmp/frames_csv.csv --lines_per_file=500 --target_folder=/tmp --prefix=products_part_ --separator=; 25 | HELP 26 | exit 0 27 | } 28 | 29 | # Parse Command Line Arguments 30 | while [ $# -gt 0 ]; do 31 | case "$1" in 32 | --file_path=*) 33 | FILE_PATH="${1#*=}" 34 | ;; 35 | --lines_per_file=*) 36 | LINES_PER_FILE="${1#*=}" 37 | ;; 38 | --target_folder=*) 39 | TARGET_FOLDER="${1#*=}" 40 | ;; 41 | --prefix=*) 42 | PREFIX_FILES="${1#*=}" 43 | ;; 44 | --separator=*) 45 | SEPARATOR="${1#*=}" 46 | ;; 47 | --help) print_help;; 48 | *) 49 | printf "Invalid argument, run --help for valid arguments.\n"; 50 | exit 1 51 | esac 52 | shift 53 | done 54 | 55 | # Count occurrences of separator in a string 56 | count_separators() { 57 | echo "$1" | awk -F"$SEPARATOR" '{print NF-1}' 58 | } 59 | 60 | if [ -e $FILE_PATH ] ; then 61 | # Get header and count expected separators per record 62 | HEADER=$(head -n 1 "$FILE_PATH") 63 | EXPECTED_SEPARATORS=$(count_separators "$HEADER") 64 | 65 | # Split CSV respecting multiline fields 66 | awk -v lines_per_file="$LINES_PER_FILE" \ 67 | -v target_folder="$TARGET_FOLDER" \ 68 | -v prefix="$PREFIX_FILES" \ 69 | -v sep="$SEPARATOR" \ 70 | -v expected_sep="$EXPECTED_SEPARATORS" \ 71 | 'BEGIN { 72 | file_num = 0 73 | line_count = 0 74 | current_record = "" 75 | current_sep_count = 0 76 | # Generate suffix like split command (aa, ab, ac...) 77 | split("a b c d e f g h i j k l m n o p q r s t u v w x y z", letters, " ") 78 | } 79 | 80 | function get_suffix(num) { 81 | first = int(num / 26) 82 | second = num % 26 83 | return letters[first + 1] letters[second + 1] 84 | } 85 | 86 | function write_record(record) { 87 | if (line_count % lines_per_file == 0) { 88 | if (file_num > 0) { 89 | close(current_file) 90 | } 91 | current_file = target_folder "/" prefix get_suffix(file_num) ".csv" 92 | file_num++ 93 | } 94 | print record > current_file 95 | line_count++ 96 | } 97 | 98 | function count_sep(str) { 99 | n = gsub(sep, sep, str) 100 | return n 101 | } 102 | 103 | NR == 1 { 104 | # Store header, do not write yet (will be added later) 105 | header = $0 106 | next 107 | } 108 | 109 | { 110 | if (current_record == "") { 111 | current_record = $0 112 | current_sep_count = count_sep($0) 113 | } else { 114 | current_record = current_record "\n" $0 115 | current_sep_count += count_sep($0) 116 | } 117 | 118 | # Check if we have a complete record 119 | if (current_sep_count >= expected_sep) { 120 | write_record(current_record) 121 | current_record = "" 122 | current_sep_count = 0 123 | } 124 | } 125 | 126 | END { 127 | # Write any remaining record 128 | if (current_record != "") { 129 | write_record(current_record) 130 | } 131 | if (file_num > 0) { 132 | close(current_file) 133 | } 134 | }' "$FILE_PATH" 135 | 136 | # Add header for all files 137 | for CURRENT_FILE in $TARGET_FOLDER/$PREFIX_FILES* 138 | do 139 | head -n 1 "$FILE_PATH" > "$TARGET_FOLDER/tmp_file" 140 | cat "$CURRENT_FILE" >> "$TARGET_FOLDER/tmp_file" 141 | mv -f "$TARGET_FOLDER/tmp_file" "$CURRENT_FILE" 142 | done 143 | 144 | # Delete original file 145 | rm -f "$FILE_PATH" 146 | printf "$FILE_PATH file splitted !\n" 147 | fi -------------------------------------------------------------------------------- /Resources/config/form_extensions/csv_advanced_product_import_show.yml: -------------------------------------------------------------------------------- 1 | extensions: 2 | pim-job-instance-csv-advanced-product-import-show: 3 | module: pim/form/common/edit-form 4 | 5 | pim-job-instance-csv-advanced-product-import-show-main-image: 6 | module: pim/form/common/main-image 7 | parent: pim-job-instance-csv-advanced-product-import-show 8 | targetZone: main-image 9 | config: 10 | path: bundles/pimui/images/illustrations/ImportCSV.svg 11 | 12 | pim-job-instance-csv-advanced-product-import-show-user-navigation: 13 | module: pim/menu/user-navigation 14 | parent: pim-job-instance-csv-advanced-product-import-show 15 | targetZone: user-menu 16 | config: 17 | userAccount: pim_menu.user.user_account 18 | logout: pim_menu.user.logout 19 | 20 | pim-job-instance-csv-advanced-product-import-show-breadcrumbs: 21 | module: pim/job/common/breadcrumb/breadcrumb 22 | parent: pim-job-instance-csv-advanced-product-import-show 23 | targetZone: breadcrumbs 24 | 25 | pim-job-instance-csv-advanced-product-import-show-switcher: 26 | module: pim/job-instance/import/switcher 27 | parent: pim-job-instance-csv-advanced-product-import-show 28 | position: 0 29 | targetZone: meta 30 | 31 | pim-job-instance-csv-advanced-product-import-show-launch-switcher-item: 32 | module: pim/job-instance/import/switcher-item 33 | parent: pim-job-instance-csv-advanced-product-import-show 34 | targetZone: content 35 | aclResourceId: pim_importexport_import_profile_launch 36 | position: 40 37 | config: 38 | label: pim_import_export.form.job_instance.button.import.launch 39 | hideForCloudEdition: true 40 | 41 | pim-job-instance-csv-advanced-product-import-show-file-path: 42 | module: pim/job/common/file-path 43 | parent: pim-job-instance-csv-advanced-product-import-show-launch-switcher-item 44 | config: 45 | label: pim_import_export.form.job_instance.file_path 46 | 47 | pim-job-instance-csv-advanced-product-import-show-import-button: 48 | module: pim/job/common/edit/launch 49 | parent: pim-job-instance-csv-advanced-product-import-show-file-path 50 | targetZone: buttons 51 | config: 52 | label: pim_import_export.form.job_instance.button.import.launch 53 | route: pim_enrich_job_instance_rest_import_launch 54 | identifier: 55 | path: code 56 | name: code 57 | 58 | pim-job-instance-csv-advanced-product-import-show-upload-switcher-item: 59 | module: pim/job-instance/import/switcher-item 60 | parent: pim-job-instance-csv-advanced-product-import-show 61 | targetZone: content 62 | aclResourceId: pim_importexport_import_profile_launch 63 | position: 50 64 | config: 65 | label: pim_import_export.form.job_instance.button.import.upload_file 66 | hideForCloudEdition: false 67 | 68 | pim-job-instance-csv-advanced-product-import-show-upload: 69 | module: pim/job/common/edit/upload 70 | parent: pim-job-instance-csv-advanced-product-import-show-upload-switcher-item 71 | position: 50 72 | config: 73 | type: csv 74 | 75 | pim-job-instance-csv-advanced-product-import-show-upload-button: 76 | module: pim/job/common/edit/upload-launch 77 | parent: pim-job-instance-csv-advanced-product-import-show-upload-switcher-item 78 | position: 60 79 | config: 80 | label: pim_import_export.form.job_instance.button.import.upload 81 | route: pim_enrich_job_instance_rest_import_launch 82 | identifier: 83 | path: code 84 | name: code 85 | 86 | pim-job-instance-csv-advanced-product-import-show-last-executions: 87 | module: akeneojob/controller/job-instance 88 | parent: pim-job-instance-csv-advanced-product-import-show 89 | position: 100 90 | targetZone: content 91 | 92 | pim-job-instance-csv-advanced-product-import-show-label: 93 | module: pim/job/common/edit/label 94 | parent: pim-job-instance-csv-advanced-product-import-show 95 | targetZone: title 96 | position: 100 97 | 98 | pim-job-instance-csv-advanced-product-import-show-edit: 99 | module: pim/job/common/edit-button 100 | parent: pim-job-instance-csv-advanced-product-import-show 101 | targetZone: buttons 102 | position: 100 103 | aclResourceId: pim_importexport_import_profile_edit 104 | config: 105 | label: pim_common.edit 106 | route: pim_importexport_import_profile_edit 107 | buttonClass: AknButton AknButton--action 108 | identifier: 109 | path: code 110 | name: code 111 | -------------------------------------------------------------------------------- /Resources/config/form_extensions/csv_advanced_product_model_import_show.yml: -------------------------------------------------------------------------------- 1 | extensions: 2 | pim-job-instance-csv-advanced-product-model-import-show: 3 | module: pim/form/common/edit-form 4 | 5 | pim-job-instance-csv-advanced-product-model-import-show-mainImage: 6 | module: pim/form/common/main-image 7 | parent: pim-job-instance-csv-advanced-product-model-import-show 8 | targetZone: main-image 9 | config: 10 | path: bundles/pimui/images/illustrations/ImportCSV.svg 11 | 12 | pim-job-instance-csv-advanced-product-model-import-show-user-navigation: 13 | module: pim/menu/user-navigation 14 | parent: pim-job-instance-csv-advanced-product-model-import-show 15 | targetZone: user-menu 16 | config: 17 | userAccount: pim_menu.user.user_account 18 | logout: pim_menu.user.logout 19 | 20 | pim-job-instance-csv-advanced-product-model-import-show-breadcrumbs: 21 | module: pim/job/common/breadcrumb/breadcrumb 22 | parent: pim-job-instance-csv-advanced-product-model-import-show 23 | targetZone: breadcrumbs 24 | 25 | pim-job-instance-csv-advanced-product-model-import-show-switcher: 26 | module: pim/job-instance/import/switcher 27 | parent: pim-job-instance-csv-advanced-product-model-import-show 28 | position: 0 29 | targetZone: meta 30 | 31 | pim-job-instance-csv-advanced-product-model-import-show-launch-switcher-item: 32 | module: pim/job-instance/import/switcher-item 33 | parent: pim-job-instance-csv-advanced-product-model-import-show 34 | targetZone: content 35 | aclResourceId: pim_importexport_import_profile_launch 36 | position: 40 37 | config: 38 | label: pim_import_export.form.job_instance.button.import.launch 39 | hideForCloudEdition: true 40 | 41 | pim-job-instance-csv-advanced-product-model-import-show-file-path: 42 | module: pim/job/common/file-path 43 | parent: pim-job-instance-csv-advanced-product-model-import-show-launch-switcher-item 44 | config: 45 | label: pim_import_export.form.job_instance.file_path 46 | 47 | pim-job-instance-csv-advanced-product-model-import-show-import-button: 48 | module: pim/job/common/edit/launch 49 | parent: pim-job-instance-csv-advanced-product-model-import-show-file-path 50 | targetZone: buttons 51 | config: 52 | label: pim_import_export.form.job_instance.button.import.launch 53 | route: pim_enrich_job_instance_rest_import_launch 54 | identifier: 55 | path: code 56 | name: code 57 | 58 | pim-job-instance-csv-advanced-product-model-import-show-upload-switcher-item: 59 | module: pim/job-instance/import/switcher-item 60 | parent: pim-job-instance-csv-advanced-product-model-import-show 61 | targetZone: content 62 | aclResourceId: pim_importexport_import_profile_launch 63 | position: 50 64 | config: 65 | allowedKey: uploadAllowed 66 | label: pim_import_export.form.job_instance.button.import.upload_file 67 | hideForCloudEdition: false 68 | 69 | pim-job-instance-csv-advanced-product-model-import-show-upload: 70 | module: pim/job/common/edit/upload 71 | parent: pim-job-instance-csv-advanced-product-model-import-show-upload-switcher-item 72 | position: 50 73 | config: 74 | type: csv 75 | 76 | pim-job-instance-csv-advanced-product-model-import-show-upload-button: 77 | module: pim/job/common/edit/upload-launch 78 | parent: pim-job-instance-csv-advanced-product-model-import-show-upload-switcher-item 79 | position: 60 80 | config: 81 | label: pim_import_export.form.job_instance.button.import.upload 82 | route: pim_enrich_job_instance_rest_import_launch 83 | identifier: 84 | path: code 85 | name: code 86 | 87 | pim-job-instance-csv-advanced-product-model-import-show-last-executions: 88 | module: akeneojob/controller/job-instance 89 | parent: pim-job-instance-csv-advanced-product-model-import-show 90 | position: 100 91 | targetZone: content 92 | 93 | pim-job-instance-csv-advanced-product-model-import-show-label: 94 | module: pim/job/common/edit/label 95 | parent: pim-job-instance-csv-advanced-product-model-import-show 96 | targetZone: title 97 | position: 100 98 | 99 | pim-job-instance-csv-advanced-product-model-import-show-edit: 100 | module: pim/job/common/edit-button 101 | parent: pim-job-instance-csv-advanced-product-model-import-show 102 | targetZone: buttons 103 | position: 100 104 | aclResourceId: pim_importexport_import_profile_edit 105 | config: 106 | label: pim_common.edit 107 | route: pim_importexport_import_profile_edit 108 | buttonClass: AknButton AknButton--action 109 | identifier: 110 | path: code 111 | name: code 112 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Advanced CSV Connector - C&M 2 | 3 | Advanced CSV Connector is an extension of classic Akeneo CSV Connector. It allows to customize columns mapping on import or export. 4 | 5 | Made with :blue_heart: by C&M 6 | 7 | ## Versions 8 | 9 | | **Bundle version** | **Akeneo version** | 10 | |--------------------|-------------------| 11 | | v7.0.* | v7.0.* | 12 | | v6.0.* | v6.0.* | 13 | | v5.0.* | v5.0.* | 14 | | v1.8.* | v4.0.* | 15 | | v1.7.* | v3.2.* (EE) | 16 | | v1.6.* | v3.1.* / v3.2.* | 17 | | v1.5.* | v3.1.* / v3.2.* | 18 | | v1.4.* | v2.3.* | 19 | | v1.3.* | v2.1.* | 20 | 21 | ## Optional 22 | 23 | You can use `php-lua` package to update your values dynamically during import or export. 24 | For LUA scripts available functions and libraries have been limited for security reasons. You can use: 25 | 26 | * string 27 | * math 28 | * ipairs 29 | * load 30 | * next 31 | * pairs 32 | * rawequal 33 | * rawgetwget 34 | * rawlen 35 | * rawset 36 | * select 37 | * tonumber 38 | * tostring 39 | * type 40 | 41 | This package is not a requirement. A classic PHP method can also be used. 42 | 43 | ## Installation 44 | 45 | ### Download the Bundle 46 | 47 | Update your `composer.json` file to use our fork of **Custom entity bundle** in `repositories` node: 48 | 49 | ```console 50 | "repositories": [ 51 | ... 52 | { 53 | "type": "vcs", 54 | "url": "https://github.com/ClickAndMortar/CustomEntityBundle" 55 | } 56 | ... 57 | ], 58 | ``` 59 | 60 | And add our bundle: 61 | 62 | ```console 63 | $ composer require "clickandmortar/advanced-csv-connector-bundle":".*" 64 | ``` 65 | 66 | Example for last version: 67 | 68 | ```console 69 | $ composer require "clickandmortar/advanced-csv-connector-bundle":"7.0.*" 70 | ``` 71 | 72 | 73 | ### Enable the Bundle 74 | 75 | Enable the bundle by adding it to the list of registered bundles 76 | in the `config/bundles.php` file of your project: 77 | 78 | ```php 79 | ['all' => true], 84 | ClickAndMortar\AdvancedCsvConnectorBundle\ClickAndMortarAdvancedCsvConnectorBundle::class => ['all' => true] 85 | ]; 86 | ``` 87 | 88 | Update your `config/routes/routes.yml` file: 89 | 90 | ``` 91 | pim_customentity: 92 | prefix: /reference-data 93 | resource: "@PimCustomEntityBundle/Resources/config/routing.yml" 94 | 95 | candm_advanced_csv_connector: 96 | prefix: /candm-advanced-csv-connector 97 | resource: "@ClickAndMortarAdvancedCsvConnectorBundle/Resources/config/routing.yml" 98 | ``` 99 | 100 | And finally clear cache and update database: 101 | 102 | ``` 103 | rm -rf var/cache/* 104 | php bin/console --env=prod pim:installer:assets --symlink --clean 105 | yarn run webpack 106 | php bin/console doctrine:schema:update --force 107 | ``` 108 | 109 | ## Usage 110 | 111 | ### Import 112 | 113 | To create a new import mapping, go to `Référenciel / Mappings d'import` and click on `Create` top right button. 114 | You can add as many mapping lines as you want by clicking on `Ajouter une ligne`. 115 | 116 | Some explanations for table columns: 117 | 118 | * `Attribut` (mandatory): Attribute code in your Akeneo project (you can use suffixes like `-fr_FR` or `-EUR` for locales, channels, currencies, ...) 119 | * `Nom de la colonne` (mandatory): Column name in your file to import 120 | * `Transformation`: LUA script name or PHP method name to update value after mapping. Example: Uppercase, lowercase, ... (you can create a new LUA script under `Référenciel / Scripts LUA`). 121 | * `Valeur par défaut`: Default value for attribute if empty data in file 122 | * `Identifiant` (mandatory): Used to defined main identifier attribute of product 123 | * `Uniquement à la création`: Set attribute value only if product is new (checked with `identifier` attribute) 124 | * `Effacer si null`: Remove key from item mapping if value is null 125 | * `Supprimer`: Click on this cell to delete mapping line 126 | 127 | Once mapping is saved, go to `Imports` part and create a new job with type `Import des produits avancé (CSV)`. 128 | After job creation, go to edition mode and update `Mapping` parameter in global parameters tab. 129 | 130 | ### Export 131 | 132 | To create a new export mapping, go to `Référenciel / Mappings d'export` and click on `Create` top right button. 133 | You can add as many mapping lines as you want by clicking on `Ajouter une ligne`. 134 | 135 | Some explanations for table columns: 136 | 137 | * `Attribut` (mandatory): Attribute code in your Akeneo project (you can use suffixes like `-fr_FR` or `-EUR` for locales, channels, currencies, ...) 138 | * `Nom de la colonne` (mandatory): Column name in your file to export 139 | * `Valeur forcée`: Force a value (erase given attribute value from Akeneo) 140 | * `Transformation`: LUA script name or PHP method name to update value after mapping. Example: Uppercase, lowercase, ... (you can create a new LUA script under `Référenciel / Scripts LUA`) 141 | * `Utiliser le libellé`: Boolean to get the label associated to the code given (for attribute options or custom entities) 142 | * `Langue`: Select a specific locale for the label to export (linked to `Utiliser le libellé` column) 143 | * `Longueur max.`: Integer use to shorten attribute value if necessary 144 | * `Valeur par défaut`: Default value for column if empty attribute value 145 | * `Supprimer`: Click on this cell to delete mapping line 146 | 147 | Once mapping is saved, go to `Exports` part and create a new job with type `Export des produits avancé (CSV)`. 148 | After job creation, go to edition mode and update `Mapping` parameter in global parameters tab. -------------------------------------------------------------------------------- /Resources/config/form_extensions/luaUpdater/edit.yml: -------------------------------------------------------------------------------- 1 | extensions: 2 | pim-luaUpdater-edit-form: 3 | module: pim/form/common/edit-form 4 | 5 | pim-luaUpdater-edit-form-breadcrumbs: 6 | module: pim/common/breadcrumbs 7 | parent: pim-luaUpdater-edit-form 8 | targetZone: breadcrumbs 9 | config: 10 | tab: pim-menu-reference_data 11 | item: candm_advanced_csv_connector-menu-reference_data-item-luaUpdater 12 | 13 | pim-luaUpdater-edit-form-cache-invalidator: 14 | module: pim/cache-invalidator 15 | parent: pim-luaUpdater-edit-form 16 | position: 1000 17 | 18 | pim-color-edit-form-label: 19 | module: custom_entity/form/common/label 20 | parent: pim-color-edit-form 21 | targetZone: title 22 | position: 90 23 | 24 | pim-luaUpdater-edit-form-form-tabs: 25 | module: pim/form/common/form-tabs 26 | parent: pim-luaUpdater-edit-form 27 | targetZone: content 28 | position: 100 29 | 30 | pim-luaUpdater-edit-form-secondary-actions: 31 | module: pim/form/common/secondary-actions 32 | parent: pim-luaUpdater-edit-form 33 | targetZone: buttons 34 | position: 50 35 | 36 | pim-luaUpdater-edit-form-delete: 37 | module: custom_entity/form/common/delete 38 | parent: pim-luaUpdater-edit-form-secondary-actions 39 | targetZone: secondary-actions 40 | aclResourceId: pim_enrich_group_remove 41 | position: 100 42 | config: 43 | route: pim_customentity_rest_delete 44 | routeParams: 45 | customEntityName: luaUpdater 46 | trans: 47 | title: candm_advanced_csv_connector.luaUpdater.message.delete 48 | container: pim_enrich.confirmation.delete_item 49 | success: pim_custom_entity.message.removed 50 | fail: pim_custom_entity.error.removing 51 | redirect: pim_customentity_index 52 | 53 | pim-luaUpdater-edit-form-save-buttons: 54 | module: pim/form/common/save-buttons 55 | parent: pim-luaUpdater-edit-form 56 | targetZone: buttons 57 | position: 120 58 | 59 | pim-luaUpdater-edit-form-state: 60 | module: pim/form/common/state 61 | parent: pim-luaUpdater-edit-form 62 | targetZone: state 63 | position: 900 64 | config: 65 | entity: pim_enrich.entity.group.title 66 | 67 | pim-luaUpdater-edit-form-save: 68 | module: custom_entity/form/common/save-form 69 | parent: pim-luaUpdater-edit-form 70 | targetZone: buttons 71 | position: 0 72 | config: 73 | updateSuccessMessage: pim_enrich.entity.generic.flash.update.success 74 | updateFailureMessage: pim_enrich.entity.generic.flash.update.fail 75 | notReadyMessage: pim_enrich.entity.generic.flash.info.field_not_ready 76 | url: pim_customentity_rest_edit 77 | route_params: 78 | customEntityName: luaUpdater 79 | redirectAfter: pim_customentity_rest_get 80 | excludedProperties: ['data'] 81 | 82 | pim-luaUpdater-edit-form-properties-tab: 83 | module: pim/common/tab 84 | parent: pim-luaUpdater-edit-form-form-tabs 85 | targetZone: container 86 | position: 100 87 | config: 88 | label: pim_custom_entity.form.tab.properties.title 89 | 90 | pim-luaUpdater-edit-form-properties: 91 | module: pim/common/simple-view 92 | parent: pim-luaUpdater-edit-form-properties-tab 93 | targetZone: self 94 | config: 95 | template: pim/template/form/tab/sections 96 | 97 | pim-luaUpdater-edit-form-state: 98 | module: pim/form/common/state 99 | parent: pim-luaUpdater-edit-form 100 | targetZone: state 101 | position: 900 102 | config: 103 | entity: pim_enrich.entity.group.title 104 | 105 | pim-luaUpdater-edit-form-properties: 106 | module: pim/common/simple-view 107 | parent: pim-luaUpdater-edit-form-properties-tab 108 | targetZone: self 109 | config: 110 | template: pim/template/form/tab/sections 111 | 112 | pim-luaUpdater-edit-form-properties-common: 113 | module: pim/common/simple-view 114 | parent: pim-luaUpdater-edit-form-properties 115 | targetZone: accordion 116 | position: 100 117 | config: 118 | template: pim/template/form/tab/section-large 119 | templateParams: 120 | sectionTitle: pim_custom_entity.form.tab.properties.section.common 121 | dropZone: content 122 | 123 | pim-luaUpdater-edit-form-properties-label: 124 | module: pim/form/common/fields/text 125 | parent: pim-luaUpdater-edit-form-properties-common 126 | targetZone: content 127 | position: 90 128 | config: 129 | fieldName: label 130 | label: candm_advanced_csv_connector.luaUpdater.field.label.label 131 | required: true 132 | 133 | pim-luaUpdater-edit-form-properties-code: 134 | module: pim/form/common/fields/text 135 | parent: pim-luaUpdater-edit-form-properties-common 136 | targetZone: content 137 | position: 100 138 | config: 139 | fieldName: code 140 | label: candm_advanced_csv_connector.luaUpdater.field.label.code 141 | required: true 142 | 143 | pim-luaUpdater-edit-form-properties-script: 144 | module: pim/form/common/fields/lua-script 145 | parent: pim-luaUpdater-edit-form-properties-common 146 | targetZone: content 147 | position: 110 148 | config: 149 | fieldName: script 150 | label: candm_advanced_csv_connector.luaUpdater.field.label.script 151 | -------------------------------------------------------------------------------- /Resources/config/form_extensions/exportMapping/edit.yml: -------------------------------------------------------------------------------- 1 | extensions: 2 | pim-exportMapping-edit-form: 3 | module: pim/form/common/edit-form 4 | 5 | pim-exportMapping-edit-form-breadcrumbs: 6 | module: pim/common/breadcrumbs 7 | parent: pim-exportMapping-edit-form 8 | targetZone: breadcrumbs 9 | config: 10 | tab: pim-menu-reference_data 11 | item: candm_advanced_csv_connector-menu-reference_data-item-exportMapping 12 | 13 | pim-exportMapping-edit-form-cache-invalidator: 14 | module: pim/cache-invalidator 15 | parent: pim-exportMapping-edit-form 16 | position: 1000 17 | 18 | pim-color-edit-form-label: 19 | module: custom_entity/form/common/label 20 | parent: pim-color-edit-form 21 | targetZone: title 22 | position: 90 23 | 24 | pim-exportMapping-edit-form-form-tabs: 25 | module: pim/form/common/form-tabs 26 | parent: pim-exportMapping-edit-form 27 | targetZone: content 28 | position: 100 29 | 30 | pim-exportMapping-edit-form-secondary-actions: 31 | module: pim/form/common/secondary-actions 32 | parent: pim-exportMapping-edit-form 33 | targetZone: buttons 34 | position: 50 35 | 36 | pim-exportMapping-edit-form-delete: 37 | module: custom_entity/form/common/delete 38 | parent: pim-exportMapping-edit-form-secondary-actions 39 | targetZone: secondary-actions 40 | aclResourceId: pim_enrich_group_remove 41 | position: 100 42 | config: 43 | route: pim_customentity_rest_delete 44 | routeParams: 45 | customEntityName: exportMapping 46 | trans: 47 | title: candm_advanced_csv_connector.exportMapping.message.delete 48 | container: pim_enrich.confirmation.delete_item 49 | success: pim_custom_entity.message.removed 50 | fail: pim_custom_entity.error.removing 51 | redirect: pim_customentity_index 52 | 53 | pim-exportMapping-edit-form-save-buttons: 54 | module: pim/form/common/save-buttons 55 | parent: pim-exportMapping-edit-form 56 | targetZone: buttons 57 | position: 120 58 | 59 | pim-exportMapping-edit-form-state: 60 | module: pim/form/common/state 61 | parent: pim-exportMapping-edit-form 62 | targetZone: state 63 | position: 900 64 | config: 65 | entity: pim_enrich.entity.group.title 66 | 67 | pim-exportMapping-edit-form-save: 68 | module: custom_entity/form/common/save-form 69 | parent: pim-exportMapping-edit-form 70 | targetZone: buttons 71 | position: 0 72 | config: 73 | updateSuccessMessage: pim_enrich.entity.generic.flash.update.success 74 | updateFailureMessage: pim_enrich.entity.generic.flash.update.fail 75 | notReadyMessage: pim_enrich.entity.generic.flash.info.field_not_ready 76 | url: pim_customentity_rest_edit 77 | route_params: 78 | customEntityName: exportMapping 79 | redirectAfter: pim_customentity_rest_get 80 | excludedProperties: ['data'] 81 | 82 | pim-exportMapping-edit-form-properties-tab: 83 | module: pim/common/tab 84 | parent: pim-exportMapping-edit-form-form-tabs 85 | targetZone: container 86 | position: 100 87 | config: 88 | label: pim_custom_entity.form.tab.properties.title 89 | 90 | pim-exportMapping-edit-form-properties: 91 | module: pim/common/simple-view 92 | parent: pim-exportMapping-edit-form-properties-tab 93 | targetZone: self 94 | config: 95 | template: pim/template/form/tab/sections 96 | 97 | pim-exportMapping-edit-form-state: 98 | module: pim/form/common/state 99 | parent: pim-exportMapping-edit-form 100 | targetZone: state 101 | position: 900 102 | config: 103 | entity: pim_enrich.entity.group.title 104 | 105 | pim-exportMapping-edit-form-properties: 106 | module: pim/common/simple-view 107 | parent: pim-exportMapping-edit-form-properties-tab 108 | targetZone: self 109 | config: 110 | template: pim/template/form/tab/sections 111 | 112 | pim-exportMapping-edit-form-properties-common: 113 | module: pim/common/simple-view 114 | parent: pim-exportMapping-edit-form-properties 115 | targetZone: accordion 116 | position: 100 117 | config: 118 | template: pim/template/form/tab/section-large 119 | templateParams: 120 | sectionTitle: pim_custom_entity.form.tab.properties.section.common 121 | dropZone: content 122 | 123 | pim-exportMapping-edit-form-properties-label: 124 | module: pim/form/common/fields/text 125 | parent: pim-exportMapping-edit-form-properties-common 126 | targetZone: content 127 | position: 90 128 | config: 129 | fieldName: label 130 | label: candm_advanced_csv_connector.exportMapping.field.label.label 131 | required: true 132 | 133 | pim-exportMapping-edit-form-properties-code: 134 | module: pim/form/common/fields/text 135 | parent: pim-exportMapping-edit-form-properties-common 136 | targetZone: content 137 | position: 100 138 | config: 139 | fieldName: code 140 | label: candm_advanced_csv_connector.exportMapping.field.label.code 141 | required: true 142 | 143 | pim-exportMapping-edit-form-properties-mapping: 144 | module: pim/form/common/fields/export-mapping 145 | parent: pim-exportMapping-edit-form-properties-common 146 | targetZone: content 147 | position: 110 148 | config: 149 | fieldName: mappingAsJson 150 | label: candm_advanced_csv_connector.exportMapping.field.label.mapping 151 | 152 | pim-exportMapping-edit-form-properties-complete-callback: 153 | module: pim/form/common/fields/text 154 | parent: pim-exportMapping-edit-form-properties-common 155 | targetZone: content 156 | position: 120 157 | config: 158 | fieldName: completeCallback 159 | label: candm_advanced_csv_connector.exportMapping.field.label.complete_callback 160 | -------------------------------------------------------------------------------- /Entity/ImportMapping.php: -------------------------------------------------------------------------------- 1 | 11 | * @package ClickAndMortar\AdvancedCsvConnectorBundle\Entity 12 | */ 13 | class ImportMapping extends AbstractCustomEntity 14 | { 15 | /** 16 | * Label 17 | * 18 | * @var string 19 | */ 20 | protected $label; 21 | 22 | /** 23 | * Mapping as JSON 24 | * 25 | * @var string 26 | */ 27 | protected $mappingAsJson; 28 | 29 | /** 30 | * Complete callback 31 | * 32 | * @var string 33 | */ 34 | protected $completeCallback; 35 | 36 | /** 37 | * Initialize callback 38 | * 39 | * @var string 40 | */ 41 | protected $initializeCallback; 42 | 43 | /** 44 | * Flush callback 45 | * 46 | * @var string 47 | */ 48 | protected $flushCallback; 49 | 50 | /** 51 | * Items limit 52 | * 53 | * @var int 54 | */ 55 | protected $itemsLimit; 56 | 57 | /** 58 | * Update product only if already exists 59 | * 60 | * @var boolean 61 | */ 62 | protected $onlyUpdate = false; 63 | 64 | /** 65 | * Get label 66 | * 67 | * @return string 68 | */ 69 | public function getLabel() 70 | { 71 | return $this->label; 72 | } 73 | 74 | /** 75 | * Set label 76 | * 77 | * @param string $label 78 | * 79 | * @return Brand 80 | */ 81 | public function setLabel($label) 82 | { 83 | $this->label = $label; 84 | 85 | return $this; 86 | } 87 | 88 | /** 89 | * @return string 90 | */ 91 | public function getMappingAsJson() 92 | { 93 | return $this->mappingAsJson; 94 | } 95 | 96 | /** 97 | * @param string $mappingAsJson 98 | * 99 | * @return Mapping 100 | */ 101 | public function setMappingAsJson($mappingAsJson) 102 | { 103 | $this->mappingAsJson = $mappingAsJson; 104 | 105 | return $this; 106 | } 107 | 108 | /** 109 | * @return string 110 | */ 111 | public function getCompleteCallback() 112 | { 113 | return $this->completeCallback; 114 | } 115 | 116 | /** 117 | * @param string $completeCallback 118 | * 119 | * @return ImportMapping 120 | */ 121 | public function setCompleteCallback($completeCallback) 122 | { 123 | $this->completeCallback = $completeCallback; 124 | 125 | return $this; 126 | } 127 | 128 | /** 129 | * @return string 130 | */ 131 | public function getInitializeCallback() 132 | { 133 | return $this->initializeCallback; 134 | } 135 | 136 | /** 137 | * @param string $initializeCallback 138 | * 139 | * @return ImportMapping 140 | */ 141 | public function setInitializeCallback($initializeCallback) 142 | { 143 | $this->initializeCallback = $initializeCallback; 144 | 145 | return $this; 146 | } 147 | 148 | /** 149 | * @return string 150 | */ 151 | public function getFlushCallback() 152 | { 153 | return $this->flushCallback; 154 | } 155 | 156 | /** 157 | * @param string $flushCallback 158 | * 159 | * @return ImportMapping 160 | */ 161 | public function setFlushCallback($flushCallback) 162 | { 163 | $this->flushCallback = $flushCallback; 164 | 165 | return $this; 166 | } 167 | 168 | /** 169 | * @return int 170 | */ 171 | public function getItemsLimit() 172 | { 173 | return $this->itemsLimit; 174 | } 175 | 176 | /** 177 | * @param int $itemsLimit 178 | * 179 | * @return ImportMapping 180 | */ 181 | public function setItemsLimit($itemsLimit) 182 | { 183 | $this->itemsLimit = $itemsLimit; 184 | 185 | return $this; 186 | } 187 | 188 | /** 189 | * @return bool 190 | */ 191 | public function getOnlyUpdate() 192 | { 193 | return $this->onlyUpdate; 194 | } 195 | 196 | /** 197 | * @param bool $onlyUpdate 198 | * 199 | * @return ImportMapping 200 | */ 201 | public function setOnlyUpdate($onlyUpdate) 202 | { 203 | $this->onlyUpdate = $onlyUpdate; 204 | 205 | return $this; 206 | } 207 | 208 | /** 209 | * {@inheritdoc} 210 | */ 211 | public static function getLabelProperty(): string 212 | { 213 | return 'label'; 214 | } 215 | 216 | /** 217 | * Returns the custom entity name used in the configuration 218 | * Used to map row actions on datagrid 219 | * 220 | * @return string 221 | */ 222 | public function getCustomEntityName(): string 223 | { 224 | return 'importMapping'; 225 | } 226 | 227 | /** 228 | * Get reference value 229 | * 230 | * @return string 231 | */ 232 | public function getReference(): string 233 | { 234 | return $this->getCode(); 235 | } 236 | 237 | /** 238 | * Get complete mapping 239 | * 240 | * @return string 241 | */ 242 | public function getMappingAsArray() 243 | { 244 | // Get attributes mapping 245 | $attributesMapping = !empty($this->getMappingAsJson()) ? $this->getMappingAsJson() : '[]'; 246 | 247 | $mapping = [ 248 | 'attributes' => json_decode($attributesMapping, true), 249 | ]; 250 | 251 | // Add complete callback if necessary 252 | if (!empty($this->getCompleteCallback())) { 253 | $mapping['completeCallback'] = $this->getCompleteCallback(); 254 | } 255 | 256 | // Add initialize callback if necessary 257 | if (!empty($this->getInitializeCallback())) { 258 | $mapping['initializeCallback'] = $this->getInitializeCallback(); 259 | } 260 | 261 | // Add flush callback if necessary 262 | if (!empty($this->getFlushCallback())) { 263 | $mapping['flushCallback'] = $this->getFlushCallback(); 264 | } 265 | 266 | // Add items limit if necessary 267 | if (!empty($this->getItemsLimit())) { 268 | $mapping['itemsLimit'] = $this->getItemsLimit(); 269 | } 270 | 271 | // Add only update parameter 272 | $mapping['onlyUpdate'] = $this->getOnlyUpdate(); 273 | 274 | return $mapping; 275 | } 276 | } 277 | -------------------------------------------------------------------------------- /Resources/config/form_extensions/importMapping/edit.yml: -------------------------------------------------------------------------------- 1 | extensions: 2 | pim-importMapping-edit-form: 3 | module: pim/form/common/edit-form 4 | 5 | pim-importMapping-edit-form-breadcrumbs: 6 | module: pim/common/breadcrumbs 7 | parent: pim-importMapping-edit-form 8 | targetZone: breadcrumbs 9 | config: 10 | tab: pim-menu-reference_data 11 | item: candm_advanced_csv_connector-menu-reference_data-item-importMapping 12 | 13 | pim-importMapping-edit-form-cache-invalidator: 14 | module: pim/cache-invalidator 15 | parent: pim-importMapping-edit-form 16 | position: 1000 17 | 18 | pim-color-edit-form-label: 19 | module: custom_entity/form/common/label 20 | parent: pim-color-edit-form 21 | targetZone: title 22 | position: 90 23 | 24 | pim-importMapping-edit-form-form-tabs: 25 | module: pim/form/common/form-tabs 26 | parent: pim-importMapping-edit-form 27 | targetZone: content 28 | position: 100 29 | 30 | pim-importMapping-edit-form-secondary-actions: 31 | module: pim/form/common/secondary-actions 32 | parent: pim-importMapping-edit-form 33 | targetZone: buttons 34 | position: 50 35 | 36 | pim-importMapping-edit-form-delete: 37 | module: custom_entity/form/common/delete 38 | parent: pim-importMapping-edit-form-secondary-actions 39 | targetZone: secondary-actions 40 | aclResourceId: pim_enrich_group_remove 41 | position: 100 42 | config: 43 | route: pim_customentity_rest_delete 44 | routeParams: 45 | customEntityName: importMapping 46 | trans: 47 | title: candm_advanced_csv_connector.importMapping.message.delete 48 | container: pim_enrich.confirmation.delete_item 49 | success: pim_custom_entity.message.removed 50 | fail: pim_custom_entity.error.removing 51 | redirect: pim_customentity_index 52 | 53 | pim-importMapping-edit-form-save-buttons: 54 | module: pim/form/common/save-buttons 55 | parent: pim-importMapping-edit-form 56 | targetZone: buttons 57 | position: 120 58 | 59 | pim-importMapping-edit-form-state: 60 | module: pim/form/common/state 61 | parent: pim-importMapping-edit-form 62 | targetZone: state 63 | position: 900 64 | config: 65 | entity: pim_enrich.entity.group.title 66 | 67 | pim-importMapping-edit-form-save: 68 | module: custom_entity/form/common/save-form 69 | parent: pim-importMapping-edit-form 70 | targetZone: buttons 71 | position: 0 72 | config: 73 | updateSuccessMessage: pim_enrich.entity.generic.flash.update.success 74 | updateFailureMessage: pim_enrich.entity.generic.flash.update.fail 75 | notReadyMessage: pim_enrich.entity.generic.flash.info.field_not_ready 76 | url: pim_customentity_rest_edit 77 | route_params: 78 | customEntityName: importMapping 79 | redirectAfter: pim_customentity_rest_get 80 | excludedProperties: ['data'] 81 | 82 | pim-importMapping-edit-form-properties-tab: 83 | module: pim/common/tab 84 | parent: pim-importMapping-edit-form-form-tabs 85 | targetZone: container 86 | position: 100 87 | config: 88 | label: pim_custom_entity.form.tab.properties.title 89 | 90 | pim-importMapping-edit-form-properties: 91 | module: pim/common/simple-view 92 | parent: pim-importMapping-edit-form-properties-tab 93 | targetZone: self 94 | config: 95 | template: pim/template/form/tab/sections 96 | 97 | pim-importMapping-edit-form-state: 98 | module: pim/form/common/state 99 | parent: pim-importMapping-edit-form 100 | targetZone: state 101 | position: 900 102 | config: 103 | entity: pim_enrich.entity.group.title 104 | 105 | pim-importMapping-edit-form-properties: 106 | module: pim/common/simple-view 107 | parent: pim-importMapping-edit-form-properties-tab 108 | targetZone: self 109 | config: 110 | template: pim/template/form/tab/sections 111 | 112 | pim-importMapping-edit-form-properties-common: 113 | module: pim/common/simple-view 114 | parent: pim-importMapping-edit-form-properties 115 | targetZone: accordion 116 | position: 100 117 | config: 118 | template: pim/template/form/tab/section-large 119 | templateParams: 120 | sectionTitle: pim_custom_entity.form.tab.properties.section.common 121 | dropZone: content 122 | 123 | pim-importMapping-edit-form-properties-label: 124 | module: pim/form/common/fields/text 125 | parent: pim-importMapping-edit-form-properties-common 126 | targetZone: content 127 | position: 90 128 | config: 129 | fieldName: label 130 | label: candm_advanced_csv_connector.importMapping.field.label.label 131 | required: true 132 | 133 | pim-importMapping-edit-form-properties-code: 134 | module: pim/form/common/fields/text 135 | parent: pim-importMapping-edit-form-properties-common 136 | targetZone: content 137 | position: 100 138 | config: 139 | fieldName: code 140 | label: candm_advanced_csv_connector.importMapping.field.label.code 141 | required: true 142 | 143 | pim-importMapping-edit-form-properties-mapping: 144 | module: pim/form/common/fields/import-mapping 145 | parent: pim-importMapping-edit-form-properties-common 146 | targetZone: content 147 | position: 110 148 | config: 149 | fieldName: mappingAsJson 150 | label: candm_advanced_csv_connector.importMapping.field.label.mapping 151 | 152 | pim-importMapping-edit-form-properties-complete-callback: 153 | module: pim/form/common/fields/text 154 | parent: pim-importMapping-edit-form-properties-common 155 | targetZone: content 156 | position: 120 157 | config: 158 | fieldName: completeCallback 159 | label: candm_advanced_csv_connector.importMapping.field.label.complete_callback 160 | 161 | pim-importMapping-edit-form-properties-initialize-callback: 162 | module: pim/form/common/fields/text 163 | parent: pim-importMapping-edit-form-properties-common 164 | targetZone: content 165 | position: 130 166 | config: 167 | fieldName: initializeCallback 168 | label: candm_advanced_csv_connector.importMapping.field.label.initialize_callback 169 | 170 | pim-importMapping-edit-form-properties-flush-callback: 171 | module: pim/form/common/fields/text 172 | parent: pim-importMapping-edit-form-properties-common 173 | targetZone: content 174 | position: 140 175 | config: 176 | fieldName: flushCallback 177 | label: candm_advanced_csv_connector.importMapping.field.label.flush_callback 178 | 179 | pim-importMapping-edit-form-properties-items-limit: 180 | module: pim/form/common/fields/text 181 | parent: pim-importMapping-edit-form-properties-common 182 | targetZone: content 183 | position: 150 184 | config: 185 | fieldName: itemsLimit 186 | label: candm_advanced_csv_connector.importMapping.field.label.items_limit 187 | 188 | pim-importMapping-edit-form-properties-only-update: 189 | module: pim/form/common/fields/boolean 190 | parent: pim-importMapping-edit-form-properties-common 191 | targetZone: content 192 | position: 160 193 | config: 194 | fieldName: onlyUpdate 195 | label: candm_advanced_csv_connector.importMapping.field.label.only_update 196 | -------------------------------------------------------------------------------- /Resources/public/js/form/common/fields/import-mapping.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | define([ 4 | 'jquery', 5 | 'underscore', 6 | 'oro/translator', 7 | 'tabulator', 8 | 'pim/fetcher-registry', 9 | 'pim/form/common/fields/field', 10 | 'pim/template/form/common/fields/import-mapping' 11 | ], 12 | function ( 13 | $, 14 | _, 15 | __, 16 | Tabulator, 17 | FetcherRegistry, 18 | BaseField, 19 | template 20 | ) { 21 | return BaseField.extend({ 22 | template: _.template(template), 23 | 24 | yesNoValues: { 25 | 'true': __('pim_common.yes'), 26 | 'false': __('pim_common.no'), 27 | }, 28 | 29 | luaUpdaters: {}, 30 | 31 | /** 32 | * {@inheritdoc} 33 | */ 34 | renderInput: function (templateContext) { 35 | return this.template(_.extend(templateContext, { 36 | value: this.getModelValue() 37 | })); 38 | }, 39 | 40 | /** 41 | * {@inherit} 42 | */ 43 | configure() { 44 | return $.when( 45 | this.fetchLuaUpdaters().then(luaUpdaters => { 46 | var self = this; 47 | _.each(luaUpdaters, function (luaUpdater) { 48 | self.luaUpdaters[luaUpdater.code] = luaUpdater.label; 49 | }); 50 | }), 51 | ); 52 | }, 53 | 54 | /** 55 | * {@inheritdoc} 56 | */ 57 | postRender: function () { 58 | var self = this; 59 | var modelValueAsString = !_.isUndefined(self.getModelValue()) ? self.getModelValue() : '[]'; 60 | var tabledata = JSON.parse(modelValueAsString); 61 | var table = new Tabulator("#mapping-table", { 62 | data: tabledata, 63 | layout: "fitColumns", 64 | responsiveLayout: true, 65 | columnHeaderSortMulti: false, 66 | addRowPos: 'bottom', 67 | cellEdited: function (cell) { 68 | self.updateModelValue(cell._cell.table.getData()); 69 | }, 70 | rowDeleted: function (row) { 71 | self.updateModelValue(row._row.table.getData()); 72 | }, 73 | columns: [ 74 | { 75 | title: __('candm_advanced_csv_connector.importMapping.columns.attribute_code'), 76 | field: 'attributeCode', 77 | headerSort: false, 78 | editor: 'input' 79 | }, 80 | { 81 | title: __('candm_advanced_csv_connector.importMapping.columns.column_name'), 82 | field: 'dataCode', 83 | headerSort: false, 84 | editor: 'input' 85 | }, 86 | { 87 | title: __('candm_advanced_csv_connector.importMapping.columns.lua_updater'), 88 | field: 'luaUpdater', 89 | headerSort: false, 90 | editor: 'autocomplete', 91 | editorParams: { 92 | allowEmpty: true, 93 | values: self.luaUpdaters, 94 | freetext: true 95 | } 96 | }, 97 | { 98 | title: __('candm_advanced_csv_connector.importMapping.columns.default_value'), 99 | field: 'defaultValue', 100 | headerSort: false, 101 | editor: 'input' 102 | }, 103 | { 104 | title: __('candm_advanced_csv_connector.importMapping.columns.identifier'), 105 | field: 'identifier', 106 | headerSort: false, 107 | editor: 'select', 108 | editorParams: { 109 | values: self.yesNoValues 110 | }, 111 | accessorData: self.booleanAccessor, 112 | formatter: self.booleanFormatter, 113 | formatterParams: {self: self} 114 | }, 115 | { 116 | title: __('candm_advanced_csv_connector.importMapping.columns.only_on_creation'), 117 | field: 'onlyOnCreation', 118 | headerSort: false, 119 | editor: 'select', 120 | editorParams: { 121 | values: self.yesNoValues 122 | }, 123 | accessorData: self.booleanAccessor, 124 | formatter: self.booleanFormatter, 125 | formatterParams: {self: self} 126 | }, 127 | { 128 | title: __('candm_advanced_csv_connector.importMapping.columns.delete_if_null'), 129 | field: 'deleteIfNull', 130 | headerSort: false, 131 | editor: 'select', 132 | editorParams: { 133 | values: self.yesNoValues 134 | }, 135 | accessorData: self.booleanAccessor, 136 | formatter: self.booleanFormatter, 137 | formatterParams: {self: self} 138 | }, 139 | { 140 | title: __('candm_advanced_csv_connector.importMapping.actions.delete_row'), 141 | field: 'delete', 142 | formatter: 'tickCross', 143 | headerSort: false, 144 | cellClick: function (e, cell) { 145 | cell._cell.row.delete(); 146 | }, 147 | } 148 | ] 149 | }); 150 | 151 | // Manage clicks 152 | $("#add-row").click(function () { 153 | table.addRow({}); 154 | }); 155 | }, 156 | 157 | /** 158 | * Accessor data used to convert string value to boolean 159 | * 160 | * @param value 161 | * @param data 162 | * @param type 163 | * @param params 164 | * @param column 165 | */ 166 | booleanAccessor: function (value, data, type, params, column) { 167 | return value == 'true' || value == true; 168 | }, 169 | 170 | /** 171 | * Boolean formatter 172 | * 173 | * @param cell 174 | * @param formaterParams 175 | * @param onRendered 176 | */ 177 | booleanFormatter: function (cell, formaterParams, onRendered) { 178 | return _.has(formaterParams.self.yesNoValues, cell.getValue()) ? formaterParams.self.yesNoValues[cell.getValue()] : __('pim_common.no'); 179 | }, 180 | 181 | /** 182 | * Update model data 183 | * 184 | * @param data 185 | */ 186 | updateModelValue: function (data) { 187 | var dataAsString = JSON.stringify(data); 188 | this.updateModel(dataAsString); 189 | }, 190 | 191 | /** 192 | * Get LUA scripts 193 | * 194 | * @returns {*|Promise} 195 | */ 196 | fetchLuaUpdaters() { 197 | const fetcher = FetcherRegistry.getFetcher('custom_entity'); 198 | 199 | return fetcher.fetchAllByType('luaUpdater'); 200 | }, 201 | }); 202 | }); -------------------------------------------------------------------------------- /Resources/public/js/form/common/fields/export-mapping.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | define([ 4 | 'jquery', 5 | 'underscore', 6 | 'oro/translator', 7 | 'tabulator', 8 | 'pim/fetcher-registry', 9 | 'pim/form/common/fields/field', 10 | 'pim/template/form/common/fields/export-mapping' 11 | ], 12 | function ( 13 | $, 14 | _, 15 | __, 16 | Tabulator, 17 | FetcherRegistry, 18 | BaseField, 19 | template 20 | ) { 21 | return BaseField.extend({ 22 | template: _.template(template), 23 | 24 | yesNoValues: { 25 | 'true': __('pim_common.yes'), 26 | 'false': __('pim_common.no'), 27 | }, 28 | 29 | localesValues: {}, 30 | 31 | luaUpdaters: {}, 32 | 33 | /** 34 | * {@inheritdoc} 35 | */ 36 | renderInput: function (templateContext) { 37 | return this.template(_.extend(templateContext, { 38 | value: this.getModelValue() 39 | })); 40 | }, 41 | 42 | /** 43 | * {@inheritdoc} 44 | */ 45 | configure() { 46 | return $.when( 47 | this.fetchLocales().then(locales => { 48 | var self = this; 49 | _.each(locales, function (locale) { 50 | self.localesValues[locale.code] = locale.code; 51 | }); 52 | }), 53 | this.fetchLuaUpdaters().then(luaUpdaters => { 54 | var self = this; 55 | _.each(luaUpdaters, function (luaUpdater) { 56 | self.luaUpdaters[luaUpdater.code] = luaUpdater.label; 57 | }); 58 | }), 59 | ); 60 | }, 61 | 62 | /** 63 | * {@inheritdoc} 64 | */ 65 | postRender: function () { 66 | var self = this; 67 | var modelValueAsString = !_.isUndefined(self.getModelValue()) ? self.getModelValue() : '[]'; 68 | var tabledata = JSON.parse(modelValueAsString); 69 | var table = new Tabulator("#mapping-table", { 70 | data: tabledata, 71 | layout: "fitColumns", 72 | responsiveLayout: true, 73 | columnHeaderSortMulti: false, 74 | addRowPos: 'bottom', 75 | cellEdited: function (cell) { 76 | self.updateModelValue(cell._cell.table.getData()); 77 | }, 78 | rowDeleted: function (row) { 79 | self.updateModelValue(row._row.table.getData()); 80 | }, 81 | columns: [ 82 | { 83 | title: __('candm_advanced_csv_connector.exportMapping.columns.attribute_code'), 84 | field: 'attributeCode', 85 | headerSort: false, 86 | editor: 'input' 87 | }, 88 | { 89 | title: __('candm_advanced_csv_connector.exportMapping.columns.column_name'), 90 | field: 'columnName', 91 | headerSort: false, 92 | editor: 'input' 93 | }, 94 | { 95 | title: __('candm_advanced_csv_connector.exportMapping.columns.forced_value'), 96 | field: 'forcedValue', 97 | headerSort: false, 98 | editor: 'input' 99 | }, 100 | { 101 | title: __('candm_advanced_csv_connector.exportMapping.columns.lua_updater'), 102 | field: 'luaUpdater', 103 | headerSort: false, 104 | editor: 'autocomplete', 105 | editorParams: { 106 | allowEmpty: true, 107 | values: self.luaUpdaters, 108 | freetext: true 109 | } 110 | }, 111 | { 112 | title: __('candm_advanced_csv_connector.exportMapping.columns.use_label'), 113 | field: 'useLabel', 114 | headerSort: false, 115 | editor: 'select', 116 | editorParams: { 117 | values: self.yesNoValues 118 | }, 119 | accessorData: self.booleanAccessor, 120 | formatter: self.booleanFormatter, 121 | formatterParams: {self: self} 122 | }, 123 | { 124 | title: __('candm_advanced_csv_connector.exportMapping.columns.locale'), 125 | field: 'locale', 126 | headerSort: false, 127 | editor: 'select', 128 | editorParams: { 129 | values: self.localesValues 130 | } 131 | }, 132 | { 133 | title: __('candm_advanced_csv_connector.exportMapping.columns.max_length'), 134 | field: 'maxLength', 135 | headerSort: false, 136 | editor: 'input' 137 | }, 138 | { 139 | title: __('candm_advanced_csv_connector.exportMapping.columns.default_value'), 140 | field: 'defaultValue', 141 | headerSort: false, 142 | editor: 'input' 143 | }, 144 | { 145 | title: __('candm_advanced_csv_connector.importMapping.actions.delete_row'), 146 | field: 'delete', 147 | formatter: 'tickCross', 148 | headerSort: false, 149 | cellClick: function (e, cell) { 150 | cell._cell.row.delete(); 151 | }, 152 | } 153 | ] 154 | }); 155 | 156 | // Manage clicks 157 | $("#add-row").click(function () { 158 | table.addRow({}); 159 | }); 160 | }, 161 | 162 | /** 163 | * Accessor data used to convert string value to boolean 164 | * 165 | * @param value 166 | * @param data 167 | * @param type 168 | * @param params 169 | * @param column 170 | */ 171 | booleanAccessor: function (value, data, type, params, column) { 172 | return value == 'true' || value == true; 173 | }, 174 | 175 | /** 176 | * Boolean formatter 177 | * 178 | * @param cell 179 | * @param formaterParams 180 | * @param onRendered 181 | */ 182 | booleanFormatter: function (cell, formaterParams, onRendered) { 183 | return _.has(formaterParams.self.yesNoValues, cell.getValue()) ? formaterParams.self.yesNoValues[cell.getValue()] : __('pim_common.no'); 184 | }, 185 | 186 | /** 187 | * Update model data 188 | * 189 | * @param data 190 | */ 191 | updateModelValue: function (data) { 192 | var dataAsString = JSON.stringify(data); 193 | this.updateModel(dataAsString); 194 | }, 195 | 196 | /** 197 | * Get activated locales 198 | * 199 | * @returns {*|Promise} 200 | */ 201 | fetchLocales() { 202 | const localeFetcher = FetcherRegistry.getFetcher('locale'); 203 | 204 | return localeFetcher.fetchActivated(); 205 | }, 206 | 207 | /** 208 | * Get LUA scripts 209 | * 210 | * @returns {*|Promise} 211 | */ 212 | fetchLuaUpdaters() { 213 | const fetcher = FetcherRegistry.getFetcher('custom_entity'); 214 | 215 | return fetcher.fetchAllByType('luaUpdater'); 216 | }, 217 | }); 218 | }); -------------------------------------------------------------------------------- /Resources/translations/jsmessages.en.yml: -------------------------------------------------------------------------------- 1 | # Custom 2 | batch_jobs: 3 | csv_advanced_product_import: 4 | label: Advanced products import (CSV) 5 | fields: 6 | mapping: 7 | label: Data mapping 8 | email_recipients: 9 | label: Email recipients 10 | help: Email addresses separated by commas 11 | success_notification: 12 | label: Notification on success 13 | help: Allows you to have an email notification in case of success 14 | from_encoding: 15 | label: From encoding 16 | help: Allows you to select the input encoding of the file (it will be re-encoded in UTF-8) 17 | import: 18 | label: Products import 19 | 20 | csv_advanced_product_model_import: 21 | label: Advanced products models import (CSV) 22 | fields: 23 | mapping: 24 | label: Data mapping 25 | email_recipients: 26 | label: Email recipients 27 | help: Email addresses separated by commas 28 | success_notification: 29 | label: Notification on success 30 | help: Allows you to have an email notification in case of success 31 | from_encoding: 32 | label: From encoding 33 | help: Allows you to select the input encoding of the file (it will be re-encoded in UTF-8) 34 | import: 35 | label: Products models import 36 | 37 | csv_advanced_product_export: 38 | label: Advanced products export (CSV) 39 | fields: 40 | mapping: 41 | label: Data mapping 42 | encoding: 43 | label: Encoding 44 | help: Output file encoding (UTF-8 by default) 45 | force_xlsx: 46 | label: Export to Excel format 47 | help: Allows to force the export in .xlsx format 48 | export: 49 | label: Products export 50 | 51 | csv_advanced_product_model_export: 52 | label: Advanced products models export (CSV) 53 | fields: 54 | mapping: 55 | label: Data mapping 56 | encoding: 57 | label: Encoding 58 | help: Output file encoding (UTF-8 by default) 59 | force_xlsx: 60 | label: Export to Excel format 61 | help: Allows to force the export in .xlsx format 62 | export: 63 | label: Products models export 64 | default_steps: 65 | notification: Email notification 66 | 67 | # Custom entity 68 | pim_menu: 69 | tab.reference_data: Referential 70 | item.reference_data: Referential 71 | navigation.reference_data: Referential 72 | 73 | pim_custom_entity: 74 | index_title: Global view 75 | create_popin.title: Create 76 | form: 77 | field.label.label: Label 78 | field.label.code: Code 79 | tab: 80 | history.title: History 81 | properties: 82 | title: Properties 83 | section: 84 | common: General 85 | label_translations: Labels 86 | button: 87 | create: Create 88 | message: 89 | created: Created with success 90 | removed: Deleted with success 91 | delete: Delete element? 92 | error: 93 | removing: This referential data can not be deleted 94 | export.csv.entity_name: 95 | label: Referential name 96 | help: Referential name that you want to export 97 | no_reference_data: No referential available 98 | import.csv.entity_name: 99 | label: Referential name 100 | help: Referential name that you want to import 101 | no_reference_data: No referential available 102 | 103 | pim_title: 104 | pim_customentity_index: 'Referential - Global view' 105 | pim_customentity_rest_create: 'Referential - Global view' 106 | pim_customentity_massedit: 'Referential' 107 | pim_customentity_quickexport: 'Referential' 108 | pim_customentity_rest_delete: 'Referential' 109 | pim_customentity_rest_list: 'Referential' 110 | pim_customentity_rest_get: 'Referential - View' 111 | 112 | # Custom 113 | candm_advanced_csv_connector: 114 | importMapping: 115 | index_title: "] -Inf, 1] {{ count }} import mapping|] 1, Inf [{{ count }} import mappings" 116 | selected: import mapping(s) selected 117 | 118 | field: 119 | label: 120 | label: Label 121 | code: Code 122 | mapping: Mapping attributes / columns 123 | complete_callback: Callback transform after mapping 124 | initialize_callback: Callback before import 125 | flush_callback: Callback after import 126 | items_limit: Items limit 127 | only_update: Products update only 128 | 129 | columns: 130 | attribute_code: Attribute 131 | column_name: Column name 132 | default_value: Default value 133 | identifier: Identifier 134 | only_on_creation: Only on creation 135 | delete_if_null: Erase if null 136 | lua_updater: Transform 137 | actions: 138 | add_row: Add a line 139 | delete_row: Delete 140 | 141 | exportMapping: 142 | index_title: "] -Inf, 1] {{ count }} export mapping|] 1, Inf [{{ count }} export mappings" 143 | selected: export mapping(s) selected 144 | 145 | field: 146 | label: 147 | label: Label 148 | code: Code 149 | mapping: Mapping attributes / columns 150 | complete_callback: Callback transform after mapping 151 | 152 | columns: 153 | attribute_code: Attribute 154 | column_name: Column name 155 | forced_value: Forced value 156 | use_label: Use label 157 | locale: Locale 158 | max_length: Max length 159 | default_value: Default value 160 | lua_updater: Transform 161 | actions: 162 | add_row: Add a line 163 | delete_row: Delete 164 | 165 | luaUpdater: 166 | index_title: "] -Inf, 1] {{ count }} LUA script|] 1, Inf [{{ count }} LUA scripts" 167 | selected: LUA script(s) selected 168 | field: 169 | label: 170 | label: Label 171 | code: Code 172 | script: Script 173 | custom: 174 | test_value: Test value 175 | test_action: Test 176 | 177 | menu.item.reference_data: 178 | importMapping: Import mappings 179 | exportMapping: Export mappings 180 | luaUpdater: LUA scripts 181 | 182 | acl: 183 | importMapping: 184 | index: List import mappings 185 | create: Create an import mapping 186 | edit: Edit an import mapping 187 | delete: Delete an import mapping 188 | exportMapping: 189 | index: List export mappings 190 | create: Create an export mapping 191 | edit: Edit an export mapping 192 | delete: Delete an export mapping 193 | luaUpdater: 194 | index: List LUA scripts 195 | create: Create a LUA script 196 | edit: Edit a LUA script 197 | delete: Delete a LUA script 198 | 199 | pim_enrich: 200 | form.attribute.tab.properties.label: 201 | name: Name 202 | entity: 203 | generic: 204 | flash: 205 | update: 206 | success: Entity updated successfully! 207 | fail: Error during entity update 208 | info: 209 | field_not_ready: Field not ready 210 | importmapping: 211 | flash: 212 | delete: 213 | success: Mapping deleted! 214 | module: 215 | delete: 216 | confirm: Are you sure you want to delete this import mapping? 217 | importMapping: 218 | flash: 219 | delete: 220 | fail: Can not delete this import mapping 221 | exportmapping: 222 | flash: 223 | delete: 224 | success: Mapping deleted! 225 | module: 226 | delete: 227 | confirm: Are you sure you want to delete this export mapping? 228 | exportMapping: 229 | flash: 230 | delete: 231 | fail: Can not delete this export mapping 232 | luaupdater: 233 | flash: 234 | delete: 235 | success: LUA script deleted! 236 | module: 237 | delete: 238 | confirm: Are you sure you want to delete this LUA script? 239 | luaUpdater: 240 | flash: 241 | delete: 242 | fail: Can not delete this LUA script 243 | attribute: 244 | info: 245 | update_failed: Error during entity update 246 | -------------------------------------------------------------------------------- /Resources/translations/jsmessages.fr.yml: -------------------------------------------------------------------------------- 1 | # Custom 2 | batch_jobs: 3 | csv_advanced_product_import: 4 | label: Import des produits avancé (CSV) 5 | fields: 6 | mapping: 7 | label: Mapping des données 8 | email_recipients: 9 | label: Destinataires pour les rapports 10 | help: Adresses emails séparées par des virgules 11 | success_notification: 12 | label: Notification en cas de succès 13 | help: Permet d'avoir une notification par email en cas de succès 14 | from_encoding: 15 | label: Encodage en entrée 16 | help: Permet de sélectionner l'encodage en entrée du fichier (il sera ré-encodé en UTF-8) 17 | import: 18 | label: Import des produits 19 | default_steps: 20 | notification: Notification par email 21 | 22 | csv_advanced_product_model_import: 23 | label: Import des modèles produits avancé (CSV) 24 | fields: 25 | mapping: 26 | label: Mapping des données 27 | email_recipients: 28 | label: Destinataires pour les rapports 29 | help: Adresses emails séparées par des virgules 30 | success_notification: 31 | label: Notification en cas de succès 32 | help: Permet d'avoir une notification par email en cas de succès 33 | from_encoding: 34 | label: Encodage en entrée 35 | help: Permet de sélectionner l'encodage en entrée du fichier (il sera ré-encodé en UTF-8) 36 | import: 37 | label: Import des modèles produits 38 | 39 | csv_advanced_product_export: 40 | label: Export des produits avancé (CSV) 41 | fields: 42 | mapping: 43 | label: Mapping des données 44 | encoding: 45 | label: Encodage 46 | help: Encodage du fichier de sortie (UTF-8 par défaut) 47 | force_xlsx: 48 | label: Exporter au format Excel 49 | help: Permet de forcer l'export au format .xlsx 50 | export: 51 | label: Export des produits 52 | 53 | csv_advanced_product_model_export: 54 | label: Export des modèles produits avancé (CSV) 55 | fields: 56 | mapping: 57 | label: Mapping des données 58 | encoding: 59 | label: Encodage 60 | help: Encodage du fichier de sortie (UTF-8 par défaut) 61 | force_xlsx: 62 | label: Exporter au format Excel 63 | help: Permet de forcer l'export au format .xlsx 64 | export: 65 | label: Export des modèles produits 66 | 67 | # Custom entity 68 | pim_menu: 69 | tab.reference_data: Référenciel 70 | item.reference_data: Référenciel 71 | navigation.reference_data: Référenciel 72 | 73 | pim_custom_entity: 74 | index_title: Vue générale 75 | create_popin.title: Créer 76 | form: 77 | field.label.label: Libellé 78 | field.label.code: Code 79 | tab: 80 | history.title: Historique 81 | properties: 82 | title: Propriétés 83 | section: 84 | common: Général 85 | label_translations: Libellés 86 | button: 87 | create: Créer 88 | message: 89 | created: Créé avec succès 90 | removed: Supprimé avec succès 91 | delete: Supprimer l'élément ? 92 | error: 93 | removing: Ce référenciel ne peut être supprimé 94 | export.csv.entity_name: 95 | label: Nom du référenciel 96 | help: Le nom du référenciel que vous souhaitez exporter 97 | no_reference_data: Aucun référenciel disponible 98 | import.csv.entity_name: 99 | label: Nom du référenciel 100 | help: Le nom du référenciel que vous souhaitez importer 101 | no_reference_data: Aucun référenciel disponible 102 | 103 | pim_title: 104 | pim_customentity_index: 'Référenciel - Vue générale' 105 | pim_customentity_rest_create: 'Référenciel - Créer' 106 | pim_customentity_massedit: 'Référenciel' 107 | pim_customentity_quickexport: 'Référenciel' 108 | pim_customentity_rest_delete: 'Référenciel' 109 | pim_customentity_rest_list: 'Référenciel' 110 | pim_customentity_rest_get: 'Référenciel - Vue' 111 | 112 | # Custom 113 | candm_advanced_csv_connector: 114 | importMapping: 115 | index_title: "] -Inf, 1] {{ count }} mapping d'import|] 1, Inf [{{ count }} mappings d'import" 116 | selected: mapping(s) d'import sélectionné(s) 117 | 118 | field: 119 | label: 120 | label: Libellé 121 | code: Code 122 | mapping: Mapping attributs / colonnes 123 | complete_callback: Méthode de transformation après mapping 124 | initialize_callback: Méthode avant l'exécution de l'import 125 | flush_callback: Méthode après l'exécution de l'import 126 | items_limit: Nombre de produits max. à importer 127 | only_update: Mise à jour des produits uniquement 128 | 129 | columns: 130 | attribute_code: Attribut 131 | column_name: Nom de la colonne 132 | default_value: Valeur par défaut 133 | identifier: Identifiant 134 | only_on_creation: Uniquement à la création 135 | delete_if_null: Effacer si nul 136 | lua_updater: Transformation 137 | actions: 138 | add_row: Ajouter une ligne 139 | delete_row: Supprimer 140 | 141 | exportMapping: 142 | index_title: "] -Inf, 1] {{ count }} mapping d'export|] 1, Inf [{{ count }} mappings d'export" 143 | selected: mapping(s) d'export sélectionné(s) 144 | 145 | field: 146 | label: 147 | label: Libellé 148 | code: Code 149 | mapping: Mapping attributs / colonnes 150 | complete_callback: Méthode de transformation après mapping 151 | 152 | columns: 153 | attribute_code: Attribut 154 | column_name: Nom de la colonne 155 | forced_value: Valeur forcée 156 | use_label: Utiliser le libellé 157 | locale: Langue 158 | max_length: Longueur max. 159 | default_value: Valeur par défaut 160 | lua_updater: Transformation 161 | actions: 162 | add_row: Ajouter une ligne 163 | delete_row: Supprimer 164 | 165 | luaUpdater: 166 | index_title: "] -Inf, 1] {{ count }} script LUA|] 1, Inf [{{ count }} scripts LUA" 167 | selected: script(s) LUA sélectionné(s) 168 | field: 169 | label: 170 | label: Libellé 171 | code: Code 172 | script: Script 173 | custom: 174 | test_value: Valeur pour le test 175 | test_action: Tester 176 | 177 | menu.item.reference_data: 178 | importMapping: Mappings d'import 179 | exportMapping: Mappings d'export 180 | luaUpdater: Scripts LUA 181 | 182 | acl: 183 | importMapping: 184 | index: Lister les mappings d'import 185 | create: Créer un mapping d'import 186 | edit: Éditer un mapping d'import 187 | delete: Supprimer un mapping d'import 188 | exportMapping: 189 | index: Lister les mappings d'export 190 | create: Créer un mapping d'export 191 | edit: Éditer un mapping d'export 192 | delete: Supprimer un mapping d'export 193 | luaUpdater: 194 | index: Lister les scripts LUA 195 | create: Créer un script LUA 196 | edit: Éditer un script LUA 197 | delete: Supprimer un script LUA 198 | 199 | pim_enrich: 200 | form.attribute.tab.properties.label: 201 | name: Nom 202 | entity: 203 | generic: 204 | flash: 205 | update: 206 | success: Entité mise à jour avec succès ! 207 | fail: Erreur pendant la mise à jour 208 | info: 209 | field_not_ready: Ce champ n'est pas prêt 210 | importmapping: 211 | flash: 212 | delete: 213 | success: Mapping supprimé avec succès ! 214 | module: 215 | delete: 216 | confirm: Êtes-vous sûr de vouloir supprimer ce mapping d'import ? 217 | importMapping: 218 | flash: 219 | delete: 220 | fail: Impossible de supprimer ce mapping d'import 221 | exportmapping: 222 | flash: 223 | delete: 224 | success: Mapping supprimé avec succès ! 225 | module: 226 | delete: 227 | confirm: Êtes-vous sûr de vouloir supprimer ce mapping d'export ? 228 | exportMapping: 229 | flash: 230 | delete: 231 | fail: Impossible de supprimer ce mapping d'export 232 | luaupdater: 233 | flash: 234 | delete: 235 | success: Script LUA supprimé avec succès ! 236 | module: 237 | delete: 238 | confirm: Êtes-vous sûr de vouloir supprimer ce script LUA ? 239 | luaUpdater: 240 | flash: 241 | delete: 242 | fail: Impossible de supprimer ce script LUA 243 | attribute: 244 | info: 245 | update_failed: Erreur lors de la mise à jour de l'entité 246 | -------------------------------------------------------------------------------- /Step/MailNotification.php: -------------------------------------------------------------------------------- 1 | 20 | * @package ClickAndMortar\AdvancedCsvConnectorBundle\Step 21 | */ 22 | class MailNotification extends AbstractStep 23 | { 24 | /** 25 | * Email recipients job parameter 26 | * 27 | * @var string 28 | */ 29 | const JOB_PARAMETERS_EMAIL_RECIPIENTS = 'emailRecipients'; 30 | 31 | /** 32 | * Sucess notification parameter 33 | * 34 | * @var string 35 | */ 36 | const JOB_PARAMETERS_SUCCESS_NOTIFICATION = 'successNotification'; 37 | 38 | /** 39 | * Import step name 40 | * 41 | * @var string 42 | */ 43 | const STEP_NAME_IMPORT = 'import'; 44 | 45 | /** 46 | * Recipients separator 47 | * 48 | * @var string 49 | */ 50 | const RECIPIENTS_SEPARATOR = ','; 51 | 52 | /** 53 | * Message type reason key 54 | * 55 | * @var string 56 | */ 57 | const MESSAGE_TYPE_REASON_KEY = 'messageType'; 58 | 59 | /** 60 | * Default message type 61 | * 62 | * @var string 63 | */ 64 | const MESSAGE_TYPE_DEFAULT = 'default'; 65 | 66 | /** 67 | * Statistics message type 68 | * 69 | * @var string 70 | */ 71 | const MESSAGE_TYPE_STATISTICS = 'statistics'; 72 | 73 | /** 74 | * @var MailNotifier $notifier 75 | */ 76 | protected $notifier; 77 | 78 | /** 79 | * @var Environment $templating 80 | */ 81 | protected $templating; 82 | 83 | /** 84 | * @var TranslatorDecorator $translator 85 | */ 86 | protected $translator; 87 | 88 | /** 89 | * @var StepExecution $stepExecution 90 | */ 91 | protected $stepExecution; 92 | 93 | /** 94 | * Identifier keys for item 95 | * 96 | * @var string[] 97 | */ 98 | protected $identifierKeys = [ 99 | 'identifier', 100 | 'code', 101 | ]; 102 | 103 | /** 104 | * @param string $name 105 | * @param EventDispatcherInterface $eventDispatcher 106 | * @param JobRepositoryInterface $jobRepository 107 | * @param MailNotifier $notifier 108 | * @param Environment $templating 109 | * @param TranslatorDecorator $translator 110 | */ 111 | public function __construct( 112 | $name, 113 | EventDispatcherInterface $eventDispatcher, 114 | JobRepositoryInterface $jobRepository, 115 | MailNotifier $notifier, 116 | Environment $templating, 117 | TranslatorDecorator $translator 118 | ) 119 | { 120 | parent::__construct($name, $eventDispatcher, $jobRepository); 121 | $this->notifier = $notifier; 122 | $this->templating = $templating; 123 | $this->translator = $translator; 124 | } 125 | 126 | /** 127 | * @param StepExecution $stepExecution 128 | */ 129 | protected function doExecute(StepExecution $stepExecution) 130 | { 131 | // Check if we have recipients 132 | $this->stepExecution = $stepExecution; 133 | $jobParameters = $this->stepExecution->getJobParameters(); 134 | if ( 135 | !$jobParameters->has(self::JOB_PARAMETERS_EMAIL_RECIPIENTS) 136 | || empty($jobParameters->get(self::JOB_PARAMETERS_EMAIL_RECIPIENTS)) 137 | ) { 138 | return; 139 | } 140 | 141 | // Check if we want success notification 142 | $successNotification = $jobParameters->has(self::JOB_PARAMETERS_SUCCESS_NOTIFICATION) && $jobParameters->get(self::JOB_PARAMETERS_SUCCESS_NOTIFICATION) === true; 143 | 144 | // Generate and send notifications 145 | $jobExecution = $this->stepExecution->getJobExecution(); 146 | $recipients = $jobParameters->get(self::JOB_PARAMETERS_EMAIL_RECIPIENTS); 147 | $recipients = explode(self::RECIPIENTS_SEPARATOR, $recipients); 148 | $mailLabel = $this->translator->trans('batch_jobs.mail_notification.subject', [ 149 | '%importLabel%' => $jobExecution->getLabel(), 150 | '%date%' => $jobExecution->getStartTime()->format('d/m/Y, H:i'), 151 | ]); 152 | 153 | // Parse data from steps 154 | $messagesByStepAndType = []; 155 | /** @var StepExecution $stepExecution */ 156 | foreach ($jobExecution->getStepExecutions() as $stepExecution) { 157 | // Get statistics data 158 | $statisticsMessages = $this->getStatisticsByStepExecution($stepExecution); 159 | 160 | // Get warnings 161 | $warningMessages = []; 162 | $warnings = $stepExecution->getWarnings(); 163 | if (!$warnings->isEmpty()) { 164 | $warningMessages = $this->getMessagesByType($warnings); 165 | } 166 | 167 | // Skip if notification success is not activated 168 | if (!$successNotification && empty($warningMessages)) { 169 | continue; 170 | } 171 | 172 | $messagesForCurrentStep = array_merge($statisticsMessages, $warningMessages); 173 | if (!empty($messagesForCurrentStep)) { 174 | $messagesByStepAndType[$stepExecution->getStepName()] = $messagesForCurrentStep; 175 | } 176 | } 177 | 178 | // Send notification 179 | if (!empty($messagesByStepAndType)) { 180 | $contentAsHtml = $this->templating->render( 181 | '@ClickAndMortarAdvancedCsvConnector/notification.html.twig', 182 | [ 183 | 'messagesByStepAndType' => $messagesByStepAndType, 184 | ] 185 | ); 186 | $this->notifier->notify($recipients, $mailLabel, '', $contentAsHtml); 187 | } 188 | } 189 | 190 | /** 191 | * Get statistics used by notification template from $stepExecution 192 | * 193 | * @param StepExecution $stepExecution 194 | * 195 | * @return array 196 | */ 197 | protected function getStatisticsByStepExecution($stepExecution) 198 | { 199 | $statistics = []; 200 | $trackingData = $stepExecution->getTrackingData(); 201 | $readCount = intval($trackingData['totalItems']); 202 | if ($readCount === 0) { 203 | return $statistics; 204 | } 205 | 206 | $warningCount = count($stepExecution->getWarnings()); 207 | $writeCount = $readCount - $warningCount; 208 | 209 | // Read lines 210 | $statistics[] = [ 211 | 'content' => $this->translator->trans( 212 | 'batch_jobs.mail_notification.statistics.read', 213 | [ 214 | '%readCount%' => $readCount, 215 | ] 216 | ), 217 | ]; 218 | 219 | // Write lines 220 | $statistics[] = [ 221 | 'content' => $this->translator->trans( 222 | 'batch_jobs.mail_notification.statistics.write', 223 | [ 224 | '%writeCount%' => $writeCount, 225 | ] 226 | ), 227 | ]; 228 | 229 | // Warning lines 230 | $statistics[] = [ 231 | 'content' => $this->translator->trans( 232 | 'batch_jobs.mail_notification.statistics.warning', 233 | [ 234 | '%warningCount%' => $warningCount, 235 | ] 236 | ), 237 | ]; 238 | 239 | 240 | return [ 241 | self::MESSAGE_TYPE_STATISTICS => $statistics 242 | ]; 243 | } 244 | 245 | /** 246 | * Get messages by type from import step execution $warnings 247 | * 248 | * @param Warning[] $warnings 249 | * 250 | * @return array 251 | */ 252 | protected function getMessagesByType($warnings) 253 | { 254 | $messages = []; 255 | foreach ($warnings as $warning) { 256 | // Get product identifier 257 | $identifier = null; 258 | $item = $warning->getItem(); 259 | foreach ($this->identifierKeys as $identifierKey) { 260 | if (isset($item[$identifierKey]) && !empty($item[$identifierKey])) { 261 | $identifier = $item[$identifierKey]; 262 | break; 263 | } 264 | } 265 | 266 | // Get message type from reason parameters 267 | $reasonParameters = $warning->getReasonParameters(); 268 | if ( 269 | isset($reasonParameters[self::MESSAGE_TYPE_REASON_KEY]) 270 | && !empty($reasonParameters[self::MESSAGE_TYPE_REASON_KEY]) 271 | ) { 272 | $messageType = $reasonParameters[self::MESSAGE_TYPE_REASON_KEY]; 273 | } else { 274 | $messageType = self::MESSAGE_TYPE_DEFAULT; 275 | } 276 | 277 | // Set message 278 | if (!array_key_exists($messageType, $messages)) { 279 | $messages[$messageType] = []; 280 | } 281 | $messages[$messageType][] = [ 282 | 'identifier' => $identifier, 283 | 'content' => $this->translator->trans($warning->getReason(), $warning->getReasonParameters()), 284 | ]; 285 | } 286 | 287 | return $messages; 288 | } 289 | } 290 | --------------------------------------------------------------------------------