diff --git a/composer.json b/composer.json
index 79b835d..537f45e 100644
--- a/composer.json
+++ b/composer.json
@@ -13,24 +13,25 @@
}
],
"require": {
- "php": "^7.4||^8.0",
+ "php": "^7.4 || ^8.0",
"ausi/slug-generator": "^1.1",
- "contao/core-bundle": "^4.9",
+ "contao/core-bundle": "^4.13 || ^5.0",
+ "elvanto/litemoji": "^5.2",
"guzzlehttp/guzzle": "^6.0 || ^7.0",
"heimrichhannot/contao-be_explanation-bundle": "^2.3",
"heimrichhannot/contao-field-value-copier-bundle": "^1.1",
- "heimrichhannot/contao-list_widget": "^2.1",
+ "heimrichhannot/contao-list-widget-bundle": "^1.5",
"heimrichhannot/contao-multi-column-editor-bundle": "^2.4",
- "heimrichhannot/contao-progress-bar-widget-bundle": "^0.1",
- "heimrichhannot/contao-utils-bundle": "^2.135",
- "symfony/cache": "^4.4 || ^5.2",
- "symfony/config": "^4.4||^5.4",
- "symfony/console": "^4.4||^5.4",
- "symfony/dependency-injection": "^4.4||^5.4",
- "symfony/event-dispatcher": "^4.4||^5.4",
- "symfony/event-dispatcher-contracts": "^1||^2||^3",
- "symfony/http-kernel": "^4.4||^5.4",
- "symfony/stopwatch": "^4.4 || ^5.2",
+ "heimrichhannot/contao-progress-bar-widget-bundle": "dev-master",
+ "heimrichhannot/contao-utils-bundle": "^2.135 || ^3.7",
+ "symfony/cache": "^5.4 || ^6.0 || ^7.0",
+ "symfony/config": "^5.4 || ^6.0 || ^7.0",
+ "symfony/console": "^5.4 || ^6.0 || ^7.0",
+ "symfony/dependency-injection": "^5.4 || ^6.0 || ^7.0",
+ "symfony/event-dispatcher": "^5.4 || ^6.0 || ^7.0",
+ "symfony/event-dispatcher-contracts": "^1 || ^2 || ^3",
+ "symfony/http-kernel": "^5.4 || ^6.0 || ^7.0",
+ "symfony/stopwatch": "^5.4 || ^6.0 || ^7.0",
"terminal42/service-annotation-bundle": "^1.1"
},
"require-dev": {
diff --git a/src/Resources/config/services.yml b/config/services.yaml
similarity index 60%
rename from src/Resources/config/services.yml
rename to config/services.yaml
index 42b5065..b747ebf 100644
--- a/src/Resources/config/services.yml
+++ b/config/services.yaml
@@ -5,8 +5,12 @@ services:
public: true
HeimrichHannot\EntityImportBundle\:
- resource: '../../{Command,Controller,DataContainer,EventListener}/*'
+ resource: '../src/{Command,Controller,DataContainer,EventListener}/*'
HeimrichHannot\EntityImportBundle\Importer\ImporterFactory: ~
HeimrichHannot\EntityImportBundle\Source\SourceFactory: ~
HeimrichHannot\EntityImportBundle\Util\EntityImportUtil: ~
+
+ HeimrichHannot\EntityImportBundle\Command\ExecuteImportCommand:
+ arguments:
+ $projectDir: '%kernel.project_dir%'
diff --git a/src/Resources/contao/config/config.php b/contao/config/config.php
similarity index 87%
rename from src/Resources/contao/config/config.php
rename to contao/config/config.php
index c822d06..ec693b7 100644
--- a/src/Resources/contao/config/config.php
+++ b/contao/config/config.php
@@ -44,8 +44,3 @@
$GLOBALS['TL_CRON']['daily'][] = [HeimrichHannot\EntityImportBundle\Controller\PoorManCronController::class, 'runDaily'];
$GLOBALS['TL_CRON']['weekly'][] = [HeimrichHannot\EntityImportBundle\Controller\PoorManCronController::class, 'runWeekly'];
$GLOBALS['TL_CRON']['monthly'][] = [HeimrichHannot\EntityImportBundle\Controller\PoorManCronController::class, 'runMonthly'];
-
-if ('BE' === TL_MODE) {
- $GLOBALS['TL_CSS']['be_entityimportbundle'] = 'bundles/heimrichhannotcontaoentityimport/assets/contao-entity-import-bundle-be.css|static';
- $GLOBALS['TL_JAVASCRIPT']['be_entityimportbundle'] = 'bundles/heimrichhannotcontaoentityimport/assets/contao-entity-import-bundle-be.js|static';
-}
diff --git a/src/Resources/contao/dca/tl_entity_import_cache.php b/contao/dca/tl_entity_import_cache.php
similarity index 92%
rename from src/Resources/contao/dca/tl_entity_import_cache.php
rename to contao/dca/tl_entity_import_cache.php
index 595a1c9..f7421be 100644
--- a/src/Resources/contao/dca/tl_entity_import_cache.php
+++ b/contao/dca/tl_entity_import_cache.php
@@ -8,7 +8,7 @@
$GLOBALS['TL_DCA']['tl_entity_import_cache'] = [
'config' => [
- 'dataContainer' => 'Table',
+ 'dataContainer' => \Contao\DC_Table::class,
'sql' => [
'keys' => [
'id' => 'primary',
diff --git a/src/Resources/contao/dca/tl_entity_import_config.php b/contao/dca/tl_entity_import_config.php
similarity index 98%
rename from src/Resources/contao/dca/tl_entity_import_config.php
rename to contao/dca/tl_entity_import_config.php
index 2089678..1d2f1a4 100644
--- a/src/Resources/contao/dca/tl_entity_import_config.php
+++ b/contao/dca/tl_entity_import_config.php
@@ -6,19 +6,17 @@
* @license LGPL-3.0-or-later
*/
+\HeimrichHannot\UtilsBundle\Dca\DateAddedField::register('tl_entity_import_config');
+
$GLOBALS['TL_DCA']['tl_entity_import_config'] = [
'config' => [
- 'dataContainer' => 'Table',
+ 'dataContainer' => \Contao\DC_Table::class,
'enableVersioning' => true,
'ptable' => 'tl_entity_import_source',
'onload_callback' => [[\HeimrichHannot\EntityImportBundle\DataContainer\EntityImportConfigContainer::class, 'initPalette']],
'onsubmit_callback' => [
- ['huh.utils.dca', 'setDateAdded'],
[\HeimrichHannot\EntityImportBundle\DataContainer\EntityImportConfigContainer::class, 'setPreset'],
],
- 'oncopy_callback' => [
- ['huh.utils.dca', 'setDateAddedOnCopy'],
- ],
'sql' => [
'keys' => [
'id' => 'primary',
@@ -77,8 +75,8 @@
'import' => [
'label' => &$GLOBALS['TL_LANG']['tl_entity_import_config']['import'],
'href' => 'key=import',
- 'icon' => 'store.svg',
- 'attributes' => 'onclick="if (!confirm(\''.($GLOBALS['TL_LANG']['tl_entity_import_config']['importConfirm'] ?? null).'\')) return false; Backend.getScrollOffset();"',
+ 'icon' => 'theme_import.svg',
+ 'attributes' => 'data-turbo="false" onclick="if (!confirm(\''.($GLOBALS['TL_LANG']['tl_entity_import_config']['importConfirm'] ?? null).'\')) return false; Backend.getScrollOffset();"',
],
],
],
@@ -110,13 +108,6 @@
'sql' => "int(10) unsigned NOT NULL default '0'",
'relation' => ['type' => 'belongsTo', 'load' => 'eager'],
],
- 'dateAdded' => [
- 'label' => &$GLOBALS['TL_LANG']['MSC']['dateAdded'],
- 'sorting' => true,
- 'flag' => 6,
- 'eval' => ['rgxp' => 'datim', 'doNotCopy' => true],
- 'sql' => "int(10) unsigned NOT NULL default '0'",
- ],
'tstamp' => [
'sql' => "int(10) unsigned NOT NULL default '0'",
],
@@ -549,7 +540,7 @@
'label' => &$GLOBALS['TL_LANG']['tl_entity_import_config']['cronLanguage'],
'exclude' => true,
'inputType' => 'select',
- 'options' => \Contao\System::getLanguages(),
+ 'options' => \Contao\System::getContainer()->get('contao.intl.locales')->getLanguages(),
'eval' => ['tl_class' => 'w50', 'mandatory' => true, 'includeBlankOption' => true, 'chosen' => true],
'sql' => "varchar(64) NOT NULL default ''",
],
diff --git a/src/Resources/contao/dca/tl_entity_import_quick_config.php b/contao/dca/tl_entity_import_quick_config.php
similarity index 88%
rename from src/Resources/contao/dca/tl_entity_import_quick_config.php
rename to contao/dca/tl_entity_import_quick_config.php
index 34ae388..be11b1e 100644
--- a/src/Resources/contao/dca/tl_entity_import_quick_config.php
+++ b/contao/dca/tl_entity_import_quick_config.php
@@ -6,23 +6,21 @@
* @license LGPL-3.0-or-later
*/
-System::getContainer()->get('huh.utils.dca')->loadLanguageFile('tl_entity_import_source');
-System::getContainer()->get('huh.utils.dca')->loadLanguageFile('tl_entity_import_config');
+\Contao\System::loadLanguageFile('tl_entity_import_source');
+\Contao\System::loadLanguageFile('tl_entity_import_config');
+
+\HeimrichHannot\UtilsBundle\Dca\DateAddedField::register('tl_entity_import_quick_config');
$GLOBALS['TL_DCA']['tl_entity_import_quick_config'] = [
'config' => [
- 'dataContainer' => 'Table',
+ 'dataContainer' => \Contao\DC_Table::class,
'enableVersioning' => true,
'onload_callback' => [
[\HeimrichHannot\EntityImportBundle\DataContainer\EntityImportQuickConfigContainer::class, 'modifyDca'],
],
'onsubmit_callback' => [
- ['huh.utils.dca', 'setDateAdded'],
[\HeimrichHannot\EntityImportBundle\DataContainer\EntityImportQuickConfigContainer::class, 'cacheCsvRows'],
],
- 'oncopy_callback' => [
- ['huh.utils.dca', 'setDateAddedOnCopy'],
- ],
'sql' => [
'keys' => [
'id' => 'primary',
@@ -79,8 +77,8 @@
'import' => [
'label' => &$GLOBALS['TL_LANG']['tl_entity_import_quick_config']['import'],
'href' => 'key=import',
- 'icon' => 'store.svg',
- 'attributes' => 'onclick="if (!confirm(\''.$GLOBALS['TL_LANG']['tl_entity_import_config']['importConfirm'].'\')) return false; Backend.getScrollOffset();"',
+ 'icon' => 'theme_import.svg',
+ 'attributes' => 'data-turbo="false" onclick="if (!confirm(\''.$GLOBALS['TL_LANG']['tl_entity_import_config']['importConfirm'].'\')) return false; Backend.getScrollOffset();"',
],
],
],
@@ -95,13 +93,6 @@
'label' => &$GLOBALS['TL_LANG']['tl_entity_import_quick_config']['tstamp'],
'sql' => "int(10) unsigned NOT NULL default '0'",
],
- 'dateAdded' => [
- 'label' => &$GLOBALS['TL_LANG']['MSC']['dateAdded'],
- 'sorting' => true,
- 'flag' => 6,
- 'eval' => ['rgxp' => 'datim', 'doNotCopy' => true],
- 'sql' => "int(10) unsigned NOT NULL default '0'",
- ],
'title' => [
'label' => &$GLOBALS['TL_LANG']['tl_entity_import_quick_config']['title'],
'exclude' => true,
diff --git a/src/Resources/contao/dca/tl_entity_import_source.php b/contao/dca/tl_entity_import_source.php
similarity index 95%
rename from src/Resources/contao/dca/tl_entity_import_source.php
rename to contao/dca/tl_entity_import_source.php
index 8ba04cb..8982996 100644
--- a/src/Resources/contao/dca/tl_entity_import_source.php
+++ b/contao/dca/tl_entity_import_source.php
@@ -6,20 +6,21 @@
* @license LGPL-3.0-or-later
*/
+\HeimrichHannot\UtilsBundle\Dca\DateAddedField::register('tl_entity_import_source');
+
+$connection = \Contao\System::getContainer()->get('doctrine.dbal.default_connection');
+$connectionParams = $connection->getParams();
+
$GLOBALS['TL_DCA']['tl_entity_import_source'] = [
// Config
'config' => [
- 'dataContainer' => 'Table',
+ 'dataContainer' => \Contao\DC_Table::class,
'ctable' => ['tl_entity_import_config'],
'enableVersioning' => true,
'onload_callback' => [[\HeimrichHannot\EntityImportBundle\DataContainer\EntityImportSourceContainer::class, 'initPalette']],
'onsubmit_callback' => [
- ['huh.utils.dca', 'setDateAdded'],
[\HeimrichHannot\EntityImportBundle\DataContainer\EntityImportSourceContainer::class, 'setPreset'],
],
- 'oncopy_callback' => [
- ['huh.utils.dca', 'setDateAddedOnCopy'],
- ],
'sql' => [
'keys' => [
'id' => 'primary',
@@ -103,13 +104,6 @@
'tstamp' => [
'sql' => "int(10) unsigned NOT NULL default '0'",
],
- 'dateAdded' => [
- 'label' => &$GLOBALS['TL_LANG']['MSC']['dateAdded'],
- 'sorting' => true,
- 'flag' => 6,
- 'eval' => ['rgxp' => 'datim', 'doNotCopy' => true],
- 'sql' => "int(10) unsigned NOT NULL default '0'",
- ],
'title' => [
'label' => &$GLOBALS['TL_LANG']['tl_entity_import_source']['title'],
'search' => true,
@@ -132,8 +126,8 @@
'exclude' => true,
'label' => &$GLOBALS['TL_LANG']['tl_entity_import_source']['dbDriver'],
'inputType' => 'select',
- 'default' => version_compare(VERSION, '4.0', '<') ? \Config::get('dbDriver') : 'pdo_mysql',
- 'options' => version_compare(VERSION, '4.0', '<') ? ['MySQLi', 'MySQL'] : ['pdo_mysql'],
+ 'default' => 'pdo_mysql',
+ 'options' => ['pdo_mysql'],
'eval' => ['mandatory' => true, 'tl_class' => 'w50'],
'sql' => "varchar(12) NOT NULL default ''",
],
@@ -141,7 +135,7 @@
'exclude' => true,
'label' => &$GLOBALS['TL_LANG']['tl_entity_import_source']['dbHost'],
'inputType' => 'text',
- 'default' => \Config::get('dbHost'),
+ 'default' => $connectionParams['host'],
'eval' => ['mandatory' => true, 'maxlength' => 64, 'tl_class' => 'w50'],
'sql' => "varchar(64) NOT NULL default ''",
],
@@ -149,7 +143,7 @@
'exclude' => true,
'label' => &$GLOBALS['TL_LANG']['tl_entity_import_source']['dbUser'],
'inputType' => 'text',
- 'default' => \Config::get('dbUser') ?: '',
+ 'default' => $connectionParams['user'] ?? '',
'eval' => ['mandatory' => true, 'maxlength' => 64, 'tl_class' => 'w50'],
'sql' => "varchar(64) NOT NULL default ''",
],
@@ -164,7 +158,7 @@
'exclude' => true,
'label' => &$GLOBALS['TL_LANG']['tl_entity_import_source']['dbDatabase'],
'inputType' => 'text',
- 'default' => \Config::get('dbDatabase') ?: '',
+ 'default' => $connectionParams['dbname'] ?? '',
'eval' => ['mandatory' => true, 'maxlength' => 64, 'tl_class' => 'w50'],
'sql' => "varchar(64) NOT NULL default ''",
],
@@ -181,7 +175,7 @@
'exclude' => true,
'label' => &$GLOBALS['TL_LANG']['tl_entity_import_source']['dbCharset'],
'inputType' => 'text',
- 'default' => \Config::get('dbCharset'),
+ 'default' => $connectionParams['charset'] ?? '',
'eval' => ['mandatory' => true, 'maxlength' => 32, 'tl_class' => 'w50'],
'sql' => "varchar(32) NOT NULL default ''",
],
@@ -189,7 +183,7 @@
'exclude' => true,
'label' => &$GLOBALS['TL_LANG']['tl_entity_import_source']['dbPort'],
'inputType' => 'text',
- 'default' => \Config::get('dbPort'),
+ 'default' => $connectionParams['port'] ?? 0,
'eval' => ['maxlength' => 5, 'tl_class' => 'w50', 'rgxp' => 'digit'],
'sql' => "int(5) unsigned NOT NULL default '0'",
],
diff --git a/src/Resources/contao/dca/tl_module.php b/contao/dca/tl_module.php
similarity index 100%
rename from src/Resources/contao/dca/tl_module.php
rename to contao/dca/tl_module.php
diff --git a/src/Resources/contao/languages/de/default.php b/contao/languages/de/default.php
similarity index 100%
rename from src/Resources/contao/languages/de/default.php
rename to contao/languages/de/default.php
diff --git a/src/Resources/contao/languages/de/modules.php b/contao/languages/de/modules.php
similarity index 100%
rename from src/Resources/contao/languages/de/modules.php
rename to contao/languages/de/modules.php
diff --git a/src/Resources/contao/languages/de/tl_entity_import_config.php b/contao/languages/de/tl_entity_import_config.php
similarity index 100%
rename from src/Resources/contao/languages/de/tl_entity_import_config.php
rename to contao/languages/de/tl_entity_import_config.php
diff --git a/src/Resources/contao/languages/de/tl_entity_import_quick_config.php b/contao/languages/de/tl_entity_import_quick_config.php
similarity index 100%
rename from src/Resources/contao/languages/de/tl_entity_import_quick_config.php
rename to contao/languages/de/tl_entity_import_quick_config.php
diff --git a/src/Resources/contao/languages/de/tl_entity_import_source.php b/contao/languages/de/tl_entity_import_source.php
similarity index 100%
rename from src/Resources/contao/languages/de/tl_entity_import_source.php
rename to contao/languages/de/tl_entity_import_source.php
diff --git a/src/Resources/contao/languages/en/default.php b/contao/languages/en/default.php
similarity index 100%
rename from src/Resources/contao/languages/en/default.php
rename to contao/languages/en/default.php
diff --git a/src/Resources/contao/languages/en/modules.php b/contao/languages/en/modules.php
similarity index 100%
rename from src/Resources/contao/languages/en/modules.php
rename to contao/languages/en/modules.php
diff --git a/src/Resources/contao/languages/en/tl_entity_import_config.php b/contao/languages/en/tl_entity_import_config.php
similarity index 100%
rename from src/Resources/contao/languages/en/tl_entity_import_config.php
rename to contao/languages/en/tl_entity_import_config.php
diff --git a/src/Resources/contao/languages/en/tl_entity_import_quick_config.php b/contao/languages/en/tl_entity_import_quick_config.php
similarity index 100%
rename from src/Resources/contao/languages/en/tl_entity_import_quick_config.php
rename to contao/languages/en/tl_entity_import_quick_config.php
diff --git a/src/Resources/contao/languages/en/tl_entity_import_source.php b/contao/languages/en/tl_entity_import_source.php
similarity index 100%
rename from src/Resources/contao/languages/en/tl_entity_import_source.php
rename to contao/languages/en/tl_entity_import_source.php
diff --git a/src/Resources/assets/scss/contao-entity-import-bundle-be.scss b/public/css/contao-entity-import-bundle-be.css
similarity index 73%
rename from src/Resources/assets/scss/contao-entity-import-bundle-be.scss
rename to public/css/contao-entity-import-bundle-be.css
index 6f8b772..025a7cf 100644
--- a/src/Resources/assets/scss/contao-entity-import-bundle-be.scss
+++ b/public/css/contao-entity-import-bundle-be.css
@@ -1,4 +1,4 @@
-#tl_entity_import_source{
+#tl_entity_import_source {
[name="fileContent"] + .ace_editor {
height: 500px !important;
}
diff --git a/public/css/contao-entity-import-bundle-be.min.css b/public/css/contao-entity-import-bundle-be.min.css
new file mode 100644
index 0000000..844e84b
--- /dev/null
+++ b/public/css/contao-entity-import-bundle-be.min.css
@@ -0,0 +1 @@
+#tl_entity_import_source{[name="fileContent"]+.ace_editor{height:500px!important}}
diff --git a/src/Resources/assets/js/contao-entity-import-bundle-be.js b/public/js/contao-entity-import-bundle-be.js
similarity index 95%
rename from src/Resources/assets/js/contao-entity-import-bundle-be.js
rename to public/js/contao-entity-import-bundle-be.js
index 2dc17eb..0fc4b27 100644
--- a/src/Resources/assets/js/contao-entity-import-bundle-be.js
+++ b/public/js/contao-entity-import-bundle-be.js
@@ -1,5 +1,3 @@
-import '../scss/contao-entity-import-bundle-be.scss';
-
class ContaoEntityImportBundleBe {
static init() {
ContaoEntityImportBundleBe.removeWidthLimitForQuickImporters();
diff --git a/public/js/contao-entity-import-bundle-be.min.js b/public/js/contao-entity-import-bundle-be.min.js
new file mode 100644
index 0000000..079c7b9
--- /dev/null
+++ b/public/js/contao-entity-import-bundle-be.min.js
@@ -0,0 +1 @@
+class ContaoEntityImportBundleBe{static init(){ContaoEntityImportBundleBe.removeWidthLimitForQuickImporters()}static removeWidthLimitForQuickImporters(){if(null===document.getElementById("tl_entity_import_quick_config")||null===document.querySelector(".list-widget"))return;document.querySelector("#header .inner").style["max-width"]="none",document.getElementById("container").style["max-width"]="none",document.getElementById("main").style.width="auto";let t=0;document.querySelectorAll(".tl_formbody_edit .widget").forEach(e=>{t++,null===e.querySelector(".list-widget")&&(e.style["max-width"]=e.classList.contains("long")?"1000px":"500px",t%2==1&&e.classList.add("clr"))})}}document.addEventListener("DOMContentLoaded",ContaoEntityImportBundleBe.init);
diff --git a/src/Command/ExecuteImportCommand.php b/src/Command/ExecuteImportCommand.php
index 7201414..8d6bcd9 100644
--- a/src/Command/ExecuteImportCommand.php
+++ b/src/Command/ExecuteImportCommand.php
@@ -8,31 +8,47 @@
namespace HeimrichHannot\EntityImportBundle\Command;
-use Contao\CoreBundle\Command\AbstractLockedCommand;
+use Contao\CoreBundle\Framework\ContaoFramework;
use HeimrichHannot\EntityImportBundle\DataContainer\EntityImportConfigContainer;
use HeimrichHannot\EntityImportBundle\Importer\ImporterFactory;
use HeimrichHannot\EntityImportBundle\Importer\ImporterInterface;
-use HeimrichHannot\UtilsBundle\Model\ModelUtil;
+use HeimrichHannot\UtilsBundle\Util\Utils;
+use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
+use Symfony\Component\Filesystem\Filesystem;
+use Symfony\Component\Lock\LockFactory;
+use Symfony\Component\Lock\Store\FlockStore;
+use Symfony\Component\Filesystem\Path;
-class ExecuteImportCommand extends AbstractLockedCommand
+class ExecuteImportCommand extends Command
{
- protected InputInterface $input;
- protected SymfonyStyle $io;
- protected ModelUtil $modelUtil;
+ protected InputInterface $input;
+ protected SymfonyStyle $io;
+ protected Utils $utils;
protected ImporterFactory $importerFactory;
+ protected ContaoFramework $framework;
+ protected Filesystem $filesystem;
+ protected string $projectDir;
/**
* ExecuteImportCommand constructor.
*/
- public function __construct(ModelUtil $modelUtil, ImporterFactory $importerFactory)
- {
- $this->modelUtil = $modelUtil;
+ public function __construct(
+ Utils $utils,
+ ImporterFactory $importerFactory,
+ ContaoFramework $framework,
+ Filesystem $filesystem,
+ string $projectDir
+ ) {
+ $this->utils = $utils;
$this->importerFactory = $importerFactory;
+ $this->framework = $framework;
+ $this->filesystem = $filesystem;
+ $this->projectDir = $projectDir;
parent::__construct();
}
@@ -52,26 +68,37 @@ protected function configure()
/**
* {@inheritdoc}
*/
- protected function executeLocked(InputInterface $input, OutputInterface $output)
+ protected function execute(InputInterface $input, OutputInterface $output): int
{
+ $store = new FlockStore($this->getTempDir());
+ $factory = new LockFactory($store);
+ $lock = $factory->createLock($this->getName());
+
+ if (!$lock->acquire()) {
+ $output->writeln('The command is already running in another process.');
+
+ return 1;
+ }
+
$this->input = $input;
- $this->io = new SymfonyStyle($input, $output);
- $this->framework = $this->getContainer()->get('contao.framework');
+ $this->io = new SymfonyStyle($input, $output);
$this->framework->initialize();
$this->import();
+ $lock->release();
+
return 0;
}
private function import()
{
- $configIds = explode(',', $this->input->getArgument('config-ids'));
- $dryRun = $this->input->getOption('dry-run') ?: false;
+ $configIds = explode(',', $this->input->getArgument('config-ids'));
+ $dryRun = $this->input->getOption('dry-run') ?: false;
$webCronMode = $this->input->getOption('web-cron-mode') ?: false;
foreach ($configIds as $configId) {
- if (null === ($configModel = $this->modelUtil->findModelInstanceByPk('tl_entity_import_config', $configId))) {
+ if (null === ($configModel = $this->utils->model()->findModelInstanceByPk('tl_entity_import_config', $configId))) {
$this->io->error("Importer config with ID $configId not found.");
continue;
@@ -93,7 +120,7 @@ private function import()
continue;
}
- $configModel->importStarted = time();
+ $configModel->importStarted = time();
$configModel->importProgressCurrent = 0;
$configModel->save();
}
@@ -133,4 +160,18 @@ private function import()
}
}
}
+
+ /**
+ * Creates an installation specific folder in the temporary directory and returns its path.
+ */
+ private function getTempDir(): string
+ {
+ $tmpDir = Path::join(sys_get_temp_dir(), md5((string)$this->projectDir));
+
+ if (!is_dir($tmpDir)) {
+ $this->filesystem->mkdir($tmpDir);
+ }
+
+ return $tmpDir;
+ }
}
diff --git a/src/ContaoManager/Plugin.php b/src/ContaoManager/Plugin.php
index 9acaeeb..e10feba 100644
--- a/src/ContaoManager/Plugin.php
+++ b/src/ContaoManager/Plugin.php
@@ -30,6 +30,6 @@ public function getBundles(ParserInterface $parser)
public function registerContainerConfiguration(LoaderInterface $loader, array $managerConfig)
{
- $loader->load('@HeimrichHannotContaoEntityImportBundle/Resources/config/services.yml');
+ $loader->load('@HeimrichHannotContaoEntityImportBundle/config/services.yaml');
}
}
diff --git a/src/Controller/PoorManCronController.php b/src/Controller/PoorManCronController.php
index fd136bf..6210d77 100644
--- a/src/Controller/PoorManCronController.php
+++ b/src/Controller/PoorManCronController.php
@@ -10,17 +10,17 @@
use HeimrichHannot\EntityImportBundle\Importer\ImporterFactory;
use HeimrichHannot\EntityImportBundle\Importer\ImporterInterface;
-use HeimrichHannot\UtilsBundle\Model\ModelUtil;
+use HeimrichHannot\UtilsBundle\Util\Utils;
class PoorManCronController
{
protected ImporterFactory $importerFactory;
- protected ModelUtil $modelUtil;
+ protected Utils $utils;
- public function __construct(ImporterFactory $importerFactory, ModelUtil $modelUtil)
+ public function __construct(ImporterFactory $importerFactory, Utils $utils)
{
$this->importerFactory = $importerFactory;
- $this->modelUtil = $modelUtil;
+ $this->utils = $utils;
}
public function runMinutely()
@@ -70,7 +70,7 @@ public function runMonthly()
protected function getConfigIds(string $interval): array
{
- $models = $this->modelUtil->findModelInstancesBy('tl_entity_import_config',
+ $models = $this->utils->model()->findModelInstancesBy('tl_entity_import_config',
['tl_entity_import_config.useCron=?', 'tl_entity_import_config.cronInterval=?', 'tl_entity_import_config.usePoorMansCron=?'], [true, $interval, true]);
if (null === $models) {
@@ -82,7 +82,7 @@ protected function getConfigIds(string $interval): array
protected function run(string $id)
{
- if (null === ($configModel = $this->modelUtil->findModelInstanceByPk('tl_entity_import_config', $id))) {
+ if (null === ($configModel = $this->utils->model()->findModelInstanceByPk('tl_entity_import_config', $id))) {
return;
}
diff --git a/src/DataContainer/EntityImportConfigContainer.php b/src/DataContainer/EntityImportConfigContainer.php
index 27cf90d..f115951 100644
--- a/src/DataContainer/EntityImportConfigContainer.php
+++ b/src/DataContainer/EntityImportConfigContainer.php
@@ -14,13 +14,13 @@
use Contao\Database;
use Contao\DataContainer;
use Contao\Date;
+use Contao\Image;
+use Contao\Input;
use Contao\StringUtil;
+use Doctrine\DBAL\Connection;
use HeimrichHannot\EntityImportBundle\Event\AddConfigFieldMappingPresetsEvent;
use HeimrichHannot\EntityImportBundle\Importer\ImporterFactory;
-use HeimrichHannot\RequestBundle\Component\HttpFoundation\Request;
-use HeimrichHannot\UtilsBundle\Database\DatabaseUtil;
-use HeimrichHannot\UtilsBundle\Model\ModelUtil;
-use HeimrichHannot\UtilsBundle\Url\UrlUtil;
+use HeimrichHannot\UtilsBundle\Util\Utils;
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
class EntityImportConfigContainer
@@ -31,7 +31,7 @@ class EntityImportConfigContainer
self::SORTING_MODE_TARGET_FIELDS,
];
- const DELETION_MODE_MIRROR = 'mirror';
+ const DELETION_MODE_MIRROR = 'mirror';
const DELETION_MODE_TARGET_FIELDS = 'target_fields';
const DELETION_MODES = [
@@ -46,30 +46,24 @@ class EntityImportConfigContainer
];
const STATE_READY_FOR_IMPORT = 'ready_for_import';
- const STATE_SUCCESS = 'success';
- const STATE_FAILED = 'failed';
-
- protected Request $request;
- protected UrlUtil $urlUtil;
- protected ModelUtil $modelUtil;
- protected ImporterFactory $importerFactory;
- protected DatabaseUtil $databaseUtil;
+ const STATE_SUCCESS = 'success';
+ const STATE_FAILED = 'failed';
+
+ protected ImporterFactory $importerFactory;
+ protected Connection $connection;
protected EventDispatcherInterface $eventDispatcher;
+ protected Utils $utils;
public function __construct(
- Request $request,
ImporterFactory $importerFactory,
- UrlUtil $urlUtil,
- ModelUtil $modelUtil,
- DatabaseUtil $databaseUtil,
- EventDispatcherInterface $eventDispatcher
+ Connection $connection,
+ EventDispatcherInterface $eventDispatcher,
+ Utils $utils
) {
- $this->request = $request;
- $this->urlUtil = $urlUtil;
- $this->modelUtil = $modelUtil;
$this->importerFactory = $importerFactory;
- $this->databaseUtil = $databaseUtil;
+ $this->connection = $connection;
$this->eventDispatcher = $eventDispatcher;
+ $this->utils = $utils;
}
public function getDryRunOperation($row, $href, $label, $title, $icon, $attributes)
@@ -78,7 +72,7 @@ public function getDryRunOperation($row, $href, $label, $title, $icon, $attribut
return '';
}
- return ''.\Image::getHtml($icon, $label).' ';
+ return '' . Image::getHtml($icon, $label) . ' ';
}
public function setPreset(?DataContainer $dc)
@@ -89,17 +83,17 @@ public function setPreset(?DataContainer $dc)
$dca = &$GLOBALS['TL_DCA']['tl_entity_import_config'];
- $this->databaseUtil->update('tl_entity_import_config', [
+ $this->connection->update('tl_entity_import_config', [
'fieldMappingPresets' => '',
- 'fieldMapping' => serialize($dca['fields']['fieldMappingPresets']['eval']['presets'][$preset]),
- ], 'tl_entity_import_config.id='.$dc->id);
+ 'fieldMapping' => serialize($dca['fields']['fieldMappingPresets']['eval']['presets'][$preset]),
+ ], ['tl_entity_import_config.id' => $dc->id]);
}
public function initPalette(?DataContainer $dc)
{
$dca = &$GLOBALS['TL_DCA'][$dc->table];
- if (null === ($configModel = $this->modelUtil->findModelInstanceByPk($dc->table, $dc->id)) || !$configModel->targetTable) {
+ if (null === ($configModel = $this->utils->model()->findModelInstanceByPk($dc->table, $dc->id)) || !$configModel->targetTable) {
$dca['palettes']['default'] = '{general_legend},title,targetTable;';
return;
@@ -123,7 +117,7 @@ public function initPalette(?DataContainer $dc)
asort($presets);
- $dca['fields']['fieldMappingPresets']['options'] = $options;
+ $dca['fields']['fieldMappingPresets']['options'] = $options;
$dca['fields']['fieldMappingPresets']['eval']['presets'] = $presets;
}
}
@@ -137,11 +131,11 @@ public function getSourceFields(?DataContainer $dc): array
{
$options = [];
- if (null === ($configModel = $this->modelUtil->findModelInstanceByPk('tl_entity_import_config', $dc->id))) {
+ if (null === ($configModel = $this->utils->model()->findModelInstanceByPk('tl_entity_import_config', $dc->id))) {
return $options;
}
- if (null === ($sourceModel = $this->modelUtil->findModelInstanceByPk('tl_entity_import_source', $configModel->pid))) {
+ if (null === ($sourceModel = $this->utils->model()->findModelInstanceByPk('tl_entity_import_source', $configModel->pid))) {
return $options;
}
@@ -155,10 +149,12 @@ public function getSourceFields(?DataContainer $dc): array
if (null === $data['sourceValue']) {
$options[$data['name']] = $data['name'];
} else {
- $options[$data['name']] = $data['name'].' ['.$data['sourceValue'].']';
+ $options[$data['name']] = $data['name'] . ' [' . $data['sourceValue'] . ']';
}
}
+ asort($options);
+
return $options;
}
@@ -166,7 +162,7 @@ public function getTargetFields(?DataContainer $dc): array
{
$options = [];
- if (null === ($configModel = $this->modelUtil->findModelInstanceByPk('tl_entity_import_config', $dc->id)) || !$configModel->targetTable) {
+ if (null === ($configModel = $this->utils->model()->findModelInstanceByPk('tl_entity_import_config', $dc->id)) || !$configModel->targetTable) {
return $options;
}
@@ -181,9 +177,11 @@ public function getTargetFields(?DataContainer $dc): array
continue;
}
- $options[$field['name']] = $field['name'].' ['.$field['origtype'].']';
+ $options[$field['name']] = $field['name'] . ' [' . $field['origtype'] . ']';
}
+ asort($options);
+
return $options;
}
@@ -199,34 +197,37 @@ public function dryRun()
public function listItems(array $row): string
{
- return '
'.$row['title'].' ['.Date::parse(Config::get('datimFormat'), $row['dateAdded']).']
';
+ return '' . $row['title'] . ' [' . Date::parse(Config::get('datimFormat'), $row['dateAdded']) . ']
';
}
private function runImport(bool $dry = false)
{
- $config = $this->request->getGet('id');
+ $config = Input::get('id');
- if (null === ($configModel = $this->modelUtil->findModelInstanceByPk('tl_entity_import_config', $config))) {
+ if (null === ($configModel = $this->utils->model()->findModelInstanceByPk('tl_entity_import_config', $config))) {
throw new \Exception(sprintf('Entity config model of ID %s not found', $config));
}
- if (null === ($sourceModel = $this->modelUtil->findModelInstanceByPk('tl_entity_import_source', $configModel->pid))) {
+ if (null === ($sourceModel = $this->utils->model()->findModelInstanceByPk('tl_entity_import_source', $configModel->pid))) {
throw new \Exception(sprintf('Entity source model of ID %s not found', $configModel->pid));
}
if ($configModel->useCronInWebContext) {
- $configModel->importStarted = $configModel->importProgressCurrent = $configModel->importProgressTotal = $configModel->importProgressSkipped = 0;
- $configModel->state = static::STATE_READY_FOR_IMPORT;
+ $configModel->importStarted = $configModel->importProgressCurrent = $configModel->importProgressTotal = $configModel->importProgressSkipped = 0;
+ $configModel->state = static::STATE_READY_FOR_IMPORT;
$configModel->importProgressResult = '';
$configModel->save();
- throw new RedirectResponseException($this->urlUtil->addQueryString('act=edit', $this->urlUtil->removeQueryString(['key'])));
+ throw new RedirectResponseException($this->utils->url()->addQueryStringParameterToUrl('act=edit', $this->utils->url()->removeQueryStringParameterFromUrl('key')));
}
$importer = $this->importerFactory->createInstance($configModel->id);
$importer->setDryRun($dry);
$result = $importer->run();
$importer->outputFinalResultMessage($result);
- throw new RedirectResponseException($this->urlUtil->addQueryString('id='.$sourceModel->id, $this->urlUtil->removeQueryString(['key', 'id'])));
+ $url = $this->utils->url()->removeQueryStringParameterFromUrl('key');
+ $url = $this->utils->url()->removeQueryStringParameterFromUrl('id', $url);
+
+ throw new RedirectResponseException($this->utils->url()->addQueryStringParameterToUrl('id=' . $sourceModel->id, $url));
}
}
diff --git a/src/DataContainer/EntityImportQuickConfigContainer.php b/src/DataContainer/EntityImportQuickConfigContainer.php
index 5684729..4d7eeaa 100644
--- a/src/DataContainer/EntityImportQuickConfigContainer.php
+++ b/src/DataContainer/EntityImportQuickConfigContainer.php
@@ -10,59 +10,63 @@
use Contao\Controller;
use Contao\CoreBundle\Exception\RedirectResponseException;
+use Contao\CoreBundle\Framework\ContaoFramework;
use Contao\Database;
use Contao\DataContainer;
+use Contao\DcaLoader;
+use Contao\Image;
+use Contao\Input;
+use Contao\Model;
use Contao\StringUtil;
use Contao\System;
+use Doctrine\DBAL\Connection;
use HeimrichHannot\EntityImportBundle\Event\BeforeImportEvent;
use HeimrichHannot\EntityImportBundle\Event\BeforeItemImportEvent;
use HeimrichHannot\EntityImportBundle\Importer\ImporterFactory;
use HeimrichHannot\EntityImportBundle\Source\SourceFactory;
use HeimrichHannot\EntityImportBundle\Source\SourceInterface;
-use HeimrichHannot\ListWidget\ListWidget;
-use HeimrichHannot\RequestBundle\Component\HttpFoundation\Request;
-use HeimrichHannot\UtilsBundle\Database\DatabaseUtil;
-use HeimrichHannot\UtilsBundle\Dca\DcaUtil;
-use HeimrichHannot\UtilsBundle\Model\ModelUtil;
-use HeimrichHannot\UtilsBundle\Url\UrlUtil;
+use HeimrichHannot\EntityImportBundle\Util\EntityImportUtil;
+use HeimrichHannot\ListWidgetBundle\Widget\ListWidget;
+use HeimrichHannot\UtilsBundle\StaticUtil\StaticArrayUtil;
+use HeimrichHannot\UtilsBundle\Util\Utils;
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
class EntityImportQuickConfigContainer
{
- protected DatabaseUtil $databaseUtil;
- protected SourceFactory $sourceFactory;
+ const ON_DUPLICATE_KEY_IGNORE = 'IGNORE';
+ const ON_DUPLICATE_KEY_UPDATE = 'UPDATE';
+
+ protected SourceFactory $sourceFactory;
protected EventDispatcherInterface $eventDispatcher;
- protected ModelUtil $modelUtil;
- protected Request $request;
- protected ImporterFactory $importerFactory;
- protected UrlUtil $urlUtil;
- protected DcaUtil $dcaUtil;
+ protected ImporterFactory $importerFactory;
+ protected Utils $utils;
+ protected ContaoFramework $framework;
+ protected Connection $connection;
+ protected EntityImportUtil $entityImportUtil;
public function __construct(
- ModelUtil $modelUtil,
EventDispatcherInterface $eventDispatcher,
- Request $request,
ImporterFactory $importerFactory,
- UrlUtil $urlUtil,
- DcaUtil $dcaUtil,
- DatabaseUtil $databaseUtil,
- SourceFactory $sourceFactory
+ SourceFactory $sourceFactory,
+ ContaoFramework $framework,
+ Connection $connection,
+ EntityImportUtil $entityImportUtil,
+ Utils $utils
) {
$this->eventDispatcher = $eventDispatcher;
- $this->modelUtil = $modelUtil;
- $this->request = $request;
$this->importerFactory = $importerFactory;
- $this->urlUtil = $urlUtil;
- $this->dcaUtil = $dcaUtil;
- $this->databaseUtil = $databaseUtil;
$this->sourceFactory = $sourceFactory;
+ $this->utils = $utils;
+ $this->framework = $framework;
+ $this->connection = $connection;
+ $this->entityImportUtil = $entityImportUtil;
}
public function getImporterConfigs()
{
$options = [];
- if (null === ($configs = $this->modelUtil->findAllModelInstances('tl_entity_import_config', [
+ if (null === ($configs = $this->utils->model()->findModelInstancesBy('tl_entity_import_config', [], [], [
'order' => 'tl_entity_import_config.title ASC',
]))) {
return [];
@@ -77,32 +81,37 @@ public function getImporterConfigs()
public function getDryRunOperation($row, $href, $label, $title, $icon, $attributes)
{
- if (null !== ($config = $this->modelUtil->findModelInstanceByPk('tl_entity_import_config', $row['importerConfig']))) {
+ if (null !== ($config = $this->utils->model()->findModelInstanceByPk('tl_entity_import_config', $row['importerConfig']))) {
if ($config->useCronInWebContext) {
return '';
}
}
- return ''.\Image::getHtml($icon, $label).' ';
+ return ''.Image::getHtml($icon, $label).' ';
}
public function modifyDca(DataContainer $dc)
{
- if (null === ($quickImporter = $this->modelUtil->findModelInstanceByPk('tl_entity_import_quick_config', $dc->id)) || !$quickImporter->importerConfig) {
+ if (!$dc->id) {
+ return;
+ }
+
+ if (null === ($quickImporter = $this->utils->model()->findModelInstanceByPk('tl_entity_import_quick_config', $dc->id)) || !$quickImporter->importerConfig) {
return;
}
- if (null === ($importer = $this->modelUtil->findModelInstanceByPk('tl_entity_import_config', $quickImporter->importerConfig))) {
+ if (null === ($importer = $this->utils->model()->findModelInstanceByPk('tl_entity_import_config', $quickImporter->importerConfig))) {
return;
}
- if (null === ($sourceModel = $this->modelUtil->findModelInstanceByPk('tl_entity_import_source', $importer->pid))) {
+ if (null === ($sourceModel = $this->utils->model()->findModelInstanceByPk('tl_entity_import_source', $importer->pid))) {
return;
}
$dca = &$GLOBALS['TL_DCA']['tl_entity_import_quick_config'];
- $this->dcaUtil->loadDc($importer->targetTable);
+ $loader = new DcaLoader($importer->targetTable);
+ $loader->load();
$targetDca = &$GLOBALS['TL_DCA'][$importer->targetTable];
@@ -154,19 +163,19 @@ public function loadCsvRowsFromCache($config, $options = [], $context = null, $d
public function cacheCsvRows(DataContainer $dc)
{
// cache might be invalid now -> delete tl_md_recipient
- $this->databaseUtil->delete('tl_entity_import_cache', 'cache_ptable=? AND cache_pid=?', ['tl_entity_import_quick_config', $dc->id]);
+ $this->connection->delete('tl_entity_import_cache', ['cache_ptable' => 'tl_entity_import_quick_config', 'cache_pid' => $dc->id]);
// cache the rows
- if (null === ($quickImporter = $this->modelUtil->findModelInstanceByPk('tl_entity_import_quick_config', $dc->id)) ||
+ if (null === ($quickImporter = $this->utils->model()->findModelInstanceByPk('tl_entity_import_quick_config', $dc->id)) ||
!$quickImporter->importerConfig || !$quickImporter->fileSRC) {
return;
}
- if (null === ($importerConfig = $this->modelUtil->findModelInstanceByPk('tl_entity_import_config', $quickImporter->importerConfig))) {
+ if (null === ($importerConfig = $this->utils->model()->findModelInstanceByPk('tl_entity_import_config', $quickImporter->importerConfig))) {
return;
}
- if (null === ($sourceModel = $this->modelUtil->findModelInstanceByPk('tl_entity_import_source', $importerConfig->pid))) {
+ if (null === ($sourceModel = $this->utils->model()->findModelInstanceByPk('tl_entity_import_source', $importerConfig->pid))) {
return;
}
@@ -218,7 +227,7 @@ public function cacheCsvRows(DataContainer $dc)
$itemsToInsert[] = $event->getMappedItem();
}
- $this->databaseUtil->doBulkInsert('tl_entity_import_cache', $itemsToInsert, [
+ $this->doBulkInsert('tl_entity_import_cache', $itemsToInsert, [
'cache_ptable' => 'tl_entity_import_quick_config',
'cache_pid' => $dc->id,
]);
@@ -248,13 +257,17 @@ public function prepareCachedCsvRows($items, $config, $options = [], $context =
return $itemData;
}
- public function getParentEntitiesAsOptions(\Contao\DataContainer $dc)
+ public function getParentEntitiesAsOptions(DataContainer $dc): array
{
- if (null === ($quickImporter = $this->modelUtil->findModelInstanceByPk('tl_entity_import_quick_config', $dc->id)) || !$quickImporter->importerConfig) {
+ if (!$dc->id) {
+ return [];
+ }
+
+ if (null === ($quickImporter = $this->utils->model()->findModelInstanceByPk('tl_entity_import_quick_config', $dc->id)) || !$quickImporter->importerConfig) {
return [];
}
- if (null === ($importer = $this->modelUtil->findModelInstanceByPk('tl_entity_import_config', $quickImporter->importerConfig))) {
+ if (null === ($importer = $this->utils->model()->findModelInstanceByPk('tl_entity_import_config', $quickImporter->importerConfig))) {
return [];
}
@@ -264,9 +277,17 @@ public function getParentEntitiesAsOptions(\Contao\DataContainer $dc)
return [];
}
- return System::getContainer()->get('huh.utils.choice.model_instance')->getCachedChoices([
- 'dataContainer' => $dca['config']['ptable'],
- ]);
+ $options = [];
+
+ $models = $this->utils->model()->findModelInstancesBy($dca['config']['ptable'], [], []);
+
+ if (null !== $models) {
+ while ($models->next()) {
+ $options[$models->id] = $models->title ?: $models->headline ?: $models->id;
+ }
+ }
+
+ return $options;
}
public function import()
@@ -279,29 +300,30 @@ public function dryRun()
$this->runImport(true);
}
- public function getHeaderFieldsForPreview($config, $widget, \DataContainer $dc)
+ public function getHeaderFieldsForPreview($config, $widget, DataContainer $dc)
{
- if (null === ($quickImporter = $this->modelUtil->findModelInstanceByPk('tl_entity_import_quick_config', $dc->id)) || !$quickImporter->importerConfig) {
+ if (null === ($quickImporter = $this->utils->model()->findModelInstanceByPk('tl_entity_import_quick_config', $dc->id)) || !$quickImporter->importerConfig) {
return [];
}
- if (null === ($importer = $this->modelUtil->findModelInstanceByPk('tl_entity_import_config', $quickImporter->importerConfig))) {
+ if (null === ($importer = $this->utils->model()->findModelInstanceByPk('tl_entity_import_config', $quickImporter->importerConfig))) {
return [];
}
$fields = [];
foreach (StringUtil::deserialize($importer->fieldMapping, true) as $mapping) {
- $fields[$mapping['columnName']] = $this->dcaUtil->getLocalizedFieldName($mapping['columnName'], $importer->targetTable);
+ $fields[$mapping['columnName']] = $this->entityImportUtil->getLocalizedFieldName($mapping['columnName'], $importer->targetTable);
}
if (Database::getInstance()->fieldExists('pid', $importer->targetTable) && $quickImporter->parentEntity) {
- $this->dcaUtil->loadDc($importer->targetTable);
+ $loader = new DcaLoader($importer->targetTable);
+ $loader->load();
$dca = &$GLOBALS['TL_DCA'][$importer->targetTable];
if (isset($dca['config']['ptable'])) {
- $fields = array_merge(['pid' => $this->dcaUtil->getLocalizedFieldName('pid', $importer->targetTable)], $fields);
+ $fields = array_merge(['pid' => $this->entityImportUtil->getLocalizedFieldName('pid', $importer->targetTable)], $fields);
}
}
@@ -310,15 +332,15 @@ public function getHeaderFieldsForPreview($config, $widget, \DataContainer $dc)
public function getItemsForPreview($config, $widget, $dc)
{
- if (null === ($quickImporter = $this->modelUtil->findModelInstanceByPk('tl_entity_import_quick_config', $dc->id)) || !$quickImporter->importerConfig || !$quickImporter->fileSRC) {
+ if (null === ($quickImporter = $this->utils->model()->findModelInstanceByPk('tl_entity_import_quick_config', $dc->id)) || !$quickImporter->importerConfig || !$quickImporter->fileSRC) {
return [];
}
- if (null === ($importer = $this->modelUtil->findModelInstanceByPk('tl_entity_import_config', $quickImporter->importerConfig))) {
+ if (null === ($importer = $this->utils->model()->findModelInstanceByPk('tl_entity_import_config', $quickImporter->importerConfig))) {
return [];
}
- if (null === ($sourceModel = $this->modelUtil->findModelInstanceByPk('tl_entity_import_source', $importer->pid))) {
+ if (null === ($sourceModel = $this->utils->model()->findModelInstanceByPk('tl_entity_import_source', $importer->pid))) {
return [];
}
@@ -344,7 +366,8 @@ protected function addParentEntityToFieldMapping($quickImporter, $importer)
return;
}
- $this->dcaUtil->loadDc($importer->targetTable);
+ $loader = new DcaLoader($importer->targetTable);
+ $loader->load();
$dca = &$GLOBALS['TL_DCA'][$importer->targetTable];
@@ -363,17 +386,17 @@ protected function addParentEntityToFieldMapping($quickImporter, $importer)
private function runImport(bool $dry = false)
{
- $config = $this->request->getGet('id');
+ $config = Input::get('id');
- if (null === ($quickImporter = $this->modelUtil->findModelInstanceByPk('tl_entity_import_quick_config', $config)) || !$quickImporter->importerConfig) {
+ if (null === ($quickImporter = $this->utils->model()->findModelInstanceByPk('tl_entity_import_quick_config', $config)) || !$quickImporter->importerConfig) {
return;
}
- if (null === ($importerConfig = $this->modelUtil->findModelInstanceByPk('tl_entity_import_config', $quickImporter->importerConfig))) {
+ if (null === ($importerConfig = $this->utils->model()->findModelInstanceByPk('tl_entity_import_config', $quickImporter->importerConfig))) {
return;
}
- if (null === ($sourceModel = $this->modelUtil->findModelInstanceByPk('tl_entity_import_source', $importerConfig->pid))) {
+ if (null === ($sourceModel = $this->utils->model()->findModelInstanceByPk('tl_entity_import_source', $importerConfig->pid))) {
return;
}
@@ -391,12 +414,177 @@ private function runImport(bool $dry = false)
$importerConfig->importProgressResult = '';
$importerConfig->save();
- throw new RedirectResponseException($this->urlUtil->addQueryString('act=edit', $this->urlUtil->removeQueryString(['key'])));
+ throw new RedirectResponseException($this->utils->url()->addQueryStringParameterToUrl('act=edit', $this->utils->url()->removeQueryStringParameterFromUrl('key')));
}
$importer->setDryRun($dry);
$result = $importer->run();
$importer->outputFinalResultMessage($result);
- throw new RedirectResponseException($this->urlUtil->removeQueryString(['key', 'id']));
+ $url = $this->utils->url()->removeQueryStringParameterFromUrl('key');
+ $url = $this->utils->url()->removeQueryStringParameterFromUrl('id', $url);
+
+ throw new RedirectResponseException($url);
+ }
+
+ /**
+ * Bulk insert SQL of given data.
+ *
+ * @param string $table The database table, where new items should be stored inside
+ * @param array $data An array of values associated to its field
+ * @param array $fixedValues A array of fixed values associated to its field that should be set for each row as fixed values
+ * @param mixed $onDuplicateKey null = Throw error on duplicates, self::ON_DUPLICATE_KEY_IGNORE = ignore error duplicates (skip this entries),
+ * self::ON_DUPLICATE_KEY_UPDATE = update existing entries
+ * @param callable $callback A callback that should be triggered after each cycle, contains $arrValues of current cycle
+ * @param callable $itemCallback A callback to change the insert values for each items, contains $arrValues as first argument, $arrFields as
+ * second, $arrOriginal as third, expects an array as return value with same order as $arrFields, if no array is
+ * returned, insert of the row will be skipped item insert
+ * @param int $bulkSize The bulk size
+ * @param string $pk The primary key of the current table (default: id)
+ */
+ public function doBulkInsert(
+ string $table,
+ array $data = [],
+ array $fixedValues = [],
+ $onDuplicateKey = null,
+ $callback = null,
+ $itemCallback = null,
+ int $bulkSize = 100,
+ string $pk = 'id'
+ ) {
+ /** @var Database $database */
+ $database = $this->framework->createInstance(Database::class);
+
+ if (!$database->tableExists($table) || empty($data)) {
+ return null;
+ }
+
+ $fields = $database->getFieldNames($table, true);
+ StaticArrayUtil::removeValue($pk, $fields); // unset id
+ $fields = array_values($fields);
+
+ $bulkSize = (int) $bulkSize;
+
+ $query = '';
+ $duplicateKey = '';
+ $startQuery = sprintf('INSERT %s INTO %s (%s) VALUES ', self::ON_DUPLICATE_KEY_IGNORE === $onDuplicateKey ? 'IGNORE' : '', $table, implode(',', $fields));
+
+ if (self::ON_DUPLICATE_KEY_UPDATE === $onDuplicateKey) {
+ $duplicateKey = ' ON DUPLICATE KEY UPDATE '.implode(
+ ',',
+ array_map(
+ function ($val) {
+ // escape double quotes
+ return $val.' = VALUES('.$val.')';
+ },
+ $fields
+ )
+ );
+ }
+
+ $i = 0;
+
+ $columnWildcards = array_map(
+ function ($val) {
+ return '?';
+ },
+ $fields
+ );
+
+ foreach ($data as $key => $varData) {
+ if (0 === $i) {
+ $values = [];
+ $return = [];
+ $query = $startQuery;
+ }
+
+ $columns = $columnWildcards;
+
+ if ($varData instanceof Model) {
+ $varData = $varData->row();
+ }
+
+ foreach ($fields as $n => $strField) {
+ $varValue = isset($varData[$strField]) ? $varData[$strField] : 'DEFAULT';
+
+ if (\in_array($strField, array_keys($fixedValues))) {
+ $varValue = $fixedValues[$strField];
+ }
+
+ // replace SQL Keyword DEFAULT within wildcards ?
+ if ('DEFAULT' === $varValue) {
+ $columns[$n] = 'DEFAULT';
+
+ continue;
+ }
+
+ $return[$i][$strField] = $varValue;
+ }
+
+ // manipulate the item
+ if (\is_callable($itemCallback)) {
+ if (!isset($return[$i])) {
+ continue;
+ }
+ $varCallback = \call_user_func_array($itemCallback, [$return[$i], $fields, $varData]);
+
+ if (!\is_array($varCallback)) {
+ continue;
+ }
+
+ foreach ($fields as $n => $strField) {
+ $varValue = isset($varCallback[$strField]) ? $varCallback[$strField] : 'DEFAULT';
+
+ // replace SQL Keyword DEFAULT within wildcards ?
+ if ('DEFAULT' === $varValue) {
+ $columns[$n] = 'DEFAULT';
+
+ continue;
+ }
+
+ $columns[$n] = '?';
+ $return[$i][$strField] = $varValue;
+ }
+ }
+
+ // add values to insert array
+ $values = array_merge($values, array_values($return[$i]));
+
+ $query .= '('.implode(',', $columns).'),';
+
+ ++$i;
+
+ if ($bulkSize === $i) {
+ $query = rtrim($query, ',');
+
+ if (self::ON_DUPLICATE_KEY_UPDATE === $onDuplicateKey) {
+ $query .= $duplicateKey;
+ }
+
+ $database->prepare($query)->execute($values);
+
+ if (\is_callable($callback)) {
+ \call_user_func_array($callback, [$return]);
+ }
+
+ $query = '';
+
+ $i = 0;
+ }
+ }
+
+ // remaining elements < $intBulkSize
+ if ($query) {
+ $query = rtrim($query, ',');
+
+ if (self::ON_DUPLICATE_KEY_UPDATE === $onDuplicateKey) {
+ $query .= $duplicateKey;
+ }
+
+ $database->prepare($query)->execute($values);
+
+ if (\is_callable($callback)) {
+ \call_user_func_array($callback, [$return]);
+ }
+ }
}
}
diff --git a/src/DataContainer/EntityImportSourceContainer.php b/src/DataContainer/EntityImportSourceContainer.php
index 6ac0805..023ae82 100644
--- a/src/DataContainer/EntityImportSourceContainer.php
+++ b/src/DataContainer/EntityImportSourceContainer.php
@@ -8,19 +8,18 @@
namespace HeimrichHannot\EntityImportBundle\DataContainer;
-use Contao\Database;
use Contao\DataContainer;
use Contao\Message;
use Contao\Model;
use Contao\System;
+use Doctrine\DBAL\Connection;
use HeimrichHannot\EntityImportBundle\Event\AddSourceFieldMappingPresetsEvent;
use HeimrichHannot\EntityImportBundle\Source\AbstractFileSource;
use HeimrichHannot\EntityImportBundle\Source\CSVFileSource;
use HeimrichHannot\EntityImportBundle\Source\RSSFileSource;
use HeimrichHannot\EntityImportBundle\Source\SourceFactory;
use HeimrichHannot\EntityImportBundle\Util\EntityImportUtil;
-use HeimrichHannot\UtilsBundle\Database\DatabaseUtil;
-use HeimrichHannot\UtilsBundle\Model\ModelUtil;
+use HeimrichHannot\UtilsBundle\Util\Utils;
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
class EntityImportSourceContainer
@@ -59,20 +58,20 @@ class EntityImportSourceContainer
protected $database;
protected $cache;
- protected ModelUtil $modelUtil;
- protected SourceFactory $sourceFactory;
- protected EntityImportUtil $util;
+ protected SourceFactory $sourceFactory;
+ protected EntityImportUtil $util;
protected EventDispatcherInterface $eventDispatcher;
- protected DatabaseUtil $databaseUtil;
+ protected Utils $utils;
+ protected Connection $connection;
- public function __construct(SourceFactory $sourceFactory, ModelUtil $modelUtil, EntityImportUtil $util, EventDispatcherInterface $eventDispatcher, DatabaseUtil $databaseUtil)
+ public function __construct(SourceFactory $sourceFactory, EntityImportUtil $util, EventDispatcherInterface $eventDispatcher, Connection $connection, Utils $utils)
{
$this->activeBundles = System::getContainer()->getParameter('kernel.bundles');
$this->sourceFactory = $sourceFactory;
- $this->modelUtil = $modelUtil;
$this->util = $util;
$this->eventDispatcher = $eventDispatcher;
- $this->databaseUtil = $databaseUtil;
+ $this->utils = $utils;
+ $this->connection = $connection;
}
public function setPreset(?DataContainer $dc)
@@ -83,15 +82,15 @@ public function setPreset(?DataContainer $dc)
$dca = &$GLOBALS['TL_DCA']['tl_entity_import_source'];
- $this->databaseUtil->update('tl_entity_import_source', [
+ $this->connection->update('tl_entity_import_source', [
'fieldMappingPresets' => '',
'fieldMapping' => serialize($dca['fields']['fieldMappingPresets']['eval']['presets'][$preset]),
- ], 'tl_entity_import_source.id='.$dc->id);
+ ], ['tl_entity_import_source.id' => $dc->id]);
}
public function initPalette(?DataContainer $dc)
{
- if (null === ($sourceModel = $this->modelUtil->findModelInstanceByPk($dc->table, $dc->id))) {
+ if (null === ($sourceModel = $this->utils->model()->findModelInstanceByPk($dc->table, $dc->id ?: 0))) {
return;
}
@@ -105,7 +104,11 @@ public function initPalette(?DataContainer $dc)
$dca['palettes'][static::TYPE_DATABASE] = str_replace('fieldMapping', '', $dca['palettes'][static::TYPE_DATABASE]);
} else {
try {
- $options = array_values(Database::getInstance($sourceModel->row())->getFieldNames($sourceModel->dbSourceTable, true));
+ $connection = $this->util->getDbalConnectionBySource($sourceModel->row());
+ $schemaManager = $connection->createSchemaManager();
+
+ $options = array_keys($schemaManager->listTableColumns($sourceModel->dbSourceTable));
+ asort($options);
$this->util->transformFieldMappingSourceValueToSelect(
array_combine($options, $options)
@@ -135,6 +138,8 @@ public function initPalette(?DataContainer $dc)
}
}
+ asort($options);
+
$this->util->transformFieldMappingSourceValueToSelect(
$options
);
@@ -159,6 +164,8 @@ public function initPalette(?DataContainer $dc)
$options = $source->getPostFieldsAsOptions();
+ asort($options);
+
$this->util->transformFieldMappingSourceValueToSelect(
array_combine($options, $options)
);
@@ -193,7 +200,7 @@ public function initPalette(?DataContainer $dc)
public function onLoadFileContent(?string $value, ?DataContainer $dc)
{
- if (null === ($sourceModel = $this->modelUtil->findModelInstanceByPk('tl_entity_import_source', $dc->id))) {
+ if (null === ($sourceModel = $this->utils->model()->findModelInstanceByPk('tl_entity_import_source', $dc->id))) {
return '';
}
@@ -240,12 +247,15 @@ public function getFileContent(Model $sourceModel)
public function getAllTargetTables(?DataContainer $dc): array
{
- if (null === ($source = $this->modelUtil->findModelInstanceByPk('tl_entity_import_source', $dc->id))) {
+ if (null === ($source = $this->utils->model()->findModelInstanceByPk('tl_entity_import_source', $dc->id))) {
return [];
}
try {
- $options = array_values(Database::getInstance($source->row())->listTables(null, true));
+ $connection = $this->util->getDbalConnectionBySource($source->row());
+ $schemaManager = $connection->createSchemaManager();
+
+ $options = array_values($schemaManager->listTableNames());
} catch (\Exception $e) {
Message::addError(sprintf($GLOBALS['TL_LANG']['MSC']['entityImport']['dbConnectionError'], $e->getMessage()));
diff --git a/src/DependencyInjection/HeimrichHannotEntityImportExtension.php b/src/DependencyInjection/HeimrichHannotEntityImportExtension.php
index ad3f6a6..a6d46bb 100644
--- a/src/DependencyInjection/HeimrichHannotEntityImportExtension.php
+++ b/src/DependencyInjection/HeimrichHannotEntityImportExtension.php
@@ -23,7 +23,7 @@ public function load(array $configs, ContainerBuilder $container)
$container->setParameter(Configuration::ROOT_ID, $this->processConfiguration($configuration, $configs));
}
- public function getAlias()
+ public function getAlias(): string
{
return Configuration::ROOT_ID;
}
diff --git a/src/EventListener/Contao/LoadDataContainerListener.php b/src/EventListener/Contao/LoadDataContainerListener.php
new file mode 100644
index 0000000..5ccc20e
--- /dev/null
+++ b/src/EventListener/Contao/LoadDataContainerListener.php
@@ -0,0 +1,31 @@
+utils = $utils;
+ }
+
+ public function __invoke(string $table): void
+ {
+ if ($this->utils->container()->isBackend()) {
+ $GLOBALS['TL_CSS']['be_entityimportbundle'] = 'bundles/heimrichhannotcontaoentityimport/css/contao-entity-import-bundle-be.min.css|static';
+ $GLOBALS['TL_JAVASCRIPT']['be_entityimportbundle'] = 'bundles/heimrichhannotcontaoentityimport/js/contao-entity-import-bundle-be.min.js|static';
+ }
+ }
+}
diff --git a/src/EventListener/Contao/SqlGetFromDcaEventListener.php b/src/EventListener/Contao/SqlGetFromDcaEventListener.php
index 68a6529..7460ae2 100644
--- a/src/EventListener/Contao/SqlGetFromDcaEventListener.php
+++ b/src/EventListener/Contao/SqlGetFromDcaEventListener.php
@@ -10,20 +10,17 @@
use Contao\CoreBundle\Framework\ContaoFramework;
use Contao\Database;
-use HeimrichHannot\UtilsBundle\Model\ModelUtil;
use HeimrichHannot\UtilsBundle\Util\Utils;
class SqlGetFromDcaEventListener
{
protected Utils $utils;
- protected ModelUtil $modelUtil;
protected ContaoFramework $framework;
- public function __construct(ContaoFramework $framework, Utils $utils, ModelUtil $modelUtil)
+ public function __construct(ContaoFramework $framework, Utils $utils)
{
$this->framework = $framework;
$this->utils = $utils;
- $this->modelUtil = $modelUtil;
}
public function __invoke(array $sqlDcaData)
@@ -44,7 +41,7 @@ public function __invoke(array $sqlDcaData)
}
// add cache fields to tl_entity_import_cache
- if (null === ($importers = $this->modelUtil->findModelInstancesBy('tl_entity_import_config', [
+ if (null === ($importers = $this->utils->model()->findModelInstancesBy('tl_entity_import_config', [
'tl_entity_import_config.useCacheForQuickImporters=?',
], [
true,
diff --git a/src/EventListener/LoadProgressListener.php b/src/EventListener/LoadProgressListener.php
index 4b158ab..688b3b2 100644
--- a/src/EventListener/LoadProgressListener.php
+++ b/src/EventListener/LoadProgressListener.php
@@ -12,8 +12,7 @@
use HeimrichHannot\EntityImportBundle\Importer\ImporterInterface;
use HeimrichHannot\ProgressBarWidgetBundle\Event\LoadProgressEvent;
use HeimrichHannot\ProgressBarWidgetBundle\Widget\ProgressBar;
-use HeimrichHannot\RequestBundle\Component\HttpFoundation\Request;
-use HeimrichHannot\UtilsBundle\Model\ModelUtil;
+use HeimrichHannot\UtilsBundle\Util\Utils;
use Terminal42\ServiceAnnotationBundle\Annotation\ServiceTag;
/**
@@ -21,28 +20,26 @@
*/
class LoadProgressListener
{
- protected Request $request;
- protected ModelUtil $modelUtil;
+ protected Utils $utils;
- public function __construct(ModelUtil $modelUtil, Request $request)
+ public function __construct(Utils $utils)
{
- $this->request = $request;
- $this->modelUtil = $modelUtil;
+ $this->utils = $utils;
}
public function __invoke(LoadProgressEvent $event)
{
if ('tl_entity_import_quick_config' === $event->getTable()) {
- if (null === ($quickImporter = $this->modelUtil->findModelInstanceByPk('tl_entity_import_quick_config', $event->getId())) ||
+ if (null === ($quickImporter = $this->utils->model()->findModelInstanceByPk('tl_entity_import_quick_config', $event->getId())) ||
!$quickImporter->importerConfig) {
return;
}
- if (null === ($importConfig = $this->modelUtil->findModelInstanceByPk('tl_entity_import_config', $quickImporter->importerConfig))) {
+ if (null === ($importConfig = $this->utils->model()->findModelInstanceByPk('tl_entity_import_config', $quickImporter->importerConfig))) {
return;
}
} else {
- if (null === ($importConfig = $this->modelUtil->findModelInstanceByPk('tl_entity_import_config', $event->getId()))) {
+ if (null === ($importConfig = $this->utils->model()->findModelInstanceByPk('tl_entity_import_config', $event->getId()))) {
return;
}
}
diff --git a/src/HeimrichHannotContaoEntityImportBundle.php b/src/HeimrichHannotContaoEntityImportBundle.php
index 45a3c86..f3750ca 100644
--- a/src/HeimrichHannotContaoEntityImportBundle.php
+++ b/src/HeimrichHannotContaoEntityImportBundle.php
@@ -9,12 +9,18 @@
namespace HeimrichHannot\EntityImportBundle;
use HeimrichHannot\EntityImportBundle\DependencyInjection\HeimrichHannotEntityImportExtension;
+use Symfony\Component\DependencyInjection\Extension\ExtensionInterface;
use Symfony\Component\HttpKernel\Bundle\Bundle;
class HeimrichHannotContaoEntityImportBundle extends Bundle
{
- public function getContainerExtension()
+ public function getContainerExtension(): ?ExtensionInterface
{
return new HeimrichHannotEntityImportExtension();
}
+
+ public function getPath(): string
+ {
+ return \dirname(__DIR__);
+ }
}
diff --git a/src/Importer/Importer.php b/src/Importer/Importer.php
index 0c6beae..95f6242 100644
--- a/src/Importer/Importer.php
+++ b/src/Importer/Importer.php
@@ -12,14 +12,18 @@
use Contao\Controller;
use Contao\CoreBundle\Exception\RedirectResponseException;
use Contao\CoreBundle\Framework\ContaoFramework;
+use Contao\CoreBundle\InsertTag\InsertTagParser;
use Contao\Database;
+use Contao\DcaLoader;
use Contao\Email;
use Contao\File;
use Contao\Folder;
+use Contao\Input;
use Contao\Message;
-use Contao\Model;
+use Contao\StringUtil;
use Contao\System;
use Contao\Validator;
+use Doctrine\DBAL\Connection;
use HeimrichHannot\EntityImportBundle\DataContainer\EntityImportConfigContainer;
use HeimrichHannot\EntityImportBundle\Event\AfterImportEvent;
use HeimrichHannot\EntityImportBundle\Event\AfterItemImportEvent;
@@ -28,61 +32,51 @@
use HeimrichHannot\EntityImportBundle\Event\BeforeItemImportEvent;
use HeimrichHannot\EntityImportBundle\Model\EntityImportConfigModel;
use HeimrichHannot\EntityImportBundle\Source\SourceInterface;
-use HeimrichHannot\RequestBundle\Component\HttpFoundation\Request;
-use HeimrichHannot\UtilsBundle\Database\DatabaseUtil;
-use HeimrichHannot\UtilsBundle\Dca\DcaUtil;
-use HeimrichHannot\UtilsBundle\File\FileUtil;
+use HeimrichHannot\EntityImportBundle\Util\EntityImportUtil;
use HeimrichHannot\UtilsBundle\Util\Utils;
use Psr\Log\LogLevel;
use Symfony\Component\Config\Definition\Exception\Exception;
use Symfony\Component\Console\Style\SymfonyStyle;
-use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\Stopwatch\Stopwatch;
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
class Importer implements ImporterInterface
{
- protected SourceInterface $source;
- protected EntityImportConfigModel $configModel;
- protected bool $dryRun = false;
- protected bool $webCronMode = false;
+ protected SourceInterface $source;
+ protected EntityImportConfigModel $configModel;
+ protected bool $dryRun = false;
+ protected bool $webCronMode = false;
protected EventDispatcherInterface $eventDispatcher;
- protected Stopwatch $stopwatch;
- protected DatabaseUtil $databaseUtil;
- protected DcaUtil $dcaUtil;
- protected ContainerInterface $container;
- protected $dbMergeCache;
- protected Request $request;
- protected FileUtil $fileUtil;
- protected Utils $utils;
- protected SymfonyStyle $io;
- protected ContaoFramework $framework;
+ protected Stopwatch $stopwatch;
+ protected $dbMergeCache;
+ protected Utils $utils;
+ protected SymfonyStyle $io;
+ protected ContaoFramework $framework;
+ protected Connection $connection;
+ protected EntityImportUtil $entityImportUtil;
+ protected InsertTagParser $insertTagParser;
/**
* Importer constructor.
*/
public function __construct(
- ContainerInterface $container,
ContaoFramework $framework,
- Model $configModel,
+ EntityImportConfigModel $configModel,
SourceInterface $source,
EventDispatcherInterface $eventDispatcher,
- Request $request,
- DatabaseUtil $databaseUtil,
- DcaUtil $dcaUtil,
- FileUtil $fileUtil,
- Utils $utils
+ Connection $connection,
+ EntityImportUtil $entityImportUtil,
+ Utils $utils,
+ InsertTagParser $insertTagParser
) {
- $this->container = $container;
- $this->configModel = $configModel;
- $this->source = $source;
- $this->databaseUtil = $databaseUtil;
- $this->eventDispatcher = $eventDispatcher;
- $this->dcaUtil = $dcaUtil;
- $this->request = $request;
- $this->fileUtil = $fileUtil;
- $this->utils = $utils;
- $this->framework = $framework;
+ $this->configModel = $configModel;
+ $this->source = $source;
+ $this->eventDispatcher = $eventDispatcher;
+ $this->utils = $utils;
+ $this->framework = $framework;
+ $this->connection = $connection;
+ $this->entityImportUtil = $entityImportUtil;
+ $this->insertTagParser = $insertTagParser;
}
public function setInputOutput(SymfonyStyle $io): void
@@ -97,7 +91,7 @@ public function run(): array
{
$this->stopwatch = new Stopwatch();
- $this->stopwatch->start('contao-entity-import-bundle.id'.$this->configModel->id);
+ $this->stopwatch->start('contao-entity-import-bundle.id' . $this->configModel->id);
try {
$items = $this->getDataFromSource();
@@ -147,7 +141,7 @@ public function getMappedItems(array $options = []): array
$mappedItems = [];
- $mapping = \Contao\StringUtil::deserialize($this->configModel->fieldMapping, true);
+ $mapping = StringUtil::deserialize($this->configModel->fieldMapping, true);
$mapping = $this->adjustMappingForDcMultilingual($mapping);
$mapping = $this->adjustMappingForChangeLanguage($mapping);
@@ -158,7 +152,7 @@ public function getMappedItems(array $options = []): array
$localizedItem = [];
foreach ($mappedItem as $field => $value) {
- $localizedItem[$this->dcaUtil->getLocalizedFieldName($field, $this->configModel->targetTable)] = $value;
+ $localizedItem[$this->entityImportUtil->getLocalizedFieldName($field, $this->configModel->targetTable)] = $value;
}
$mappedItem = $localizedItem;
@@ -189,7 +183,7 @@ public function outputResultMessage(string $message, string $type): void
$messages = json_decode($this->configModel->importProgressResult, true);
$messages[] = [
- 'type' => $type,
+ 'type' => $type,
'message' => $message,
];
@@ -197,7 +191,7 @@ public function outputResultMessage(string $message, string $type): void
} else {
$this->configModel->importProgressResult = json_encode([
[
- 'type' => $type,
+ 'type' => $type,
'message' => $message,
],
]);
@@ -242,11 +236,11 @@ public function outputFinalResultMessage(array $result): void
if ('error' === $result['state']) {
$message = $GLOBALS['TL_LANG']['tl_entity_import_config']['error']['errorImport']
- ."\n\n".$GLOBALS['TL_LANG']['tl_entity_import_config']['error']['error'].':'."\n\n".($result['error'] ?? '');
+ . "\n\n" . $GLOBALS['TL_LANG']['tl_entity_import_config']['error']['error'] . ':' . "\n\n" . ($result['error'] ?? '');
$this->outputResultMessage($message, static::MESSAGE_TYPE_ERROR);
} else {
- $count = $result['count'];
+ $count = $result['count'];
$duration = $result['duration'];
$duration = str_replace('.', ',', round($duration / 1000, 2));
@@ -265,8 +259,8 @@ public function outputFinalResultMessage(array $result): void
}
}
- if ($this->request->getGet('redirect_url')) {
- throw new RedirectResponseException(html_entity_decode($this->request->getGet('redirect_url')));
+ if (Input::get('redirect_url')) {
+ throw new RedirectResponseException(html_entity_decode(Input::get('redirect_url')));
}
}
@@ -283,13 +277,17 @@ public function sendErrorEmail(string $errorMessage)
}
if (isset($config['email']) && $config['email']) {
- $email = new Email();
+ $email = new Email();
$email->subject = sprintf($GLOBALS['TL_LANG']['MSC']['entityImport']['exceptionEmailSubject'], $this->configModel->title);
- $email->text = sprintf('An error occurred on domain "%s"', $this->configModel->cronDomain).' : '.$errorMessage;
+ $email->text = sprintf('An error occurred on domain "%s"', $this->configModel->cronDomain) . ' : ' . $errorMessage;
$email->sendTo($this->configModel->errorNotificationEmail ?: $GLOBALS['TL_CONFIG']['adminEmail']);
}
- $this->databaseUtil->update('tl_entity_import_config', ['errorNotificationLock' => '1'], 'tl_entity_import_config.id=?', [$this->configModel->id]);
+ $this->connection->update(
+ 'tl_entity_import_config',
+ ['errorNotificationLock' => '1'],
+ ['tl_entity_import_config.id' => $this->configModel->id]
+ );
}
public function postProcess(string $table, array $mappedItems, array $dbIdMapping, array $dbItemMapping)
@@ -305,9 +303,9 @@ public function postProcess(string $table, array $mappedItems, array $dbIdMappin
}
if (!$this->dryRun) {
- $this->databaseUtil->update($table, [
- $table.'.'.$langPidField => $dbIdMapping[$itemMapping['source']['langPid']],
- ], "$table.id=?", [$itemMapping['target']->id]);
+ $this->connection->update($table, [
+ $table . '.' . $langPidField => $dbIdMapping[$itemMapping['source']['langPid']],
+ ], ["$table.id" => $itemMapping['target']->id]);
}
}
}
@@ -321,9 +319,9 @@ public function postProcess(string $table, array $mappedItems, array $dbIdMappin
}
if (!$this->dryRun) {
- $this->databaseUtil->update($table, [
- $table.'.draftParent' => $dbIdMapping[$itemMapping['source']['draftParent']],
- ], "$table.id=?", [$itemMapping['target']->id]);
+ $this->connection->update($table, [
+ $table . '.draftParent' => $dbIdMapping[$itemMapping['source']['draftParent']],
+ ], ["$table.id" => $itemMapping['target']->id]);
}
}
}
@@ -336,16 +334,16 @@ public function postProcess(string $table, array $mappedItems, array $dbIdMappin
}
// map the languageMain id
- $newsroomPost = $this->databaseUtil->findOneResultBy($table, [
- $table.'.'.$this->configModel->changeLanguageTargetExternalIdField.'=?',
+ $newsroomPost = $this->entityImportUtil->findOneResultBy($table, [
+ $table . '.' . $this->configModel->changeLanguageTargetExternalIdField . '=?',
], [
$itemMapping['source']['languageMain'],
]);
if (!$this->dryRun && $newsroomPost->numRows > 0) {
- $this->databaseUtil->update($table, [
- $table.'.languageMain' => $newsroomPost->id,
- ], "$table.id=?", [$itemMapping['target']->id]);
+ $this->connection->update($table, [
+ $table . '.languageMain' => $newsroomPost->id,
+ ], ["$table.id" => $itemMapping['target']->id]);
}
}
}
@@ -353,7 +351,7 @@ public function postProcess(string $table, array $mappedItems, array $dbIdMappin
$this->deleteAfterImport($mappedItems);
$this->applySorting();
- $this->databaseUtil->commitTransaction();
+ $this->entityImportUtil->commitTransaction();
}
protected function applyFieldMappingToSourceItem(array $item, array $mapping): ?array
@@ -368,7 +366,7 @@ protected function applyFieldMappingToSourceItem(array $item, array $mapping): ?
if ('source_value' === $mappingElement['valueType']) {
$mapped[$mappingElement['columnName']] = $item[$mappingElement['mappingValue']] ?? null;
} elseif ('static_value' === $mappingElement['valueType']) {
- $mapped[$mappingElement['columnName']] = $this->framework->getAdapter(Controller::class)->replaceInsertTags($mappingElement['staticValue']);
+ $mapped[$mappingElement['columnName']] = $this->insertTagParser->replace($mappingElement['staticValue']);
}
// only trim if string -> else e.g. int or null would be translated to string leading to mysql errors
@@ -382,19 +380,19 @@ protected function applyFieldMappingToSourceItem(array $item, array $mapping): ?
protected function executeImport(array $items): array
{
- $this->dcaUtil->loadLanguageFile('default');
- $this->dcaUtil->loadLanguageFile('tl_entity_import_config');
+ System::loadLanguageFile('default');
+ System::loadLanguageFile('tl_entity_import_config');
$database = Database::getInstance();
- $table = $this->configModel->targetTable;
+ $table = $this->configModel->targetTable;
if (!$database->tableExists($table)) {
throw new Exception($GLOBALS['TL_LANG']['tl_entity_import_config']['error']['tableDoesNotExist']);
}
try {
- $count = 0;
- $targetTableColumns = $database->getFieldNames($table);
+ $count = 0;
+ $targetTableColumns = $database->getFieldNames($table);
$targetTableColumnData = [];
foreach ($database->listFields($table) as $columnData) {
@@ -405,15 +403,15 @@ protected function executeImport(array $items): array
$mode = $this->configModel->importMode;
- $mapping = \Contao\StringUtil::deserialize($this->configModel->fieldMapping, true);
+ $mapping = StringUtil::deserialize($this->configModel->fieldMapping, true);
$mapping = $this->adjustMappingForDcMultilingual($mapping);
$mapping = $this->adjustMappingForChangeLanguage($mapping);
- $dbIdMapping = [];
+ $dbIdMapping = [];
$dbItemMapping = [];
if ('merge' === $mode) {
- $mergeIdentifiers = \Contao\StringUtil::deserialize($this->configModel->mergeIdentifierFields, true);
+ $mergeIdentifiers = StringUtil::deserialize($this->configModel->mergeIdentifierFields, true);
if (empty(array_filter($mergeIdentifiers))) {
throw new Exception($GLOBALS['TL_LANG']['tl_entity_import_config']['error']['noIdentifierFields']);
@@ -430,7 +428,7 @@ protected function executeImport(array $items): array
$this->deleteBeforeImport();
- $this->databaseUtil->beginTransaction();
+ $this->entityImportUtil->beginTransaction();
foreach ($items as $item) {
$mappedItem = $this->applyFieldMappingToSourceItem($item, $mapping);
@@ -458,7 +456,7 @@ protected function executeImport(array $items): array
$this->dryRun
), BeforeItemImportEvent::NAME);
- $item = $event->getItem();
+ $item = $event->getItem();
$mappedItem = $event->getMappedItem();
// developer can decide to skip the item in an event listener if certain criteria is met
@@ -476,10 +474,10 @@ protected function executeImport(array $items): array
if ('insert' === $mode) {
if (!$this->dryRun) {
- $statement = $this->databaseUtil->insert($table, $mappedItem);
+ $this->connection->insert($table, $mappedItem);
- $record = (object) $mappedItem;
- $record->id = $statement->insertId;
+ $record = (object)$mappedItem;
+ $record->id = $this->connection->lastInsertId();
$set = $this->setDateAdded($record);
$set = array_merge($set, $this->generateAlias($record));
@@ -487,7 +485,7 @@ protected function executeImport(array $items): array
$set = array_merge($set, $this->applyFieldFileMapping($record, $mappedItem));
if (!empty($set) && !$this->dryRun) {
- $this->databaseUtil->update($table, $set, "$table.id=?", [$record->id]);
+ $this->connection->update($table, $set, ["$table.id" => $record->id]);
}
$importedRecord = $record;
@@ -498,10 +496,10 @@ protected function executeImport(array $items): array
}, $identifierFields));
if ($key && isset($this->dbMergeCache[$key]) &&
- ($existingRecord = $this->databaseUtil->findResultByPk($table, $this->dbMergeCache[$key])) && $existingRecord->numRows > 0) {
+ ($existingRecord = $this->entityImportUtil->findResultByPk($table, $this->dbMergeCache[$key])) && $existingRecord->numRows > 0) {
$this->updateMappingItemForSkippedFields($mappedItem);
- $existing = (object) $existingRecord->row();
+ $existing = (object)$existingRecord->row();
$set = $this->setDateAdded($existing);
$set = array_merge($set, $this->generateAlias($existing));
@@ -509,16 +507,16 @@ protected function executeImport(array $items): array
$set = array_merge($set, $this->applyFieldFileMapping($existing, $mappedItem));
if (!$this->dryRun) {
- $this->databaseUtil->update($table, array_merge($mappedItem, $set), "$table.id=?", [$existing->id]);
+ $this->connection->update($table, array_merge($mappedItem, $set), ["$table.id" => $existing->id]);
}
$importedRecord = $existing;
} else {
if (!$this->dryRun) {
- $statement = $this->databaseUtil->insert($table, $mappedItem);
+ $this->connection->insert($table, $mappedItem);
- $record = (object) $mappedItem;
- $record->id = $statement->insertId;
+ $record = (object)$mappedItem;
+ $record->id = $this->connection->lastInsertId();
$set = $this->setDateAdded($record);
$set = array_merge($set, $this->generateAlias($record));
@@ -526,7 +524,7 @@ protected function executeImport(array $items): array
$set = array_merge($set, $this->applyFieldFileMapping($record, $mappedItem));
if (!empty($set) && !$this->dryRun) {
- $this->databaseUtil->update($table, $set, "$table.id=?", [$record->id]);
+ $this->connection->update($table, $set, ["$table.id" => $record->id]);
}
$importedRecord = $record;
@@ -543,17 +541,19 @@ protected function executeImport(array $items): array
$dbItemMapping[] = [
'source' => [
- 'langPid' => $item['langPid'] ?? null,
- 'draftParent' => $item['draftParent'] ?? null,
+ 'langPid' => $item['langPid'] ?? null,
+ 'draftParent' => $item['draftParent'] ?? null,
'languageMain' => $item['languageMain'] ?? null,
],
'target' => [
- 'id' => $importedRecord->id,
+ 'id' => $importedRecord ? $importedRecord->id : 0,
],
];
// categories bundle
- $this->importCategoryAssociations($mapping, $item, $importedRecord->id);
+ if (!$this->dryRun) {
+ $this->importCategoryAssociations($mapping, $item, $importedRecord->id);
+ }
/* @var AfterItemImportEvent $event */
$this->eventDispatcher->dispatch(new AfterItemImportEvent(
@@ -581,7 +581,7 @@ protected function executeImport(array $items): array
$this->postProcess($table, $mappedItems, $dbIdMapping, $dbItemMapping);
} catch (\Exception $e) {
- $this->stopwatch->stop('contao-entity-import-bundle.id'.$this->configModel->id);
+ $this->stopwatch->stop('contao-entity-import-bundle.id' . $this->configModel->id);
$this->sendErrorEmail($e->getMessage());
@@ -591,20 +591,20 @@ protected function executeImport(array $items): array
];
}
- $event = $this->stopwatch->stop('contao-entity-import-bundle.id'.$this->configModel->id);
+ $event = $this->stopwatch->stop('contao-entity-import-bundle.id' . $this->configModel->id);
$duration = $event->getDuration();
if ($this->configModel->errorNotificationLock) {
- $this->databaseUtil->update('tl_entity_import_config', ['errorNotificationLock' => ''], 'tl_entity_import_config.id=?', [$this->configModel->id]);
+ $this->connection->update('tl_entity_import_config', ['errorNotificationLock' => ''], ['tl_entity_import_config.id' => $this->configModel->id]);
}
return [
- 'state' => 'success',
- 'count' => $count,
- 'duration' => $duration,
- 'mappedItems' => $mappedItems,
- 'dbIdMapping' => $dbIdMapping,
+ 'state' => 'success',
+ 'count' => $count,
+ 'duration' => $duration,
+ 'mappedItems' => $mappedItems,
+ 'dbIdMapping' => $dbIdMapping,
'dbItemMapping' => $dbItemMapping,
];
}
@@ -634,7 +634,7 @@ protected function updateMappingItemForSkippedFields(array &$mappingItem): void
return;
}
- $skipFields = \Contao\StringUtil::deserialize($this->configModel->skipFieldsOnMerge, true);
+ $skipFields = StringUtil::deserialize($this->configModel->skipFieldsOnMerge, true);
foreach ($skipFields as $skipField) {
if (!\array_key_exists($skipField, $mappingItem)) {
@@ -653,7 +653,7 @@ protected function importCategoryAssociations(array $mapping, array $item, $targ
$categoryManager = System::getContainer()->get('huh.categories.manager');
- $table = $this->configModel->targetTable;
+ $table = $this->configModel->targetTable;
$sourceTable = $this->source->getSourceModel()->dbSourceTable;
$dca = &$GLOBALS['TL_DCA'][$table];
@@ -725,13 +725,13 @@ protected function initDbCacheForMerge(array $mergeIdentifiers)
if ($this->configModel->mergeIdentifierAdditionalWhere) {
$columns = [html_entity_decode($this->configModel->mergeIdentifierAdditionalWhere)];
- $values = [];
+ $values = [];
} else {
$columns = null;
- $values = null;
+ $values = null;
}
- if (null === ($records = $this->databaseUtil->findResultsBy($table, $columns, $values)) || $records->numRows < 1) {
+ if (null === ($records = $this->entityImportUtil->findResultsBy($table, $columns, $values)) || $records->numRows < 1) {
$this->dbMergeCache = [];
return;
@@ -762,7 +762,7 @@ protected function initDbCacheForMerge(array $mergeIdentifiers)
protected function getDebugConfig(): ?array
{
- $config = $this->container->getParameter('huh_entity_import');
+ $config = System::getContainer()->getParameter('huh_entity_import');
return $config['debug'] ?? [];
}
@@ -772,7 +772,7 @@ protected function deleteBeforeImport()
$table = $this->configModel->targetTable;
if ($this->configModel->deleteBeforeImport && !$this->dryRun) {
- $this->databaseUtil->delete($table, html_entity_decode($this->configModel->deleteBeforeImportWhere));
+ $this->connection->executeStatement("DELETE FROM $table WHERE " . html_entity_decode($this->configModel->deleteBeforeImportWhere));
}
}
@@ -782,7 +782,7 @@ protected function deleteAfterImport(array $mappedItems)
switch ($this->configModel->deletionMode) {
case EntityImportConfigContainer::DELETION_MODE_MIRROR:
- $deletionIdentifiers = \Contao\StringUtil::deserialize($this->configModel->deletionIdentifierFields, true);
+ $deletionIdentifiers = StringUtil::deserialize($this->configModel->deletionIdentifierFields, true);
if (empty($deletionIdentifiers)) {
throw new Exception($GLOBALS['TL_LANG']['tl_entity_import_config']['error']['noIdentifierFields']);
@@ -794,29 +794,29 @@ protected function deleteAfterImport(array $mappedItems)
$identifiers = '';
foreach ($mappedItems as $value) {
- $identifiers .= '"'.$value[$deletionIdentifier['target']].'",';
+ $identifiers .= '"' . $value[$deletionIdentifier['target']] . '",';
}
$identifiers = rtrim($identifiers, ',');
if ($identifiers) {
- $conditions[] = '('.$table.'.'.$deletionIdentifier['target'].' NOT IN ('.$identifiers.'))';
+ $conditions[] = '(' . $table . '.' . $deletionIdentifier['target'] . ' NOT IN (' . $identifiers . '))';
}
}
if ($this->configModel->targetDeletionAdditionalWhere) {
- $conditions[] = '('.html_entity_decode($this->configModel->targetDeletionAdditionalWhere).')';
+ $conditions[] = '(' . html_entity_decode($this->configModel->targetDeletionAdditionalWhere) . ')';
}
if (!$this->dryRun && !empty($conditions)) {
- $this->databaseUtil->delete($table, implode(' AND ', $conditions), []);
+ $this->connection->executeStatement("DELETE FROM $table WHERE " . implode(' AND ', $conditions));
}
break;
case EntityImportConfigContainer::DELETION_MODE_TARGET_FIELDS:
if ($this->configModel->deleteBeforeImport && !$this->dryRun) {
- $this->databaseUtil->delete($table, html_entity_decode($this->configModel->targetDeletionWhere));
+ $this->connection->executeStatement("DELETE FROM $table WHERE " . html_entity_decode($this->configModel->targetDeletionWhere));
}
break;
@@ -828,7 +828,7 @@ protected function setDateAdded($record): array
$table = $this->configModel->targetTable;
$field = $this->configModel->targetDateAddedField;
- if (!$this->configModel->setDateAdded || !$field || $record->{$field} || !$record->id) {
+ if (!$this->configModel->setDateAdded || !$field || ($record->{$field} ?? false) || !$record->id) {
return [];
}
@@ -860,8 +860,8 @@ protected function setTstamp($record): array
protected function generateAlias($record): array
{
- $table = $this->configModel->targetTable;
- $field = $this->configModel->targetAliasField;
+ $table = $this->configModel->targetTable;
+ $field = $this->configModel->targetAliasField;
$fieldPattern = $this->configModel->aliasFieldPattern;
if (!$this->configModel->generateAlias || !$field || !$fieldPattern || !$record->id) {
@@ -876,7 +876,7 @@ function ($matches) use ($record) {
$fieldPattern
);
- $alias = $this->dcaUtil->generateAlias(
+ $alias = $this->entityImportUtil->generateAlias(
$record->{$field} ?? '',
$record->id,
$table,
@@ -892,18 +892,18 @@ function ($matches) use ($record) {
protected function applyFieldFileMapping($record, $item): array
{
- $set = [];
+ $set = [];
$slugGenerator = new SlugGenerator();
- $fileMapping = \Contao\StringUtil::deserialize($this->configModel->fileFieldMapping, true);
+ $fileMapping = StringUtil::deserialize($this->configModel->fileFieldMapping, true);
foreach ($fileMapping as $mapping) {
- if (($record->{$mapping['targetField']} ?? NULL) && $mapping['skipIfExisting']) {
+ if (($record->{$mapping['targetField']} ?? null) && $mapping['skipIfExisting']) {
continue;
}
// retrieve the file
try {
- $content = $this->fileUtil->retrieveFileContent(
+ $content = $this->entityImportUtil->retrieveFileContent(
$item[$mapping['mappingField']], $this->utils->container()->isBackend()
);
} catch (\Exception $e) {
@@ -914,7 +914,7 @@ protected function applyFieldFileMapping($record, $item): array
// sleep after http requests because of a possible rate limiting
if (Validator::isUrl($item[$mapping['mappingField']]) && $mapping['delayAfter'] > 0) {
- sleep((int) ($mapping['delayAfter']));
+ sleep((int)($mapping['delayAfter']));
}
// no file found?
@@ -947,16 +947,16 @@ function ($matches) use ($record) {
$filename = $slugGenerator->generate($filename);
}
- $extension = $this->fileUtil->getExtensionFromFileContent($content);
+ $extension = $this->entityImportUtil->getExtensionFromFileContent($content);
- $extension = $extension ? '.'.$extension : '';
+ $extension = $extension ? '.' . $extension : '';
// check if a file of that name already exists
- $folder = new Folder($this->fileUtil->getPathFromUuid($mapping['targetFolder']));
+ $folder = new Folder($this->utils->file()->getPathFromUuid($mapping['targetFolder']));
- $filenameWithoutExtension = $folder->path.'/'.$filename;
+ $filenameWithoutExtension = $folder->path . '/' . $filename;
- $file = new File($filenameWithoutExtension.$extension);
+ $file = new File($filenameWithoutExtension . $extension);
if ($file->exists()) {
if (!isset($record->{$mapping['targetField']}) || !$record->{$mapping['targetField']}) {
@@ -964,8 +964,8 @@ function ($matches) use ($record) {
$i = 1;
while ($file->exists()) {
- $filenameWithoutExtension .= '-'.$i++;
- $file = new File($filenameWithoutExtension.$extension);
+ $filenameWithoutExtension .= '-' . $i++;
+ $file = new File($filenameWithoutExtension . $extension);
}
} else {
// only rewrite if content has changed
@@ -978,7 +978,7 @@ function ($matches) use ($record) {
$event = $this->eventDispatcher->dispatch(new BeforeFileImportEvent(
$file->path,
$content,
- (array) $record,
+ (array)$record,
$item,
$this->configModel,
$this,
@@ -1003,7 +1003,7 @@ protected function applySorting()
{
$field = $this->configModel->targetSortingField;
- $where = $this->framework->getAdapter(Controller::class)->replaceInsertTags(
+ $where = $this->insertTagParser->replace(
html_entity_decode($this->configModel->targetSortingContextWhere), false
);
@@ -1017,7 +1017,7 @@ protected function applySorting()
switch ($this->configModel->sortingMode) {
case EntityImportConfigContainer::SORTING_MODE_TARGET_FIELDS:
- $results = $this->databaseUtil->findResultsBy($table, [$where], [], [
+ $results = $this->entityImportUtil->findResultsBy($table, [$where], [], [
'order' => $order,
]);
@@ -1032,9 +1032,9 @@ protected function applySorting()
continue;
}
- $this->databaseUtil->update($table, [
+ $this->connection->update($table, [
$field => $count++ * 128,
- ], "$table.id=?", [$results->id]);
+ ], ["$table.id" => $results->id]);
}
break;
@@ -1050,22 +1050,23 @@ protected function adjustMappingForDcMultilingual(array $mapping)
$table = $this->configModel->targetTable;
- $this->dcaUtil->loadDc($table);
+ $loader = new DcaLoader($table);
+ $loader->load();
$dca = $GLOBALS['TL_DCA'][$table];
- $langPidField = $dca['config']['langPid'] ?? 'langPid';
+ $langPidField = $dca['config']['langPid'] ?? 'langPid';
$languageField = $dca['config']['langColumnName'] ?? 'language';
$mapping[] = [
- 'columnName' => $langPidField,
- 'valueType' => 'source_value',
+ 'columnName' => $langPidField,
+ 'valueType' => 'source_value',
'mappingValue' => 'langPid',
];
$mapping[] = [
- 'columnName' => $languageField,
- 'valueType' => 'source_value',
+ 'columnName' => $languageField,
+ 'valueType' => 'source_value',
'mappingValue' => 'language',
];
@@ -1073,24 +1074,24 @@ protected function adjustMappingForDcMultilingual(array $mapping)
$publishedField = $dca['config']['langPublished'] ?? 'langPublished';
$mapping[] = [
- 'columnName' => $publishedField,
- 'valueType' => 'source_value',
+ 'columnName' => $publishedField,
+ 'valueType' => 'source_value',
'mappingValue' => 'langPublished',
];
if ($dca['config']['langStart']) {
$publishedStartField = $dca['config']['langStart'] ?? 'langStart';
- $publishedStopField = $dca['config']['langStop'] ?? 'langStop';
+ $publishedStopField = $dca['config']['langStop'] ?? 'langStop';
$mapping[] = [
- 'columnName' => $publishedStartField,
- 'valueType' => 'source_value',
+ 'columnName' => $publishedStartField,
+ 'valueType' => 'source_value',
'mappingValue' => 'langStart',
];
$mapping[] = [
- 'columnName' => $publishedStopField,
- 'valueType' => 'source_value',
+ 'columnName' => $publishedStopField,
+ 'valueType' => 'source_value',
'mappingValue' => 'langStop',
];
}
@@ -1106,8 +1107,8 @@ protected function adjustMappingForChangeLanguage(array $mapping)
}
$mapping[] = [
- 'columnName' => 'languageMain',
- 'valueType' => 'source_value',
+ 'columnName' => 'languageMain',
+ 'valueType' => 'source_value',
'mappingValue' => 'languageMain',
];
diff --git a/src/Importer/ImporterFactory.php b/src/Importer/ImporterFactory.php
index b25a687..27619c0 100644
--- a/src/Importer/ImporterFactory.php
+++ b/src/Importer/ImporterFactory.php
@@ -9,63 +9,52 @@
namespace HeimrichHannot\EntityImportBundle\Importer;
use Contao\CoreBundle\Framework\ContaoFramework;
+use Contao\CoreBundle\InsertTag\InsertTagParser;
+use Doctrine\DBAL\Connection;
use HeimrichHannot\EntityImportBundle\Source\SourceFactory;
use HeimrichHannot\EntityImportBundle\Source\SourceInterface;
-use HeimrichHannot\RequestBundle\Component\HttpFoundation\Request;
-use HeimrichHannot\UtilsBundle\Database\DatabaseUtil;
-use HeimrichHannot\UtilsBundle\Dca\DcaUtil;
-use HeimrichHannot\UtilsBundle\File\FileUtil;
-use HeimrichHannot\UtilsBundle\Model\ModelUtil;
+use HeimrichHannot\EntityImportBundle\Util\EntityImportUtil;
use HeimrichHannot\UtilsBundle\Util\Utils;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
class ImporterFactory
{
- protected DatabaseUtil $databaseUtil;
protected EventDispatcherInterface $eventDispatcher;
- protected ModelUtil $modelUtil;
- protected SourceFactory $sourceFactory;
- protected DcaUtil $dcaUtil;
- protected ContainerInterface $container;
- protected Request $request;
- protected FileUtil $fileUtil;
- protected Utils $utils;
- protected ContaoFramework $framework;
+ protected SourceFactory $sourceFactory;
+ protected Utils $utils;
+ protected ContaoFramework $framework;
+ protected Connection $connection;
+ protected EntityImportUtil $entityImportUtil;
+ protected InsertTagParser $insertTagParser;
public function __construct(
- ContainerInterface $container,
ContaoFramework $framework,
- DatabaseUtil $databaseUtil,
EventDispatcherInterface $eventDispatcher,
- Request $request,
- ModelUtil $modelUtil,
- DcaUtil $dcaUtil,
+ Connection $connection,
+ EntityImportUtil $entityImportUtil,
SourceFactory $sourceFactory,
- FileUtil $fileUtil,
- Utils $utils
+ Utils $utils,
+ InsertTagParser $insertTagParser
) {
- $this->databaseUtil = $databaseUtil;
$this->eventDispatcher = $eventDispatcher;
- $this->modelUtil = $modelUtil;
$this->sourceFactory = $sourceFactory;
- $this->dcaUtil = $dcaUtil;
- $this->container = $container;
- $this->request = $request;
- $this->fileUtil = $fileUtil;
$this->utils = $utils;
$this->framework = $framework;
+ $this->connection = $connection;
+ $this->entityImportUtil = $entityImportUtil;
+ $this->insertTagParser = $insertTagParser;
}
public function createInstance($configModel, array $options = []): ?ImporterInterface
{
$sourceModel = $options['sourceModel'] ?? null;
- if (is_numeric($configModel) && null === ($configModel = $this->modelUtil->findModelInstanceByPk('tl_entity_import_config', $configModel))) {
+ if (is_numeric($configModel) && null === ($configModel = $this->utils->model()->findModelInstanceByPk('tl_entity_import_config', $configModel))) {
return null;
}
- if (null === $sourceModel && null === ($sourceModel = $this->modelUtil->findModelInstanceByPk('tl_entity_import_source', $configModel->pid))) {
+ if (null === $sourceModel && null === ($sourceModel = $this->utils->model()->findModelInstanceByPk('tl_entity_import_source', $configModel->pid))) {
return null;
}
@@ -78,16 +67,14 @@ public function createInstance($configModel, array $options = []): ?ImporterInte
$source->setDomain($configModel->cronDomain);
return new Importer(
- $this->container,
$this->framework,
$configModel,
$source,
$this->eventDispatcher,
- $this->request,
- $this->databaseUtil,
- $this->dcaUtil,
- $this->fileUtil,
- $this->utils
+ $this->connection,
+ $this->entityImportUtil,
+ $this->utils,
+ $this->insertTagParser
);
}
}
diff --git a/src/Resources/public/assets/contao-entity-import-bundle-be.css b/src/Resources/public/assets/contao-entity-import-bundle-be.css
deleted file mode 100644
index 96126b2..0000000
--- a/src/Resources/public/assets/contao-entity-import-bundle-be.css
+++ /dev/null
@@ -1 +0,0 @@
-#tl_entity_import_source [name=fileContent]+.ace_editor{height:500px!important}
\ No newline at end of file
diff --git a/src/Resources/public/assets/contao-entity-import-bundle-be.js b/src/Resources/public/assets/contao-entity-import-bundle-be.js
deleted file mode 100644
index 21c149d..0000000
--- a/src/Resources/public/assets/contao-entity-import-bundle-be.js
+++ /dev/null
@@ -1 +0,0 @@
-!function(e){var t={};function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(r,o,function(t){return e[t]}.bind(null,o));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="/bundles/heimrichhannotcontaoentityimportbundle/assets/",n(n.s="6Yoe")}({"6Yoe":function(e,t,n){"use strict";n.r(t);n("niFc");function r(e,t){for(var n=0;nfileUtil = $fileUtil;
- $this->stringUtil = $stringUtil;
- $this->containerUtil = $containerUtil;
$this->eventDispatcher = $eventDispatcher;
+ $this->utils = $utils;
+ $this->insertTagParser = $insertTagParser;
parent::__construct();
}
@@ -48,11 +47,11 @@ public function getLinesFromFile(int $limit, bool $cache = false): string
public function getFileContent(bool $cache = false): string
{
$content = '';
- $projectDir = $this->containerUtil->getProjectDir();
+ $projectDir = System::getContainer()->getParameter('kernel.project_dir');
switch ($this->sourceModel->retrievalType) {
case EntityImportSourceContainer::RETRIEVAL_TYPE_CONTAO_FILE_SYSTEM:
- $path = $projectDir.'/'.$this->fileUtil->getPathFromUuid($this->sourceModel->fileSRC);
+ $path = $projectDir.'/'.$this->utils->file()->getPathFromUuid($this->sourceModel->fileSRC);
if (file_exists($path)) {
$content = file_get_contents($path);
@@ -64,7 +63,7 @@ public function getFileContent(bool $cache = false): string
$auth = [];
if (null !== $this->sourceModel->httpAuth) {
- $httpAuth = \Contao\StringUtil::deserialize($this->sourceModel->httpAuth, true);
+ $httpAuth = StringUtil::deserialize($this->sourceModel->httpAuth, true);
$auth = ['auth' => [$httpAuth['username'], $httpAuth['password']]];
}
diff --git a/src/Source/AbstractSource.php b/src/Source/AbstractSource.php
index 16b93b3..09a2742 100644
--- a/src/Source/AbstractSource.php
+++ b/src/Source/AbstractSource.php
@@ -8,8 +8,10 @@
namespace HeimrichHannot\EntityImportBundle\Source;
+use Contao\CoreBundle\InsertTag\InsertTagParser;
use Contao\Environment;
use Contao\Model;
+use Contao\StringUtil;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;
use Symfony\Component\Cache\Adapter\FilesystemAdapter;
@@ -89,7 +91,7 @@ protected function getMappedItemData(?array $element, array $mapping): array
foreach ($mapping as $mappingElement) {
if ('static_value' === $mappingElement['valueType']) {
- $result[$mappingElement['name']] = $this->stringUtil->replaceInsertTags($mappingElement['staticValue']);
+ $result[$mappingElement['name']] = $this->container->get(InsertTagParser::class)->replaceInsertTags($mappingElement['staticValue']);
} elseif ('source_value' === $mappingElement['valueType']) {
$result[$mappingElement['name']] = $element[$mappingElement['sourceValue']];
}
@@ -103,7 +105,7 @@ protected function getContentFromUrl(string $method, string $url, array $auth =
$client = new Client();
try {
- $response = $client->request($method, \Contao\StringUtil::decodeEntities($url), $auth);
+ $response = $client->request($method, StringUtil::decodeEntities($url), $auth);
} catch (RequestException $e) {
return [
'statusCode' => $e->getResponse()->getStatusCode(),
diff --git a/src/Source/CSVFileSource.php b/src/Source/CSVFileSource.php
index 95c63f0..471edab 100644
--- a/src/Source/CSVFileSource.php
+++ b/src/Source/CSVFileSource.php
@@ -8,6 +8,7 @@
namespace HeimrichHannot\EntityImportBundle\Source;
+use Contao\File;
use Contao\Message;
use HeimrichHannot\EntityImportBundle\Util\CsvReader;
use HeimrichHannot\EntityImportBundle\Event\AfterCsvFileSourceGetRowEvent;
@@ -18,9 +19,9 @@ public function getMappedData(array $options = []): array
{
$data = [];
$settings = $this->getCsvSettings();
- $file = $this->fileUtil->getFileFromUuid($this->sourceModel->fileSRC);
+ $file = new File($this->utils->file()->getPathFromUuid($this->sourceModel->fileSRC));
- if (null === $file || !$file->exists()) {
+ if (!$file->exists()) {
return [];
}
diff --git a/src/Source/DatabaseSource.php b/src/Source/DatabaseSource.php
index 486f707..126df21 100644
--- a/src/Source/DatabaseSource.php
+++ b/src/Source/DatabaseSource.php
@@ -9,21 +9,18 @@
namespace HeimrichHannot\EntityImportBundle\Source;
use Contao\Database;
-use HeimrichHannot\UtilsBundle\Dca\DcaUtil;
+use Contao\DcaLoader;
+use Contao\StringUtil;
+use Doctrine\DBAL\Connection;
+use HeimrichHannot\EntityImportBundle\Util\EntityImportUtil;
class DatabaseSource extends AbstractSource
{
- /**
- * @var DcaUtil
- */
- private $dcaUtil;
-
- /**
- * AbstractFileSource constructor.
- */
- public function __construct(DcaUtil $dcaUtil)
+ protected EntityImportUtil $util;
+
+ public function __construct(EntityImportUtil $util)
{
- $this->dcaUtil = $dcaUtil;
+ $this->util = $util;
parent::__construct();
}
@@ -31,21 +28,22 @@ public function __construct(DcaUtil $dcaUtil)
public function getMappedData(array $options = []): array
{
$sourceModel = $this->sourceModel;
- $mapping = \Contao\StringUtil::deserialize($this->sourceModel->fieldMapping, true);
+ $mapping = StringUtil::deserialize($this->sourceModel->fieldMapping, true);
$mapping = $this->adjustMappingForDcMultilingual($mapping);
$mapping = $this->adjustMappingForChangeLanguage($mapping);
// retrieve the source records
- $db = Database::getInstance($sourceModel->row());
$where = $sourceModel->dbSourceTableWhere ?: '1=1';
- $records = $db->prepare("SELECT * FROM $sourceModel->dbSourceTable WHERE $where")->execute();
+ $connection = $this->util->getDbalConnectionBySource($sourceModel->row());
+
+ $records = $connection->prepare("SELECT * FROM $sourceModel->dbSourceTable WHERE $where")->executeQuery()->fetchAllAssociative();
$data = [];
- while ($records->next()) {
- $data[] = $this->getMappedItemData($records->row(), $mapping);
+ foreach ($records as $record) {
+ $data[] = $this->getMappedItemData($record, $mapping);
}
return $data;
@@ -68,7 +66,8 @@ protected function adjustMappingForDcMultilingual(array $mapping)
'skip' => true,
];
- $this->dcaUtil->loadDc($table);
+ $loader = new DcaLoader($table);
+ $loader->load();
$dca = $GLOBALS['TL_DCA'][$table];
diff --git a/src/Source/JSONFileSource.php b/src/Source/JSONFileSource.php
index adb7f89..fe353eb 100644
--- a/src/Source/JSONFileSource.php
+++ b/src/Source/JSONFileSource.php
@@ -53,7 +53,7 @@ protected function getMappedItemData(?array $element, array $mapping): array
foreach ($mapping as $mappingElement) {
if ('static_value' === $mappingElement['valueType']) {
- $result[$mappingElement['name']] = $this->stringUtil->replaceInsertTags($mappingElement['staticValue']);
+ $result[$mappingElement['name']] = $this->insertTagParser->replace($mappingElement['staticValue']);
} elseif ('source_value' === $mappingElement['valueType']) {
$result[$mappingElement['name']] = $this->getValue($element, $mappingElement);
}
diff --git a/src/Source/RSSFileSource.php b/src/Source/RSSFileSource.php
index c93ebc6..2bad6d7 100644
--- a/src/Source/RSSFileSource.php
+++ b/src/Source/RSSFileSource.php
@@ -8,6 +8,9 @@
namespace HeimrichHannot\EntityImportBundle\Source;
+use Contao\StringUtil;
+use LitEmoji\LitEmoji;
+
class RSSFileSource extends AbstractFileSource
{
public function getPostFieldsAsOptions()
@@ -73,7 +76,7 @@ public function getChannelItems()
public function getMappedData(array $options = []): array
{
$sourceModel = $this->sourceModel;
- $mapping = \Contao\StringUtil::deserialize($sourceModel->fieldMapping, true);
+ $mapping = StringUtil::deserialize($sourceModel->fieldMapping, true);
$data = [];
@@ -94,7 +97,7 @@ protected function getMappedItemData(?array $element, array $mapping): array
foreach ($mapping as $mappingElement) {
if ('static_value' === $mappingElement['valueType']) {
- $result[$mappingElement['name']] = $this->stringUtil->replaceInsertTags($mappingElement['staticValue']);
+ $result[$mappingElement['name']] = $this->insertTagParser->replace($mappingElement['staticValue']);
} elseif ('source_value' === $mappingElement['valueType']) {
$value = $element[$mappingElement['sourceValue']];
@@ -110,7 +113,7 @@ protected function getMappedItemData(?array $element, array $mapping): array
break;
case 'encoded':
- $result[$mappingElement['name']] = $this->stringUtil->replaceUnicodeEmojisByHtml($value);
+ $result[$mappingElement['name']] = LitEmoji::encodeHtml($value);
break;
diff --git a/src/Source/SourceFactory.php b/src/Source/SourceFactory.php
index 10815d3..4cc1f2a 100644
--- a/src/Source/SourceFactory.php
+++ b/src/Source/SourceFactory.php
@@ -8,43 +8,36 @@
namespace HeimrichHannot\EntityImportBundle\Source;
+use Contao\CoreBundle\InsertTag\InsertTagParser;
+use Contao\StringUtil;
+use Contao\System;
use HeimrichHannot\EntityImportBundle\DataContainer\EntityImportSourceContainer;
use HeimrichHannot\EntityImportBundle\Event\SourceFactoryCreateSourceEvent;
-use HeimrichHannot\UtilsBundle\Container\ContainerUtil;
-use HeimrichHannot\UtilsBundle\Dca\DcaUtil;
-use HeimrichHannot\UtilsBundle\File\FileUtil;
-use HeimrichHannot\UtilsBundle\Model\ModelUtil;
-use HeimrichHannot\UtilsBundle\String\StringUtil;
-use Symfony\Component\DependencyInjection\ContainerInterface;
+use HeimrichHannot\EntityImportBundle\Util\EntityImportUtil;
+use HeimrichHannot\UtilsBundle\Util\Utils;
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
class SourceFactory
{
- protected ContainerInterface $container;
- protected ModelUtil $modelUtil;
- protected FileUtil $fileUtil;
protected EventDispatcherInterface $eventDispatcher;
- protected StringUtil $stringUtil;
- protected ContainerUtil $containerUtil;
- protected DcaUtil $dcaUtil;
+ protected Utils $utils;
+ protected InsertTagParser $insertTagParser;
+ protected EntityImportUtil $entityImportUtil;
/**
* SourceFactory constructor.
*/
- public function __construct(ContainerInterface $container, ModelUtil $modelUtil, FileUtil $fileUtil, EventDispatcherInterface $eventDispatcher, StringUtil $stringUtil, ContainerUtil $containerUtil, DcaUtil $dcaUtil)
+ public function __construct(EventDispatcherInterface $eventDispatcher, Utils $utils, InsertTagParser $insertTagParser, EntityImportUtil $entityImportUtil)
{
- $this->modelUtil = $modelUtil;
- $this->fileUtil = $fileUtil;
$this->eventDispatcher = $eventDispatcher;
- $this->stringUtil = $stringUtil;
- $this->containerUtil = $containerUtil;
- $this->dcaUtil = $dcaUtil;
- $this->container = $container;
+ $this->utils = $utils;
+ $this->insertTagParser = $insertTagParser;
+ $this->entityImportUtil = $entityImportUtil;
}
public function createInstance(int $sourceModel): ?SourceInterface
{
- if (null === ($sourceModel = $this->modelUtil->findModelInstanceByPk('tl_entity_import_source', $sourceModel))) {
+ if (null === ($sourceModel = $this->utils->model()->findModelInstanceByPk('tl_entity_import_source', $sourceModel))) {
return null;
}
@@ -52,29 +45,29 @@ public function createInstance(int $sourceModel): ?SourceInterface
switch ($sourceModel->type) {
case EntityImportSourceContainer::TYPE_DATABASE:
- $source = new DatabaseSource($this->dcaUtil);
+ $source = new DatabaseSource($this->entityImportUtil);
break;
case EntityImportSourceContainer::TYPE_FILE:
switch ($sourceModel->fileType) {
case EntityImportSourceContainer::FILETYPE_JSON:
- $source = new JSONFileSource($this->eventDispatcher, $this->fileUtil, $this->stringUtil, $this->containerUtil);
+ $source = new JSONFileSource($this->eventDispatcher, $this->utils, $this->insertTagParser);
break;
case EntityImportSourceContainer::FILETYPE_XML:
- $source = new XmlFileSource($this->eventDispatcher, $this->fileUtil, $this->stringUtil, $this->containerUtil);
+ $source = new XmlFileSource($this->eventDispatcher, $this->utils, $this->insertTagParser);
break;
case EntityImportSourceContainer::FILETYPE_CSV:
- $source = new CSVFileSource($this->eventDispatcher, $this->fileUtil, $this->stringUtil, $this->containerUtil);
+ $source = new CSVFileSource($this->eventDispatcher, $this->utils, $this->insertTagParser);
break;
case EntityImportSourceContainer::FILETYPE_RSS:
- $source = new RSSFileSource($this->eventDispatcher, $this->fileUtil, $this->stringUtil, $this->containerUtil);
+ $source = new RSSFileSource($this->eventDispatcher, $this->utils, $this->insertTagParser);
break;
}
@@ -93,9 +86,9 @@ public function createInstance(int $sourceModel): ?SourceInterface
throw new \Exception('No file source class found for file type '.$sourceModel->fileType);
}
- $source->setFieldMapping(\Contao\StringUtil::deserialize($sourceModel->fieldMapping, true));
+ $source->setFieldMapping(StringUtil::deserialize($sourceModel->fieldMapping, true));
$source->setSourceModel($sourceModel);
- $source->setContainer($this->container);
+ $source->setContainer(System::getContainer());
return $source;
}
diff --git a/src/Source/XmlFileSource.php b/src/Source/XmlFileSource.php
index 56d3d86..1fc38ff 100644
--- a/src/Source/XmlFileSource.php
+++ b/src/Source/XmlFileSource.php
@@ -55,7 +55,7 @@ protected function getMappedItemData(?array $element, array $mapping): array
foreach ($mapping as $mappingElement) {
if ('static_value' === $mappingElement['valueType']) {
- $result[$mappingElement['name']] = $this->stringUtil->replaceInsertTags($mappingElement['staticValue']);
+ $result[$mappingElement['name']] = $this->insertTagParser->replace($mappingElement['staticValue']);
} elseif ('source_value' === $mappingElement['valueType']) {
$result[$mappingElement['name']] = $this->getValue($element, $mappingElement);
}
diff --git a/src/Util/EntityImportUtil.php b/src/Util/EntityImportUtil.php
index 11574cc..5a5c331 100644
--- a/src/Util/EntityImportUtil.php
+++ b/src/Util/EntityImportUtil.php
@@ -8,8 +8,32 @@
namespace HeimrichHannot\EntityImportBundle\Util;
+use Contao\CoreBundle\Framework\ContaoFramework;
+use Contao\Database;
+use Contao\DcaLoader;
+use Contao\File;
+use Contao\Message;
+use Contao\StringUtil;
+use Contao\System;
+use Contao\Validator;
+use Doctrine\DBAL\Connection;
+use Doctrine\DBAL\DriverManager;
+use GuzzleHttp\Client;
+use HeimrichHannot\UtilsBundle\Util\Utils;
+
class EntityImportUtil
{
+ protected ContaoFramework $contaoFramework;
+ protected Connection $connection;
+ protected Utils $utils;
+
+ public function __construct(ContaoFramework $contaoFramework, Connection $connection, Utils $utils)
+ {
+ $this->contaoFramework = $contaoFramework;
+ $this->connection = $connection;
+ $this->utils = $utils;
+ }
+
public function transformFieldMappingSourceValueToSelect($options)
{
$dca = &$GLOBALS['TL_DCA']['tl_entity_import_source']['fields']['fieldMapping']['eval']['multiColumnEditor']['fields']['sourceValue'];
@@ -20,4 +44,407 @@ public function transformFieldMappingSourceValueToSelect($options)
$dca['eval']['mandatory'] = true;
$dca['eval']['chosen'] = true;
}
+
+ public function getDbalConnectionBySource(array $sourceParams): Connection
+ {
+ $mapping = [
+ 'dbDriver' => 'driver',
+ 'dbHost' => 'host',
+ 'dbUser' => 'user',
+ 'dbPass' => 'password',
+ 'dbDatabase' => 'dbname',
+ 'dbPconnect' => 'persistent',
+ 'dbCharset' => 'charset',
+ 'dbPort' => 'port',
+ 'dbSocket' => 'unix_socket',
+ ];
+
+ $dbalParams = [];
+
+ foreach ($sourceParams as $k => $v) {
+ if (isset($mapping[$k])) {
+ $dbalParams[$mapping[$k]] = $v;
+ }
+ }
+
+ $dbalParams['persistent'] = $dbalParams['persistent'] === 'true';
+
+ $connection = DriverManager::getConnection($dbalParams);
+
+ return $connection;
+ }
+
+ public function getLocalizedFieldName(string $strField, string $strTable): ?string
+ {
+ $loader = new DcaLoader($strTable);
+ $loader->load();
+ System::loadLanguageFile($strTable);
+
+ return $GLOBALS['TL_DCA'][$strTable]['fields'][$strField]['label'][0] ?: $strField;
+ }
+
+ public function beginTransaction(): void
+ {
+// $this->connection->beginTransaction();
+ }
+
+ public function commitTransaction(): void
+ {
+// $this->connection->commit();
+ }
+
+ /**
+ * Returns a database result for a given table and id(primary key).
+ *
+ * @param mixed $pk
+ *
+ * @return mixed
+ */
+ public function findResultByPk(string $table, $pk, array $options = [])
+ {
+ /* @var Database $db */
+ if (!($db = $this->contaoFramework->getAdapter(Database::class))) {
+ return null;
+ }
+
+ $options = array_merge(
+ [
+ 'limit' => 1,
+ 'column' => 'id',
+ 'value' => $pk,
+ ],
+ $options
+ );
+
+ $options['table'] = $table;
+
+ if (isset($options['selectFields'])) {
+ $query = $this->createQueryWithoutRelations($options['selectFields']);
+ } else {
+ $query = \Contao\Model\QueryBuilder::find($options);
+ }
+
+ $statement = $db->getInstance()->prepare($query);
+
+ // Defaults for limit and offset
+ if (!isset($options['limit'])) {
+ $options['limit'] = 0;
+ }
+
+ if (!isset($options['offset'])) {
+ $options['offset'] = 0;
+ }
+
+ // Limit
+ if ($options['limit'] > 0 || $options['offset'] > 0) {
+ $statement->limit($options['limit'], $options['offset']);
+ }
+
+ return $statement->execute($options['value']);
+ }
+
+ /**
+ * Return a single database result by table and search criteria.
+ *
+ * @return mixed
+ */
+ public function findOneResultBy(string $table, ?array $columns, ?array $values, array $options = [])
+ {
+ /* @var Database $db */
+ if (!($db = $this->contaoFramework->getAdapter(Database::class))) {
+ return null;
+ }
+
+ $options = array_merge(
+ [
+ 'limit' => 1,
+ 'column' => $columns,
+ 'value' => $values,
+ ],
+ $options
+ );
+
+ $options['table'] = $table;
+
+ if (isset($options['selectFields'])) {
+ $query = $this->createQueryWithoutRelations($options['selectFields']);
+ } else {
+ $query = \Contao\Model\QueryBuilder::find($options);
+ }
+
+ $statement = $db->getInstance()->prepare($query);
+
+ if (!isset($options['offset'])) {
+ $options['offset'] = 0;
+ }
+
+ // Limit
+ if ($options['limit'] > 0 || $options['offset'] > 0) {
+ $statement->limit($options['limit'], $options['offset']);
+ }
+
+ return $statement->execute($options['value']);
+ }
+
+ public function findResultsBy(string $table, ?array $columns, ?array $values, array $options = [])
+ {
+ /* @var Database $db */
+ if (!($db = $this->contaoFramework->getAdapter(Database::class))) {
+ return null;
+ }
+
+ if (null !== $columns) {
+ $options = array_merge(
+ [
+ 'column' => $columns,
+ ],
+ $options
+ );
+ }
+
+ if (null !== $values) {
+ $options = array_merge(
+ [
+ 'value' => $values,
+ ],
+ $options
+ );
+ }
+
+ $options['table'] = $table;
+
+ if (isset($options['selectFields'])) {
+ $query = $this->createQueryWithoutRelations($options);
+ } else {
+ $query = \Contao\Model\QueryBuilder::find($options);
+ }
+
+ $statement = $db->getInstance()->prepare($query);
+
+ // Defaults for limit and offset
+ if (!isset($options['limit'])) {
+ $options['limit'] = 0;
+ }
+
+ if (!isset($options['offset'])) {
+ $options['offset'] = 0;
+ }
+
+ // Limit
+ if ($options['limit'] > 0 || $options['offset'] > 0) {
+ $statement->limit($options['limit'], $options['offset']);
+ }
+
+ return isset($options['value']) ? $statement->execute($options['value']) : $statement->execute();
+ }
+
+ /**
+ * Adapted from \Contao\Model\QueryBuilder::find().
+ *
+ * @return string
+ */
+ private function createQueryWithoutRelations(array $options)
+ {
+ $fields = $options['selectFields'] ?? [];
+
+ $query = 'SELECT '.(empty($fields) ? '*' : implode(', ', $fields)).' FROM '.$options['table'];
+
+ // Where condition
+ if (isset($options['column'])) {
+ $query .= ' WHERE '.(\is_array($options['column']) ? implode(' AND ', $options['column']) : $options['table'].'.'.Database::quoteIdentifier($options['column']).'=?');
+ }
+
+ // Group by
+ if (isset($options['group'])) {
+ @trigger_error('Using the "group" option has been deprecated and will no longer work in Contao 5.0. See https://github.com/contao/contao/issues/1680', \E_USER_DEPRECATED);
+ $query .= ' GROUP BY '.$options['group'];
+ }
+
+ // Having (see #6446)
+ if (isset($options['having'])) {
+ $query .= ' HAVING '.$options['having'];
+ }
+
+ // Order by
+ if (isset($options['order'])) {
+ $query .= ' ORDER BY '.$options['order'];
+ }
+
+ return $query;
+ }
+
+ /**
+ * Return if the current alias already exist in table.
+ */
+ public function aliasExist(string $alias, int $id, string $table, $options = []): bool
+ {
+ $aliasField = $options['aliasField'] ?? 'alias';
+
+ $stmt = $this->connection->prepare('SELECT id FROM '.$table.' WHERE '.$aliasField.'=? AND id!=?');
+
+ return $stmt->executeQuery([$alias, $id])->rowCount() > 0;
+ }
+
+ /**
+ * Generate an alias with unique check.
+ *
+ * @param mixed $alias The current alias (if available)
+ * @param int $id The entity's id
+ * @param string|null $table The entity's table (pass a comma separated list if the validation should be expanded to multiple tables like tl_news AND tl_member. ATTENTION: the first table needs to be the one we're currently in). Pass null to skip unqiue check.
+ * @param string $title The value to use as a base for the alias
+ * @param bool $keepUmlauts Set to true if German umlauts should be kept
+ *
+ * @throws \Exception
+ *
+ * @return string
+ */
+ public function generateAlias(?string $alias, int $id, ?string $table, string $title, bool $keepUmlauts = true, $options = []): string
+ {
+ $autoAlias = false;
+ $aliasField = $options['aliasField'] ?? 'alias';
+
+ // Generate alias if there is none
+ if (empty($alias)) {
+ $autoAlias = true;
+ $alias = StringUtil::generateAlias($title);
+ }
+
+ if (!$keepUmlauts) {
+ $alias = preg_replace(['/ä/i', '/ö/i', '/ü/i', '/ß/i'], ['ae', 'oe', 'ue', 'ss'], $alias);
+ }
+
+ if (null === $table) {
+ return $alias;
+ }
+
+ $originalAlias = $alias;
+
+ // multiple tables?
+ if (false !== strpos($table, ',')) {
+ $tables = explode(',', $table);
+
+ foreach ($tables as $i => $partTable) {
+ // the table in which the entity is
+ if (0 === $i) {
+ if ($this->aliasExist($alias, $id, $table, $options)) {
+ if (!$autoAlias) {
+ throw new \InvalidArgumentException(sprintf($GLOBALS['TL_LANG']['ERR']['aliasExists'], $alias));
+ }
+
+ $alias = $originalAlias.'-'.$id;
+ }
+ } else {
+ // another table
+ $stmt = $this->connection->prepare("SELECT id FROM {$partTable} WHERE ' . $aliasField . '=?");
+
+ // Check whether the alias exists
+ if ($stmt->executeQuery([$alias])->rowCount() > 0) {
+ throw new \InvalidArgumentException(sprintf($GLOBALS['TL_LANG']['ERR']['aliasExists'], $alias));
+ }
+ }
+ }
+ } else {
+ if (!$this->aliasExist($alias, $id, $table, $options)) {
+ return $alias;
+ }
+
+ // Check whether the alias exists
+ if (!$autoAlias) {
+ throw new \Exception(sprintf($GLOBALS['TL_LANG']['ERR']['aliasExists'], $alias));
+ }
+
+ // Add ID to alias
+ $alias .= '-'.$id;
+ }
+
+ return $alias;
+ }
+
+ public function getExtensionFromFileContent($content): string|false
+ {
+ if (!class_exists('\finfo')) {
+ return false;
+ }
+
+ $finfo = new \finfo(\FILEINFO_MIME_TYPE);
+
+ return $this->getExtensionByMimeType($finfo->buffer($content));
+ }
+
+ public function getExtensionByMimeType($mimeType): string|false
+ {
+ foreach ($GLOBALS['TL_MIME'] as $extension => $data) {
+ if ($data[0] === $mimeType) {
+ if ('jpeg' === $extension) {
+ $extension = 'jpg';
+ }
+
+ return $extension;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Tries to get the binary content from a file in various sources and returns it if possible.
+ *
+ * Possible sources:
+ * - url
+ * - contao uuid
+ * - string is already a binary file content
+ *
+ * @param $source
+ *
+ * @return bool|mixed Returns false if the file content could not be retrieved
+ */
+ public function retrieveFileContent($source, $silent = true): mixed
+ {
+ // url
+ if (Validator::isUrl($source)) {
+ $client = new Client();
+ $request = $client->request('GET', $source);
+
+ if (200 === $request->getStatusCode()) {
+ $content = $request->getBody()->__toString();
+
+ if ($content) {
+ return $content;
+ }
+ } else {
+ if (!$silent) {
+ $body = $request->getBody()->__toString();
+
+ Message::addError(sprintf($GLOBALS['TL_LANG']['ERR']['httpRequestError'], $source, 'Code '.$request->getStatusCode().': '.$body));
+ }
+ }
+ }
+
+ // contao uuid
+ if (Validator::isUuid($source)) {
+ $content = $this->getFileContentFromUuid($source);
+
+ if (false !== $content) {
+ return $content;
+ }
+ }
+
+ // already binary -> ctype_print() checks if non-printable characters are in the string -> if so, it's most likely a file
+ if (!ctype_print($source)) {
+ return $source;
+ }
+
+ return false;
+ }
+
+ public function getFileContentFromUuid($uuid): false|string
+ {
+ $file = new File($this->utils->file()->getPathFromUuid($uuid));
+
+ if (!$file || !$file->exists()) {
+ return false;
+ }
+
+ return file_get_contents(System::getContainer()->getParameter('kernel.project_dir').'/'.$file->path);
+ }
}