aplia/content-tools

改进了与eZ publish遗留内容对象工作的API

v1.8.8 2021-08-31 12:53 UTC

README

此包包含类,这些类使得在创建和更新内容时与内容对象一起工作更加容易。它还具有使用Phinx迁移内容的功能。

当某些内容缺失或操作失败时,它将抛出一个合适的异常,请参阅命名空间Aplia\Content\Exceptions以获取可能错误列表。

Latest Stable Version Minimum PHP Version

ContentType

围绕eZContentClass包装器,它使用所选属性定义一个新类。

示例,创建一个新的内容类

<?php
// Define the class, does not modify the database
$type = new Aplia\Content\ContentType('folder', 'Folder', array(
    'groups' => array('Content'),
    'isContainer' => true,
    'contentObjectName' => '<title>',
    'alwaysAvailable' => false,
    'description' => 'Container for other content objects',
    'sortBy' => 'name',
))
->addAttribute('ezstring', 'title', 'Title');

// Create the content-class in the database
$type->create();

sortBy是一个特殊属性,它应该包含一个字符串,该字符串包含由eZContentObjectTreeNode指定的按标识符排序的字段,要反转排序,请将负号添加到前面。例如:name-name

每次调用addAttribute都会创建一个新的ContentTypeAttribute实例,当调用create()update()save()时,它将在eZ publish中创建。属性主要由数据类型、标识符和名称组成。此外,还可以设置第四个参数,它是一个包含附加命名参数的数组。

以下适用于所有属性。

  • isRequired - 是否需要此属性,默认为false。
  • isSearchable - 是否将属性注册到搜索索引,默认为true。
  • canTranslate - 是否允许翻译属性,默认为true,但也取决于使用的数据类型。
  • isInformationCollector - 是否是信息收集器,默认为false。
  • value - 发送到数据类型的附加值,这是一个关联数组,内容取决于数据类型。
  • language - 属性的语言,默认为属于它的ContentType相同的语言。
  • description - 属性的描述性文本。
  • placeAfter - 在指定标识符的现有属性之后放置属性
  • placeBefore - 在指定标识符的现有属性之前放置属性

同样,可以使用removeAttribute和标识符来删除属性。这将安排在下次调用save()时删除属性。

