madj2k/t3-core-extended

为您的TYPO3安装添加一些基本功能

安装: 101

依赖项: 33

建议者: 0

安全性: 0

星标: 0

关注者: 2

分支: 0

开放问题: 0

类型:typo3-cms-extension


README

core_extended

内容渲染的自定义错误消息

使用以下配置,您可以在前端发生错误时返回自定义消息。

config {
``
	[...]

    //===============================================================
    // Exceptions for FE-Rendering
    //===============================================================
    // Custom class
    contentObjectExceptionHandler = Madj2k\CoreExtended\Error\ContentObjectProductionExceptionHandler

    // Customizing error message
    contentObjectExceptionHandler.errorMessage = Leider ist ein Fehler aufgetreten. Helfen Sie uns, den Fehler zu beheben und schreiben Sie uns unter Angabe des Fehlercodes "%s" an <a href="mailto:service@example.de?subject=Errorcode:%20%s">service@example.de</a>

    // Ignore these error codes
    // contentObjectExceptionHandler.ignoreCodes.10 = 1414512813

媒体版权信息

使用此插件可以输出所有使用的媒体的相关版权信息。这对于库存图片特别有帮助。您也可以通过Typoscript使用它,例如在每页打印媒体源的版权信息。

imageResources = USER
imageResources {
    userFunc = TYPO3\CMS\Extbase\Core\Bootstrap->run
    extensionName = CoreExtended
    pluginName = MediaSources
    vendorName = Madj2k
    controller = MediaSources
    switchableControllerActions {
        // Again: Controller-Name and Action
        MediaSources {
            1 = listPage
        }
    }

    view =< plugin.tx_coreextended.view
    persistence =< plugin.tx_coreextended.persistence
    settings =< plugin.tx_coreextended.settings
    settings.resources.includeFieldsList = pages.tx_coreextended_preview_image, pages.media, tt_content.image, tt_content.assets
}

Google Sitemap

此扩展包含一个自动更新的Google-Sitemap,可以通过以下链接访问

https://your-domain.com/?type=1453279478

缺失的资产文件 - @已弃用!

当使用渲染的图像时,清除所有缓存可能导致通过社交媒体共享但哈希值已更改的图像出现404错误。处理程序会尝试通过搜索具有相同文件名的文件并设置符号链接来找到图像。

在您的Apache配置中实现此指令以激活处理程序

### Begin: Adding rewrite for missing asset files (e.g. og:image) ###
<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_FILENAME} !-l
    RewriteRule ^(typo3temp/assets/images/((csm_.+)\.(gif|png|jpg|jpeg)))$ https://%{HTTP_HOST}/index.php?type=1605802513&file=$2 [R=301,NC,L]
</IfModule>
### End: Adding rewrite for missing asset files (e.g. og:image) ###

或者您可以使用此配置来设置NGINX

### Begin: Adding rewrite for missing asset files (e.g. og:image) ###
location ~* ^/(typo3temp/assets/images/((csm_.+)\.(gif|png|jpg|jpeg)))$ {
    try_files $uri $scheme://$host/index.php?type=1605802513&file=$2 =404;
}
### End: Adding rewrite for missing asset files (e.g. og:image) ###

StoragePidAwareAbstractRepository

此扩展包含一个抽象仓库类,该类修复了仓库使用调用扩展的storagePid的麻烦行为。

如果您的仓库扩展了这个类,它将始终使用自己的storagePid - 即使是通过另一个扩展调用

路由的Slug助手

此slug助手在加载表字段到路由时规范化生成的路由。这对于处理德语元音字母特别有用。

routeEnhancers:
  RkwAuthors:
    type: Extbase
    namespace: 'tx_rkwauthors_rkwauthorsdetail'
    routes:
      - routePath: '/rkw-author/{author}'
        _controller: 'Authors::show'
      - routePath: '/rkw-authorform/{author}'
        _controller: 'Authors::contactFormSend'
    defaultController: 'Authors::show'
    aspects:
      author:
        type: PersistedSlugifiedPatternMapper
        tableName: 'tx_rkwauthors_domain_model_authors'
        routeFieldPattern: '^(.*)-(?P<uid>\d+)$'
        routeFieldResult: '{first_name|sanitized}-{last_name|sanitized}-{uid}'

