markocupic/import-from-csv-bundle

Contao开源CMS的后端扩展。从CSV电子表格导入数据记录。


README

Logo

从CSV导入(Contao 4.x的后端模块)

该模块允许通过CSV文件一次性导入大量数据记录。当需要生成大量用户或成员时,非常有用。CSV文件最好在电子表格程序(如MS-EXCEL)中创建,然后保存为逗号分隔文件(CSV)。示例文件可在docs目录中找到。

import_from_csv_bundle.mp4

警告!

注意!该模块非常有用。但是,用户应该知道自己在做什么,因为错误使用可能会导致数据记录被删除或损坏,并且Contao可能无法正常工作。

CSV导入文件结构

可以使用MS-Excel或文本编辑器创建一个(逗号分隔)文本文件(csv)。第一行必须是字段名。各个字段必须通过分隔符(通常是分号";")分隔。在数据库中作为序列化数组存储的内容(例如,组成员资格、新闻通讯订阅等)必须通过两个连续的管道符号分隔,例如“2||5”。字段定界符和字段分隔符可以单独设置。

重要!每个数据记录必须占用一行。数据记录中的换行符会阻止导入。创建的csv文件必须通过文件管理器上传到Web服务器,并在导入配置中选择。

在导入过程中,内容将根据目标表的DCA设置进行检查。

注意!只有当您非常确信时才应使用该模块。如果之前没有创建数据库备份,则删除的数据无法恢复。

设置

创建并上传逗号分隔文件

首先必须创建一个CSV文件。首行必须包含字段名。

firstname;lastname;dateOfBirth;gender;company;street;postal;city;state;country;phone;mobile;fax;email;website;language;login;username;password;groups
Hans;Meier;1778-05-22;male;Webdesign AG;Ringelnatterweg 1;6208;Oberkirch;Kanton Luzern;ch;041 921 99 97;079 620 99 91;045 789 56 89;h-meier@me.ch;www.hans-meier.ch;de;1;hansmeier;topsecret;1||2
Fritz;Nimmersatt;1978-05-29;male;Webdesign AG;Entenweg 10;6208;Oberkirch;Kanton Luzern;ch;041 921 99 98;079 620 99 92;046 789 56 89;f-nimmersatt@me.ch;www.fritz-nimmersatt.ch;de;1;fritznimmer;topsecret2;1||2
Annina;Meile;1878-05-29;female;Webdesign AG;Nashornstrasse 2;6208;Oberkirch;Kanton Luzern;ch;043 921 99 99;079 620 93 91;047 789 56 89;a-meile@me.ch;www.annina-meile.ch;de;1;anninameile;topsecret3;1

选择导入的数据表(必填项)

选择要导入数据记录的表。

选择导入过程中的字段(必填项)

在数据库表中只写入选定的字段。通常,在这里选择所有字段是有意义的。

字段分隔符(必填项)

指定CSV文件中字段内容之间的分隔符。

字段定界符(必填项)

检查CSV文件中字段内容是否还由一个字符包含。通常是双引号。=> "

导入模式(必填项)

指定是否将CSV文件中的数据记录附加到目标表,还是首先清空目标表(旧表)。注意!如果没有备份,则无法恢复已删除的数据。

选择文件(必填项)

最后选择要写入数据库的文件。提示:选择文件后,请先点击“保存”,以便预览文件内容。

换行符

CSV文件中的所有[NEWLINE]标签在导入过程中将转换为\r\n或\n。

空字段值

不处理空字段值。在导入新数据记录时,将始终使用默认值从$GLOBALS['TL_DCA']['tl_my_table']['fields']['myField']['sql']设置。

计划任务

根据需求,可以激活CRON。通过这种方式,导入可以在预定的时间间隔内自动执行。

通过钩子调整导入机制

使用更新安全的钩子可以绕过或调整验证。以下示例中,将根据街道、城市和国家缩写自动通过GoogleMaps的Curl请求获取地理坐标进行导入。如果无法确定地理坐标,还可以生成错误信息。这样,数据集将被跳过,不会写入数据库。

可能的钩子类的结构

<?php

// src/EventListener/MyImportFromCsvHook.php

declare(strict_types=1);

namespace App\EventListener;

use Contao\CoreBundle\DependencyInjection\Attribute\AsHook;
use Contao\Widget;
use Markocupic\ImportFromCsvBundle\Import\ImportFromCsv;

#[AsHook(MyImportFromCsvHook::HOOK)]
class MyImportFromCsvHook
{
    public const HOOK = 'importFromCsv';
    public const PRIORITY = 100;

    /**
     * @var string
     */
    private $curlErrorMsg;

    public function __invoke(Widget $objWidget, array $arrRecord, int $line, ImportFromCsv $importFromCsv = null): void
    {
        // tl_member
        if ('tl_member' === $objWidget->strTable) {
            // Get geolocation from a given address
            if ('geolocation' === $objWidget->strField) {
                // Do custom validation and skip the Contao-Widget-Input-Validation
                $arrSkip = $importFromCsv->getData('arrSkipValidationFields');
                $arrSkip[] = $objWidget->strField;
                $importFromCsv->setData('arrSkipValidationFields', $arrSkip);

                $strStreet = $arrRecord['street'];
                $strCity = $arrRecord['city'];
                $strCountry = $arrRecord['country'];

                $strStreet = str_replace(' ', '+', $strStreet);
                $strCity = str_replace(' ', '+', $strCity);
                $strAddress = $strStreet.',+'.$strCity.',+'.$strCountry;

                // Get position from Google Maps
                $arrPos = $this->curlGetCoordinates(sprintf('https://maps.googleapis.com/maps/api/geocode/json?address=%s&sensor=false', $strAddress));

                if (null !== $arrPos && \is_array($arrPos['results'][0]['geometry'])) {
                    $latPos = $arrPos['results'][0]['geometry']['location']['lat'];
                    $lngPos = $arrPos['results'][0]['geometry']['location']['lng'];

                    $objWidget->value = $latPos.','.$lngPos;
                } else {
                    // Error handling
                    if ('' !== $this->curlErrorMsg) {
                        $objWidget->addError($this->curlErrorMsg);
                    } else {
                        $objWidget->addError(sprintf('Setting geolocation for (%s) failed!', $strAddress));
                    }
                }
            }
        }
    }

    /**
     * Curl helper method.
     */
    private function curlGetCoordinates(string $url): array|null
    {
        // is cURL installed on the webserver?
        if (!\function_exists('curl_init')) {
            $this->curlErrorMsg = 'Sorry cURL is not installed on your webserver!';

            return null;
        }

        // Set a timout to avoid the OVER_QUERY_LIMIT
        usleep(25000);

        // Create a new cURL resource handle
        $ch = curl_init();

        // Set URL to download
        curl_setopt($ch, CURLOPT_URL, $url);

        // Should cURL return or print out the data? (true = return, false = print)
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

        // Timeout in seconds
        curl_setopt($ch, CURLOPT_TIMEOUT, 10);

        // Download the given URL, and return output
        $arrOutput = json_decode(curl_exec($ch), true);

        // Close the cURL resource, and free system resources
        curl_close($ch);

        return $arrOutput;
    }
}

祝您使用“从CSV导入包”愉快!!