还有用于检查属性存在性和获取属性对象的方法。(hasAttribute()classAttribute()

要删除一个类,请使用remove(),首先检查它是否exists()

要方便地访问内容类和属性,请使用属性contentClassattributes,这些属性将懒加载值。请注意,它们需要内容类存在。

ezselection2

示例

<?php
$type->addAttribute('ezselection2', 'selection2', 'Selection 2', array(
    'value' => array(
        'delimiter' => '',
        'is_checkbox' => true,
        'is_multiselect' => true,
        'options' => array(
            ['identifier' => 'first', 'name' => 'First', 'is_selected' => false],
            ['identifier' => 'second', 'name' => 'Second', 'is_selected' => true],
            ['identifier' => 'third', 'name' => 'Third', 'is_selected' => false],
        ),
        'use_identifier_name_pattern' => true,
    )
));

可以使用ContentType管理类组。要创建或删除组,请使用ContentType::createGroupContentType::deleteGroup

例如

ContentType::createGroup('Sections');

通过使用addToGroup()removeFromGroup()setGroups()将类分配给组。这些更改将安排在下一次同步时写入。如果组分配存在(添加/删除),则不进行任何更改。

例如

$type
    ->addToGroup('Sections')
    ->removeFromGroup('Content')
    ->save();

组分配也可以在set()调用中通过使用groups键条目来指定。

例如

$type
    ->set(array(
        'groups' => array('Sections'),
    ));
    ->save();

组可以是ID、名称或eZContentClassGroup对象。由于组没有持久ID,通常最好使用名称。

翻译

内容类的一些字段及其属性可能会被翻译,这是通过使用 addTranslation()removeTranslation() 实现的。

以下内容类字段可能会被翻译

  • 名称
  • 描述

以下内容类属性字段可能会被翻译

  • 名称
  • 描述
  • data_text

例如

$type
    ->addTranslation(
        'nor-NO',
        array(
            'name' => 'Seksjon',
            'description' => 'Seksjonssystem',
            'attributes' => array(
                'title' => array(
                    'name' => 'Tittel',
                )
            ),
        )
    )
    ->save();

对于直接操作,也存在 createTranslation()deleteTranslation()

目前不支持翻译数据类型的自定义内容,这可以通过使用插件系统来解决。

数据类型

虽然可以创建具有任何数据类型的属性,但在设置额外的类属性时,并非所有类型都受支持。所有受支持的类型都通过向 addAttribute 传递 value 参数来设置,该值始终是一个具有特定于数据类型条目的数组。例如,为 ezstring 属性设置最大 50 个字符。

<?php
$type->addAttribute('ezstring', 'title', 'Title', array(
    'value' => array(
        'max' => 50,
    )
))

ezstring

最大长度可以通过在 value 中的 max 参数中设置来设置,默认为 0(无限制)。

默认值可以通过在 value 中的 default 参数中设置来设置,默认为 ''(空字符串)。

<?php
$type->addAttribute('ezstring', 'title', 'Title', array(
    'value' => array(
        'max' => 50,
        'default' => 'Perfect Circle',
    )
))

ezboolean

默认值可以通过在 value 中的 default 参数中设置来设置,默认为 0(未选中)。

<?php
$type->addAttribute('ezboolean', 'has_size', 'Has size?', array(
    'value' => array(
        'default' => true,
    )
))

ezinteger

最小值可以通过在 value 中的 min 参数中设置来设置,默认为 null(无限制)。

最大值可以通过在 value 中的 max 参数中设置来设置,默认为 null(无限制)。

默认值可以通过在 value 中的 default 参数中设置来设置,默认为 null。

<?php
$type->addAttribute('ezinteger', 'size', 'Size', array(
    'value' => array(
        'min' => 5,
        'max' => 10,
        'default' => 7,
    )
))

eztext

列大小可以通过在 value 中的 columns 参数中设置来设置,默认为 10。

<?php
$type->addAttribute('eztext', 'body', 'Body', array(
    'value' => array(
        'columns' => 15,
    )
))

ezxmltext

列大小可以通过在 value 中的 columns 参数中设置来设置,默认为 10。

可以通过在 value 中的 tag_preset 参数中设置来设置标签预设。

<?php
$type->addAttribute('ezxmltext', 'body', 'Body', array(
    'value' => array(
        'columns' => 15,
        'tag_preset' => 'whatever this is',
    )
))

ezimage

可以通过在 value 中的 max_file_size 参数中设置来设置最大文件大小(以 MB 为单位),默认为 0(无限制)。

<?php
$type->addAttribute('ezimage', 'image', 'Image', array(
    'value' => array(
        'max_file_size' => 10, // 10MB
    )
))

ezobjectrelation

可以通过在 value 中的 selection_type 参数中设置选择类型。值为 0 表示浏览关系,1 表示下拉菜单。

可以通过在 value 中的 default_selection_node 参数中设置默认选择节点。

可以通过在 value 中的 fuzzy_match 参数中开启或关闭模糊匹配。

<?php
$type->addAttribute('ezimage', 'image', 'Image', array(
    'value' => array(
        'selection_type' => 1,
        'default_selection_node' => 2,
        'fuzzy_match' => false
    )
))

ezurl

默认值可以通过在 value 中的 default 参数中设置来设置,默认为 ''(空字符串)。

<?php
$type->addAttribute('ezurl', 'link', 'Link', array(
    'value' => array(
        'default' => 'http://example.com',
    )
))

ContentObject

围绕 eZContentObject 的包装,用于定义具有所选属性的内容对象。首先使用标识符创建 ContentType 实例,无论是使用现有的内容类还是使用 create() 新的内容类。然后使用该类型实例来实例化新的对象实例。

示例,实例化内容类

<?php
// Create an object wrapper which is filled with data
$type = new Aplia\Content\ContentType('folder');
$folder = $type->contentObject(array(
    'locations' => array(array('parent_id' => 2)),
))
->setAttribute('title', 'New folder');

// Create the object in the database and publish it
$folder->create(true);

数据类型和对象属性

大多数属性内容是通过向 setAttribute 传递 $content 参数来设置的,该值将使用 fromString 方法以原样发送到数据类型。然而,某些数据类型需要特殊的内容值,以下是一些受支持的。

ezxmltext

内容必须从 HTML 导入或使用内部 XML 格式。

要导入 HTML 内容,请使用 Aplia\Content\HtmlText 类,用 HTML 文本实例化它,并将其作为内容传递。然后系统将负责将其转换为内部格式。注意:ezxmltext 期望 HTML 包含 <p> 标签作为主要文本内容,因此设置简单文本需要将其包裹在 <p> 标签中。

要导入 XML 内容,请使用 Aplia\Content\RawXmlText 类,用文本实例化它,可选地包含对象链接、相关对象 ID 或链接对象 ID。

HTML 文本示例

<?php
$object->setAttribute('body', new Aplia\Content\HtmlText('<p>My text</p>'));

ezselection

这期望选择值是所选键的整数值,第一个选择是 0,下一个是 1,以此类推。

ezselection2

标识符可以像支持数据类型一样指定 fromString

<?php
$object->setAttribute('selection2', 'first|second')

或者作为数组

<?php
$object->setAttribute('selection2', ['first', 'second'])

ezimage

目前仅支持上传的HTTP文件。创建一个名为$_FILES中文件条目名称的Aplia\Content\HttpImage实例。

例如,如果HTML表单包含一个<input type="file" name="portrait_image">,则图像文件将在文件条目portrait_image中可用。

<?php
$object->setAttribute('image', new Aplia\Content\HttpFile('portrait_image'));

内容导出/导入

内容工具支持跨站点的子树导出/导入,同时保留所有权、关系和嵌入内容。记住,在从一个项目导出和导入到另一个项目时,不要有不匹配的包版本。这可能需要导入时使用配置文件,它将导出的内容映射到目标内容。有关更多信息,请参阅“导入配置”部分。

内容导出

使用bin/dump_content进行内容导出。在编写本文时,这些是当前可用的选项

(vendor/bin/dump_content --help)

Options:
  --format=VALUE           Type of format, choose between json, ndjson, php and line
  --preamble               Whether to include preamble when exporting php (php format only)
  --use-namespace          Whether to include ContentType namespace use statement (php format only)
  --class=VALUE            Limit search of objects to only these type of content-classes. Comma separated list
  --parent-node=VALUE      Choose starting point for export, defaults to root-node 1. Specifiy either node ID, node:<id>, object:<id> or path:<alias-path>
  --depth=VALUE            Choose how deep in the tree structure to search, defaults to 1 level. Use * for unlimited
  --exclude-parent         Exclude the parent node from the export, the result is then only the child/sub-nodes
  --only-visible           Only export visible nodes
  --file-storage=VALUE     Store file content in specified folder, instead of embedding as base64 in export.
  --include-relations      Include all objects which are related in export
  --include-embeds         Include all objects which are embedded in export
  --include-owners         Include objects for all owners
  --include-parents        Include all parents of objects
  --no-exclude-top-nodes   Turn off exclusion of top-level nodes
  --exclude-node=VALUE...  Excluded specific node from export, can be used multiple times
  --summary                Include commented summary at the end (php format only)

脚本回显,所以将结果管道到文件。

示例

这是一个配置,它将导出给定路径下给定内容类的所有对象(容器路径,对应于--parent-node选项)。此导出假定父目录在导入目标上已存在(即,如果要导入整个目录,请删除--exclude-parent)。

(尖括号中的值(《<》和《>》)应替换为您自己的选项。)

vendor/bin/dump_content <container_path> --class=<content_class> --exclude-parent --file-storage=export_files --format=ndjson > <export_name>.ndjson;

在设置文件存储路径时,此文件夹应位于导出文件相同的文件夹中。例如

export_content
|-  <export_name.ndjson>
|-  export_files
    |-  file 1
    |-  file 2

内容导入

使用bin/import_content进行内容导入。在编写本文时,这些是当前可用的选项

(vendor/bin/import_content --help)

--parent-node=VALUE  Choose starting point for import of content objects, defaults to root-node 1. Specifiy either node ID, node:<id>, object:<id>, path:<alias-path>, or tree:<id> e.g tree:content, tree:media, tree:users, tree:top
--config=VALUE       Config file for mapping content in the export (e.g. node ids, uuids) to content in the import destination. See more about this in the section about configuration.
--temp-path=VALUE    Path to place to use for temporary files
--yes                Whether to answer yes on all questions. Use with care.

导入日志通过stdout输出,所以将结果管道到文件以保存日志输出。例如使用| tee import_log.txt。 (通过tee管道可能不会显示交互式问题,因此请确保脚本没有等待问题响应,如果没有更新显示。)

如果问题中的对象在目标数据库或导入中都不存在,则脚本可能会询问是否删除对象关系或重置所有权。(大导入可能会提示很多次,这就是为什么添加了--yes参数。)

注意!内容导入开始数据库事务,并在整个导入完成后才提交。这样,在发生错误的情况下,不成功的导入将回滚数据库事务,因此不会将错误数据提交到数据库。这意味着在导入运行时,在目标上发布新内容将不起作用,并将给出数据库事务错误。有关如何在导入内容的同时发布内容,请参阅“批量导出/导入”部分的示例。

示例

vendor/bin/import_content --temp-path=temp --parent-node=path:kompetansetorget --config=extension/site/import/<config_file>.ini <export_file>

注意!批量导出/导入

通过将导出的内容分割成多个文件,我们减少了内容提交到数据库之前需要进行的操作数量,从而使得发布内容成为可能。

(这是目前对此的唯一支持,因为导入特定对象所需的所有操作。即:1. 创建节点/对象骨架,2. 创建对象,3. 使用数据更新对象。这样做是为了在导入依赖于其他对象的对象时保留位置、关系和所有权)

示例

  • 导出:给定现有的导出<export_name>。ndjson,以下bash脚本将导出分割成一个.head文件,该文件将附加到编号文件之前。它采用第一个出现的ez_contentobject,并将以下内容分割为5行,这对应于5个内容对象。PS:这可能会生成很多文件。
cat <export_name>.ndjson | sed -e '/ez_contentobject/,$d' > <export_name>.head; cat <export_name>.ndjson | sed -n -e '/ez_contentobject/,$p' | split -l5 - <export_name>- --additional-suffix=.tmp --numeric-suffixes=1; for f in <export_name>-*.tmp; do cat <export_name>.head "$f" > "${f%.*}".ndjson; rm "$f"; done
  • 导入
for f in <export_name>-*.ndjson; do vendor/bin/import_content --temp-path=temp --parent-node=path:<path> --config=extension/site/import/<config_file>.ini "$f" | tee import_log.txt; done

导入配置

内容导入器支持使用配置文件来定义数据映射和定义要运行的转换代码。

转换类

导入系统支持自定义转换类,这些类以导入器作为第一个参数,ini文件作为第二个参数进行实例化。

它们应包含将导入数据转换为新数据的方法。具体内容将在后续章节中解释。

NodeMap

NodeMap允许将导入节点的uuid重新映射到新的uuid。它从原始UUID映射到新UUID。

例如:

[Object]
NodeMap[16a72100ab6e3831dd0dffb10ef22902]=15ab238880ef4e989ab15823c906c005

这用于对象节点、父uuid和所有者uuid。一个典型的用例是将父节点重新定位到新位置。

ObjectMap

ObjectMap允许将导入对象的uuid重新映射到新的uuid。它从原始UUID映射到新UUID。

例如:

[Object]
ObjectMap[c1426628bb809712ac78e8527ef93739]=15ab238880ef4e989ab15823c906c005

对象转换

在导入系统处理之前,对象导入数据可能需要转换。这可以针对特定的对象uuid、类标识符或所有对象进行。

要转换单个对象,请指定TransformByUuid

TransformByUuid[c1426628bb809712ac78e8527ef93739]=FrontpageTransformation

要转换给定类的对象,请指定TransformByClass

TransformByClass[user]=UserTransform

所有对象的转换使用Transform指定。

Transform[]=GenericTransform

所有对象转换类都必须实现ContentObjectTransformation接口。

内容输入处理程序

Content-tools通过定义输入处理程序支持扩展对第三方数据类型的支持。输入处理程序负责以任何有意义的方式将输入值存储在属性中。它还可以将输入值转换为数据类型期望的格式。

处理程序是一个实现了ContentInputHandler接口的类,必须在content.ini中的DataTypeSettings下定义变量ContentInputHandler。例如,如果我们想支持ezselection,则添加以下内容:

[DataTypeSettings]
ContentInputHandler[ezselection2]=class;Selection2Handler

然后处理程序必须实现storeContent方法,并将值存储在属性中或在数据库中。以下是一个简单的示例:

class Selection2Handler extends ContentBaseHandler implements ContentInputHandler
{
    public function storeContent($value)
    {
        $this->attribute->setAttribute('data_int', $value);
    }
}

如果输入值是简单的文本、整数、浮点数或类似字符串的输入,则将class替换为相应的类型textintfloatstring。要忽略输入值,请使用类型ignorestring表示将值传递到数据类型的fromString方法。

[DataTypeSettings]
ContentInputHandler[ezselection2]=string

迁移

此软件包支持Phinx系统对数据库内容和其它数据的迁移。首先使用composer安装Phinx。

composer require "robmorgan/phinx:^0.10.6"

如果您遇到symfony/console问题,请尝试添加symfony/console:^3.0作为要求。

接下来,Phinx需要一个配置文件,最简单的方法是创建sphinx.php文件并使用Aplia\Migration\Configuration类根据eZ publish站点获取自动设置。

创建该文件并添加以下内容:

<?php
require 'autoload.php';
$configuration = new \Aplia\Migration\Configuration();
return $configuration->setupPhinx();

并将其添加到git。

该配置假设所有迁移都位于extension/site/migrations。如果您有一个较老的站点,站点扩展名不同,则必须在project.ini中配置路径,添加以下内容:

[Migration]
Path=extension/mysite/migrations

或者,如果您已迁移到使用命名空间,请添加以下内容(如果需要,可以添加多个命名空间路径):

[Migration]
NamespacedPaths[Namespace\Path]=extension/mysite/migrations

然后使用vendor/bin/phinx处理迁移,请记住在所有命令后添加-c phinx.php。例如,要查看当前状态,可以使用以下命令:

vendor/bin/phinx status -c phinx.php

要创建新的迁移文件,请使用create命令,例如:

vendor/bin/phinx create -c phinx.php Initial

要运行迁移,请使用migrate命令,例如:

vendor/bin/phinx migrate -c phinx.php

要在迁移中迁移eZ publish内容,可以在迁移中使用ContentTypeContentObject类。

内容类导出

此软件包支持将给定标识符的内容类导出到可运行的脚本。该脚本可以作为迁移风格的PHP代码片段运行。

要手动运行此脚本:

php bin/dump_contentclass [identifier ...] [php-style] [preamble] [delete-existing] [update-class-group] [update-creator-id]

输出到stdout,因此可以将它重定向到文件以保存它。

选项

identifier

指定要导出的内容类标识符。它支持多个值。例如:folder article

php-style

设置为migrate,以使用迁移风格。例如:php-style=migrate

preamble

在类定义之前设置包含模板脚本选项。例如:preamble

delete-existing

使用此选项删除现有内容类,而不是更新现有类。

update-class-group

使用此选项将所有导出类的类组重置为您选择的某个选项。例如:update-class-group=Seksjoner

注意!请先创建此类组。

update-creator-id

使用此选项通过对象 ID 设置用户为内容类的创建者。例如:使用 update-creator-id=14 将创建者设置为管理员。(此操作使用 eZUser::setCurrentlyLoggedInUser()。)

示例

假设位置为项目根目录

php vendor/aplia/content-tools/bin/dump_contentclass preamble delete-existing update-class-group=Seksjoner update-creator-id=14 news_section campaign_section logo_section > import_content_classes.php

工具

使用 content-tools 的实用程序类位于 Aplia/Utilities,而脚本位于 bin

搜索和替换

此实用程序可以用于在所有对象中搜索给定搜索字符串的所有出现,或者用给定的替换字符串替换出现。脚本将打印匹配出现的路径。它使用 ContentObject 类更新每个对象。

搜索

假设项目根目录,运行 php vendor/bin/ezp_search_and_replace <search_string> 以在对象的 data_text 属性中搜索包含给定 search_string 的对象。

替换

假设项目根目录,运行 php vendor/bin/ezp_search_and_replace <search_string> <replace_string> --replace 以将 search_string 的出现替换为 replace_string。在确认所有将要更改的对象后,先运行搜索,然后追加替换字符串可能更明智。使用逗号分隔的对象 ID 通过 --ignore 参数忽略特定对象(例如,--ignore=<objectId1>,<objectId2>,<objectId3>)。

注意!某些属性可能无法更新。例如 eZImage。如果发生这种情况,对象将不会更新,并且在运行脚本后会打印出来,以便手动更新。

其他参数

  • --print-urls:是否打印对象的 URL。如果未设置,则打印每个出现的 path_identification_string
  • --case-insensitive:不区分大小写的搜索。(sql 使用 REGEXPBINARY 上。设置此选项将省略 BINARY 从 sql。)
  • --new-version:是否发布更新对象的新的版本作为管理员。这可能会返回可以忽略的模板错误。此参数假定管理员用户是对象 ID 14。

运行 php vendor/bin/ezp_search_and_replace --help 以获取完整概述。

重新索引迁移内容类的对象

以下是将给定类的内容对象添加到索引队列表的 SQL 脚本。例如,当使用 eZFind/Solr 时。(运行此脚本的脚本为 php runcronjobs.php -s <siteaccess> indexcontent)这可以作为迁移添加。(注意:未来版本的此脚本可能用内容类更新的标志替换此脚本,该标志将类排队进行索引。)

INSERT INTO ezpending_actions (action, created, param)
SELECT "index_object", NULL, ezcontentobject.id
FROM ezcontentobject
INNER JOIN ezcontentclass
ON ezcontentobject.contentclass_id=ezcontentclass.id
WHERE ezcontentclass.identifier="<content class identifier ie. article>";