CSV导入器

CSV导入器使用TCA设置,因此可以在TYPO3的上下文中用于所有表。特殊功能是CSV导入器还可以自动接管TypeCasting,并支持在导入过程中导入子表。这使得可以直接导入不同表中的数据记录之间的关系。CSV导入器在数据记录中传递uid时自动识别是否必须进行更新或插入。通过指定搜索字段,还可以根据定义的表列独立于指定uid搜索现有数据记录。这可以防止重复条目。此外,可以传输字段的默认值并设置限制。

用法

首先,您必须初始化CSV-导入器,并定义导入的主表。

/** @var \TYPO3\CMS\Extbase\Object\ObjectManager $objectManager */
$objectManager = GeneralUtility::makeInstance(ObjectManager::class);

/** @var \Madj2k\CoreExtended\Transfer\CsvImporter $csvImporter */
$csvImporter = $objectManager->get(CsvImporter::class);
$csvImporter->setTableName('your_table');

然后,您设置要读取的文件或字符串。数据可以通过文件或字符串读取。

$csvImporter->readCsv($stringOrFile);

现在,您必须告诉CSV-导入器它允许导入哪些表。这很重要,因为它还可以导入相关的子表。请确保至少将您的主表包括在列表中。否则,根本不会导入任何内容。

$csvImporter->setAllowedTables(['fe_users'])

之后,您可以添加一些以下描述的附加设置。最后,通过调用

$csvImporter->import();

功能:导入关系

假设对于创建与其他表关系的表字段,您想直接导入第二个表的对应数据。这可以通过在CSV数据的标题中提供与主表字段名称相对应的前缀来完成。然后CSV导入器会自动使用TCA配置解析关系并导入两个数据集。这可以实现无限嵌套。

示例:仅插入

示例CSV文件,用于导入到fe_users

+------------+------------+-----------------+-----------------------+--------------------------+--------------------------------+
| first_name | last_name  | usergroup.title | usergroup.description | usergroup.subgroup.title | usergroup.subgroup.description |
+------------+------------+-----------------+-----------------------+--------------------------+--------------------------------+
| Sabine     | Mustermann | Usergroup 1     | Ipsum Bibsum          | Subgroup 1               | Sub-Ipsum Bibsum               |
| Matthias   | Musterfrau | Usergroup 2     | Ipsum Lorem           | Subgroup 2               | Sub Ipsum Lorem                |
| Sam        | Person     | Usergroup 3     | Lorem Ipsum           | Subgroup 3               | Sub Lorem Ipsum                |
+------------+------------+-----------------+-----------------------+--------------------------+--------------------------------+

重要的是,相关的表也允许进行关系操作,并且它们必须允许导入。

$csvImporter->setAllowedTables(['fe_users', 'fe_groups']); // allows both tables for import
$csvImporter->setAllowedRelationTables(
[
    'fe_users' => ['fe_groups'], // allows all realtions from fe_users to fe_groups
    'fe_groups' => ['fe_groups'] // allows all relation from fe_groups to fe_groups (used for subgroups-property)
]
);

导入结果将是每行三个直接相互关联的记录。

  1. fe_users表中插入一条记录,并通过字段usergroup
  2. fe_groups表中插入的记录“Usergroup X”相关联,该记录将插入并反过来通过字段subgroup
  3. fe_groups表中插入的记录“Subgroup X”相关联,该记录代表子组。

这是因为TCA包含有关相关字段关系的相关信息,并且CSV导入器会自动解释这些信息。

fe_users

return [
    'columns' => [
        'usergroup' => [
            'label' => 'LLL:EXT:frontend/Resources/Private/Language/locallang_tca.xlf:fe_users.usergroup',
            'config' => [
                'type' => 'select',
                'renderType' => 'selectMultipleSideBySide',
                'foreign_table' => 'fe_groups',
                'foreign_table_where' => 'ORDER BY fe_groups.title',
                'enableMultiSelectFilterTextfield' => true,
                'size' => 6,
                'minitems' => 1,
                'maxitems' => 50
            ]
        ],

fe_groups

return [
    'columns' => [
        'subgroup' => [
            'exclude' => true,
            'label' => 'LLL:EXT:frontend/Resources/Private/Language/locallang_tca.xlf:fe_groups.subgroup',
            'config' => [
                'type' => 'select',
                'renderType' => 'selectMultipleSideBySide',
                'foreign_table' => 'fe_groups',
                'foreign_table_where' => 'AND NOT(fe_groups.uid = ###THIS_UID###) ORDER BY fe_groups.title',
                'enableMultiSelectFilterTextfield' => true,
                'size' => 6,
                'autoSizeMax' => 10,
                'minitems' => 0,
                'maxitems' => 20
            ]
        ],

示例:插入和更新

如果您包括例如用户组的uid,则CSV导入器将按上述方式工作,但会检查是否可以找到指定的uid,并对相应的记录进行更新而不是插入。

示例CSV文件,用于导入到fe_users

+------------+------------+---------------+-----------------+-----------------------+--------------------------+--------------------------------+
| first_name | last_name  | usergroup.uid | usergroup.title | usergroup.description | usergroup.subgroup.title | usergroup.subgroup.description |
+------------+------------+---------------+-----------------+-----------------------+--------------------------+--------------------------------+
| Sabine     | Mustermann |             1 | Usergroup 1     | Ipsum Bibsum          | Subgroup 1               | Sub-Ipsum Bibsum               |
| Matthias   | Musterfrau |             2 | Usergroup 2     | Ipsum Lorem           | Subgroup 2               | Sub Ipsum Lorem                |
| Sam        | Person     |             3 | Usergroup 3     | Lorem Ipsum           | Subgroup 3               | Sub Lorem Ipsum                |
+------------+------------+---------------+-----------------+-----------------------+--------------------------+--------------------------------+

假设数据库中存在用户组1、2和3,以下将发生

导入结果将是每行两个直接相互关联的记录。

  1. fe_users表中插入一条记录,并通过字段usergroup
  2. fe_groups表中存在的记录“Usergroup X”(通过给定的uid识别),该记录将被更新,并通过字段subgroup
  3. fe_groups表中插入的记录“Subgroup X”相关联,该记录代表子组。

您可以以任何可能的组合执行此操作。

功能:避免重复

通过指定搜索字段,还可以根据定义的表列独立于指定uid来搜索现有数据记录。这可以防止重复条目。

$csvImporter->setUniqueSelectColumns(['fe_users' => ['address', 'email']]);

使用上述设置,CSV导入器将使用两个字段addressemailfe_user表中搜索,并将它们与您即将通过CSV导入的这两个列的值进行比较。如果它们匹配,CSV导入器将不会插入或更新记录,但设置所有相关关系(如果有)。保留现有关系。

请注意:如果通过搜索字段找到记录,CSV导入器将更新记录。

功能:导入并引用最后导入的行

可能的情况是您想将两个记录添加到同一导入记录中。让我们看看以下虚构的例子

+------------+------------+----------------------+---------------+-----------------+-----------------------+
| first_name | last_name  |        email         | usergroup.uid | usergroup.title | usergroup.description |
+------------+------------+----------------------+---------------+-----------------+-----------------------+
| Sabine     | Mustermann | mustermann@muster.de |             1 | Usergroup 1     | Ipsum Bibsum          |
| Sabine     | Mustermann | mustermann@muster.de |             2 | Usergroup 2     | Ipsum Lorem           |
+------------+------------+----------------------+---------------+-----------------+-----------------------+

显然前两行指的是同一个人,她属于两个不同的用户组。但如果您不修改地导入上述示例,它将导致Mrs. Mustermann有两个记录,每个记录都有一个相关的用户组。为了达到我们想要的效果,我们可以告诉CSV导入器通过在添加的uid列中使用关键字LAST将第二行引用到第一行。

+------+------------+------------+----------------------+---------------+-----------------+-----------------------+
| uid  | first_name | last_name  |        email         | usergroup.uid | usergroup.title | usergroup.description |
+------+------------+------------+----------------------+---------------+-----------------+-----------------------+
| 0    | Sabine     | Mustermann | mustermann@muster.de |             1 | Usergroup 1     | Ipsum Bibsum          |
| LAST | Sabine     | Mustermann | mustermann@muster.de |             2 | Usergroup 2     | Ipsum Lorem           |
+------+------------+------------+----------------------+---------------+-----------------+-----------------------+

该导入的结果将是

  1. fe_users中插入一个“Sabine Mustermann”记录,并通过字段usergroup
  2. 插入的两个fe_usergroup记录(“Usergroup 1”和“Usergroup 2”)相关联

请注意

  • LAST仅适用于第一级,不适用于子表。这是因为子表只能引用一个记录,因此在此处LAST没有意义。
  • LAST可以使用多次。它始终引用最后执行插入操作的表的uid

设置:从导入中排除字段

如果您出于某些原因想要在导入时排除某些字段,您可以定义每个可导入表(及其子表)在导入过程中要忽略哪些字段。

$csvImporter->setExcludeColumns(
        [
            'fe_users' => [
                'hidden', 'deleted', 'tstamp', 'crdate', 'tx_extbase_type', 'TSconfig'
            ],
            'fe_groups' => [
                'hidden', 'deleted', 'tstamp', 'crdate'
            ]
        ],
    );

设置:导入时包含字段

如果您出于某些原因想要在导入时包含某些字段,这些字段不属于TCA(例如pid),您可以定义每个可导入表(及其子表)在导入过程中将添加哪些字段。

请注意:不会检查字段是否存在于数据库中!

$csvImporter->setIncludeColumns(
        [
            'fe_users' => [
                'pid'
            ],
            'fe_groups' => [
                'pid', 'newly_included'
            ]
        ],
    );

设置:显式添加数据到导入

如果您想确保CSV导入的某些字段无论通过CSV设置什么值都填充预定义的值,您可以使用以下方法。这将覆盖定义的列的CSV数据的值,并添加CSV数据可能缺失的列。如果您想设置子表的值,也可以通过添加列名作为前缀来完成。

请注意:调用applyAdditionData()是强制性的,因为此功能会更改原始导入数据。因此,您必须两次确认更改。

$additionalData = [
    'zip' => 'Override Value!',
    'not_included_in_csv' => 'New Column And Value!',
    'usergroup.description => 'Description override!'
];
$csvImporter->setAdditionalData($additionalData);
$csvImporter->applyAdditionalData();

设置:设置默认值

如果您想为某些列设置默认值,可以使用以下方法。它将设置定义的值,但如果CSV数据包含非空值(0被视为空值),则这些值将被覆盖。它还将添加CSV数据可能缺失的列。

请注意:调用applyDefaultValues()是强制性的,因为此功能会更改原始导入数据。因此,您必须两次确认更改。

$defaultValues = [
    'zip' => 'Default value',
    'no_included_incsv' => 'New Column and Value!',
    'usergroup.description => 'Description default value!'
];
$csvImporter->setDefaultValues($defaultValues);
$csvImporter->applyDefaultValues();

功能:类型转换和清理

类型转换和清理将根据列的TCA配置自动执行。这包括

  • 基于eval将DateTime转换为时间戳的类型转换
  • 基于eval/类型的浮点数类型转换
  • 基于eval/类型的整数类型转换
  • 基于渲染类型复选框(1/0)的类型转换
  • 基于渲染类型链接的链接修复
  • 对于启用了RTE的列,使用nl2br和包裹P标签
  • 对所有值进行修剪

在后台上下文中模拟前端

当使用CLI命令或单元测试,并且需要TYPO3像在前端上下文中一样表现时,这非常有用。如果在单元测试的上下文中使用它,请注意,您必须定义一个域名和一个页面对象!示例

Rootpage.typoscript

page = PAGE
page {
    10 = TEXT
    10.value = Hallo Welt!
}

Global.xml

dataset>
    <pages>
        <uid>1</uid>
        <pid>0</pid>
        <title>Rootpage</title>
        <doktype>1</doktype>
        <perms_everybody>15</perms_everybody>
    </pages>
</dataset>

config.yaml

base: www.example.com
languages:
  -
    title: Deutsch
    enabled: true
    base: /
    typo3Language: de
    locale: de_DE.UTF-8
    iso-639-1: de
    navigationTitle: ''
    hreflang: de-DE
    direction: ltr
    flag: de
    languageId: '0'
  -
    title: Englisch
    enabled: false
    base: /en/
    typo3Language: default
    locale: en_US.UTF-8
    iso-639-1: en
    navigationTitle: ''
    hreflang: ''
    direction: ''
    flag: gb
    languageId: '1'
    fallbackType: strict
    fallbacks: ''
rootPageId: '{rootPageId}'
routes: {  }
imports:
  - { resource: "EXT:core_extended/Configuration/Routes/Default.yaml" }

routeEnhancers:
  #========================================
  # PageTypes
  #========================================
  PageTypeSuffix:
    type: PageType
    default: '/'
    index: ''
    map:

      # defaults and trailing slash
      '/': 0
      'print/': 98
      'xml/': 150
      'content-only/': 160
      'plaintext/': 170
      'csv/': 180

您的测试文件中的setUp()

    $this->importDataSet(self::FIXTURE_PATH . '/Database/Global.xml');
    $this->setUpFrontendRootPage(
        1,
        [
            'EXT:core_extended/Configuration/TypoScript/setup.txt',
            self::FIXTURE_PATH . '/Frontend/Configuration/Rootpage.typoscript',
        ],
        ['example.com' => self::FIXTURE_PATH .  '/Frontend/Configuration/config.yaml']
    );

    FrontendSimulatorUtility::simulateFrontendEnvironment(1);

您的测试文件中的tearDown()

    FrontendSimulatorUtility::resetFrontendEnvironment();

元标签生成器:机器人

此扩展包含用于ext:seo的noindex-和nofollow-属性的元标签生成器。主要区别是,这两个属性都继承到相应的子页面。这样,您就能为一整个页面树设置noindex和/或nofollow。当您准备设置一个新网站,但不想让它被爬取时,这很有用。

元标签生成器:元标签

此扩展包含用于keywords-和description-属性的元标签生成器。主要区别是,这两个属性都继承到相应的子页面。这样,您就能为一整个页面树设置关键词和/或描述。

元标签生成器:规范路径

使用Madj2k\DrSeo\MetaTag\CanonicalGenerator->getPath()获取由ext:seo生成的当前规范路径,ext:seo是TYPO3核心的一部分。例如,这有助于生成共享链接。

示例

lib.txYourExtension {

    socialMedia {
        shareUrl = USER_INT
        shareUrl.userFunc = Madj2k\DrSeo\MetaTag\CanonicalGenerator->getPath
        shareUrl.stdWrap.rawUrlEncode = 1
    }
}
<a href="https://twitter.com/intent/tweet?url={f:cObject(typoscriptObjectPath:'lib.txYourExtension.socialMedia.shareUrl')}">
    Share on Twitter
</a>

TypoScript库

此扩展包含以下库

  • 向页面标题添加组合页面标题
  • 向页面标题添加openGraph数据,包括水印和版权信息

使用示例

page {
    headerData {

        // Title-Tag
        1010 < lib.txCoreExtended.titleTag

        // OpenGraph
        1030 < lib.txCoreExtended.openGraph
    }
}

TypoScript条件

此扩展包含三个TypoScript条件

BackendColPos(后台上下文)

此条件对于例如允许或禁止根据编辑的colPos对后台编辑器的内容元素很有帮助。

用法

[backendColPos() == 111]
    // do whatever
[END]

BackendLayout(后台上下文)

此条件对于例如允许或禁止根据后台布局对后台编辑器的内容元素很有帮助。它还检查backend_layout_subpages字段。

用法

[backendLayout() == 'pagets__homePages']
    // do whatever
[END]

扩展已加载(后端和前端上下文)

此条件检查指定的扩展是否已安装

用法

[extensionLoaded('fictive_ext')]
    // do whatever
[END]
[! extensionLoaded('fictive_ext')]
    // do whatever
[END]

FlashMessages和FormErrors的标准部分

此扩展包含两个标准文件用于FlashMessages和FormErrors,您可以在自己的扩展中使用。

用法

  1. 将部分添加到您自己的扩展
plugin.tx_yourextension {

    view {
        partialRootPaths {
            0 = EXT:yourextension/Resources/Private/Partials/
            1 = {$plugin.tx_yourextension.view.partialRootPath}
            2 = {$plugin.tx_coreextended.view.partialRootPath}
        }
    }
}
  1. 按常规引用部分
<f:render partial="FlashMessages" arguments="{_all}" />
<f:render partial="FormErrors" arguments="{for:yourObject}"/>

sr_freecap使用时的附加功能

此扩展修复了sr_freecap中的一些错误(如果已安装该扩展)。除此之外,它

  • 添加了一个基本的部分,防止您在每个扩展中复制相同的属性和部分,使得在您的扩展中使用sr_freecap成为可选的
  • 添加了一个自定义验证器,使得在您的扩展中使用sr_freecap成为可选的

用法

  1. 将部分添加到您自己的扩展
plugin.tx_yourextension {

    view {
        partialRootPaths {
            0 = EXT:yourextension/Resources/Private/Partials/
            1 = {$plugin.tx_yourextension.view.partialRootPath}
            2 = {$plugin.tx_coreextended.view.partialRootPath}
        }
    }
}
  1. 在您的模型中扩展AbstractCaptcha类。这将添加sr_freecap工作所需的所有字段。无需扩展您的数据库表!
<?php
namespace YourNamespace\YourExtension\Domain\Model;

/*
 * This file is part of the TYPO3 CMS project.
 *
 * It is free software; you can redistribute it and/or modify it under
 * the terms of the GNU General Public License, either version 2
 * of the License, or any later version.
 *
 * For the full copyright and license information, please read the
 * LICENSE.txt file that was distributed with this source code.
 *
 * The TYPO3 project - inspiring people to share!
 */

use Madj2k\CoreExtended\Domain\Model\AbstractCaptcha;

/**
 * Class MyClass
 *
 * @author You <you@you.de>
 * @copyright You
 * @package YourNamespace_YourExtension
 * @license https://gnu.ac.cn/licenses/gpl.html GNU General Public License, version 3 or later
 */
class MyClass extends AbstractCaptcha
{

  1. 将验证器添加到控制器中需要验证的相应操作
    /**
     * action create
     *
     * @param \YourNamespace\YourExtension\Domain\Model\MyClass $class
     * @return void
     * @TYPO3\CMS\Extbase\Annotation\Validate("Madj2k\CoreExtended\Validation\CaptchaValidator", param="class")
     */
    public function createAction(
        \YourNamespace\YourExtension\Domain\Model\MyClass $class,
    ): void {
  1. 将验证码添加到您的表单中
<f:render partial="CaptchaElement" />

XClasses

  • 添加额外的cookie "fe_login",如果用户已登录,则可通过JavaScript访问。这可以用于例如触发仅对登录用户相关的AJAX调用。
  • 扩展\TYPO3\CMS\Extbase\Service\EnvironmentService::isEnvironmentInFrontendMode()和\TYPO3\CMS\Extbase\Service\EnvironmentService::isEnvironmentInBackendMode(),以便这些方法也检查$GLOBALS['TSFE']。
  • 修复了\TYPO3\CMS\Extbase\Service\ExtensionService中的奇怪错误,该错误在没有原因的情况下抛出异常

一些通用方法、验证器和视图辅助器

[稍后描述]