Pimcore-现代企业级-CMS-全-

Pimcore 现代企业级 CMS(全)

原文:zh.annas-archive.org/md5/e7e225db386d5045c53103ff117db88a

译者:飞龙

协议:CC BY-NC-SA 4.0

前言

现在,数字创新对任何中等或大型组织来说都是一个挑战。这段旅程,也被称为数字化转型,不仅与技术相关,而且受文化和动机支柱的引导。许多经理或沟通大师会告诉你,技术并不重要,它只是公司(营销、销售等)的一种商品或一系列工具。我们相信,只有当你选择的技术真正能够支持你的业务倡议时,这种做法才是可能的。在开始忘记技术问题,只关注业务的情况下,我们必须找到一个在所有条件下都能完美工作、可以扩展并支持业务增长的技术解决方案。经过一段长时间的调研,我们发现这个解决方案被称为 Pimcore。

简而言之,Pimcore 是一种技术促进者,它消除了公司思维与双手之间的大部分操作摩擦。Pimcore 可以作为PIM(产品信息管理)系统,在整个公司范围内分发产品信息,或者集中管理公司的重要数据(主数据管理),允许所有其他方安全地消费它。

此外,Pimcore 是一个强大的 CMS 引擎,可以管理比简单的网页多得多的内容。它是一个非常灵活的解决方案,涵盖了你在日常生活中遇到的几乎所有问题。在这本书中,我们将学习如何充分利用 Pimcore。

在阅读这本书之后,你将能够做到以下事情:

  1. 你将了解 Pimcore 是什么以及它是如何工作的。实际上,我们相信这不仅仅是一个工具选择的问题,而是如何将其完美地融入大局。

  2. 你将能够使用 Pimcore 作为数字体验平台来创建网站和门户。这包括使用 CMS 引擎,但还包括创建自定义的 Web MVC 页面和可重用组件。

  3. 你将能够使用 Pimcore 的企业功能(PIM、DAM、MDM)。你将学习如何收集数据,将其纳入统一数据库,并与所有潜在消费者(应用程序、网站、遗留应用程序等)共享。

  4. 你将能够安装、维护和部署 Pimcore 网站。

简而言之,这本书将引导你通过理论和实践课程,成为 Pimcore 开发者!

这本书面向谁

这本书旨在鼓励你以直接的方式学习 Pimcore。我们将涵盖所有重要主题,以便你能够开始并完成一个真实世界的项目。为了达到这个目标,我们开发了一本不仅是一套信息,而且是理论与实践相结合的书籍。这种实用方法将教会你 Pimcore 是如何工作的,以及如何将你的知识付诸实践,而不会感到烦恼或几乎无法通过询问为什么需要这样做来跟随教程。实际上,前几章将向你介绍 Pimcore 的高级视角,让你了解所有其优点,然后我们将开始一段旅程,逐步逐步地揭示 Pimcore 的所有细节,而不会引入任何过度的复杂性。

这本书是为任何希望提供基于 Pimcore 的解决方案的开发者、CTO 或任何其他类型的技术人员而设计的,或者愿意构建数字平台以支持他们的客户或业务在数字化转型之旅上。

这本书逐步介绍了最重要的概念,因此你不需要任何特殊背景。为了理解这本书,你所需要知道的就是 PHP 语言的基础知识以及一些涉及 HTML 和 CSS 的实践。

本书涵盖的内容

第一章, 介绍 Pimcore,解释了 Pimcore 是什么。它介绍了主要特性并描述了它是如何工作的。本章向读者介绍了这个工具,并从广泛的角度揭示了所有功能。

第二章, 设置您的 Pimcore 开发环境,涵盖了 Pimcore 的安装,并深入探讨了如何设置一个与源代码仓库兼容的本地环境。

第三章, 开始使用 Pimcore 管理界面,解释了管理 UI 是如何工作的以及如何找到基本命令的 UI。这对于导航 Pimcore 菜单和功能非常有用。

第四章, 在 Pimcore 中创建文档,解释了如何创建 Pimcore 的文档以及如何处理基本设置。当涉及到编辑文档和创建网页时,这是一个非常有用的资源。

第五章, 探索 对象和类,解释了如何创建和管理 Pimcore 对象和类。这一步骤构成了大多数 Pimcore 任务的基础,例如创建复杂的网站。

第六章, 使用数字资产管理,解释了如何在 Pimcore 中使用 DAM 功能来管理资产。这对于上传资产以及在网页内传播或集成它们非常重要。

第七章管理 Pimcore 站点,涵盖了管理和维护路由。它解释了如何安装 Pimcore 站点以及如何管理第三方插件。这是保持 Pimcore 正常运行所必需的。

第八章创建自定义 CMS 页面,解释了如何实现主题并为自定义 CMS 页面准备模板。在掌握自定义网页构建的基本知识时,这样做非常重要。

第九章配置实体和渲染数据,解释了如何在实现网页的术语中向用户展示数据。这是一个现实世界的用例,有助于将你所学到的知识付诸实践。

第十章创建 Pimcore 砖块,解释了如何创建用户可配置的可重用组件。这是节省大量工作并简化维护的方法。

第十一章完成网站建设,包含节省时间和在多个项目中重用组件的技巧和窍门。

第十二章实施产品信息管理,展示了 Pimcore 的 PIM 配置。它解释了如何调整它以作为 PIM 系统进行管理。通过本章,你可以开始使用 Pimcore 作为 PIM 系统。

第十三章实施主数据管理,解释了如何使用 GraphQL API 公开数据。有了这个,你可以激活此功能并开始数据集成。

第十四章数据集成,涵盖了 Pimcore 的数据集成功能。这有助于以标准方式与其他系统集成,而无需任何开发工作。

为了充分利用本书

Pimcore 是一个优秀的平台,得到了许多供应商和社区的支撑。这意味着你的应用程序将始终托管在更新的平台上,该平台将定期发布新功能。本书基于 Pimcore X,这是出版时的最新版本,因此通过阅读本书,你将学习到当时可用的最新版本!

Pimcore X 附带了许多新功能和更新的技术堆栈(Symfony 5、PHP 8 和 ExtJS 7),这提供了许多性能改进。尽管 Pimcore X 与之前的版本之间有巨大的变化,但你在阅读本书时学到的许多概念也适用于所有之前的版本。

本书旨在提供无缝的学习体验,并且除了基本的 PHP 和 HTML 知识外,不需要任何其他相关专业知识。无论如何,任何在其他平台上有一定经验的开发者都将能够遵循说明并理解代码。此外,我们没有介绍任何付费或与操作系统相关的工具,这使得本书对所有读者都无任何限制:

图片

所有标记有()的项目仅在您不选择使用 Docker 时才需要。实际上,我们提供了一个基于 Docker 的设置选项,它不需要除了 Docker 之外的其他任何东西。所有依赖项都将自动管理,因此您不必担心这一点。无论如何,如果您打算手动安装,您还需要在本地 PC 上安装所有标记有()的工具。

如果您正在使用本书的数字版,我们建议您亲自输入代码或通过 GitHub 仓库(下一节中提供链接)访问代码。这样做将帮助您避免与代码复制粘贴相关的任何潜在错误。

下载示例代码文件

您可以从 GitHub 下载本书的示例代码文件:github.com/PacktPublishing/Modernizing-Enterprise-CMS-using-Pimcore。如果代码有更新,它将在现有的 GitHub 仓库中更新。

我们还提供其他代码包,这些代码包来自我们丰富的图书和视频目录,可在github.com/PacktPublishing/找到。查看它们吧!

下载彩色图像

我们还提供包含本书中使用的截图/图表的彩色图像的 PDF 文件。您可以从这里下载:static.packt-cdn.com/downloads/9781801075404_ColorImages.pdf

使用的约定

本书使用了多种文本约定。

文本中的代码:表示文本中的代码单词、数据库表名、文件夹名、文件名、文件扩展名、路径名、虚拟 URL、用户输入和 Twitter 昵称。以下是一个示例:“在/bundles/BlogBundle/Resources/views/Areas中添加一个名为view.html.twig的模板。”

代码块按照以下方式设置:

<?php
use Pimcore\Bundle\BundleGeneratorBundle\PimcoreBundleGeneratorBundle;
return [
    PimcoreBundleGeneratorBundle::class => ['all' => true],
];

当我们希望您注意代码块中的特定部分时,相关的行或项目将以粗体显示:

"autoload": {
    "psr-4": {
      "App\\": "src/",
      "BlogBundle\\": "bundles/BlogBundle/",
      "Pimcore\\Model\\DataObject\\": "var/classes/DataObject",
      "Pimcore\\Model\\Object\\": "var/classes/Object",
      "Website\\": "legacy/website/lib"
    }
  },

任何命令行输入或输出都按照以下方式编写:

docker-compose exec php bash

粗体:表示新术语、重要单词或屏幕上看到的单词。例如,菜单或对话框中的单词在文本中显示如下。以下是一个示例:“填写带有数据的表单(这是一个联系表单,因此字段含义应该是显而易见的)然后点击发送。”

小贴士或重要注意事项

看起来像这样。

联系我们

欢迎读者反馈。

customercare@packtpub.com

勘误:尽管我们已经尽最大努力确保内容的准确性,但错误仍然可能发生。如果您在这本书中发现了错误,我们将不胜感激,如果您能向我们报告这个问题。请访问www.packtpub.com/support/errata,选择您的书籍,点击勘误提交表单链接,并输入详细信息。

copyright@packt.com,并附上相关材料的链接。

如果您有兴趣成为作者:如果您在某个领域有专业知识,并且您有兴趣撰写或为书籍做出贡献,请访问authors.packtpub.com

评论

请留下评论。一旦您阅读并使用了这本书,为何不在您购买它的网站上留下评论呢?潜在读者可以查看并使用您的客观意见来做出购买决定,Packt 公司可以了解您对我们产品的看法,我们的作者也可以看到他们对书籍的反馈。谢谢!

如需了解 Packt 的更多信息,请访问packt.com

第一章:第一章:介绍 Pimcore

如果你购买了这本书,你可能已经对 Pimcore 有一个大致的了解。Pimcore是一个开源的企业级数字体验平台DXP)解决方案,旨在成为其市场领域的领导者。但这个定义究竟意味着什么呢?在 IT 世界中,术语经常被用作描述某物的填充词,因此听起来非常模糊。这就是为什么我们必须正确地解释 Pimcore 是什么,而不仅仅是告诉你它能做什么,而是深入到它解决的问题。

理解我们将要研究的工具将应用到的场景总是一个很好的开始,尤其是当你想学习 Pimcore,一个将彻底改变你的开发体验的平台时。

在本章中,我们将探索 Pimcore 平台,了解它提供的益处和机会,以及它与其它解决方案的不同之处。

本章的结构如下:

  • 为什么你需要一个比简单的 CMS 更强大的系统?

  • 什么是 Pimcore?

  • 发现 Pimcore 的功能

  • 了解 Pimcore 的益处

  • 了解使用开源软件的益处

为什么你需要一个比简单的 CMS 更强大的系统?

在本节中,我们将了解内容管理系统(CMS)在近年来是如何演变的,以及这些变化带来了哪些新的需求。理解市场趋势和需求对于成功采用能够支持我们或我们的客户业务多年的 CMS 平台是至关重要的。在不完全了解它如何有用的情况下学习像 Pimcore 这样的工具可能会浪费时间,你可能会错失许多可能解决你或你的客户问题的技术机会。

那么,让我们介绍 Pimcore 解决的问题。然后,就会很容易理解为什么 Pimcore 以这种方式创建了这个产品,以及为什么我们应该采用它。

理解需求的变化

首先需要接受的是,市场已经发生了演变。我们不再满足于仅仅建立一个网站的工具。这在 10 年前是可以的,但现在,大多数公司对数字通信有更全面的方法,并希望得到更多。你不必因为这种变化而感到害怕;自从互联网诞生以来,我们已经看到了许多演变,事物变得越来越好。我们只需要跟随趋势,或者更好的是,预测趋势。

想想过去 20 年发生了什么。我们开始时,互联网只是产生静态文本内容。这实际上意味着手动编写每一页,如果你幸运的话,使用文件传输协议FTP)链接上传。我们仍然记得当时我们与脚本语言作斗争,混合 HTML、数据和 Flash 内容,只是为了渲染一个简单网站的两三页。

CMS 是一次非常大的飞跃。从浏览器管理动态内容解锁了让最终用户管理他们数据的机会,减少了所需的开发工作量。这是一场革命,许多 CMS 解决方案在互联网上传播开来。WordPress、Drupal 和其他产品成为创建网站不可或缺的选择。它们(可能现在仍然是)在大多数场景下都是好的解决方案,但我们在这里是为了增强我们的工具范围,并为市场明天提出的要求做好准备。

现在是时候将用户体验提升到下一个层次,我们需要一个优秀的工具来支持这一数字进化。

什么是 DXP?

要了解市场在数字创新方面的当前需求,主要需要了解的是DXP。这个缩写词由 Gartner 提出,它描述了一种可以支持公司数字体验的技术解决方案。如今,公司应该将客户放在一切的中心,并利用技术将正确的内容传递给正确的人。大多数想要在线扩展业务的公司几年前就开始了他们的数字化转型。他们创建了电子商务网站来在线销售,并使用合适的产品触及所有客户。他们从互联网开始就有网站(一些公司甚至拥有多个)。企业可以拥有一个全球性的单一网站,一个品牌一个网站,或者根据目标市场拥有不同的网站。他们还有一个门户,以供代理商或第三方供应商访问商业对商业B2B)信息。

所有这些细分都是一场噩梦:我们拥有太多的平台,我们必须保持它们之间的通信,我们必须在不同的 GUI 中管理内容,我们需要多个登录来完成所有这些。这个解决方案不是最优的,因此需要改变。

但这个变化还有一个更重要的原因——我们忘记了所有这一切中最重要的一点:我们忽略了客户。在应对技术和它们的演变时,我们失去了对最关键事物的关注。这就是为什么我们需要一个独特的软件解决方案来有效地管理我们刚才描述的所有问题:这个解决方案就是数字体验平台(DXP)。

在下面的图中,我们可以看到 DXP 如何包括电子商务、网站和门户以创造独特的体验:

图 1.1:DXP 图解

图 1.1:DXP 图解

如前图所示,电子商务和门户解决方案有一些共同之处;例如,它们共享相同的认证系统。我们还可以看到网站和门户使用相同的 CMS 创建网络内容。根据您的经验,您可能已经理解到这三个解决方案需要共享一些功能。在单独的平台中复制它们是多余的,但将所有元素集中在一个平台上可以帮助我们减少复杂性并避免数据的重复。

简而言之,我们谈论的是拥有一个集成的软件框架,可以解决所有数字公司的需求。这将导致通过所有数字接触点吸引广泛的用户。

Pimcore 是这样一个框架。Pimcore 的使命是让技术成为数字转型的推动者,而不是障碍。Pimcore 的愿景非常明确:仅使用一个工具,我们就应该能够整合公司中的所有其他工具,并加速所有流程。

大多数公司都难以找到数据,或者他们在系统中重复了数据。这通常是因为,从历史上看,这些公司采用了许多垂直解决方案,而后来他们才开始考虑如何整合它们。这些孤立的数据集被称为 数据孤岛。打破数据孤岛的一个快速方法是创建一个包含所有所需信息的中央数据库,并通过简单透明的 API 协议促进对消费者的交付。这种解决方案被称为 主数据管理MDM),它是 Pimcore 提供的功能之一(我们将在 第六章使用数字资产管理 中看到这一点)。

我们始终需要拥有中央信息,但当我们必须处理产品数据时,这种需求往往成为痛点。我们可能在多个渠道销售产品,我们可能需要在实体目录上打印信息,我们不能在不同地方关于同一事物有不同的信息。产品管理的集中化被称为 产品信息管理PIM),这是 Pimcore 的另一个功能。我们将在稍后了解更多关于这个功能的内容,但现在请记住,成长中的公司有这样的需求。

最后,我们可能希望集中管理数字资产,如视频、图像和其他文件。一个收集和提供数字资产的系统被称为 数字资产管理DAM)系统,你可能已经猜到了,Pimcore 也涵盖了这一点。我们将在下一节中了解更多关于这个主题的内容。

Pimcore 平台是任何面临数字体验转型的公司的正确工具。此外,数字体验转型并不是这样的公司唯一会面临的问题。这就是为什么 Pimcore 不仅仅是 PIM、CMS、MDM 和 DAM 的简单组合。Pimcore 是一个帮助我们实现客户数字体验重大变革的解决方案。

在本节中,你了解了最重要的公司所面临的挑战。作为技术人员或顾问,我们的职责是帮助公司审视他们的简单网站,提出他们数字通信的更全面愿景,并使用合适的技术解决方案来满足他们的需求。在下一节中,我们将了解 Pimcore 是什么以及为什么它是解决这个问题的正确方案。

那么,Pimcore 是什么?

在定义 Pimcore 是什么的时候,首先要考虑的是它的名字本身。名字暗示 PIM 是主要部分,但你不要被外表所迷惑。Pimcore 远不止是一个 PIM 产品。

我们可以将 Pimcore 描述为一个框架,因为它为我们提供了实现项目所需的所有工具。这个定义并不比第一个定义更直观,但它给我们一个重要的提示。Pimcore 是一套工具,但我们不能将其视为一个库或是一些代码片段。Pimcore 是一套协作工具;每个工具都能解决它自己的问题。它不是一个产品,而是一系列产品的集合。所有这些工具的结合有助于设计一个完整的数字解决方案。从这个意义上说,Pimcore 是一个真正的 DXP:一个使开发者能够实现数字项目的平台。这个定义有点模糊,但它告诉我们 Pimcore 为我们提供了非常广泛的机会。我们不能仅仅说“Pimcore 能做这个或那个”,因为 Pimcore 可以做任何事情。

Pimcore 是一把瑞士军刀,允许开发者创建任何软件解决方案。我们在这里讨论的是网站,但 Pimcore 还有其他应用,例如向公司提供数字资产或成为公司所有信息的中心数据库。Pimcore 提供了一个包含 DAM、PIM、MDM 和Datahub等许多功能的单包解决方案。我们已经在前面简要介绍了 DAM、PIM 和 MDM 是什么,但在接下来的章节中,我们将更深入地探讨这些主题,包括 Datahub。所以,如果这些定义仍然看起来很高级,请不要担心。

现在需要知道的重要事情是,Pimcore 允许你管理大多数与数据相关的应用,而无需编写一行代码,同时提供一个现成的稳固的电子商务框架。

这是我们应该问自己是否真的需要所有这些功能的时候。你真的需要管理像 Pimcore 这样的复杂平台的开销来构建你的简单网站吗?市场上有很多更容易的解决方案来实现网站。你可以找到一个超级便宜的 CMS 托管提供商,或者使用网站构建器。这些解决方案可能适合小型公司,但不适合中型或大型组织。企业需要做更多的事情,在本章中,你将了解到使用简单的 CMS 解决方案来实现网站你会错过的机会。

如果你正在阅读这本书,你正在寻找一个能够管理所有场景的 CMS 解决方案,从最简单的到最复杂的。你不想为了满足营销部门的所有需求而实施 10 个不同的工具。此外,你不想为随着业务增长而不断重新平台化的成本付费。构建应用程序的技术解决方案必须是一个提升,它给你带来的好处比从头开始做事更多,但同时也不会限制不断的改变。你需要有自定义网站每个部分的选项,而不需要做出诸如添加数千个插件并逐渐失去对解决方案控制这样的妥协。

你可能仍然认为 Pimcore 是一个具有许多你实际上并不需要的特性的平台——这是可以理解的。仅仅为了实现一个简单的网站而拥有一个功能强大的平台可能看起来有些过度。有时这可能会让人感到害怕。无论如何,如果你再次阅读本章的第一节,你会同意,迟早你需要比简单的 CMS 更多的东西,在那个时刻,你将希望能够在不改变平台的情况下进行扩展。

在接下来的章节中,我们将了解 Pimcore 最相关的特性。这将帮助您理解为什么 Pimcore 可以在所有场景下支持您的开发,从简单的网站到复杂的企业门户。这些特性包括以下内容:

  • 将数据从 UI 中解耦

  • 正确渲染内容

  • 准备好迎接云计算

让我们来看看这些。

将数据从 UI 中解耦

现代 CMS 的第一个特性是将展示层从数据结构中分离出来。简单来说,你必须在一边添加数据,然后在另一边提取它,这两层之间没有任何依赖关系。

使用 Pimcore,我们有两种选择:

  • 实施完全解耦的解决方案(解耦 CMS)。

  • 实施一个无头 CMS解决方案。

在分离模型中,通过从渲染过程中分离生成的数据,可以实现业务逻辑和展示层之间的分离。在 Pimcore 中,我们有一个模型视图控制器MVC)模型,其中Twig模板引擎不能处理业务逻辑。对于不是 MVC 和 Twig 专家的人来说,MVC 是一种将业务逻辑(控制器)从展示(视图)和数据(模型)中分离出来的模式,而 Twig 是一个 PHP 模板引擎。

另一个选择是采用完全无头解决方案。在这种情况下,我们通过 API 公开数据,然后使用现代单页应用SPA),例如使用 Gatsby 静态化的 React 网站来渲染它。这种无头解决方案在各个方面(如数据定义和数据展示)之间提供了强大的分离,并且公开给应用的数据也可以被其他应用使用。

市场提供了许多无头 CMS 解决方案,但 Pimcore 自带了这两种解决方案,即无头和分离。因此,你可以使用标准的分离方法来管理简单的网站,这让你可以像往常一样创建模板,但无需任何展示和业务逻辑之间的相互依赖。这保持了设计的简单性,你将受益于解耦的优势,因此只需重新实现模板,就可以轻松地刷新你的网站。

无论如何,如果你想创建一个边缘解决方案,你可以使用 Pimcore 来实现。实际上,它自带了一个开箱即用的解决方案,用于以 GraphQL 格式公开数据,这足以将其转换为一个无头内容提供者。对于那些不熟悉它的人来说,GraphQL 是一种用于 API 的查询语言,它描述了数据并减少了数据生产者和消费者之间的摩擦。

统一用户体验

在 CMS 时代的初期,交互式网站(也称为门户网站)和机构网站之间存在分歧。这导致了 CMS 网站和门户解决方案之间的分歧。由于这些 CMS 网站和门户网站有不同的需求,我们习惯了采用不同的工具,也许每个都需要不同的供应商团队。

例如,在过去,创建一个公共网站相当简单,所以有一个简单的 CMS 解决方案是可以接受的。另一方面,创建一个门户网站更为复杂,因此我们需要一个高度可定制的解决方案。但随着数字技术的普及,越来越多的公司开始在线销售,增加了这一新需求。那么,解决方案是什么呢?公司只是从市场上取了一个工具,安装了它,就开始销售。这是一种快速解决在线销售问题的方法,但它引发了一个问题:它向 CMS 和门户中添加了第三个平台(电子商务)。这通常意味着一个新的供应商、一个新的图形界面和不同的用户体验。换句话说,这意味着在数据和用户体验方面,三个系统处于不同的领域。经过几年的数据流、集成和在这些环境中复制业务逻辑的斗争后,有一天,像 Gartner 这样的顾问提出了一个解决方案。他们告诉我们,我们在组织中有隔阂,隔阂是坏事,我们应该消除它们。此外,同样的顾问告诉我们,商业、门户网站和内容管理不是不同的需求,而是同一数字体验的一部分。问题是:如果所有这些组件都是用户想要的,谁可以为我们提供一个工具来提供它们?

Pimcore 与竞争对手的做法不同。它的 CMS 引擎管理公共和私有网站,因此你可以创建预留区域和门户,以及简单的单页公司网站。此外,这个解决方案还与企业保持联系,添加了一些有助于与其他支柱集成的关键组件。这种特殊配置使 Pimcore 成为一个通过在一个平台上包含所有你需要来吸引用户的特性,统一用户体验的理想平台。

因此,你可以扩展网站的功能,直到涵盖整个公司,包括电子商务。换句话说,你可以采用一个工具来满足你大部分的数字需求。

为您的公司做好云准备

我们购买物理服务器的古老时代已经过去了。我们现在处于云时代,我们想要利用这个新世界提供的一切机会。然而,我们生活在一个复杂的世界里,由于许多原因,云并不总是可行的选择。我们可能必须处理需要保存在私有数据中心中的敏感数据,或者我们的预算可能只允许使用廉价的托管提供商。每个公司都有不同的需求,但它们都需要有一个网站。无论是在云端还是本地拥有数据,都不应该是采用数字平台的原因。它必须原生支持两者。

作为一名开发者,你不想使用不同的工具来服务不同的客户端目标。这样会让你不得不学习许多不同的工具,并且同时使用它们;如果你想在某一技术领域保持深入的专业化,这总是很困难的。

要使用不同的产品来服务市场的不同细分市场,你可能需要不同的技术,并且成为双重专家。对于每天工作时间有限的开发者来说,使用过多的技术意味着专业化的减少。你使用的科技越多,你用来学好它的时间就越少。我们可以找到一些例外,但一般来说,情况就是这样。

Pimcore 与众不同。它能够从最简单的网站到最复杂的公司网站提供一切服务,这得益于它的灵活性和开源代码,它提供了一套免费的完整解决方案。这种敏捷性也体现在其托管方面。Pimcore 可以通过上传文件到廉价的托管服务或常规虚拟机,仅通过 FTP 上传文件即可作为简单的 PHP 应用程序部署,并且它原生支持容器化。

换句话说,作为一个容器,Pimcore 可以部署在大多数平台即服务PaaS)、Docker 或 Kubernetes 解决方案上,无论是在云端还是本地。因此,云是一个机会,但不是必需的。你可以将 Pimcore 部署到云端,实施一个无需人工监控和维护即可扩展和站立起来的解决方案。如果你对不同的解决方案有信心,或者你根本不需要扩展,使用 Pimcore 仍然是一个可行的选择。

了解 Pimcore 是什么对于理解其功能和跟随接下来的章节至关重要。事实上,在下一节中,我们将开始深入研究 Pimcore 的功能,如果没有发现 Pimcore 是什么,这将是不可能的。

发现 Pimcore 的功能

正如我们在本章前面所说,Pimcore 自带一些巨大的功能,使其成为实施简单和复杂项目的理想平台。

在本节中,我们将介绍主要功能:

  • 数据管理

  • CMS 和 DXP

  • PIM

  • MDM

  • DAM

  • 电子商务

  • 客户数据平台(CDP)

让我们逐一看看。

数据管理

数据管理是 Pimcore 所有功能的根源。数据管理功能聚合任何类型的数据,并将其分发到多个渠道。与其他解决方案相比,Pimcore 拥有最佳的数据管理系统。它允许你通过 UI 定义数据,这非常好,因为你不需要编写任何一行代码。你可以停止与数据库表、字段长度和数据查询的麻烦;你所需要做的就是简单地打开你的浏览器,创建你的实体,并选择你想要的字段。这个特性与低代码平台或无头 CMS 上可以找到的特性非常相似,但更加强大。

大多数数据管理工具的独特目标,是数据模型定义。这样的解决方案使我们能够快速定义数据模型和 API,但产生的 UI 对普通用户来说很难使用。基本上,你非常受限,只能使用标准的数据录入界面,所以在大多数情况下,你必须从头开始编写用户 UI。这正是纯无头原则所追求的:将所有渲染方面委托给系统之外。当为最终用户(如客户或门户用户)设计应用程序时,这是一个好原则,但如果我们需要允许管理员或编辑在我们平台上输入内容怎么办?对于这样的内部用户,Pimcore 提供了一个可以在定义数据模型时定制的管理界面。

换句话说,当你向项目集合添加一个字段,例如为产品实体添加 SKU 字段时,你不仅定义了数据的存储方式(唯一性、字段长度、日期类型等),还定义了该字段将如何展示给用户。例如,你可以将字段分组在标签页或面板中,或者简单地重新排序,为后台用户创造良好的用户体验,而不需要修改任何一行代码。此外,Pimcore 支持多语言,因此你可以通过建模字段来选择哪些字段需要翻译。这个特性使 Pimcore 成为完美的无头 CMS,因为它结合了现成的管理后端灵活性和构建自定义应用程序的数据 API 的强大功能。

当后台用户第一次看到管理界面时,许多人可能会感到有些迷茫,因为 Pimcore 管理界面提供了数千个功能。仅仅几分钟的 Pimcore 操作后,你就可以清楚地了解这个工具能让你达到何种自由度。多标签环境使得你可以在同一个窗口中打开多个数据标签页,轻松地从一处剪切粘贴数据到另一处,并在几秒钟内导入/导出数据。

如果这还不能让你感到震惊,那么接下来我们要告诉你的将会让你震惊。所有这些数据都是通过 REST API 提供的;这是一个不需要任何开发工作的原生功能。这意味着,你使用 Pimcore 界面建模的每个实体都可以通过 REST API 轻松访问,无需额外努力(自从 PimcoreX 以来,这个功能将仅作为企业订阅功能提供)。你可以通过 HTTP 调用将一行数据放入数据库或查询实体列表,而无需编写任何代码。

如果你仍然不感到震惊,我们可以再次提及 DataHub 模块——你可以通过 GraphQL 标准为 API 建模来开启并暴露你的数据给外部系统。

很容易看出,当你管理好数据层时,接下来的一切都会变得更容易。

CMS 和 DXP

Pimcore 在其网站上被定义为“最适应的 DXP 平台”。询问任何使用 Pimcore 的开发者,他们都会确认你几乎可以用它做任何事情。使用这个 CMS,你不仅可以实现酷炫的网页,还可以在每一个接触点为每位客户提供个性化的数字体验。多亏了其 CMS 引擎,Pimcore 使公司能够有效地实施其数字战略,并将更多的时间和金钱投入到真正重要的事情上。

从开发者的角度来看,Pimcore 的 DXP 是一个用于实现任何类型数字解决方案的集成框架,无论是网站还是门户。此外,它结合了实现电子商务的所有工具,你可以将你的网站或门户转变为完整的 DXP 解决方案。这是一个以 API 驱动的方法,使平台可集成到每个系统中,并有助于打破孤岛。

从用户的角度来看,Pimcore 是他们创造力的自然延伸。丰富的所见即所得WYSIWYG)界面显示了内容在发布时的样子。因此,你可以输入数据并构建页面,而无需对最终结果有任何疑问。此外,你可以创建页面模板,引导用户通过辅助页面组成。这个过程要求编辑只写相关的内容,而无需浪费时间更改样式或文本位置。

组件模型让您可以使用大量的小部件,所有这些小部件都准备好放置在页面上,并且可以完全配置。这些小部件被称为砖块,正如其名所示,它们构建了网页。借助强大的模板引擎,您可以渲染实体,例如文章或产品,或者您可以定义一个自定义模板来从头开始构建非标准页面。

还有什么可说的呢?使用集成工具,您可以在编辑时预览网站,并且通过发布工作流程,您可以放心保存,不用担心会破坏任何东西。

PIM

多亏了其强大的数据引擎,Pimcore 可以管理任何类型和任何数量的数据。如果您模型了一个名为“产品”的项目集合,并在数据模型中添加了一个价格,那会怎样呢?嗯,这使得 Pimcore 成为一个 PIM。这不是玩笑。这就是与 Pimcore 一起工作的简单性。您可以在几分钟内使用浏览器将 PIM 添加到您的公司。完成这个 5 分钟的任务后,您就有了一个独特的数据库,用于您公司所有的产品。多亏了 Pimcore 的数据集成能力,您可以从任何 CSV 文件中摄取数据,而无需编写任何代码,或者在任何情况下,只需付出非常少的努力。任务完成。

公司中的任何其他系统都可以与您集成,并且营销团队将管理所有产品在独特的中央管理中。在这里,他们将定义哪些产品进入哪个渠道,为哪个市场启用哪些语言,等等。因此,即使在这种情况下,Pimcore 也为我们提供了简单性和完整的解决方案。

如果我们还没有说服您,我们可以告诉您关于工作流程的事情。当您需要在产品管理中添加审批流程或某些业务逻辑时,您可以使用 Pimcore 工作流程来建模。在下一张图中,我们有一个解释 PIM 在行动中的架构图:

![图 1.2:PIM 架构]

![图 B17073_01_02.jpg]

图 1.2:PIM 架构

前面的图显示了 Pimcore 作为 PIM,是产品的单一事实来源,为许多消费者提供服务,例如 B2B 电子商务、B2C 电子商务、亚马逊或 eBay 市场或简单的印刷目录。正如您在图中可以看到的,多亏了数据集成层,Pimcore 解决方案可以链接到现有的平台,例如 企业资源规划(ERP)。

PIM 是现代公司不能错过的功能,它对于在不重复信息的情况下与多个用户接触点进行扩展是必需的。它让您能够控制产品数据并加快您的软件集成。此外,在这种情况下,Pimcore 使您能够轻松地完成这项工作,因为这是一个即插即用的功能,可以随时激活。

MDM

我们关于 PIM 所告诉你的所有内容都很酷,但它有一个很大的局限性:它仅与产品相关。实际上,从你公司的需求来看,你会发现许多其他类型的数据需要在公司内部共享并集中管理。订单、客户以及可能还有大量其他数据被公司从各种应用程序中使用,每次项目开始时,你都必须知道数据在哪里。但问题并不仅限于这些少数实体。

使用 Pimcore,我们可以使信息对所有黄金记录(对公司至关重要的信息)独特且集中。这种能力是现成的、免费的,并且只需付出有限的努力。如何做到?只需定义数据模型并将其与数据主控系统集成,例如 CRM、ERP 或任何拥有你想要移动的实体的系统。然后,你可以定义数据访问策略,实现你想要的全部逻辑。这不仅仅很酷...它超级酷!只需一个工具和几分钟,你就可以准备好将重要数据暴露给所有需要的公司应用程序。这样的解决方案使你能够掌控你的数据(这项任务通常被称为数据治理)。

整个配置就是我们在这章的第一节中提到的 MDM(主数据管理)。Pimcore 的 MDM 的主要好处是它可以管理结构,还可以管理元素的验证、版本控制和丰富化。实际上,大多数实体根据其目的地具有不同的属性。为了解释 MDM 的好处,我们可以使用任何实体,但我们将再次谈论产品。这仅仅是因为它是最常见的场景,我们可以最好地理解它。在阅读下一段时,你可以将“产品”这个词替换为任何其他类型的数据,而不会改变意义(订单、客户、发票等等)。

想想一个产品。它从哪里开始?这是一个难题,因为我们通常有一个研发团队在原型上工作,然后有人批准它进入市场,然后我们开始销售。可能在这个流程中,我们可以谈论具体产品的第一个阶段是当记录进入 ERP 系统,创建产品代码时。产品由管理产品代码和价格的 ERP 系统拥有。在这个阶段,你实际上不需要更多的数据。你已经有了一切你需要来制作报价或发票的数据。此外,大多数技术解决方案都不是为了管理带有多个图像和长描述的酷产品信息而构建的。ERP 是一个垂直解决方案,它只在其范围内的事物上做得很好。试图让它做不同的事情是没有意义的。

好吧,这里你需要的是一个数据丰富化过程。在没有 PIM 或 MDM 的情况下,通常每个用户都会根据他们的需求增强数据。因此,你可以有电子商务增加更大的图片和长的 HTML 描述,但这个电子商务只为在商业对消费者B2C)渠道销售的产品提供信息。所以,你必须在 B2B 门户中为其他产品做同样的事情。这就是为什么在这个例子中,产品不是集中管理的。使用 Pimcore,产品和其他任何实体可以在交付给消费者之前进行翻译和丰富,包括图片、视频和附件。这是唯一能够掌握数据并能够将大部分精力投入到公司真正关心的事情上的方法,比如实施良好的应用程序而不是与数据斗争。

在下面的图中,我们可以看到 Pimcore 作为 MDM 平台的架构图:

![图 1.3:MDM 架构

![图片/B17073_01_03.jpg]

图 1.3:MDM 架构

在前面的图中,你可以看到 Pimcore 如何与许多数据所有者(ERP电子商务CRM)集成。这一步通过数据集成层收集数据,并将其提供给公司的所有应用程序(市场目录B2BB2C应用程序,或第三方应用程序)。使用一个 API 网关,这是一个安全地暴露 API 的工具,我们还可以与供应商或第三方应用程序共享 API。

MDM 是数字创新的一个支柱。没有它,在组织内传播数据将是一件混乱的事情。使用 Pimcore,你可以集中管理数据,节省实施定制解决方案所需的时间或节省在昂贵工具上花费的钱。

DAM

在讨论了产品和数据之后,很明显,每个公司都必须将数据保存在一个地方,使用唯一的数据模型定义,并且他们需要确保每个消费者只接收和阅读他们需要的信息。当我们在这里谈论产品和数据时,我们是在谈论无形数据——不是文件、图像、视频或可以下载或作为附件发送的数据,而是纯粹的信息。

有形数据,如文件、视频和图像,仍然是公司的重要资源。在一个通信变得越来越数字化的世界中,数字资产至关重要,特别是当你需要通过多个渠道传达相同的信息时。

你可能已经猜到了这个解决方案:我们可以在 Pimcore 内部收集所有这些信息,然后在整个系统中分发。当你已经将其启动并运行时,这是一个非常简单的解决方案,但它为你的公司提供了巨大的飞跃。

这个解决方案是由 Pimcore 实施的。Pimcore 的 DAM 软件不仅仅是一个数字资产管理应用程序:它是一个真正的数字化转型推动者。它是一个集成的数字媒体库,提供了一个可重复使用的数字资产坚实数据库,并优化了数据分发和内容搜索过程。

在下一个图表中,我们看到 Pimcore 作为 DAM 的作用:

![图 1.4:DAM 架构

![图片 B17073_01_04.jpg]

图 1.4:DAM 架构

在前面的图中,Pimcore 是所有数字资产存储的中心点。它向任何需要它们的消费者应用程序提供内容。

与 MDM 和 PIM 一样,DAM 是现代企业必备的服务之一。它使公司内部媒体资产的分发成为可能。在这里,Pimcore 也是一个强大的低成本解决方案。

数字商务

好吧,我们知道 Pimcore 是一个非常强大的平台,用于管理和处理一般的数据和数字内容,并且它包括出色的 CMS 支持。现在我们需要讨论电子商务模块。

实际上,一个 DXP 需要这一点来拥抱 DXP 的全部含义:门户、网站和电子商务的融合。如今,电子商务是一个巨大的市场,你可能想知道为什么这个功能被添加到 Pimcore 中。

只需想想一个电子商务解决方案包含哪些内容。首先需要讨论的是预算。并非所有电子商务系统都像亚马逊或 eBay 那样,因此我们需要根据我们的需求以及我们能支付多少来找到合适的解决方案。当电子商务市场开始时活跃的开发者来自一个本地化、高度可定制的时代,那时一个垂直开源解决方案,如 Magento 电子商务系统,是标准。这个解决方案很好,因为它允许你自定义流程的每一部分,但你必须自己托管,承担所有相关风险,并且定制元素需要持续维护。因此,总拥有成本TCO)非常高,许多公司转向软件即服务SaaS)解决方案,这些解决方案提供的定制选项较少,但无需维护和托管责任。这种摩擦的减少使电子商务更加民主化,但在许多情况下减少了电子商务个性化的机会。对于许多公司来说,其服务的独特性和公司流程的自动化对于电子商务解决方案至关重要。我们主要谈论的是大玩家,但也有很多初创公司通过跳出思维定式而取得成功。唯一的区别是,大玩家可以采用巨大型供应商解决方案,成本呈指数增长,但可以得到相应的结果。那么,对于预算有限的普通公司呢?

在这种情况下,Pimcore 填补了完全托管 SaaS 解决方案和大型供应商之间的差距。事实上,Pimcore 附带了一个旨在加快电子商务开发的电子商务框架,但不会引入约束或限制。此外,使用稳定的基于云的解决方案,你可以达到低维护成本的目标,在黑色星期五期间(可用性至关重要的时期)可以安心入睡。

使用 Pimcore 作为电子商务平台的另一个优势是,得益于其多站点功能,它可以处理 B2B 和 B2C,显然不需要任何数据集成,因为其内部有 PIM。

如果你还没有被说服,只需阅读这份必看的企业电子商务解决方案特性清单,Pimcore 恰好提供了这些特性:

  • 复杂的价格和产品结构

  • 复杂的可用性计算

  • 需求不断变化的敏捷项目

  • 个性化设计和结账

  • 多个目录、货币、价格表和产品视图

  • 多个前端应用和灵活的促销

在本章的前三节中,我们已经了解了 Pimcore 是什么,并探讨了其特性。这已经是对产品的全面概述,但我们还需要更详细地了解为什么我们应该使用它。在下一节中,我们将了解采用 Pimcore 带来的好处。

了解 Pimcore 的好处

Pimcore 给我们带来巨大机会的事实并不意味着它一定是适合你的工具。你可以断言市场上有很多其他解决方案,你可以混合使用多个解决方案来实现相同的结果。还有许多其他大型供应商在销售集成解决方案。所以,问题是,Pimcore 有什么好处?换句话说,它能为我们的哪些方面提供比其他解决方案更好的东西?

为了避免片面性,我们决定避免直接比较。然而,我们希望给你所有需要的工具,以便确定 Pimcore 是否是你正确的解决方案。在本节中,你将发现选择 Pimcore 作为 DXP 解决方案、PIM 或 CMS 的好处。有了这些信息,你将能够自己做出结论。

在本节中,你将发现最重要的 Pimcore 好处:

  • 快速创新

  • 无与伦比的灵活性

  • 稳固的平台

  • 被大众使用

  • 简单的网页开发

让我们来看看。

快速创新

经常不是成本问题,而是时间问题。市场变化迅速,每个公司都需要跟上时代的步伐。唯一的选择是准备好应对变化。这导致我们快速创新。在许多情况下,拥有垂直工具、选择软件然后激活一个项目的过程太慢了。也许从理论上讲,这是最好的过程,但它需要大量的时间,并且往往不符合市场的趋势和速度。你应该领先市场一步,在你需要之前规划投资,但这并不总是可行的。没有人有水晶球。提前规划和支出是一种风险,因为你不知道未来会怎样。

在这种情况下,Pimcore 是正确的工具。这个框架已经包含了实现数字创新的最重要组件,并且可以在任何时间点激活,无需任何成本。这对于将时间作为优先事项的初创公司或成长中的公司来说,这是最好的方法。Pimcore 帮助公司从小项目开始,逐步构建目标解决方案,降低风险和返工。你可以根据需求简单地扩展,或者更好的是,你可以更快地开始你的下一个想法,并且风险更小。

无与伦比的灵活性

正如我们之前所说,数据管理给我们带来了无与伦比的灵活性。它有助于无头场景、常规 CMS 或企业应用。多亏了可扩展的 API 系统,用户的需求没有限制。实现解决方案只是时间问题,而不是可行性问题。此外,由于所有内容都通过 Web UI 管理,因此实施数据管理的资源和时间成本也降低了。

一个稳固的平台

Pimcore 是一个由优秀的框架Symfony支持的优秀工具。这个 PHP 框架带来了许多使开发更简单的优势:

  • 强大的代码模块化(分为包)

  • 应用程序和框架之间的分离

  • 依赖注入

  • 海量的组件和文档

  • Composer 管理包的强大功能

采用 Symfony 有助于创建标准的代码结构并加快 Web 应用程序的创建。此外,通过实现原生的字节码缓存,Symfony 有助于提高应用程序的性能。Pimcore 完全基于 Symfony 编写,在底层使用它,并且具有相同的流畅的开发者体验。

受大众使用

Pimcore 平台在 56 个国家的超过 10 万家公司中使用。其开源社区拥有数千名追随者。国际资金的支援确保了产品开发的连续性,每年都有新功能推出。Pimcore 获得了许多奖项,包括来自市场最重要的顾问公司 Gartner 和 Forrester 的奖项,这让我们在对其下注时更加有信心。

Web 开发变得简单

当您离开 Web CMS 的舒适区,例如在添加网页或博客文章时,您经常会陷入需要编码的情况。这意味着,在大多数情况下,定义数据结构,使用对象关系映射ORM)工具进行映射,并通过实现读取/保存例程与数据交互。如果您想将此功能作为 Web API 发布,可能需要采取额外的步骤。

开发过程由少数几个带来价值的活动组成,例如建模您的业务逻辑和执行大量其他重复性任务,包括数据建模或公开 API。这些无聊的任务必须执行,否则您的项目将无法运行。理想情况下,我们希望只将精力投入到真正有价值的工作中。自动化可自动化的事物将节省时间并防止人为错误。

Pimcore 在这种情况下可以帮助您完成所有重复性的工作。您只需要登录浏览器,配置您所需的内容,然后您就可以开始数据管理。您节省的所有时间都可以投入到更有价值的事情上,比如为用户提供更好的体验。

现在应该很清楚 Pimcore 可以为任何公司带来哪些好处,以及为什么我们应该使用它来推动数字化转型。Pimcore 是我们从构建简单网站到创建复杂应用的一切盟友。在下一节中,我们将重点关注 Pimcore 的许可以及它如何帮助我们减少采用时的摩擦。

了解使用开源软件的好处

大多数人认为使用开源软件的最佳理由是免费获得软件解决方案。免费获得产品的机会很有吸引力,但这不应成为选择开源产品的主要动机。

在本节中,您将了解采用开源软件如 Pimcore 以及 Pimcore 解决方案所有优势的最重要论点:

  • 速度和敏捷性

  • 共享维护成本

  • 透明度和安全性

  • 成本效益

  • 社区

  • Pimcore 许可

让我们逐一看看。

速度和敏捷性

开源产品可以立即使用。您可以下载并安装它,然后就可以开始使用。您还可以在无需担心项目增长过程中的试用或成本激增的情况下对其进行测试。开源软件附带大量插件,允许您快速激活功能而无需开发成本。此外,您还有源代码,所以如果某些东西不符合您的需求,您可以对其进行修改。

共享维护成本

开源项目的核心由社区维护。这比从头开始构建整个定制软件并自行维护的方法具有很大优势。在开源项目中,你只需负责维护你的定制部分,这通常是在平台之上的一小层。如果你从头开始创建软件,你则需要负责 100%的代码维护。此外,如果你开发了一个可能对社区有用的模块,你可以将其开源,社区可以从它中受益。

透明度和安全性

源代码是公开的。这意味着你不仅可以看到它是如何工作的,全世界的人都可以看到。作为用户,你可以信任开源软件,因为这样的软件不会包含任何诡计;否则,社区会发现它们并拒绝这个项目。此外,谈到安全性,这种透明度意味着任何问题都会迅速出现并迅速得到解决。

成本效益

从无费用开始,你可以无任何义务地采用开源解决方案,然后进行扩展。许多开源产品都有一个“专业版”,具有更多功能。在这种情况下,你只有在开始使用产品后才开始付费,而且对于这样一个有用的工具,成本是可持续的。

社区

另一个重要点是社区。它有助于提供文档、测试产品并回答你的问题。由数千名成员组成的社区是无法与之竞争的。世界上没有哪家公司能够独自做到这一点。

Pimcore 许可

Pimcore 的公共版本被称为社区版,并使用 GNU 通用公共许可证(GPL-3)进行许可。对于需要更广泛支持和额外功能的企业的版本,Pimcore 提供了一种企业许可,称为Pimcore 商业许可PCL)。

这个解决方案使 Pimcore 成为大型供应商提供的商业企业解决方案的完美替代品。你不仅限于购买软件,也不会面临任何供应商锁定。此外,如果你不想使用 GPL 许可证,你可以简单地避免使用它,保持对你代码的完全所有权。如果你打算基于 Pimcore 创建产品并希望保护你的知识产权IP),这将非常有用。在许多情况下,你可以使用社区或第三方供应商的模块来定制产品。

最后,开源的特性意味着你可以选择是否在本地部署或在云端部署。由多个 SaaS 服务支持的云解决方案有助于降低成本,并构建具有典型本地开源解决方案所有优势(如定制和所有权)以及云优势(例如,低 TCO 和高性能)的解决方案。

对于想要充分利用 Pimcore 并移除 GPLv3 许可证法律约束的软件公司,有Pimcore 企业订阅选项。此订阅解锁所有商业服务和产品,例如 Pimcore 企业扩展(Pimcore 体验门户产品数据同步等)。企业订阅提供对长期支持LTS)和服务级别协议SLAs)的访问。简单来说,它增加了在中大型商业场景中可能节省大量时间(和金钱)的特殊功能,以及高质量支持下的额外保修。

用一句话总结开源的所有好处,开源解决方案是可以无限制定制的解决方案,代码透明且安全,免费提供,并且仍然保留了云的好处。

摘要

在本章中,我们了解了 Pimcore 是什么,不仅停留在定义上,而且深入探讨了 Pimcore 的功能。Pimcore 是一个非常灵活的平台,可以提供许多解决方案,而无需重新发明轮子。通过使用它,您将体验到始终拥有满足您需求的正确解决方案的舒适感。

Pimcore 自带许多有趣的功能(PIM、CMS、DAM 和 MDM),并且采用低摩擦的许可模式,随时可用。一旦您采用它来满足单一需求,例如 CMS,您就可以使用所有其他功能,并且可以根据您的需求变化激活它们。

现在既然本章已经结束,您就可以开始实践部分了。第一步将是学习如何在您的 PC 上安装和配置 Pimcore。这门课程对于开始使用 Pimcore 和为后续课程做好准备非常重要。

第二章:第二章:设置您的 Pimcore 开发环境

在第一章中,我们对 Pimcore 进行了广泛的概述。现在是时候开始动手编写一些代码了!

在本章中,我们将学习如何设置开发环境并开始使用 Pimcore 进行开发。这一章对于拥有一个可工作的本地环境并尝试使用 Pimcore 是必需的。

本章的组织结构如下:

  • 使用 Composer 从 Composer 安装 Pimcore(不使用 Docker)

  • 使用 Docker 安装 Pimcore

  • 探索文件夹约定

让我们开始设置 Pimcore!

技术要求

在 Pimcore 中编写代码非常简单,且不需要任何付费工具。尽管大多数付费工具都增加了附加值,但我们决定只使用免费工具,以便您不受任何限制地获取本书的内容。

您将需要以下内容:

  • Visual Studio Code 作为 集成开发环境IDE

  • 一个不错的网页浏览器(例如 Chrome、Firefox 或 Edge)

  • Docker(可选,但强烈推荐)

为什么使用 Docker?

如果您使用 Docker,所有额外的需求(Apache、必要的库、PHP 等)都将自动管理。此外,使用 Docker 消除了开发和生产环境之间的任何摩擦,提供了一个在所有阶段都相同的虚拟环境。这就是为什么,如今,使用 Docker 是开发应用程序的首选方法,这也是我们在本书中采用的方法。因此,本书的示例基于这项技术。对于那些不熟悉 Docker 的读者,它是一个可以下载(拉取)一个现成的环境(容器)并在您的本地 PC 上运行的系统。我们将提供的所有示例都包含在一个 docker-compose 文件中(一个为您列出和配置容器的文件),所以您需要做的只是激活环境,Docker 将下载所有所需的资产并透明地启动它。因此,即使您对 Docker 不太熟悉,为了本书的目的,您只需要了解以下内容:

  • 包含 docker-compose.yml 文件,运行 docker-compose up

  • 停止您的环境:在启动 Docker Compose 的终端上按 Ctrl+C;这将停止一切。

  • docker-compose exec php <command> 用于在名为 php 的容器内运行命令(在我们的设置中,这是 Pimcore 的容器),或者只需使用 bash 进入容器,并通过 docker-compose exec php bash 启动您想要的任何内容。

对于安装 Docker,它可在 Windows、Mac 和 Linux 上使用,只需导航到官方文档:docs.docker.com/get-docker/

对于手动安装

如果您想手动安装 Pimcore,您将不得不手动配置您的本地机器(或服务器)及其所有依赖项。这仅适用于您不使用 Docker 的情况,所以如果您想使用 Docker,您可以跳过这一部分。

本书唯一使用这种手动方法的章节是以下部分,使用 Composer 安装 Pimcore(不使用 Docker),我们将解释如何从头开始执行 Pimcore 的安装。

对于手动安装,您需要手动安装所有依赖项,包括 Composer、Apache、MySQL、PHP 以及 PHP 库。这些先决条件可能会随着新 Pimcore 版本和技术更新的到来而改变。因此,我们不是添加 Pimcore 的官方系统要求副本,而是提供了指向包含确切规格的官方页面的链接:pimcore.com/docs/pimcore/current/Development_Documentation/Installation_and_Upgrade/System_Requirements.html

注意

Pimcore 支持 MySQL 和 MariaDB 数据库引擎,实际上 MariaDB 是 MySQL 的一个分支。在本章中,我们使用 MySQL 作为参考,因为它是最常见的选项。我们基于 MariaDB 使用了官方的docker-compose文件。为了避免混淆,请在本章中将 MySQL 和 MariaDB 视为同一事物。

本书的所有源代码都包含在官方 GitHub 仓库中,您可以通过此 URL 找到:github.com/PacktPublishing/Modernizing-Enterprise-CMS-using-Pimcore。在这个仓库中,您将找到每个章节的文件夹。在每个文件夹内,将有一个包含运行代码所有说明的Readme文件。

对于使用 Docker 作为环境的人来说,关于操作系统没有限制。有关 Docker 兼容性和系统要求,您可以查看官方 Docker 网站上的下载部分。

从 Composer 安装 Pimcore(不使用 Docker)

尽管我们鼓励使用 Docker,本书也是基于 Docker 容器编写的,但我们不应忽视解释如何进行纯安装。正如您在完成所有步骤后将会了解到的,以纯方式安装 Pimcore 的过程基本上与 Docker 容器内部执行的操作相同。最重要的区别是,使用 Docker,您无需与服务器、依赖项等打交道。这是因为 Pimcore 是通过Composer(PHP 包管理器)发布的。这使得安装在各种可能的情况下都是相同的。如果您在 Docker 容器内、虚拟机或您的 PC 上,Composer 都是一样的。

因此,您要在本地环境中安装 Pimcore,只需在安装了技术要求部分中提到的所有必需依赖项之后,在终端中运行几个命令即可:

注意

本书使用一个现成的 Docker 容器来完成此过程。我们包括这一部分是为了解释 Pimcore 的低级安装是如何工作的,但如果您想快速启动 Pimcore,您可以跳过这一部分,直接转到 使用 Docker 安装 Pimcore。此外,与 Docker 不同,在您的本地环境中使用 Composer 有很多依赖项(MySQL、Composer 等)并且需要复杂的 PHP 调整。这已经在 Pimcore 文档中得到了很好的说明,您可以遵循官方指南。在本节中,我们将介绍 Pimcore 的安装,假设您已经设置了环境,只需要安装 Pimcore。

  1. 在您的文件系统中创建一个文件夹。我们假设这个文件夹命名为 my-project。Pimcore 对您创建该文件夹的位置没有限制。这取决于您的本地设置(也就是说,它必须能够被您的 web 服务器访问)。例如,当使用 Apache 时,一个常见的值是 /var/www/html

  2. 运行以下命令:

    Pimcore/skeleton package in the my-project folder. This will also create a new folder in your filesystem, and the final path will be /your/project/my-project. Pimcore is available in two different releases: skeleton and demo. When starting a new project, it is recommended that you use the skeleton template, but if you want to see Pimcore's features, you can install the demo package to get a website with data that is ready to test. The process will take a moment, and you will see some console output that will display its progress.
    
  3. 如果您还没有,您需要创建一个数据库。为此,请在您的终端中输入以下命令:

    utf8mb4, to fully support Unicode encoding.
    
  4. 编辑您的 Apache 虚拟主机。它需要指向 my-project 内的 web 文件夹,因此您的 Apache 文件应该将文档根目录设置为以下内容:

    DocumentRoot /my/project/my-project/public
    

    注意,Pimcore 需要安装在文档根目录之外。因此,如果您在 my-project 内安装了它,您不能使用这个文件夹作为文档根目录。这不仅会导致功能问题,还会使您面临安全风险,允许访问受保护的内容。Apache 的完整配置可以在以下位置找到:pimcore.com/docs/pimcore/current/Development_Documentation/Installation_and_Upgrade/System_Setup_and_Hosting/Apache_Configuration.html

  5. 设置文件系统权限。Apache 用户(或您使用的 web 服务器上的 Nginx 用户)需要访问 Pimcore 目录中的所有文件,并且对于 /var/public/var 文件夹需要额外的写权限。在大多数情况下,这是通过输入以下代码来完成的:

    chown makes www-data (usually the group where the user that runs the web server belongs) the group owner of the Pimcore folder, and then chmod adds write permission to the required folders.
    
  6. 导航到 Pimcore 目录并输入以下命令:

    /your/project/my-project directory.
    
  7. 通过输入以下命令启动 Pimcore 安装:

    MySQL-host-socket is the hostname of the MySQL database, MySQL-username and MySQL-password are the database credentials, and MySQL-database is the database name. This command will set up the Pimcore connection settings and will install Pimcore in the database. You will be prompted to choose the admin user for the Pimcore back office; we will choose admin\pimcore as a credential, but you can use whatever you want (although the use of simple passwords in your production environment is discouraged).In the following screenshot, we can see the console output that we receive after launching the installation command:![Figure 2.1 – Pimcore installation and admin password prompt    ](https://github.com/OpenDocCN/freelearn-php-zh/raw/master/docs/mdn-entp-cms-pimcore/img/Figure_2.01_B17073.jpg)Figure 2.1 – Pimcore installation and admin password prompt
    
  8. 您将被提示输入 Pimcore 管理用户的用户名和密码,然后您将需要确认安装。

  9. 最后一步是设置维护任务。像许多平台一样,Pimcore 需要执行定期的维护任务,例如日志轮换和清理临时或旧数据。Pimcore 的指南要求我们每 5 分钟执行此任务,以确保环境始终高效。为此,我们需要添加一个 cron 任务。输入以下内容:

    crontab -e
    
  10. 然后,将以下内容输入到 crontab

    */5 * * * * /your/project/bin/console maintenance
    

配置通过运行带有 maintenance 参数的 console 可执行文件来激活维护任务,这调用了标准的 Pimcore 维护任务。

在本节中,我们介绍了 Pimcore 的安装过程。这些说明非常容易遵循,但你需要已经安装了托管环境。安装 Apache、MySQL 以及配置网络部分对于大多数开发者来说是标准的,但需要一些系统工程知识,并非所有开发者都具备(也许他们也不想学习)。此外,使用这种设置,你可能每次设置新项目时都需要复制你大部分的工作。

在下一节中,我们将学习如何使用 Docker 使事情变得如此简单,看看你如何只需两个命令就能完成我们在这里所实现的事情(也许还有更多)。

使用 Docker 安装 Pimcore

Docker 是开发容器化应用程序的领先解决方案,允许开发者在其 PC 上配置一个虚拟环境,该环境可以轻松地转移到服务器上并由用户使用。实际上,使用 Docker 是开发 Web 应用程序的现代方式。它加速了设置过程,减少了环境之间的摩擦,并确保了一个易于使用、可复制的系统。

Pimcore 拥抱 Docker 开发,并已发布可用于使用的 Docker 镜像。此外,它还发布了一个 docker-compose 文件,该文件协调运行 Pimcore 所需的所有容器。

使用 Docker,你将能够在几分钟内设置和启动 Pimcore。使用本书 GitHub 仓库中提供的脚本,大多数过程都很简单。

第一步是克隆 Pimcore 仓库并导航到 2. 设置 Pimcore 开发环境 文件夹。你可以从那里复制文件并将它们粘贴到你的目标文件夹中。文件如下:

  • docker-compose.yml:这包含容器的定义;它与默认的 Pimcore 文件非常相似。

  • install.sh:这包含安装脚本,它是官方指南中安装步骤的自动化版本。

让我们看看这两个文件以及我们如何使用它们。

docker-compose 文件

docker-compose 文件包含许多容器定义,用于启用所有必需的组件。第一个是 database 组件:

db:
    image: mariadb:10.4
working_dir: /application
    command: [MySQLd, --character-set-server=utf8mb4, --collation-server=utf8mb4_unicode_ci, --innodb-file-format=Barracuda, --innodb-large-prefix=1, --innodb-file-per-table=1]
    environment:
      - MYSQL_ROOT_PASSWORD=ROOT
      - MYSQL_DATABASE=pimcore
      - MYSQL_USER=pimcore
      - MYSQL_PASSWORD=pimcore

在前面的片段中,我们有一个针对 Pimcore 使用的 MariaDB 实例。使用环境变量,我们设置了数据库最重要的参数:

  • 根用户凭据:MYSQL_ROOT_PASSWORD

  • 数据库名称:MYSQL_DATABASE

  • 服务用户凭据:MYSQL_USERMYSQL_PASSWORD

使用此配置,我们需要使用 Pimcore/Pimcore 凭据连接到主机数据库。

需要考虑的第二个容器是 Pimcore 容器。请参考以下来自 docker-compose 文件的代码片段:

  php:
    image: Pimcore/Pimcore:PHP7.4-apache
    volumes:
     - .:/var/www/html:cached
    ports:
     - 80:80
     - 443:443
depends_on:
     - db

这个容器的名字是php,因为 Pimcore 依赖于 PHP 镜像。使用卷映射,我们在容器内的 Pimcore 目录上挂载了docker-compose文件所在的文件夹。

安装文件

安装文件只是一组您应该单独运行的命令,但被压缩成单个脚本。这可以防止任何手动错误,并减少设置新环境所需的努力。

脚本涵盖了以下步骤:

  1. 第一步是 Pimcore 下载。为此,我们需要将以下命令添加到脚本中:

    COMPOSER_MEMORY_LIMIT=-1 composer create-project Pimcore/skeleton tmp
    

    这里的问题是容器镜像设置。它是为监听/var/www/html/public文件夹而创建的,因此 Pimcore 的安装必须在/var/www/html/级别进行。问题是 Composer 命令需要一个文件夹来下载文件。这将创建一个子文件夹,并需要更改默认的容器设置。所以,最常见的方法是在临时文件夹中下载 Pimcore,然后将临时文件夹的内容移动到标准的 Apache 文件夹中。这个技巧使用以下命令执行:

    mv tmp/.[!.]* .
    mv tmp/* .
    rmdir tmp
    
  2. 接下来,我们需要修复 PHP 的内存使用。Pimcore 在安装过程中需要 512 MB,而在大多数情况下,PHP 的默认值是不够的。在我们的脚本中,我们将通过更改以下命令中的配置文件来增加内存限制:

    echo 'memory_limit = 512M' >>/usr/local/etc/php/conf.d/docker-php-memlimit.ini;
    service apache2 reload
    
  3. 现在我们已经准备好开始 Pimcore 的安装。我们将使用硬编码在docker-compose文件中的设置来安装 Pimcore。为此,我们需要将以下命令添加到我们的脚本中:

    ./vendor/bin/Pimcore-install --MySQL-host-socket=db --MySQL-username=Pimcore --MySQL-password=Pimcore --MySQL-database=Pimcore
    
  4. 最后,我们必须记住,我们迄今为止启动的所有命令都是以 root 用户的身份执行的。因此,所有创建的文件和文件夹都属于 root 用户和组。运行 Web 服务器的用户将不同,并将属于www-data组。这意味着 Web 服务器无法根据chmod设置写入或读取文件。这就是为什么我们需要在过程结束时重置权限。以下代码行执行此操作:

    chown command adds the www-data group to the files and folders permission; this is enough to enable Pimcore to read and write files.
    

脚本的最终版本如下:

#!/bin/bash
#Pimcore download
COMPOSER_MEMORY_LIMIT=-1 composer create-project Pimcore/skeleton tmp
#trick for moving the files
mv tmp/.[!.]* .
mv tmp/* .
rmdirtmp
#increase the memory_limit to >= 512MB as required by Pimcore-install
echo 'memory_limit = 512M' >>/usr/local/etc/php/conf.d/Docker-php-memlimit.ini;
service apache2 reload
#run installer
./vendor/bin/Pimcore-install --MySQL-host-socket=db --MySQL-username=Pimcore --MySQL-password=Pimcore --MySQL-database=Pimcore
# fix permission
chown -R www-data .

上述脚本包含在源代码中,被称为install.sh。您只需将其复制粘贴到源代码目录中,并遵循下一节的说明。

使用 Docker 启动 Pimcore

现在我们已经了解了 Pimcore 如何使用 Docker 工作,我们可以使用我们的脚本启动 Pimcore:

  1. 第一步是导航到包含 Pimcore 设置文件的文件夹;在我们的案例中,文件夹被称为/my/project

  2. 在这里打开终端并运行以下命令:

    -d parameter (run as daemon), if you close the console, the Docker environment will shut down. This console is helpful because it shows all the logs from the containers, including the Pimcore container.
    
  3. 然后,打开另一个终端并运行以下命令:

    install.sh script inside the container named PHP. The script will run all the instructions needed to install Pimcore. This command is only required the first time you run the container. Its purpose is just for installation.
    
  4. 最后,打开一个网页浏览器并输入 URL localhost/。您将看到标准的 Pimcore 页面,如下面的截图所示:![Figure 2.2 – Pimcore 欢迎页面 img/Figure_2.02_B17073.jpg

    图 2.2 – Pimcore 欢迎页面

  5. 现在,我们可以通过访问地址栏中的http://localhost/admin 来测试设置期间使用的凭证。您将被重定向到登录页面,并能够输入凭证并登录到 Pimcore 的管理部分。以下截图显示了登录页面:

![图 2.3 – Pimcore 登录页面图片

图 2.3 – Pimcore 登录页面

从现在开始,执行步骤 2就足以运行 Pimcore!

在本节中我们学到的是如何在几分钟内使用 Docker 安装 Pimcore。如您在使用 Docker 启动 Pimcore部分所看到的,我们只运行了两个命令,所有进程都已设置。这减少了从小时(安装和配置 Apache、Redis、MySQL 等)到分钟的时间和精力。现在很清楚为什么我们决定在这本书中使用 Docker。

在下一节中,我们将进入 Pimcore 文件夹结构,并了解每个文件夹中有什么内容。

探索文件夹约定

在上一节中,我们在我们的 PC 上下载并安装了 Pimcore。在开始 Pimcore 开发之前,了解文件系统内部的文件结构非常重要。

让我们从探索我们的文件系统开始。在以下截图中,我们将看到 Pimcore 文件夹已展开:

![图 2.4 – Pimcore 文件夹图片

图 2.4 – Pimcore 文件夹

Pimcore 的文件夹结构非常类似于 Symphony 标准。让我们看看第一级内容:

  • bin:这个文件夹包含可执行文件。

  • config:这个文件夹包含 YAML 配置文件。

  • src:这个文件夹包含与您的项目相关的源代码。

  • var:这个文件夹包含从 Pimcore 保存的数据,如日志或缓存数据。

  • vendor:这是 Composer 用于存储应用程序要求的标准文件夹。

  • public:这是您的文档根目录。

  • templates:这是包含所有模板文件的文件夹。

  • translations:这是翻译文件的文件夹。

让我们逐一详细查看这些内容。

配置文件夹

这包含所有 YAML 配置文件和设置。例如,在/config/local/database.yml中,您将找到访问数据库的连接设置。作为额外的例子,如果您想管理路由、覆盖服务或调整安全设置,您可以在这里玩配置文件(config.yml文件是主要配置文件,通常分为子模块,如routing.ymlservices.ymlsecurity.yml)。

模板文件夹

这个文件夹包含模板。你可以为每个包创建一个子目录。将文件添加到包文件夹将覆盖包附带默认模板文件。这种覆盖机制是标准的 Symfony 功能,要覆盖模板文件,你只需要在templates内部创建一个以包命名的文件夹,并在包内部复制文件夹结构。

bin 文件夹

这个文件夹包含二进制文件。默认情况下,它只包含控制台可执行文件,但你可以在这里添加自己的脚本。控制台可执行文件构成了我们用来运行维护任务的程序。向 Pimcore 添加更多任务不需要你创建多个可执行文件;你只需要运行一个如./bin console <myjobname>的命令。这就是为什么在大多数情况下,这个文件夹除了控制台文件之外不包含任何其他内容。

src 文件夹

src文件夹内部,你还会找到Kernel.php文件,它代表你的应用程序内核。Kernel类是 Symfony 应用程序配置的主要入口点,因此存储在src/目录中。

var 文件夹

var文件夹被设计用来包含所有私有的 Pimcore 文件,并且被划分为多个子文件夹,每个子文件夹存储不同类型的文件。这个文件夹必须可以从网络服务器进行写入。

这个文件夹由以下子文件夹组成:

  • application-logger:在这里,Pimcore 保存应用程序日志器生成的文件。应用程序日志器是追踪与应用程序相关事件的系统。这些日志存储在这里,并且可以从 Pimcore 管理界面中读取。

  • cache:这是 Symfony 缓存文件夹。在这里,你可以找到所有生成的文件。

  • classes:这个文件夹包含与类相关的文件。实际上,每个类的定义都存储在这个文件夹内的多个文件中。

  • config:这个文件夹包含从app/config结构覆盖和扩展的基本设置文件。

  • email:这里存储了发送的交易性电子邮件的历史记录。

  • installer:这与安装器内核相关。它包含缓存数据和与安装器相关的其他信息。

  • logs:这个文件夹包含 Apache 和 PHP 的日志。它与 Docker 安装相关。

  • recyclebin:这个文件夹包含从用户那里删除的数据。

  • tmp:用于临时文件存储,例如创建动态压缩的 JavaScript 文件。

vendor 文件夹

这个文件夹是标准的 Composer 文件夹,因此没有必要花费更多时间来讨论它。Pimcore 核心包就像任何其他包一样存储在这里。

公共文件夹

这是你的应用程序的文档根目录,并且它暴露给网络。这个文件夹由.htaccess文件保护,并实现了某些重写规则。

这个文件夹由以下子文件夹组成:

  • bundles:您将为每个包找到一个文件夹;这些子文件夹中的每个都指向包内部的文件夹的符号链接(因此,/src/bundlename 将在 /public/bundlename 中可见)。这是因为您可以在包内部更改文件,而无需复制或编译即可看到更改。

  • var:此文件夹包含上传的文件:图像、视频文件或简单的附件。

此文件夹还包含 index.php 文件,其中包含所有请求的路由的 PHP 应用程序。

在本节中,我们学习了 Pimcore 的文件夹和文件如何在源代码内部组织。这一点非常重要,以便您能够无任何困难地使用源代码示例。现在,当我们需要这个功能来启动一个正在运行的 Pimcore 实例并查看本书中展示的示例时,您不会在第四章“在 Pimcore 中创建文档”中迷失方向。

摘要

在本章中,我们学习了如何从头开始安装和启动 Pimcore 环境。通过使用 Docker 镜像,我们简化了首次安装的复杂性,使我们的环境独立于不同的操作系统,并成功缩短了设置时间。只需在终端中输入几个命令,所有复杂的流程都会自动完成。这不仅适用于开发环境,也适用于生产环境。此外,如果您想迁移到云端,使用容器将使事情变得简单。Pimcore 还可以通过负责所有依赖配置来在常规环境中安装。

在接下来的章节中,我们将利用这些知识来运行本书中提供的示例。此外,提供的安装脚本可以作为快速入门指南使用,如果您想自己开始一个新项目并在现实世界中与 Pimcore 玩耍。在下一章中,我们将发现 Pimcore 的管理界面,并学习如何在菜单项之间切换。完成这一步后,您将能够导航 Pimcore 的功能,这对于遵循本书的教程是基本要求。

第三章:第三章:开始使用 Pimcore 管理界面

在本章中,我们将检查 Pimcore 管理界面的所有组件和菜单,这是你进行网站管理所需的大部分操作的控制室。通过阅读本书,你将能够从头开始构建网站。

为了完成你的网站,Pimcore 允许你创建捆绑包、修改核心组件,或者覆盖构成网站的大部分部分(从控制器到模型,从视图到路由规则等)。所有这些方面将在本书的后续章节中进行探讨,但你在学习如何作为用户在网页界面中导航之前,无法处理这些主题。

尤其是在本章中,我们将发现配置你的网站最有用的工具以及它们在管理页面上的位置。

在本章中,我们将涵盖以下主题:

  • 理解 Pimcore 架构

  • 探索 UI 组件

  • 与网格组件一起工作

  • 检查菜单

因此,让我们从对 Pimcore 架构的简要介绍开始。

技术要求

要跟随本章的教程,你不需要一个正在运行的 Pimcore 实例。你可以直接阅读本章,但如果你想要实践,你可以打开 Pimcore 并跟随操作。

你在这里需要做的只是遵循第二章**,设置你的 Pimcore 开发环境中的说明,来安装一个空的 Pimcore 实例。

完成这些后,你只需打开浏览器并输入 http://localhost,在用户界面中导航即可。

理解 Pimcore 架构

在本节中,我们将查看 Pimcore 架构的简化概述,特别关注我们在本章讨论中将重点关注的架构部分。

在以下图中,我们可以查看 Pimcore 架构,并了解在本章中我们将重点关注 Pimcore 的哪个部分:

图 3.1:Pimcore 架构

图 3.1:Pimcore 架构

图 3.1:Pimcore 架构

如前图所示,我们探索 Pimcore 的旅程的起点由包含文本“你在这里”的虚线矩形表示。

只是为了了解 Pimcore 在所有部分是如何组成的,让我们看看图中的每个方面;即使我们看到的是 Pimcore 架构的简化版本,我们仍然可以识别出平台的所有重要部分。我们不会对每个部分进行详细说明,但我们仍然可以快速描述它们。

PIMCORE UI LAYER 是用户界面层,即所有与用户交互的入口点。在里面我们可以识别出两个更进一步的方面,ADMIN UIPUBLIC UI:这种公共和私有的划分是必要的,以保持与管理的相关服务,仅对具有管理角色的用户可用,与公共的解耦。

APIs 指的是第三方软件可以通过它访问 Pimcore 的层,与之功能和数据进行交互;迭代的可能性很多,例如导入数据、更新数据、导出数据、创建内容等。在这个层内访问所有这些操作都是可能的,使用通信协议,如 REST API 或 GraphQL,它们在这个 Pimcore 的部分公开其服务。

最后,PIMCORE 核心架构是包含业务逻辑层、数据模型、数据库访问的数据访问层、创建 HTML 页面的模板引擎的层——换句话说,这是 Pimcore 的核心。在本书中,我们将这部分称为 Pimcore 管理员管理页面,甚至在某些情况下称为 Pimcore 仪表板

让我们开始我们的 Pimcore 管理之旅,从 UI 组件开始。

探索 UI 组件

Pimcore 是一个庞大的环境,由同样重要且广泛的框架(Symfony)支持,这可能会有些令人困惑,尤其是对于 Pimcore 新手来说。但就像所有漫长的旅程一样,我们必须从第一步开始。这是我们的第一步。让我们登录管理面板。

首先,我们需要访问 Pimcore 管理界面;为此,我们必须通过访问页面 yoursite.com/admin/ 登录管理页面。这是我们面临的第一屏,Pimconaut,Pimcore 的吉祥物欢迎我们:

![Figure 3.2: Pimcore Administration Login Page (the image on this page changes from time to time)

![img/Figure_3.02_B1073.jpg]

图 3.2:Pimcore 管理登录页面(此页面的图片会不时更改)

登录后,我们将进入管理页面,Pimcore 控制室。在下一张截图,我们将看到控制室的外观:

![Figure 3.3 – Pimcore administration

![img/Figure_3.03_B1073.jpg]

图 3.3 – Pimcore 管理

如我们所见,Pimcore 仪表板被分为四个部分,本节将讨论这些部分:

  1. 侧边栏菜单

  2. 左侧边栏

  3. 主框架

  4. 右侧边栏

让我们逐一查看。

侧边栏菜单

侧边栏菜单是您看到的左侧最黑的条。它包含两部分:

  • 顶部第一部分包含平台开发和配置所需的所有操作,从语言到路由规则,再到研究和创建对象。

  • 第二部分,在底部,包含有关系统和用户的信息、通知以及 Pimcore 标志。

正在侧边栏的下部上方,可以看到 Symfony 标志。Symfony 是 Pimcore 开发的 PHP 框架;换句话说,其引擎。在 Pimcore 上所做的所有操作都通过这个框架进行。当您点击 Symfony 标志时,页面的底部将出现另一个细长的工具栏,如以下截图所示:

图 3.4:Symfony 工具栏

图 3.4:Symfony 工具栏

这个新菜单包含一些关于系统的基本信息,例如内存使用情况、当前用户、缓存使用情况或数据库查询。将鼠标悬停在其上时,将出现一些弹出窗口,显示附加信息,如以下截图所示:

图 3.5:Symfony 工具栏和附加细节

图 3.5:Symfony 工具栏和附加细节

当点击项目时,会加载一个新页面,其中包含关于系统每个部分的更详细信息。如果您需要比这更多的系统信息,您可以点击工具栏中的一个条目,将打开一个页面,其中包含有关缓存、日志、事件、例程以及 Pimcore 所使用的所有其他 Symfony 部分的更多信息。

左侧边栏

总是在左侧,紧邻菜单侧边栏,有一个第二个侧边栏;这个侧边栏包含对文档、资产和数据对象的快捷方式。我们将在以下章节中讨论它们,但它们是我们将在创建美丽的 Pimcore 网站时最常用的功能。

主框架

主框架是 Pimcore 管理界面的中心面板。所有需要更改的元素都加载在这里。换句话说,这是打开与菜单项相关内容的地点。以下是在动作中的主框架截图:

图 3.6:Pimcore 管理界面部分标签页已打开

图 3.6:Pimcore 管理界面部分标签页已打开

如前一个截图所示,有一些文档已打开,每个文档都在一个单独的标签页中。换句话说,主框架是我们将在 Pimcore 的工作中打开的所有配置窗口的容器。

右侧边栏

主框架右侧的侧边栏是一个可以移动左侧侧边栏组件的地方。这可以通过点击箭头(见 图 3.3)轻松完成。这种布局在您需要同时处理多个项目并希望保持控制时非常有用。例如,您可能想要浏览页面,同时让产品准备好在页面上使用。因此,您可以使用右侧工具栏来显示数据对象。我们将在 第五章**,探索对象和类 中学习如何使用数据对象来建模产品实体。

Pimcore 允许更改侧边栏配置,包括通过添加菜单项,这对于快速访问特定功能通常很有用。例如,在电子商务的情况下,可能需要为订单或客户提供快捷方式。这些定制功能的示例可以在官方 Pimcore 网站上看到:demo.pimcore.fun/admin/

在对菜单的简要介绍之后,我们可以详细查看我们刚刚列出的所有元素,从 Pimcore 仪表板的主要组件——主框架开始。从侧边栏(或菜单条目)打开的任何对象都在主框架内作为一个新标签打开。换句话说,主框架是所有编辑标签的容器,用户可以逐个或全部关闭,就像通常在浏览器中做的那样。

现在我们已经熟悉了 UI 组件,我们可以更进一步,开始详细分析其他部分,例如网格组件和菜单。在下一节中,我们将继续查看网格组件,在那里我们将花费大部分时间来处理 Pimcore 数据。

使用网格组件

在本节中,我们将详细分析网格组件的工作原理。我们将发现如何执行简单的活动,如搜索。此外,我们还将了解工具栏上每个主要按钮的功能。

首先,让我们看一下下面的屏幕截图,看看网格在使用时的样子:

图 3.7:网格组件

图 3.7:网格组件

如前一个屏幕截图所示,这个组件中至少有四个感兴趣的点:

  1. 已经见过的带有打开实体的第一个标签栏

  2. 用于主要操作的按钮工具栏

  3. 特定文档的第二标签栏

  4. 打开的文档

我们已经列出了构成图 3.7中看到的网格组件的元素,因此现在我们可以更详细地描述它们,从第一个开始。

第一个标签栏

我们已经看到这个第一个元素,它不需要进一步解释;如果需要,可以参考主框架部分。

工具栏

现在让我们看看工具栏,以及其中的一些操作按钮。

根据我们正在修改的对象类型,以及在某些情况下根据文档本身的发布状态,这个工具栏中可能有不同的按钮。换句话说,工具栏根据您正在编辑的元素(即文档或对象)及其发布状态而变化。例如,如果我们正在编辑一个网页,根据它是否已发布或尚未发布,我们将看到保存保存并发布按钮,或者保存并发布取消发布按钮。

下面的屏幕截图显示了一个用于不同对象的工具栏——对于一个文件夹、一个网页,然后是不同状态下的对象:

图 3.8:编辑文件夹、网页和不同状态下的对象时显示的工具栏

图 3.8:编辑文件夹、网页和不同状态下的对象时显示的工具栏

如您在前一个屏幕截图中所见,顶部工具栏中的按钮数量不同——这是因为操作会根据我们正在编辑的对象类型动态变化。

例如,SAVE & PUBLISH按钮始终出现在必须使可见的所有元素中,例如网页或对象。对于其他内部使用的元素,如文件夹,它不可见,因为它不是必需的。

图 3.8中,您可以在一个红色矩形内看到一些按钮。这三个按钮始终存在于工具栏中,如下所示(从左到右):

  • Reload:重新加载文档(不是整个页面)。

  • Show in tree:当您点击此按钮时,Pimcore 会识别并选择左侧树文件中的当前对象。

  • Info:此按钮打开一个包含有关我们正在编辑的文档的一些信息的模态窗口。

现在我们已经看到了网格组件的第二个元素,让我们继续到下一个部分,并分析我们列出的四个元素中的第三个:第二个标签栏。

第二个标签栏

在工具栏下方还有一个标签栏,其中包含可变数量的标签,每个标签将显示我们正在编辑的对象的一组属性。此外,在这种情况下,正如我们刚才看到的标签栏一样,标签的数量和类型会根据对象及其修改时的状态而变化。

根据我们正在编辑的元素,无论是网页、对象还是文件夹,标签的数量及其含义都会变化。例如,如图 3.8所示,如果我们正在编辑网页,我们将有SEO & SettingsPreview标签,而如果我们正在编辑对象,我们可以看到Properties标签。

在这两种情况下,都有一个版本标签;如果我们打开这个标签,内容将会显示,如这个屏幕截图所示:

图 3.9:对象的版本标签

图 3.9:对象的版本标签

从这个屏幕截图中我们可以看到,版本标签的内容正是我们预期的:关于对象所做的所有更改的信息,更改的日期以及谁做的更改。通过点击任何版本,您可以查看文档之前的状态,通过选择两个(Ctrl + 点击)您可以看到两个版本之间的差异。

在本节中,我们还描述了我们列表的第三个元素,第二个标签栏。我们可以继续到我们列表的第四个和最后一个项目,即打开的文档。

打开的文档

这是显示打开的标签内容的部分。正如您所想象的那样,它是整个组件中最大的部分,因为它包含修改和配置文档所需的所有属性和操作。

例如,如图 3.9所示,版本标签将此组件分为两部分:在左侧的表格中显示了文档所做的所有更改,而在右侧则显示了所选更改的预览。

因此,每个标签将根据文档和我们要编辑的内容包含不同的布局和属性。

在本节中,我们详细了解了组成网格组件的各个部分,这是处理文档的基本工具。本章的最后一部分将专门介绍菜单,我们现在将对其进行探索。

检查菜单

现在我们将处理菜单,由于我们在这里找到的大量操作,它们通常扮演着非常重要的角色。我们无法逐一详细查看它们,因此我们将限制自己讨论每个菜单的范围以及我们可以使用其中找到的项目做什么。这对于在 Pimcore 界面中移动并学习下一章我们将学到的课程至关重要。

以下截图显示了所有菜单:

![Figure_3.10: The Pimcore menus]

![Figure_3.10_B1073.jpg]

图 3.10:Pimcore 菜单

从左到右,菜单如下:

  • 文件

  • 工具

  • 营销

  • 设置

  • 搜索

点击菜单项将在主框架中打开一个配置页面作为新标签页。然而,有些菜单项包含子菜单(通过项目右侧的箭头可识别),当鼠标悬停在项目上时会出现。

正如我们所说,无法描述所有菜单中每个项目的功能,因此现在让我们看看我们可以在其中找到的主要命令。

文件

文件菜单,正如我们通常所知,包含打开文档(各种类型)、关闭所有打开的标签、导航到 Pimcore 网站阅读官方文档或显示 Pimcore 信息模态的操作。此外,还有仪表板页面的快捷方式,在那里我们可以找到一些图表,显示上一时期所做的更改数量,或最后修改的元素列表。

工具

在此菜单中,我们可以找到一些有用的网站管理工具,例如重定向、网站语言管理或发送的电子邮件,以及发送测试电子邮件的能力。除此之外,还有其他辅助功能,如笔记和有用的数据库管理页面链接。在此菜单中,还有一些关于系统的信息,例如缓存状态或正在使用的 PHP 版本。

营销

此菜单专用于营销管理,包括搜索引擎优化、统计报告、配置分析工具(如 Google Tag Manager 和 Google Analytics)等功能,这些工具对于从事网络营销的你们来说,了解其监控网站访问的重要性。

设置

在这个菜单中,我们可以找到配置我们网站所需的所有操作。例如,可以创建和修改文档类型、对象的通用属性,还可以管理用户及其角色,配置系统的所有部分(时区、默认语言、电子邮件设置等),创建静态路由,以及管理缓存或翻译。

正如我们所预料的,这是最重要的菜单之一,但不需要记住它确切包含哪些项目,我们只需要记住,在这里我们可以找到我们将在网站上从管理角度必须进行的几乎所有配置。通过实践和经验,我们将能够记住各个菜单的所有功能,尽管现在这可能看起来像是一个遥远的目标。

为了理解甚至一个菜单项中可以隐藏多少东西,这里展示了系统设置页面:

![图 3.11:系统设置页面

![img/Figure_3.11_B1073.jpg]

图 3.11:系统设置页面

如我们所见,每个部分都可以通过点击+来展开,从而访问该部分的配置参数。

搜索

最后,在这个最后一个菜单中,您可以找到通用搜索功能的快捷键,以及针对网站某些元素(如资产、文档和数据对象)的特定搜索功能的快捷键。

在本节中,我们了解了 Pimcore 中每个菜单的功能以及可用的众多特性。虽然无法逐一描述,但我们仍讨论了书中最重要的项目,并将探索我们未描述的所有菜单项的乐趣留给了您。

摘要

在阅读本章后,您现在知道如何在 Pimcore 管理 UI 内部移动,在那里您可以找到 Pimcore 治理最重要的工具。我们讨论了各个菜单的动作,如何使用网格组件,以及管理 UI 的主要元素。到目前为止,这已经是一大堆信息了,但对于理解下一章我们将学习的内容是至关重要的。

现在我们已经了解了如何导航 Pimcore 最重要的功能,我们可以继续下一步,即学习如何使用 Pimcore 创建文档。

第四章:第四章:在 Pimcore 中创建文档

在前三个章节中,我们提供了 Pimcore 的介绍,并解释了如何浏览管理界面。这些步骤是必要的,因为我们现在有了开始学习如何使用 Pimcore 创建精美网站和解决我们在第一章中介绍的所有数字创新问题的基础知识。

现在是时候开始面对 Pimcore 的实际元素了。在接下来的章节中,我们将介绍许多主题,难度逐渐增加,以掌握整个 Pimcore 平台。在本章中,我们将逐步学习如何使用 Pimcore 创建网页。

在本章中,我们将涵盖以下主题:

  • 什么是文档?

  • 创建文档

  • 创建模板

  • 编辑文档

  • 继承文档

了解 Pimcore 文档将有助于您在构建简单网站时定义页面格式和设计。

技术要求

如果您遵循了 第二章**,设置您的 Pimcore 开发环境 中的说明,您应该在您的本地机器上有一份与本书相关的源代码副本。

因此,您要运行与本章相关的演示,只需克隆源代码,导航到 4\. 在 Pimcore 中创建文档 文件夹,并启动 Docker 环境。

您可以在此处找到本章的所有代码文件:github.com/PacktPublishing/Modernizing-Enterprise-CMS-using-Pimcore/tree/main/4.%20Creating%20documentes%20in%20Pimcore

要在您的 PC 上开始编写代码,只需导航到文件夹 4. 在 Pimcore 中创建 文档,并按照以下说明操作:

  1. 使用以下命令运行 Docker:

    docker-compose up
    
  2. 然后,为了从您的本地恢复所有设置,请输入以下内容:

    docker-compose exec php bash restore.sh
    
  3. 导航到 localhost/admin 并使用您的管理员/pimcore 凭据登录。

现在,您已经准备好玩与本章相关的演示了!

什么是文档?

一般而言,每个人每天都在使用文档。我们处理文档规范以供我们的老板或客户使用,我们编写文档以跟踪我们软件中的变化……但在 Pimcore 中,什么是文档?在信息科学领域,我们不是指纸张,而是指包含非结构化信息的数字资产;在我们的案例中,网页就是一个文档。文档被组织成一个文档树,在元素之间创建了一个层次结构。这种文档结构将代表网站的架构。这看起来可能很复杂,但实际操作起来非常简单。

在以下示例中,我们有一个由一个树状网页组成的简单网站:

图 4.1:文档列表

图 4.1:文档列表

本章我们将创建这些页面,并将展示所有文档功能。

我们告诉您,文档可以是任何类型的非结构化数据容器。这些容器可以根据其中找到的信息类型非常不同。为了以适当的信息量表示每个文档,我们需要使用文档类型对文档进行分类。

Pimcore 提供了许多不同的文档类型,让您可以轻松管理您将面临的大多数用例:

  • 页面:这是典型的网页。文档树中的路径定义了最终的 URL。

  • 片段:正如其名所示,片段是文档的片段,可以嵌入到页面中进行内容重用。我们还可以将片段添加到片段中。

  • 链接:这是一个可以在导航树内部使用的原始网页链接。

  • 电子邮件:这是一个生成 HTML 内容的文档,如页面,但也支持发送交易性电子邮件,允许您定义发件人和收件人。

  • 新闻通讯:与电子邮件内容非常相似,但有一些额外功能以支持作为新闻通讯的使用(例如,群发)。

  • 硬链接:允许您创建内部链接并更改文档的常规结构。

  • 文件夹:类似于您 PC 文件系统中的文件夹,Pimcore 文件夹包含多个文档。

  • 打印页面:为了打印目的,具有一些额外功能,例如生成 PDF按钮。

  • 打印容器:一个将页面组织成组以创建一个多页文档并准备打印的容器。

Pimcore 不仅自带文档类型,您还可以创建自己的。

在本章的第一节中,我们学习了 Pimcore 中的文档是什么。这有助于我们理解接下来将要做什么,因为我们将学习如何创建一个新的文档并实现一个简单的网页。

创建文档

在本节中,我们将了解如何使用 Pimcore CMS 创建文档。为此,请按照以下步骤操作:

  1. 导航到文档树并右键单击以激活上下文菜单。

  2. 选择添加页面然后空白(以创建一个空页面)![图 4.2:在 Pimcore 中添加页面 图 4.2:B17073.jpg

    图 4.2:在 Pimcore 中添加页面

  3. 将出现一个名为添加页面的模态弹出窗口,有三个参数供您填写。标题参数是页面的标题,导航参数是在导航菜单中使用的名称,是您为文档选择的唯一键:![图 4.3:输入我们正在创建的页面的数据 图 4.3:B17073.jpg

    图 4.3:输入我们正在创建的页面的数据

  4. 点击确定,您将看到您的主页已添加到菜单树中:![图 4.4:树菜单中添加的页面 图 4.4:B17073.jpg

    图 4.4:树菜单中添加的页面

  5. 点击你新创建的页面,首页,页面元素将在新标签页中打开。下一张图显示了页面编辑器:

图 4.5:网页

图 4.5:网页

这个页面告诉我们我们已经创建了一个网页,但网站是空的,因为我们还没有模板。这个信息可能有点令人沮丧,因为经过所有这些步骤,你仍然不能创建 HTML 模板而不输入内容。如果你习惯了像 WordPress 这样的现成解决方案,这可能会显得相当奇怪,在那里任何人都可以添加内容而无需编写一行代码。这是因为 Pimcore 的哲学,其中你与工具之间没有超结构。

在下一节中,我们将学习如何创建一个简单的模板。目前,我们可以满意的是我们已经学会了如何使用文档创建网页。

创建模板

本章的目的是为你提供正确渲染文档的基础知识。这仅仅是 Pimcore 渲染能力的一小部分,我们将在第十章**,创建 Pimcore 砖块*中深入探讨这个主题,以发现渲染自定义数据的所有秘密。目前,我们将只关注我们创建简单网站所需的信息。

Pimcore 页面设计过程

首先要介绍的概念是模板和布局。布局是一个通用的页面原型,你可以在其中留下一些占位符,这些占位符将由模板填充。例如,你可以有一个有两列和两个占位符的布局页面,每列一个。在每一页上,你都将能够填写每个占位符内的内容。这样的占位符在 Twig 语法中被称为,你可以定义你想要的块的数量。

在下面的图中,你可以看到网页设计过程是如何工作的:

图 4.6:模板引擎在行动

图 4.6:模板引擎在行动

让我们看看每个阶段:

  • 第一步是定义一个布局。这一步必须由开发者或精通 HTML、CSS 和 Twig 模板语言的人来完成。这并不复杂,但需要你访问源代码并写下文件,通常最终用户无法完成。在这个阶段,我们将定义页面的结构;在示例中,定义了行数/常见页面部分。

  • 在布局内部,为模板留出一个用于页面实现的空白空间。在模板内部,设计师或开发者可以添加用户填写的内容。通过这种方式,你可以创建产品页面原型,然后内容管理员可以创建许多产品页面。

  • 作为最后一步,用户将能够将数据输入到模板占位符中。在这个例子中,用户可以输入标题,填写正文内容,并添加图片。

    注意

    Pimcore 支持 Twig 或 PHP 模板。如官方文档所述,PHP 模板已被弃用,并将随着 Pimcore X 的发布而退役。这就是为什么,尽管官方 Pimcore 文档中只展示了 PHP 示例,但我们决定以 Twig 模板为基础编写这本书。我们意识到,大多数 PHP 开发者可能更习惯于纯 PHP 模板,但基于已弃用的功能编写一本书是困难的。

在本节中,我们对 Pimcore 的模板进行了概述;现在是时候学习如何从头开始创建一个模板了。

实现简单布局

在本节中,我们将实现一个简单的布局,可用于创建网页和构建网站。正如您将看到的,这个过程很简单,只需几个步骤就可以得到一个可工作的模板:

  1. 首先,我们需要告诉系统使用 Twig 文件而不是 PHP 模板。导航到/src/Controller并打开DefaultController.php。您只需在控制器中的defaultAction方法上添加一个@Template()注解:

    <?php
    namespace App\Controller;
    use Pimcore\Controller\FrontendController;
    use Symfony\Component\HttpFoundation\Request;
    use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
    class DefaultController extends FrontendController
    {
        /** 
         * @Template() 
         */    
        public function defaultAction(Request $request)
        {
        }
    }
    

    在接下来的步骤中,我们将学习布局引擎的工作原理以及如何为您的 Pimcore 网站创建模板。这非常简单,因为我们只需要一些 HTML、CSS 和 PHP 的知识来创建结构化的网站。

  2. 到目前为止,我们已经准备好开始创建模板。导航到/templates并创建一个名为layout.html.twig的文件。Pimcore 背后的模板引擎是 Symfony,因此对于通用 Symphony 项目有效的多数事物对于 Pimcore 也是适用的。在下面的示例中,我们有一个实现 Pimcore 布局的代码片段。您可以将此代码片段复制到layout.html.twig文件中,或者检查我们提供的演示文件:

    <!DOCTYPE html>
    <html lang="en">
    <head>
    <!-- head omitted -->
    </head>
    <body>
     <!--Navigation bar omitted   --> 
    {% block content %}
    {% endblock %}
      <hr>
    <!--footer bar omitted --> 
    </body>
    </html>
    

    如您在前面的代码中所见,Pimcore 布局只是一个 HTML 文件(或 Twig 模板),在其中您添加以下代码片段以创建用户放置内容的位置:

    {% block content %}
    {% endblock %}
    

    在模板内部,您想要添加您网站的所有常见部分,例如菜单、页脚和页面结构。当然,您可以在不同页面中使用多个布局,甚至是同一网站(例如,树形列与两列布局)。

  3. 布局不能被最终用户使用,因为它只包含页面结构定义。因此,我们必须定义一个模板。模板是另一个 Twig 文件,在其中您实现布局中留下的空白块。导航到/templates并创建一个名为Default的文件夹,其中包含一个名为default.html.twig的文件。在这里,您必须扩展我们在上一步中创建的布局。为此,添加一个包含标题、副标题和页面主体的简单模板:

    layout.html.twig file.The next statement indicates the beginning of the block of code that will fill the placeholder called `content` into the main layout file:
    
    

    {% block content %}

    
    
  4. 然后,混合使用 HTML,我们有一些特殊的指令,允许用户在模板中放置内容。我们的目标是消除编辑过程中对开发者的任何依赖(换句话说,用户必须能够自行输入数据)。在这种情况下,可以通过使用 Pimcore 的headline指令轻松实现。然后我们可以有许多参数;在这种情况下,我们在编辑过程中使用固定宽度。

    要添加 HTML 文本,我们做的是相同的,但使用所见即所得WYSIWYG)界面。这与前一个案例非常相似,如下一代码片段所示:

    {{ pimcore_wysiwyg('body') }}
    

现在我们能够编辑文档了!在下一节中,我们将学习如何将数据放入模板以及如何迭代此过程以实现真正的网站。

编辑文档

在本节中,我们将学习如何创建和编辑文档。正如我们告诉您的,文档可以是您的 CMS 网页中的任何一种,所以仅仅从这个简单的课程中,您就能创建任何类型的网站。编辑文档的过程非常简单,我们将通过完成一些简单的步骤来探讨它:

  1. 打开管理面板并找到主页,这是我们之前在什么是文档?部分创建的页面。通过选择它,您将在管理的主框架中打开网页。如下一图所示,我们将直接编辑网页,并使用一种称为 WYSIWYG 的模式,这非常有用,因为它使编辑器在编辑过程中意识到他们正在做什么:图 4.7:网页编辑器

    图 4.7:网页编辑器

    如前图所示,我们有一些虚线区域,这些是我们添加到 Twig 模板中的占位符。这些占位符就像常规输入框一样工作,所以您只需点击它们并开始输入文本。在 Pimcore 中,这样的项目被称为可编辑项(如前所述)。

  2. 点击较大的占位符并输入单词主页;您将在输入字符的同时看到编辑器被填充。在下一张图中,您可以看到填写标题字段的最终结果:图 4.8:编写标题

    图 4.8:编写标题

  3. 点击第二个占位符(位于标题下方的一个)。与上一个案例一样,点击编辑器将解锁您写入任何文本的能力。不同之处在于标题字段是一个单行可编辑框,而此字段是一个 HTML 编辑器;您可以选择文本,然后像在任何文字处理程序中一样应用样式。在下一张图中,您可以看到这一功能的使用情况:图 4.9:HTML 编辑器使用情况

    图 4.9:HTML 编辑器使用情况

    前一张图显示了 HTML 文本和允许设置文本样式的上下文菜单。

  4. 一旦我们填写了文档的可编辑部分,网页就完成了。我们可以使用工具栏中的保存并发布按钮来发布它。

  5. 然后,要查看页面的预览,只需点击预览按钮。在下一张图中,我们可以看到预览工具的实际应用。如图所示,我们可以选择用于渲染页面的设备(在这个例子中,我们正在模拟一部手机):图 4.10:文档预览

    图 4.10:文档预览

  6. 最后,我们必须注意搜索引擎设置。点击SEO & 设置标签以进入我们可以编辑这些设置的面板。在这里,我们可以添加标题、描述以及我们想要的任何元标签:图 4.11:SEO & 设置面板

    图 4.11:SEO & 设置面板

    在同一页面上,你可以看到你网页的 Google 预览,这样你就可以知道用户搜索你的网页时会看到什么。在最后一个可编辑组件中,你可以为页面定义一个自定义 URL。此设置覆盖了正常页面结构,因此它是一个绝对 URL。

  7. 最后,点击版本标签。你将看到文档的历史记录,如下所示。在版本面板中,你可以访问网页的历史记录,并在出错的情况下恢复旧版本:

图 4.12:版本面板

图 4.12:版本面板

编辑文档使我们能够创建简单的网站。这很简单,只需定义一个模板,然后将信息放入其中。我们已经了解到,我们可以通过创建不同的模板来创建文档实例,并且用户可以使用网络界面自主管理它们。复制我们迄今为止所做的一切就足以构建简单的网站。

然而,事情可能会变得稍微复杂一些。例如,假设你想创建一个包含一系列要出售的产品目录的网站。使用我们迄今为止所学到的知识,你可以通过为产品页面添加文档模板来创建目录;然后,你可以创建一个产品页面并填写数据。现在,想象一下每个产品都有各种变体;这些(子)变体与原始(父)产品共享大量信息。使用我们刚才介绍的过程为这些变体创建多个页面将会很耗时。此外,如果你复制粘贴了所有产品变体中相似的数据,然后其中一条信息发生了变化,你就必须逐个更新每个页面。这个例子告诉我们,通过复制粘贴信息来复制数据会导致难以维护的网站。

在下一节中,我们将学习如何通过文档继承来重用文档内容,以避免数据复制。

继承文档

文档继承是一个功能,允许你创建一个预先填充的文档,你可以只覆盖你需要覆盖的部分。将此功能想象为“模板中的模板”。此功能通过在文档设置中设置内容主文档属性来激活。此功能适用于所有文档类型,对于重复性内容(如通讯或技术文档)非常有用。

在以下步骤中,我们将了解如何利用继承来重复使用内容并更好地组织网站内容。我们将创建一个简单的产品目录,其中包含一个产品(在这里是 T 恤)和多个变体(每个颜色一个变体),每个变体都将有自己的网页。

按照以下步骤进行操作:

  1. 首先,我们必须为产品页面创建一个模板。因此,让我们在/templates/Default中创建一个名为product.html.twig的文件。这个过程与编辑文档部分中遵循的过程非常相似,但这次我们将有一个更复杂的布局。实际上,我们必须显示产品数据,因此我们必须添加更多的输入。下一个布局片段显示了布局文件的相应部分:

    <div class="breadcrumb-item">Category:{{ category, title, discounted price, price, producer, and origin). We are now able of going into the Pimcore administrative interface and create a document item.
    
  2. 在树菜单中创建一个页面。在我们的例子中,我们将为一些变体(T 恤)创建一个页面,因此页面标题将是TShirt。在我们的情况下,我们在这个产品菜单项中创建了此页面,它是我们目录的根。然后,你必须迭代这个过程,为每个颜色变体(TShirt-RedTShirt-GreenTShirt-Yellow)创建一个子页面。最终结果如图所示:图 4.13:产品菜单

    图 4.13:产品菜单

  3. 现在双击父页面TShirt并打开文档。

  4. 现在点击SEO & 设置。点击模板下拉菜单并选择默认/default.html.twig图 4.14:选择产品模板

    图 4.14:选择产品模板

  5. 为所有子页面重复前面的步骤。

  6. 为我们在模板中添加的每个字段输入数据。结果应该类似于以下图所示:图 4.15:编辑 T 恤产品

    图 4.15:编辑 T 恤产品

    在编辑我们使用这些文档创建的产品变体之前,我们将假设为该产品输入的大部分信息将适用于所有子项。事实上,所有产品只是相同的 T 恤,只是颜色不同。让我们在接下来的步骤中看看如何避免数据重复。

  7. 打开TShirt页面并点击SEO & 设置。然后,将TShirt页面从文档树拖放到内容-主文档字段:图 4.16:拖放父文档

    图 4.16:拖放父文档

  8. 点击应用后,你会收到提示信息:您确定吗?所有内容都将丢失。当你确认操作时,你页面上现有的所有内容将被继承的内容覆盖。由于操作已完成,你现在拥有所有可编辑组件已禁用。在下一张图中,我们可以看到页面看起来如何。正如你所见,占位符已自动填充来自父页面的值。你可以看到,可编辑组件现在已禁用,当你将鼠标移至可编辑区域时,会出现右键单击以覆盖的消息:图 4.17:覆盖继承属性

    图 4.17:覆盖继承属性

  9. 右键单击禁用的可编辑区域;在这种情况下,右键单击一件 T 恤。这一步将解锁字段,并允许你更改此页面实例的默认值。在这种情况下,我们输入了一件红色 T 恤图 4.18:覆盖后,文本可编辑

    图 4.18:覆盖后,文本可编辑

    在上一张图中,你可以看到产品名称已被替换。所有非继承的字段将反映来自父文档的更改;因此,如果你更改价格,此字段将在所有子页面上更新。这样,所有常用字段只需输入一次,你只在真正需要时复制信息。

  10. 现在,为T 恤页面树中的所有子页面复制步骤 6-8

在本节中,我们学习了如何通过从父文档继承一些数据来创建文档。这个 Pimcore 功能让我们能够在整个网站上重用信息。使用这个继承功能,我们避免了在产品层次结构中复制常用字段。这个功能是管理非结构化数据的一种更方便的选项,并避免数据重复。

摘要

在本章中,我们学习了如何创建文档以及这个功能如何使我们能够创建和管理非常简单的网站。我们首先发现,与其他 CMS 解决方案相比,我们没有现成可用的东西。仅仅为了创建第一个网页,我们需要定义一些模板。这看起来可能像是一种浪费时间的行为,但实际上正好相反。模板迫使你在整个过程中以结构化的方式工作。它们迫使你创建可编辑的网页,最终用户将能够编辑数据而不会破坏布局。这允许非开发者掌握他们的内容。这就是我们在第一章中提到的分离方法。

如果你有一些网络开发经验,你可能想知道你可以用可编辑的内容走多远。它们的灵活性可以帮助你实现大量的网页,理论上你可以继续使用它们来管理复杂的网站。这种方法的唯一限制是我们正在处理的是纯文档。你还记得我们给出的文档定义吗?我们说它们是无结构化信息的容器。这就是限制。我们可以结构化信息在页面上的分布方式,但这并不允许我们查询或重用数据。我们可以轻松地创建成千上万的博客或产品页面,但这还不够。事实上,我们需要更加动态,比如在分类页面上列出产品或按标签分组博客文章。你可能想使用文档来实现这些功能,但尽管 Pimcore 功能强大,在大多数情况下,这将需要大量的努力,而且结果可能不尽如人意。事实上,文档适合渲染网页,但并不完全适合结构化数据或交互式内容。

所以,如果你在思考如何处理结构化数据,请不要担心。在下一章中,我们将描述数据对象是什么以及如何以结构化的方式表示信息。这将是我们开始正确管理数据并避免内容或源代码重复的基础。

第五章:第五章:探索对象和类

在本章中,我们将看到 Pimcore 为我们提供的主要功能之一:通过创建类和对象定义每个项目的个人和完全定制的数据集的可能性。

使用 Pimcore 的一个主要优势是您可以通过用户界面完成所有操作,无需编写任何代码或定义复杂的数据库结构,您可以在任何时候更改或添加新属性。Pimcore 将完成所有魔法,您无需担心在数据库上运行风险性迁移。此外,您还可以导出和导入所有类定义,以便在不同项目之间共享,无需每次都重新发明轮子。

在以下章节中,我们将介绍类配置,重点关注可以添加到其中的各种字段类型,以及如何通过数据输入具体查看这些类的操作。如果我们激发了您的兴趣,只需通读本章,了解使用 Pimcore 创建和更新类是多么简单。章节结构组织如下:

  • 什么是类?

  • 创建和编辑类定义

  • 发现相关字段类型

  • 理解和建立关系

  • 执行数据输入

到本章结束时,您将了解如何创建 Pimcore 类以及如何正确配置它们以充分利用其潜力。

技术要求

正如您在第四章中做的那样,在 Pimcore 中创建文档,运行与本章相关的演示所需要做的只是导航到官方书库中的5\. 对象和类文件夹并启动 Docker 环境。

要做到这一点,只需遵循以下说明:

  1. 使用以下命令运行 Docker:

    docker-compose up
    
  2. 然后,为了恢复您本地机器上的所有设置,只需打开一个新的 shell 并输入以下命令:

    docker-compose exec php bash restore.sh
    
  3. 导航到localhost/admin并使用您的 admin/pimcore 凭据登录。

您可以通过以下链接访问官方书库以获取源代码:

github.com/PacktPublishing/Modernizing-Enterprise-CMS-using-Pimcore/tree/main/5.%20Object%20and%20Classes

现在,您已准备好导航演示以发现与本章相关的所有方面。

什么是类?

在本节中,您将了解在 Pimcore 中类是什么以及它如何有助于管理任何类型的数据。在面向对象编程的背景下,一个由一组适合表示概念的数据(或属性)、影响值的方法以及实例化该类的对象的行为组成。

Pimcore 类反映了这个定义,但不仅如此。在接下来的章节中,我们将更好地了解这些类是如何工作的,以及它们如何简化我们在数据集开发上的工作。特别是,我们将看到尽管名称如此,Pimcore 并不仅限于产品信息管理;此外,你将发现定义类根本不需要编写任何代码。

设计不同的概念

如我们所知,Pimcore 的主要功能之一是产品信息管理,因此我们倾向于认为一切围绕 Product 类的定义展开。当然,这通常是正确的,但不应将其视为限制。

考虑一个基本的电子商务结构:将会有一个 Product 类,正如我们所期望的,但也许我们想要对产品进行分类;我们可以考虑创建一个 Category 类来链接到产品,而不是在每个产品中重复分类的属性。我们可以在产品材料或其他属性上应用相同的推理,根据需要逐步增加结构的复杂性。那么,如果我们需要为我们的电子商务网站实现商店定位器呢?我们只需要创建一个 Store 类!

为了更通用,我们可以通过创建相应的类来设计每种不同类型的概念。也就是说,你可以很容易地理解如何简单地设计 CMS 的数据集。你只需要定义文章、作者等类的类,并开始插入你的数据。更好的是,你可以做到这一点而不需要编写任何一行代码。

无需编写代码

你可能会认为定义这些类需要大量的代码开发或数据库工程,但你错了。你只需要定义你的类及其属性,Pimcore 将完成所有魔法。更具体地说,我们可以说我们对每个类进行的每个操作都会影响定义这些类本身所需的几个 PHP 文件。

definition 文件包含表示类字段的复杂数组结构,所有关于视觉方面的信息,如宽度、高度或 CSS 规则,以及这些字段的空間组织。这个文件包含所有类属性定义,因此可以用来恢复类本身。

class 文件以类本身命名,包含所有获取器、设置器和其他常见方法,这些方法使我们能够操作将要实例化类的对象。这个类可以在项目中引用,并用于访问类属性以及创建或更新类实例。

这些类都带有灵活且针对每个类的专用数据库表以及它们之间的关系。再次强调,所有这些都在幕后发生,所以你永远不必担心这一点;你所需要做的就是定义反映你需求的结构。

在本节中,我们发现了类是什么以及任何人都可以配置它,而无需任何代码开发知识。在下一节中,我们将看到如何创建和编辑类定义。

创建和编辑类定义

现在我们已经了解了基本定义,在本节中,我们准备创建我们的第一个类。要打开类定义面板,请通过设置 | 数据对象 | 。现在,我们可以点击左侧的添加按钮。在下面的屏幕截图中,我们可以看到出现的类创建弹出模态框:

图 5.1:创建新类

图 5.1:创建新类

在出现的弹出窗口中,我们必须定义以下内容:

  • 类名:我们类的名称。请注意避免空格。

  • 唯一标识符:一个用于唯一标识类的短字符串。如果我们省略标识符,则将应用第一个可用的整数 ID。此标识符不能再次更新。

点击确定,类将被创建。

现在我们需要定义类的常规设置。我们将列出所有这些设置,解释它们的含义以及如何正确配置它们。请记住,所有设置都是可选的,并且某些设置可能对您的项目没有用。

在下面的屏幕截图中,我们可以看到这些设置与合理的值:

图 5.2:常规设置

图 5.2:常规设置

让我们现在描述我们在前面的屏幕截图中看到的每个属性:

  • 描述:这只是对你类的描述。它没有其他含义。在远程协作的情况下,这可能有助于传达类的目的。

  • Pimcore\Model\DataObject\Concrete 类,它包含所有类的通用方法。

  • 实现接口:您希望类实现的接口的逗号分隔列表。

  • 使用(特性):在 PHP 中,特性是代码重用的机制,它允许减少单继承带来的某些限制。在 Pimcore 中,我们可以使用特性来实现先前接口的方法。

  • Pimcore\Model\DataObject\Listing\Concrete 类。

  • 列出使用(特性):正如我们刚才提到的,特性是用于实现接口方法的 PHP 编程范式。同样的概念也适用于类列表。

  • AbstractProductLinkGenerator 类实现了 LinkGeneratorInterface 接口。链接生成器将接收引用的对象以及根据上下文提供的附加数据。

  • 预览 URL:预览 URL 对于直接在类定义上生成对象的动态 URL 很有用。您可以使用占位符来表示您类中定义的每个属性,以及常见的属性,如对象 ID 或键。此功能在最新版本中已弃用,建议使用链接提供器类

  • 图标:您可以从图标列表中选择您类的自定义图标。如果您愿意,还有链接图标的可能性,提供图标本身的路径。建议使用 SVG 文件。

  • 分组:此属性对于将类分组到类定义树中的文件夹中是必要的。具有相同前缀词的类会自动分组,即使没有明确提供分组也是如此。

  • 允许继承:如果勾选此属性,将以树状结构方式启用对象之间的继承。子对象可以是同一类的实例或不同类的对象。如果子对象属于与父对象相同的类,它们将自动继承父对象的所有数据值,并可以覆盖它们。

  • 允许变体:对象变体是一种特殊的继承。变体的类不能选择;它必须与父对象相同。我们必须注意,默认情况下,变体被排除在列表查询之外。

  • 在树中显示变体:此属性允许您在对象树中看到变体。如果未启用,变体仅在对象编辑模态中的适当标签中显示。

  • 显示应用程序日志标签:如果启用,应用程序日志标签将显示在对象编辑模态中。在该标签中,可以读取与对象相关的最终创建的日志事件。

  • 启用网格锁定:这允许您在对象网格视图中锁定某些列。

  • 加密数据:此属性启用了对存储类信息表中的对象数据的加密的可能性。

  • 系统属性可见性:这允许您选择在网格视图和搜索视图中默认显示哪些属性。这些属性是IdKeyPathPublishedCreation DateModification date。这些属性对于网格筛选很有用。

  • 复合索引:Pimcore 允许您在存储类对象信息的表中创建自定义索引。您可以选择索引名称和参与其中的类属性。

在填写了这些类属性后,您必须点击保存按钮以应用它们。

在本节中,您学习了如何创建 Pimcore 类。然后,您发现了类的设置,以及如何根据您的特定需求正确填写这些属性。此外,您还看到了如何启用类继承。在下一节中,我们将介绍可以附加到类上的所有不同类型的组件。

发现相关字段类型

在上一节中,我们创建了我们的第一个类。创建的类就像一个空盒子,比如说,我们刚刚确定了形状和尺寸。在本节中,我们将看到如何对我们的类进行建模,定义布局组件和所有不同种类的属性。这些概念对于根据您的需求正确配置类至关重要。特别是,我们将描述两种不同类型的属性:

  • 布局组件

  • 数据组件

让我们在下一节中看看这两种类型的组件。

布局组件

布局组件使我们能够通过空间来组织类属性。为了更好地理解这些组件的实用性,让我们思考一下网站结构。没有任何规则禁止将所有网站信息垂直放置在页面上。所有文本、输入字段、图片和相关链接,只是依次列出。当然,创建起来很容易,但用户的阅读体验相当混乱,不是吗?

可能最好将常见信息分组在不同的标签页中,或者创建一个带有输入字段的框,用户必须填写所需信息。图片可以分组到右侧的画廊中,或者我们可能想要展开或折叠某些信息。

好吧,类布局组件就是为了这个目的而设计的。您必须至少添加一个布局组件到类中,才能允许添加类属性;要添加布局组件,只需在您的类定义中的常规设置上右键单击。

让我们看看所有组件的共同特征以及每个组件的具体属性:

  • 名称:组件名称仅会在类定义面板中显示。

  • 区域:与父布局组件结合使用,可以用于在不同位置定位组件,使用西中心

  • 标题:组件标题将在类的对象实例中显示。标题的位置和样式取决于特定的组件。

  • 宽度:组件在对象编辑模式中的宽度。

  • 高度:组件在对象编辑模式中的高度。

  • 可折叠:如果启用,这将使组件可由用户折叠。

  • 折叠:如果启用,则在对象打开时默认折叠组件。

  • CSS 样式:同意为组件编写自定义 CSS 样式规则,例如边距或浮动位置。

  • 边框:为元素添加边框。

我们现在可以具体看看每种布局组件。在下面的截图中,我们可以看到所有不同类型的布局组件:

图 5.3:添加布局组件

图 5.03_B17073.jpg

图 5.3:添加布局组件

让我们在下一节中描述每个组件的属性,如图表所示。

Tabpanel

此组件允许您在内部分组不同的面板。每个面板将作为对象编辑模态中的标签。除了常见属性外,对于 Tabpanel,您可以指定 Tab Position 属性。这允许您选择将标签放置在哪个位置;可能的值是 top(默认)、leftrightbottom

面板

一个简单的组件,允许您在其中添加属性。此组件可以嵌套在其他组件内部,如 Tabpanel 和 Region,并位于不同的位置。

对于此组件,我们可以指定以下附加属性:

  • 布局:如果选择 Fit 选项,面板内的所有字段将适应屏幕尺寸。

  • 标签宽度:设置面板标签的宽度。

  • 图标:允许选择一个自定义图标,该图标将显示在标签的左侧。

折叠面板

与面板组件类似,此组件旨在根据需要折叠和展开。这个概念通常用于网站开发,以便用户隐藏或显示一些可能有用或无用的额外信息。对于此组件,没有额外的属性可以添加。

在以下截图中,您将看到面板和折叠面板之间的区别:

图 5.4:面板和折叠面板

图 5.4:面板和折叠面板

如前几张截图所示,面板在 Tab Panel Component 内部上方放置。折叠面板包含其他布局和数据组件,并且可以折叠或展开。

区域

此组件旨在仅包含其他布局组件。如果您在某个区域内部添加面板,您可以按照之前提到的五个固定位置来组织它们。请注意,您必须指定一个固定区域高度,否则您的区域将不会显示。至于面板,您可以选择一个自定义图标。

Fieldset

此组件仅允许您在其中添加一些数据组件,并通过顶部标签将它们分组,并用一个小边框包围。您可以使用它来分组一系列相似的字段,如果一起显示则更有意义。唯一可以设置的特定属性是标签宽度。

Field Container

Field Container 的行为类似于 Fieldset。主要区别在于您可以通过正确选择 Layout 属性来选择是否垂直或水平分组字段。

在以下截图中,您可以看到 FieldsetField Container 之间的区别:

图 5.5:Fieldset 和 Field Container

图 5.5:Fieldset 和 Field Container

如前一张截图所示,Fieldset 内的数据组件是垂直分组在一个框内的。Field Container 没有设计边框,内部组件可以水平分组。

按钮

允许您在对象编辑模态中添加自定义按钮。按钮的处理程序必须在组件定义中定义。

文本

此组件只是一个静态文本框,可以在对象编辑模态中显示。框内的 HTML 文本可以直接在类定义中定义,或者你可以在自定义渲染类属性中指定类命名空间来生成动态文本。

预览/Iframe

此组件仅允许我们在对象编辑模态中渲染自定义 Iframe。Iframe 的 URL 必须是扩展了Pimcore\Controller\FrontendController类的控制器中的相对 URL。

现在我们已经发现了布局组件的所有选项,让我们来看看数据组件。

数据组件

数据组件是类的具体属性。有大量的可用属性,分为不同的主要类型,允许你根据需要建模你的类。在下面的截图中,你可以看到所有类型的数据组件的全景:

图 5.6:添加数据组件

图 5.6:添加数据组件

如前一个截图所示,有 10 种主要的数据组件类型,它们包含不同数量的组件。每种组件类型和每个属性都有其特定的属性,但所有数据组件都有一组共同的属性,我们在这里进行解释:

  • 名称: 属性的名称。它不能包含空格或特殊字符,因为这是将在数据库表列和 PHP 类中使用的名称。

  • 标题: 将在对象编辑模态中显示的属性的标签。

  • 工具提示: 用于解释属性含义的建议文本,以帮助用户。

  • 必填字段: 如果勾选,则使属性成为必填项。如果所有必填字段均未填写,则对象无法发布。

  • 索引: 如果勾选,将在数据库表中为字段创建索引。

  • 唯一: 如果勾选,则在数据库表中创建唯一约束。

  • 不可编辑: 如果勾选,则属性变为只读。

  • 不可见: 如果勾选,则该属性在对象编辑模态中不可见。

  • 在网格视图中可见: 如果勾选,则该属性在类的预定义网格中显示。

  • 在搜索结果中可见: 如果勾选,则该属性在类的专用搜索模态中可见并可搜索。

  • CSS 样式: 就像布局组件一样,同意为组件编写自定义 CSS 样式规则,例如边距或浮动位置。

  • 宽度: 组件的像素宽度。

  • 高度: 组件的像素高度。

  • 默认值: 许多字段类型都提供了定义默认值的可能性。如果为字段键入了任何值,则默认值将被保存。如果启用了类的继承,则此值将持久保存在数据库中,以供其子类使用。

  • \Pimcore\Model\DataObject\ClassDefinition\DefaultValueGeneratorInterface 类,并且当你打开对象以执行默认值计算时,它会被调用一次。

现在您已经了解了各种数据组件的常见属性,我们将专注于每个特定的组件组,以描述它们的特性。

文本组件

这种组件包含基本的文本输入字段。所有这些组件都非常相似,并且共享我们之前提到的所有常见属性,但也有一些区别:

  • 输入组件是最简单的文本字段。由于它旨在只包含一行,因此无法设置输入高度。我们确实可以显示字符计数并添加正则表达式验证。

  • Textarea 组件与上一个组件相当相似,但允许您指定文本的高度。作为输入组件,它可以显示字符计数,但我们不能添加正则表达式。

  • WYSIWYG 组件,正如著名的缩写所暗示的,允许您插入和编辑 HTML 格式的文本。您可以通过在组件定义中提供 CKEditor 配置来自定义编辑器配置。

  • 密码组件是一个隐藏输入字符的输入文本。列长度不能选择,因为内容总是使用所选算法进行散列。

  • 输入数量值字段由值和度量单位组成。我们将在以下关于数值字段的章节中深入探讨这一概念。

数字组件

本节包含一些简单的数值属性。

数字组件是最简单的数值字段。可以定义数据库列的小数位数和输入值的小数精度。值可以限制为仅整数或仅无符号。我们还可以指定最小和最大值。

Slider 组件存储一个数值,但它通过滑动光标来选择值。通过指定最小-最大值和增量步长,可以定义此滑动组件。

如前所述,数量值组件允许将度量单位附加到数值字段,从而可以定义诸如价格、重量等概念。要定义您的单位,只需通过设置 | 数据对象 | 数量值,然后简单地添加您需要的单位。单位可以随时添加和删除,并且每个操作都会自动保存在数据库中。在下面的屏幕截图中,您将看到数量值定义面板:

![图 5.7:数量值单位]

图片

图 5.7:数量值单位

如您在屏幕截图中所见,可以使用静态转换因子或通过定义转换服务类将不同的单位相关联;第二种选项对于需要公式的转换可能很有用,例如温度转换。

日期组件

这些组件旨在包含日期和时间值。数据库中的日期可以存储为时间戳或日期字符串。

选择组件

这种组件允许您定义不同类型的下拉列表。其中一些带有预定义选项,例如国家语言用户。相反,我们有三种自定义下拉列表类型可以定义。对于布尔选择,我们无法定义下拉列表值,但可以自定义两个状态标签。选择是这个组中最常见的组件。下拉列表值可以随时添加、删除和排序。值可以是数字或字符串。在下一张屏幕截图中,您将看到选择选项是如何定义的:

图 5.8:选择值

图 5.8:选择值

正如您所看到的,我们可以定义值和显示名称。或者,您也可以定义一个自定义类,为您的字段提供动态选项。多选组件的行为与上一个组件相同,不同之处在于我们可以在对象中选择多个值。

媒体组件

这套组件使我们能够在我们的类对象中显示媒体文件。我们可以链接内部资产或外部图像,创建相册,并显示视频预览。

我们将在第六章中深入探讨这部分内容,使用数字资产管理

关系组件

这些组件用于在不同类之间建立关系,或将类对象链接到文档或资产。请注意,对于资产关系,资产预览不会像之前提到的组件组那样在对象中显示。所有类型的关联可以是多对一或多对多。对于多对多对象关系,我们可以选择在关系框中显示哪些字段。我们还可以使用高级关系组件来向关系添加自定义元数据字段。

我们将在本章下一节中查看关系细节。

地理组件

这些特定类型的字段使我们能够在渲染的地图上搜索和标记。您可以在地图上添加简单的地理点或绘制线条和多边形。所有点的纬度和经度都存储在数据库中。

CRM 组件

这些组件旨在在 Pimcore 中注册客户信息。我们必须注意,几乎所有这些组件,例如电子邮件,都有一个固定的字段名,因此不可能在同一个类中多次添加此类组件。

其他组件

本节包含了一组混合组件。

有一些简单的组件,如复选框颜色,或者链接到外部网站。然后我们可以引用加密字段组件,该组件允许在生成并正确配置了密钥的情况下,在数据库中存储加密值。

我们已经提到了除了Pimcore\Model\DataObject\ClassDefinition\CalculatorClassInterface接口之外的所有组件,它可以根据其他对象的值动态计算字段的值。计算出的值不会存储在数据库中,但每次打开对象和每次调用特定的 getter 时都会进行计算。

总结本节,我们描述了所有不同类型的组件。首先,我们介绍了所有数据组件的常见属性。然后,我们列出了不同类型的组件,并为每个组件指定了可能的附加属性。在下一节中,我们将描述一种特定类型的数据组件,即结构化组件。

Structured Components

这些特定的组件是为了扩展类定义而设计的,通过定义可以附加到类对象上的属性组来定义结构或模式。

在未来的章节中,我们将看到一些这些组件在实际的产品信息管理和主数据管理功能中的应用。在本节中,我们将描述这些组件及其设计用于何时使用。

Field-Collection

最常用的组件是Field-Collection。你可以像我们为类解释的那样定义你的字段集合。只需通过设置 | 数据对象 | Field-Collection,通过添加布局和数据组件简单地创建一个新的字段集合。

在你的类定义中,Field-Collection组件可以允许一个或多个不同的Field-Collection类型。在类对象实例中,你可以动态添加多个定义的字段集合实例,以多次添加相同的属性组。这种组件在具有可以在不同对象中出现不同基数(cardinality)的特定属性时非常有用。在下图中,你可以看到一个概述Field-Collection如何工作的模式:

![图 5.9:Field-Collection图片 5.09_B17073.jpg

图 5.9:Field-Collection

正如前图所示,我们可以在类定义中添加一个Field-Collection组件。正如我们为类定义所做的那样,在Field-Collection定义中,我们可以添加一组布局和数据组件。在类对象中,你可以添加一个或多个相同的Field-Collection实例。

Objectbricks

Field-Collection不同,Objectbricks可以在不更改类定义的情况下扩展对象。

想象一家想要存储其产品信息的时尚公司。我们可以很容易地想象衬衫和鞋子会有不同的属性。当然,我们可以为衬衫和鞋子创建两个不同的类,但你需要为两个类之间不共享的属性定义冗余字段。

使用Objectbricks,我们只需创建一组小的属性集来描述特定字段,并允许我们的类动态添加这些砖块。正如其名所示,类对象可以由添加到公共属性中的一个或多个砖块组成。

与类和字段集合类似,只需通过设置 | 数据对象 | Objectbricks来定义它们。Objectbricks在父对象和子对象之间是可继承的。

在以下图中,您可以看到一个模式,说明Objectbricks是如何工作的:

图 5.10:Objectbricks

图 5.10:Objectbricks

如前图所示,我们可以在类定义中添加Objectbricks组件。在类实例中,我们可以附加一个或多个砖块,以向对象本身添加特定的组件集,为对象提供分类。

本地化字段

我们可能还需要定义应在对象内翻译成多种语言的属性,例如多语言网站的标题和描述。使用本地化字段组件,我们只需在内部插入子组件并配置系统设置中的语言。在以下屏幕截图中,我们可以看到组件在对象上的渲染方式:

图 5.11:本地化字段

图 5.11:本地化字段

如您所见,为每个定义的语言在组件中添加了一个特定的标签页。

组件充当其他数据组件的简单容器。类似于字段集合,可以创建无限数量的块元素。块数据被序列化到一个单独的数据库列中。因此,如果计划查询数据,则此容器类型不合适。

表格

另外两个相当简单的组件是TEXT字段,列值由管道字符分隔。结构化表格遵循相同的原则,但行和列始终是固定的并且有名称。

分类存储

最最终和最复杂的组件是分类存储。该组件允许您定义一个分层键值对结构,以便动态地向类对象实例添加属性组。要定义分类存储组件,请通过设置 | 数据对象 | 分类存储。为了正确创建分类存储,我们必须定义以下内容:

  • 键定义:为您的分类存储定义键。所有基本数据组件都可用于此目的。对于每个键,我们可以选择它是否应该是必填的或可编辑的,以及其他标准属性。

  • :选择一个或多个键来定义组。在组内,您可以定义哪些键是必填的,并定义顺序。

  • 组集合:不同的组可以被组合成集合。在对象编辑模式中,我们可以添加一个或多个定义好的集合。

现在您已经发现了各种数据组件,在下一节中,我们将重点关注关系,深入探讨组件定义并提供关系的一个具体示例。

理解和建立关系

在本节中,我们将深入探讨如何在 Pimcore 中将对象与其他实体相关联。正如我们在上一节中看到的,第一步是在我们的类中添加适当的字段来配置两个类之间的关系,或者类与其他实体(如文档或资产)之间的关系。在这里,您将看到所有不同类型的关联组件:

图 5.12:关系组件

图 5.12:关系组件

如您所见,存在两种主要的不同类型的关联字段,允许关联对象、文档或资产的通用关系字段,以及针对对象类的特定关系字段。对于每种类型,我们可以建立多对一关系、多对多关系或高级多对多关系。最后一种关系允许您定义可以附加到关系实例的一些附加元数据字段。

在接下来的几节中,我们将重点关注两种主要的关联组件类型,如下所示:

  • 通用关系:对象实例与其他实体之间的关系(这可能包括另一个对象或资产或文档的实例)。

  • 对象关系:对象实例之间的特定关系。

让我们看看这些不同类型关系的详细信息。

通用关系

通用关系字段允许对象实例与其他先前创建的实体之间的关系,这些实体可以是其他对象、文档或资产。我们无法决定我们想在对象上显示相关实体的哪些属性。对于多对一关系,仅显示实体路径;对于多对多关系,显示 ID 和实体类型作为附加信息。

此外,我们还可以对关系属性提供一些限制,特别是以下内容:

  • 对于文档,我们可以指定哪些类型可以在关系中。如果没有选择,则允许所有类型。

  • 对于资产,我们可以指定哪些类型可以在关系中。如果没有选择特定的类型,则允许所有类型。还有为可以通过对象直接上传的资产定义上传路径的可能性。

  • 对于对象,我们可以指定哪些类可以在关系中。如果没有选择特定的类,则允许所有类。

在下一节中,我们将重点关注另一种类型的关联组件,即专门用于关联对象的组件。

对象关系

这种关系严格限于对象之间的关系。至于之前的一组,有可能将关系限制在一或多个类中。主要区别在于我们可以在对象元素的关系中选出我们想要显示的字段。但如果选择了多个类,则只能选择涉及类之间的公共字段。

对于高级关系,我们可以为每个关系定义特定的元数据字段。这些字段可以是基本数据类型之一(文本数字布尔值选择),并将添加在原始对象字段之后。另一个特定的组件是反向多对多对象关系。此组件只能在之前配置了多对多对象关系的情况下工作。

在下一节中,我们将通过一个具体示例来了解如何实际使用关系组件来连接不同类别的对象。

关系的实例化示例

为了提供一个具体的例子,考虑产品和类别。我们可以在Product类和Category类之间指定一个直接关系,并在Category类中指定一个与直接关系相关的反向关系。让我们首先创建一个Product类。遵循这里给出的步骤:

  1. 对于第一个组件,添加一个名为Product Data的 tabpanel。

  2. 创建一个名为General Information的面板,作为之前创建的 tabpanel 组件的子组件。

  3. 添加一个产品标题的输入字段,然后保存你的类。

  4. 创建Category类。

  5. 然后创建Product类。在这里,创建一个新的面板并添加codename字段,然后保存该类。

  6. 现在,回到产品类,并添加一个多对多关系组件来关联ProductCategory类。

  7. 在关系上,指定你想显示codename属性,然后再次保存该类。

  8. 现在,我们可以向Category类添加一个反向关系组件。要添加此组件,我们只需定义原始关系的类和字段。将此组件设置为不可编辑,以使反向关系完全自动。

在下面的屏幕截图中,我们可以看到最终结果:

图 5.13:反向多对多对象关系

图 5.13:反向多对多对象关系

在前面的屏幕截图中,你可以看到配置的组件是如何出现的。在左侧,我们可以看到在类配置树中出现的组件。在右侧,有一些定义组件的特定设置。在最上面,我们可以看到将Product类与Category类关联的多对多关系组件。在底部,显示了反向关系。

在本节中,你学习了如何将类与其他实体关联起来。在下一节中,我们将看到这些定义的关系如何在对象数据录入中体现。

执行数据录入

在本节中,我们将检查类定义如何在具体对象实例中体现,发现如何创建 Pimcore 对象并执行数据录入以填写它们的信息。我们将看到如何轻松创建文件夹和对象,如何将它们关联起来,以及如何创建对象变体。然后我们将发现添加新属性或编辑一些现有属性是多么容易和快速,同时注意最后一点以避免数据丢失。

创建文件夹和对象

在 Pimcore 中,与你的想象不同,文件夹只是我们无法添加自定义属性的一个通用基类的实例。创建文件夹不是强制性的;把它看作是帮助你在 PC 桌面语义上组织对象的一个辅助功能。不同的文件夹可以嵌套在树结构中。要创建你的第一个文件夹,请遵循这里给出的步骤:

  1. 在主左面板上打开数据对象部分,然后右键点击首页元素。

  2. 选择首页是一个具有1的特殊文件夹对象。这个组件不能被删除,它将是整个树结构的根元素。

  3. 话虽如此,让我们创建一个Products文件夹和一个Categories文件夹。再次强调,这种命名只是为了区分概念,但不是强制性的。你可以在一个唯一的文件夹内创建所有对象,或者作为首页组件的直接子元素。

  4. 右键点击创建的文件夹以在其中添加对象,选择类并添加对象名称。请注意,这些名称只是出现在树结构中的键,必须在同一文件夹内是唯一的,但它们与任何类数据属性完全无关。

  5. 基于这些信息,让我们创建一个Product对象。如之前在类定义中定义的,可以填写产品标题的输入字段。由于我们需要先创建分类,因此目前还不能进行分类的关系。

  6. 复制之前的操作,在专用文件夹中添加几个分类对象,并填写它们的信息。你会看到由于我们有一个反向关系,将无法选择相关产品。

  7. 切换回产品,在关系组件中点击搜索按钮以选择创建的分类,并保存产品。

  8. 刷新分类对象,看看产品关系如何显示。结果如下图所示:

图 5.14:对象关系

图 5.14:对象关系

在前面的图中,我们可以清楚地看到对象是如何相互关联的。正如你在直接关系组件中看到的那样,我们在组件配置中要求的分类属性在关系中显示。

在下一节中,你将学习继承是如何工作的以及如何添加对象变体。

添加对象变体

如果在类定义中启用,可以为创建的对象添加变体。要创建一个变体,只需右键单击之前创建的对象,选择添加变体,并输入变体名称。

变体继承所有父属性的所有值。正如您将在以下屏幕截图中看到的那样,继承的值以只读形式出现,但可以在变体上覆盖值:

图 5.15:对象变体

图 5.15:对象变体

图 5.15:对象变体

变体在对象树结构中像其他对象一样出现,但对于每个对象,可以通过点击对象工具栏中的相反按钮轻松访问变体。

编辑类和对象

创建和编辑类定义部分,我们看到了创建类并添加一些数据组件是多么容易。使用 Pimcore 的一个主要优点是,这可以增量完成,因为我们可以在任何时候添加新组件或编辑现有组件。

在类上的每一个操作都会反映在相应的 PHP 类中,尤其是在数据库表中。因此,编辑数据组件可能会很危险,在最坏的情况下,可能会导致数据丢失。显然,如果一个输入组件被转换成关系组件,或者一个复选框变成了图像组件,数据丢失是预期的。这并不是我们的重点,但我们将关注那些表面上看似安全但实际上并不安全的操作,因为它们可能导致数据不可逆的丢失。这些内容将在以下章节中介绍。

文本转数字

将数字组件转换为文本组件永远不会导致数据丢失,因为这仅仅是将数据库列从十进制转换为文本,而十进制值是文本列的有效输入。相反的流程则不适用。在这种情况下,我们有三种可能的情况:

  • 如果字段值是一个有效的数字,数据将是安全的。

  • 如果字段值是一个包含文本的混合数字,则只保留“数字”部分,删除遇到的首个字母或空白符之后的所有内容。

  • 如果字段值是文本,转换后的值变为0

现在我们来看看在不同类型的数字字段之间更改数据类型的风险。

数字到数量值

我们可能会认为这个操作没有风险,因为我们只是在我们的数值上附加一个度量单位,但这完全错误。

事实上,在对象表中,原始的数字列会被删除,不可避免地导致数据丢失,并且会创建两个新的列。特别是,给定一个“字段名”,我们有以下列:

  • fieldname__value

  • fieldname__unit

因此,不建议将数字组件修改为QuantityValue

将组件移动到本地化字段

如果我们将组件移动到本地化字段,组件的数据将会丢失。这是因为数据库列从主对象表中删除,并在为每个定义的语言创建的特定本地化表中创建。

在本节中,我们描述了数据输入的不同方面。首先,你学习了如何在对象树中创建文件夹和对象,以及如何创建对象变体。然后,你发现了如何在类定义编辑过程中防止数据丢失,避免在更改组件类型时进行风险操作。

摘要

在本章中,我们学习了类的概念。在 Pimcore 中,一个类代表了一个概念的定义,例如产品或类别。我们可以添加布局和数据组件来建模我们的类,并在任何时间将其集成,同时添加或编辑它们的属性。

我们了解到定义一个类,不需要编写任何代码或创建数据库表,因为每次你在类上做出更改时,Pimcore 都会自动更新代码和数据库。

我们知道可以创建一个自定义的 PHP 类,该类可以被一个或多个类扩展;这可以用于在开发中添加类方法。按照同样的原则,可以定义规则为类字段提供默认值或计算特定类型组件的值。

我们还学习了如何通过特定类型的组件将不同的类关联起来,或链接资产和文档到类对象,以及如何定义类的继承规则。然后我们学习了数据输入以及它如何通过易于使用的 Pimcore 界面变得简单;类定义的任何更改都会立即反映在对象上;你只需要刷新即可。

在下一章中,我们将发现 DAM Pimcore 功能,以及它是如何帮助我们管理多媒体内容并为分发做准备。

第六章:第六章:使用数字资产管理

在上一章中,你学习了什么是 Pimcore 类以及如何为定义的类创建对象实例。

在本章中,我们将重点关注数字资产管理DAM),这是 Pimcore 的主要功能之一。这个功能不仅仅是让你像存储平台一样上传图像,它还帮助你分类、详细说明和版本控制图像以及一般类型的文件,并将它们分发到不同的渠道。本章的组织结构如下:

  • 什么是 DAM?

  • 上传和关联资产

  • 编辑图像

  • 如何创建缩略图

在解释了什么是 DAM 之后,我们将介绍 Pimcore 的 DAM 功能。然后,我们将探讨如何在 Pimcore 上上传数字资产以及如何将它们与对象关联起来。接下来,我们将特别关注图像,以便让你看到如何在 Pimcore 内部编辑或增强图像,然后我们将探索创建不同缩略图有多容易。

技术要求

正如你在第五章**,探索对象和类中所做的那样,要运行与本章相关的演示,你只需要导航到官方书库中的6. 使用数字资产管理文件夹并启动 Docker 环境。

要这样做,只需遵循以下说明:

  1. 使用以下命令运行 Docker:

    docker-compose up
    
  2. 然后,为了恢复你本地机器上的所有设置,只需打开一个新的 shell 并输入以下命令:

    docker-compose exec php bash install.sh
    
  3. 导航到localhost/admin并使用你的管理员/pimcore 凭据登录。

你可以使用以下链接访问官方书库以获取源代码:

github.com/PacktPublishing/Modernizing-Enterprise-CMS-using-Pimcore/tree/main/6.%20Using%20Digital%20Asset%20Management

现在,你已经准备好导航到演示,以发现与本章相关的所有方面。

什么是 DAM?

在本节中,你将了解数字资产管理的概念。DAM 软件是一个集成的系统,旨在对媒体内容进行集中式战略管理。它是允许你在不同的渠道(如网站和应用程序)上创建、组织和分发内容,并提高沟通有效性的软件。

现在我们知道了学术定义,让我们看看 DAM 软件有什么用途以及其主要功能是什么。正如其名所示,DAM 围绕数字资产;这个概念并不局限于图像或视频,而是涉及所有类型的数字文件,如文档和音频记录。

因此,考虑到数字资产,我们现在将转向定义中的管理部分。数字资产管理不仅仅是将资产组织在几个文件夹中,就像在您的 PC 桌面一样;当然,在 DAM 系统中,以及在 Pimcore 中,我们总会找到文件夹的概念,但这只是结构化组织的起点。当涉及到管理时,DAM 是关于能够通过索引搜索资产,在用户之间共享资产,并跟踪版本控制的能力,同时能够定义支持资产生命周期的流程。

在本节中,我们将首先探讨所有 DAM 系统的共同特征,然后我们将介绍 Pimcore DAM 系统的具体功能。

DAM 系统的特征

让我们看看每个 DAM 系统必须具备哪些特征。

组织

正如我们之前提到的,组织是资产管理的关键方面之一。我们必须考虑的第一件事是在分层结构中创建文件夹和子文件夹。文件夹范式已成为许多不同类型软件中的普遍概念,对于组织内容至关重要。

然而,这本身并不足够,因此需要具备改进内容组织的功能,例如通过标签或其他属性进行分类,以及用于过滤和搜索内容的先进研究方法。

内容丰富化

毕竟,每个数字资产都是一个数字文件。每个文件都有必须显示或下载的内容,但可能需要提供一些信息来描述资产或其内容;我们可以将这些信息视为资产元数据。

在非常常见的场景中,元数据被用来提供对数字资产的另一种视图,而不显示其内容。以图片为例,在网站上使用替代标签并用简短的文字描述视觉内容是一种良好的做法,以防出现连接问题或提高视觉障碍者的可访问性。

除了用于提高可访问性之外,元数据的正确设计对提高搜索引擎优化(SEO)也很有用,因为它增加了网站在搜索引擎中的索引。

共享和访问控制

使用 DAM 系统对于集中资产信息并在所有需要图像副本的用户之间共享资产非常重要。通过不同类型的分发渠道,如电子邮件或共享托管服务发送和接收资产是一项繁重且危险的操作,因为我们可能会在数百封其他收到的电子邮件中丢失文件,或者如果我们上传一个修改过的文件到共享文件夹,可能会覆盖他人的更改。

在数字资产管理(DAM)系统中,每个用户都有自己的账户,可以定义适当的规则来共享文件或限制某些用户或具有特定角色的所有用户查看或修改资产。这些规则可以防止例如意外删除文件。

版本控制

与前面的特性相关,维护数字资产的版本控制非常重要。任何具有写入模式访问资产的用户都可能将其更新为新版本。版本控制允许你记录资产随时间的变化历史,记录做出更改的用户。这个概念对于实现工作流程和通过不同的审批阶段来调节资产创建过程非常有用。

资产分发

在现代场景中,相同的资产可能在不同需要不同规格的上下文中使用。以图像为例,它可能需要在网站上显示,也可能需要在相应的应用中显示,还可能需要放置在纸质目录中。显然,对于不同的目标,可能需要不同的图像尺寸。

为了满足这一需求,通常需要从同一原始图像手动创建不同的裁剪版本。这种做法会导致混乱,因为必须维护同一图像的许多不同版本;如果原始图像发生变化,所有裁剪都必须重新创建。现代 DAM 系统通过允许你上传高质量版本的图像,并在需要时定义规则来创建运行时裁剪,从而绕过这个问题。

总结来说,在本节中,你学习了 DAM 系统的常见特性。所有这些特性都在 Pimcore DAM 系统中实现,在下一节中,我们将介绍 Pimcore DAM 系统,展示其主要特性。

介绍 Pimcore DAM 功能

之前,我们介绍了 DAM 的定义,介绍了 DAM 系统应具备的主要特性。在本节中,我们将介绍 Pimcore DAM 组件,并简要介绍其主要特性,以发现 Pimcore 的 DAM 潜力。

资产组织

对于对象管理,Pimcore 的用户友好界面帮助用户进行资产组织。使用文件夹结构存储资产,以及通过网格组件进行搜索和过滤的能力,结合多标签页导航,使得资产管理变得简单快捷。你可以使用简单的搜索选项在资产的树结构中工作,或者利用网格视图通过标签、元数据和其它有助于组织资产的属性进行过滤。

Pimcore 提供了一种高度灵活和可配置的元数据管理系统。可以为每个特定资产定义元数据,如果需要,也可以定义将自动附加到所有资产的通用元数据属性。

Pimcore 的 DAM 软件支持 Office 文档格式,包括 Word、Excel、PowerPoint 和 PDF。除了开源功能外,企业功能允许您在不离开应用程序的情况下将 Pimcore 连接到 Adobe Creative Cloud 应用程序和 Microsoft Office 软件。

图像和视频转换

如我们之前提到的,DAM 的关键方面之一是能够在不同渠道之间分发内容。这些渠道在目标大小或媒体格式方面可能不同,这需要您为同一图像或视频制作不同版本。

与上传同一资产的多个不同版本相比,Pimcore 提供了上传仅高清版本的能力,并通过集成的转换管道为每个目标动态生成优化版本。您将在本章的最后部分了解更多关于创建图像缩略图的内容。

原始图像和转换后的图像可以作为公开链接提供,或者最终通过内容分发网络或 Pimcore 集成 API 提供。Pimcore 的 DAM 软件还提供了适合离线和印刷渠道的图像转换,以正确的质量和格式。

用户权限和权限

DAM 的关键方面之一是能够在不同用户之间共享资产,因此定义共享规则很重要。在 Pimcore 中,您有能力创建不同的用户和角色。在以下图中,您将看到如何配置用户和角色的权限:

图 6.1:用户权限和权限

图 6.1:用户权限和权限

如前图所示,对于每个资产文件夹,用户可以查看资产列表并打开每个资产。同样,用户可以拥有创建、编辑或删除资产以及更改其设置或属性的权限。同样的原则可以应用于文档和对象文件夹。在第七章**,管理 Pimcore 站点中,您将了解更多关于用户和角色管理的内容。

总结来说,在本节中,您了解了 DAM 系统的主要特点,并介绍了 Pimcore 的 DAM 功能。在接下来的章节中,您将看到一些这些功能的应用,并了解如何使用它们。在下一节中,我们将了解如何创建资产以及如何将它们与创建的对象关联起来。

上传和关联资产

在上一节中,我们介绍了 DAM 系统的特点,并介绍了一些 Pimcore 的特定功能。在本节中,我们将了解如何在 Pimcore 中上传资产,然后我们将了解资产是如何组织的,以及如何将资产与现有对象关联起来,介绍对象类别的各种媒体组件。

上传资产

在本节中,我们将开始探索如何在 Pimcore 中上传资产。要上传文件,您只需在资产文件夹上右键单击,并将鼠标悬停在添加资产(s)选项上以展开菜单。如图所示,资产可以从不同的来源上传:

图 6.2:上传资产

图 6.2:上传资产

让我们描述图中所显示的不同方法:

  • 上传文件:这是一个标准的文件上传表单,允许上传 200 多种文件格式。可以同时上传多个文件,它们不需要是同一类型。图像是最常见的资产类型,但 PDF 和其他 Office 文档也被使用。Pimcore 可以为大多数文件类型生成预览图像。

  • 上传文件(兼容模式):对于较旧的浏览器,之前的功能可能无法正常工作。如果出现这种情况,您必须使用此方法上传单个文件。

  • 上传 ZIP 存档:此方法允许您上传包含资产的 ZIP 文件。导入过程中,ZIP 文件将自动解包。

  • 从服务器导入:使用之前的方法,文件必须通过您的本地文件系统上传。此功能允许您选择存储在 Pimcore 托管服务器文件系统中的文件。如果文件通过例如 SFTP 文件夹共享,这可能特别有用。

  • 从 URL 导入:不是上传物理文件,您可以通过粘贴外部 URL 来上传资产。在这里,资产名称由 URL 本身提取。

对于每个上传的资产,都可以在任何时候上传新版本。请确保只能使用标准上传方法上传新版本。现在让我们来看看如何组织上传的资产。

组织资产

在本节中,我们将看到资产如何在文件夹中组织,以及如何列出和筛选它们。与对象文件夹的情况不同,对于资产文件夹,我们有两个不同的标签页:预览标签页正如其名所示,显示各种资产的预览图像,按字母顺序排列。列表标签页则显示,依次是小型预览图像和资产属性列表。在下面的图中,您将看到此标签页的外观:

图 6.3:资产列表

图 6.3:资产列表

观察图例,您会注意到,与在第三章**“使用 Pimcore Admin UI 入门”部分的“使用网格组件”*中展示的对象网格不同,有一些额外的功能。在网格上方,我们可以看到仅未引用复选框;如果选中,则仅显示与对象或文档无关的资产。附近,您可以看到一个按钮,允许您将选定的项目下载为 ZIP 文件。最后但同样重要的是,在网格左侧我们可以找到一个可折叠的部分,允许通过分配给资产的标签筛选资产。重要的是要指出,只有与所有选定的标签相关联的资产才会显示在网格中。

现在我们来看看如何关联资产,介绍各种媒体组件类型。

将资产关联到数据对象

在本节中,我们将了解如何将资产与对象实际关联。首先,我们将介绍可以附加到类上的不同类型的媒体组件,并解释每个组件的独特之处。然后,我们将展示如何直接在对象上上传、搜索或拖动资产。在下面的图中,您可以查看各种媒体组件:

Figure 6.4: 数据对象类编辑器中的媒体组件

图 6.4:数据对象类编辑器中的媒体组件

让我们描述图中显示的每个字段:

  • 图像:允许您将图像附加到对象上。如图中所示,可以设置组件的宽度和高度,并为通过组件直接上传的资产定义上传路径。定义的文件夹和子文件夹路径将在第一次上传时创建(如果它们之前未在资产文件夹树中创建)。

  • 外部图像:允许您通过提供图像 URL 来链接外部图像,而不是链接物理资产。在组件设置中,您可以设置图像预览的宽度和高度。

  • 高级图像:这是简单图像组件的扩展;这允许您定义和渲染上传图像的热点、标记和裁剪。对于每个热点或标记,我们可以设置一个名称,并最终添加一个或多个元数据,这些元数据可以是文本信息或与其他资产、对象或文档的关系。

  • 图像库:正如其名所示,此组件允许您添加无限数量的图像以创建图像库,该库可以随时排序。对库中已存在的图像没有控制权,因此您可能将相同的图像多次添加到库中。对于库中的每一张图像,我们都可以添加热点和标记,就像之前的组件一样。

  • 视频:这允许您将视频附加到对象上。此视频可以是之前在 Pimcore 上上传的物理资产,或外部视频。对于外部视频,您只需附加视频 ID;允许的平台是 YouTube、Vimeo 和 Dailymotion。对于内部视频资产,我们可以通过拖动现有的图像资产来附加海报图像,并提供标题和描述。

现在我们已经介绍了各种媒体组件,让我们看看如何将图像与对象关联起来。以下图所示的不同方式展示了进行此操作的不同方法:

Figure 6.5:图像关系

图 6.5:图像关系

如图中所示,有三种方式将组件中的图像关联起来:

  • 直接上传:点击上传图标后,将打开标准上传表单,让您从文件系统中上传文件。

  • 搜索:点击搜索图标后,将打开搜索模态,让您从之前上传的图像中选择一个。

  • 拖放:只需将图像从资产树拖放到组件中即可将其附加。

一旦图像被附加,你就可以直接从组件中打开资产。

总结来说,在本节中,你学习了如何在 Pimcore 上传资产,特别关注了不同的上传方法。然后,你看到了如何将资产组织到文件夹中,以及如何过滤它们以执行搜索。在本节的最后部分,你发现了不同类型的媒体组件以及如何将这些组件与图像关联起来。

在下一节中,我们将查看 Pimcore 内部图像编辑器,并了解如何通过添加元数据来丰富图像。

图像编辑和丰富

在前一节中,你学习了如何在 Pimcore 上传资产以及如何将它们与对象关联起来。在本节中,我们将介绍 Pimcore 集成的图像编辑器以及如何通过为图像创建元数据来执行产品丰富化。之后,我们将看到如何为图像设置焦点。

探索图像编辑器

Pimcore 集成了基于网络的图像编辑组件。基于miniPaint,图像编辑器对于简单的操作任务,如颜色校正和裁剪,是必不可少的。在下面的图中,你可以看到这个编辑器的样子:

图 6.6:图像编辑器

图 6.6:图像编辑器

如图中所示,在左侧菜单中我们可以找到所有常见的图像编辑工具,例如铅笔、橡皮擦、文本等。然后,在顶部工具栏中,我们可以访问其他功能:

  • 保存:这允许你保存对图像的更改。

  • 文件:这允许你上传新图像以替换当前图像。

  • 编辑:在这里你可以找到复制和粘贴选定区域或撤销更改的方法。

  • 图像:在这里你可以找到放大和调整图像大小的方法,以及翻转和旋转图像的功能。此外,还有调整颜色亮度、对比度的校正功能,以及获取图像调色板和直方图的工具。

  • 图层:在这里你可以找到创建和管理图像不同图层的方法。

  • 效果:在这里你可以为图像添加效果/过滤器,例如黑白过滤器。

  • 工具:在这个菜单中,你可以找到一些用于颜色替换、创建边框和在图像上计算关键点的先进功能。

现在我们已经探索了图像编辑器,我们将看到如何定义资产元数据。

定义资产元数据

在本节中,我们将了解如何为资产定义元数据。通常,元数据用于增强资产信息,以描述内容而不显示它;这在内容因网络连接差或出于可访问性原因无法显示的情况下可能很有用。例如,对于图像,在网站上使用替代标签以简短文本描述视觉内容是一种良好的做法。

在 Pimcore 中,可以创建预定义的元数据,这些元数据可以应用于每个资产。您可以通过设置 | 预定义资产元数据打开元数据定义面板。以下图显示了元数据属性和可以创建的不同类型的元数据:

![图 6.7:预定义元数据定义图 6.07:预定义元数据定义

图 6.7:预定义元数据定义

让我们看看图中可以看到的各种属性:

  • 名称:元数据属性的名称(此字段没有唯一约束)。

  • 描述:元数据的可选描述。

  • 类型:我们可以定义简单的元数据类型,如输入文本区域日期复选框选择。作为一个更复杂的选项,还有将对象文档或另一个资产作为元数据链接的能力。

  • :对于每个元数据,可以定义一个默认值。此值的类型反映了之前定义的类型。

  • 配置:对于选择型元数据,在此属性中,我们必须指定可以用于元数据的选项。这些选项必须以逗号分隔。

  • 语言:这指定了元数据的语言。

  • 目标类型:我们可以指定某些元数据是否仅限于特定类型的资产。如果没有选择,元数据可以应用于所有类型的资产。

要定义新的元数据,只需点击添加按钮;所有更改都会自动保存,无需点击按钮。

预定义的元数据可以附加到资产上。您可以通过点击资产窗口中的自定义元数据选项卡来完成此操作,如图所示:

![图 6.8:资产元数据图 6.8:资产元数据

图 6.8:资产元数据

如图中所示,对于每个资产,可以创建自定义元数据。对于每条元数据,我们可以定义值并指定语言。之前创建的元数据可以通过点击添加预定义定义按钮附加到资产上。

现在你已经学会了如何创建资产元数据,让我们看看如何在 Pimcore 图像中设置焦点。

设置焦点

在本节中,你将学习如何为图像设置焦点。此属性可以通过点击以下图中的设置焦点按钮在图像编辑器中进行配置:

![图 6.9:设置焦点图 6.09:设置焦点

图 6.9:设置焦点

如前图所示,点击之前提到的按钮将在图像上添加一个标记。默认情况下,焦点位于图像中间,但您可以将其拖动到所需的位置。

正如你将在下一节中学习的那样,焦点可以被用来动态创建图像缩略图,以确保图像的焦点在焦点上。

总结来说,在本节中,你学习了如何通过集成编辑器编辑图像。然后,你学习了如何创建预定义的元数据,以及如何将元数据附加到资产上以丰富它们,以及如何在图像上设置焦点。在下一节中,你将学习如何创建图像和视频缩略图以及它们如何用于在不同媒体上分发资产。

定义和使用缩略图

在上一节中,你发现了如何使用内部编辑器编辑图像以及如何为资产创建元数据。在本节中,你将学习如何定义图像和视频的缩略图,以便在不同平台上分发。

在许多场景中,相同的图像必须在网站和移动应用上显示,并且由于不同的空间内容组织以及各种设备屏幕的不同形状和大小,这需要不同的调整大小。将不同版本的图像作为不同的资产上传并不是最佳解决方案,因为如果我们想对原始图像进行更改,我们必须再次调整所有图像的大小。

为了避免这个问题,Pimcore 提供了定义转换规则的能力,以动态地为图像和视频创建不同的缩略图。因此,我们可以上传资产的高清版本,并定义规则来创建较小的调整大小。

在本节中,我们将首先了解如何定义缩略图创建的规则。然后,我们将发现如何在模板中实际要求它们,以及如何动态生成公共 URL。当第一次请求某个缩略图时,Pimcore 会自动创建物理缩略图文件。

定义缩略图

要为图像定义缩略图生成规则,请转到设置 | 缩略图 | 图像缩略图。在打开的选项卡中,点击添加按钮,填写缩略图名称,然后点击确定以创建一个新的缩略图定义。

在以下图中,你可以看到缩略图定义面板的显示方式:

图 6.10:图像缩略图

图 6.10:图像缩略图

如前图所示,缩略图定义名称是在创建时定义的名称;这个名称在缩略图定义中作为唯一标识符,并且无法重命名缩略图定义。因此,我们可以为缩略图添加描述,并将多个缩略图分组到一个文件夹中。

第一个相关的属性是输出格式。我们可以选择保留原始图像格式,生成一个针对网页优化的图像,或者强制输出格式为 PNG、JPG、GIF 或 TIFF。在高级设置中,我们可以设置额外的属性来定义 JPEG 和打印格式的图像质量和分辨率。

在屏幕底部,你可以看到转换定义管道。对于每个缩略图,我们可以定义一个或多个转换,这些转换将按照从上到下的定义顺序执行。你可以从大量转换中选择执行裁剪、调整大小、旋转或颜色过滤。例如,在前面的图像中,我们定义了一个通过宽度缩放图像的转换,给出最大像素宽度和保持图像比例。如果我们启用强制调整大小复选框,我们将强制生成具有所需宽度的缩略图;这也适用于原始图像小于此宽度的情况。此外,还可以为不同的媒体查询应用不同的转换,以根据屏幕大小动态调整图像宽高比。

一旦定义了转换管道,只需点击保存即可持久化缩略图定义。

对于图像缩略图所说的也适用于视频缩略图。在下图中,你可以看到视频缩略图定义的外观:

图 6.11:视频缩略图

图 6.11:视频缩略图

如图中所示,与图像相比,视频的可设置选项有限。基本上,对于视频缩略图,我们可以定义比特率和缩放操作。

现在你已经学会了如何创建缩略图定义,让我们来看看如何定义一个使用图像焦点点的缩略图。

缩略图上的焦点

图像编辑和增强部分的设置焦点点子节中,你学习了如何为图像设置焦点点。

如该子节所述,焦点点可以用来定义特定类型的缩略图转换。在下图中,你可以看到如何设置这种转换:

图 6.12:缩略图封面转换

图 6.12:缩略图封面转换

如前图所示,你可以添加一个封面转换,它支持焦点点的使用。这种转换将创建一个以焦点为中心的裁剪图像。这个缩略图的大小是通过宽度高度参数定义的。

如果没有为图像设置焦点点,默认定位参数将允许你创建一个放置在定义位置的裁剪图像。

在下一节中,我们将看到如何在模板上调用缩略图以及如何动态生成公共缩略图 URL。

使用缩略图

在上一节中,你学习了如何为图像和视频定义缩略图。在本节中,我们将看到这些缩略图如何在模板和后端开发中使用。然后,我们将向你展示如何在外部应用程序中动态生成公共 URL 来检索缩略图。

使用示例

让我们通过一些代码技巧来展示如何使用缩略图。首先,你需要获取一个资源实例;这让你可以调用getThumbnail方法,就像我们在这里展示的那样:

<?php
    use Pimcore\Model\Asset\Image;
   $image = Image::getByPath("/Path/To/The/Image.jpg");
   $myThumbnail= $image->getThumbnail("my-thumbnail");
?>

在前面的代码片段中,我们可以看到如何根据先前创建的缩略图定义的名称检索图像缩略图。此方法还允许在运行时创建自定义缩略图定义,通过传递缩略图配置作为输入,如下面的代码片段所示:

<?php
    use Pimcore\Model\Asset\Image;
   $image = Image::getByPath("/Path/To/The/Image.jpg");
   $customThumbnail = $image->getThumbnail(["width" => 500,      "format" => "png"]);
?>

如我们所见,我们可以通过设置基本的配置选项,如widthformat,来创建一个自定义缩略图。

获取的缩略图可以放置在 HTML 模板中。正如我们在下面的代码片段中所见,一个选项是为图像标签设置源属性:

<img src="img/{{ image.thumbnail('my-thumbnail').path }}" />

getPath方法检索文件系统路径,并可用于设置图像标签的源;如果省略此方法,它将自动调用,因为它是由隐式的__toString函数调用的。

作为替代,我们还有一个选项让缩略图自己生成 HTML 标签:

{{ image.thumbnail('my-thumbnail').html({'class' => 'my-css-class', 'alt' => 'The image alt text'}) }}

getHtml方法返回图像 HTML 标签;作为此方法的输入,我们可以传递一个属性数组,这些属性将应用于标签。这可能有助于动态添加 CSS 类或数据属性,如替代文本。

如果你正在你的缩略图配置中使用媒体查询,getHtml方法将返回一个图片 HTML 标签。如果你想为特定格式要求图像标签,你可以使用getMedia函数,如下面的代码片段所示:

{{ image.thumbnail('my-thumbnail').getMedia("(min-width: 576px)").html}}

定义好的图像缩略图定义也可以用来在需要将视频资源插入模板时显示视频的预览图像。在下面的代码片段中,我们可以看到如何获取这些快照:

<?php
    use Pimcore\Model\Asset\Video;
$asset = Video::getById(123);
    echo $asset->getImageThumbnail("my-thumbnail");
    echo $asset->getImageThumbnail(["width" => 250], 20);
?>

如我们在代码中所见,getImageThumbnail方法接受一个缩略图定义名称或一个内联配置作为输入。作为第二个参数,我们可以指定我们想要从视频中截取的哪一秒。

所有这些示例都展示了如何内部使用资源,但 Pimcore 中的每个资源都有一个公开的 URL,缩略图也是如此。让我们看看如何根据资源信息动态生成缩略图 URL。

下载缩略图

Pimcore 缩略图在第一次请求下载或需要在页面上显示时动态生成。要使缩略图可以从资产详情面板下载,你必须检查缩略图定义中的下载部分列表选项标志在图像详情视图中。正如我们在下面的图中所见,所有启用了此选项的缩略图都列在资产的下载缩略图下拉菜单中:

![图 6.13:下载缩略图图 6.13:下载缩略图

图 6.13:下载缩略图

要下载缩略图,你只需从图中可以看到的下拉菜单中选择所需的缩略图定义,然后点击下载按钮。

缩略图也可以通过它们的公共 URL 通过网络浏览器访问和下载。这些 URL 具有固定的规则来定义它们。让我们看看以下示例 URL:

https://your-pimcore-url.com/Path/To/The/image-thumb__123__my-thumbnail/Image.jpg

让我们解释构成前面 URL 的所有部分:

  • https://your-pimcore-url.com:这是您 Pimcore 安装的基准 URL。

  • Path/To/The:这是包含图片的文件夹和子文件夹的路径。

  • image-thumb:这是 URL 中的一个固定部分,用于指定您需要缩略图。

  • 123:资产的 ID。它由两个下划线前后包围。

  • my-thumbnail:缩略图定义的名称。

  • Image.jpg:图片的名称。

使用这种模式,您可以从图片路径和 ID 开始动态生成所有缩略图定义的公共 URL。

总结来说,在本节中,您学习了如何通过定义转换规则管道来定义图像和视频的不同缩略图。然后,您看到了一些代码示例,展示了如何在开发期间实际使用缩略图。在最后一部分,您发现了如何动态生成缩略图的公共 URL 以使其可下载。

摘要

在本章中,我们介绍了 Pimcore 的 数字资产管理 (DAM) 功能。在定义了所有 DAM 系统的共同特征之后,我们展示了这些特征如何在 Pimcore 中实现。

我们随后学习了如何在 Pimcore 中上传资产,从不同类型的来源选择各种格式的文件,这些来源可以是离线或在线的。然后,我们学习了如何使用文件夹和标签来组织资产,以及如何将资产与对象关联起来。特别是,我们介绍了可以用来将资产附加到对象的不同数据组件。

之后,我们看到了如何通过集成编辑器编辑图片,以及如何通过为它们定义元数据来增强图片内容。特别是,我们学习了如何创建预定义的元数据定义以及如何为每个资产定义自定义元数据。

我们随后专注于资产分发,学习了如何为图片和视频创建缩略图定义。我们展示了如何在开发中实际使用缩略图,展示了代码片段,以及如何动态生成缩略图的公共 URL。

在下一章中,我们将介绍 Pimcore 网站的行政管理,解释如何安装第三方插件以及如何管理用户和角色。

第七章:第七章:管理 Pimcore 网站

在上一章中,我们学习了如何使用 DAM 功能在 Pimcore 中管理图像、缩略图和资产。在本章中,我们将首先了解如何通过使用捆绑包来增强 Pimcore 的功能,这些捆绑包是由 Pimcore 团队或第三方开发者创建的,并且可以轻松安装。

另一个不容忽视的基本功能是用户及其权限的组织。为了限制网站在管理和内容管理部分的功能,我们将学习如何创建角色,如何为角色创建权限,以及如何将它们分配给用户。

我们还将了解如何导入和导出我们的 Pimcore 安装的设置到其他环境。最后,我们将对 Pimcore 控制台有一个初步的了解,这是一个强大且有用的工具,可以执行命令,而无需访问网络管理面板。

本章我们将涵盖以下主题:

  • 安装捆绑包

  • 探索用户和角色

  • 管理视角

  • 导入和导出 Pimcore 设置

  • 使用 Pimcore 控制台

到本章结束时,我们将学习如何通过安装组件来为我们的网站添加功能,配置不同角色和权限的用户访问,导入和导出设置和类,以及通过命令行使用 Pimcore 控制台。

技术要求

要跟随本章,唯一的要求是拥有一个运行中的 Pimcore 安装,并且能够通过命令行访问它。

如果你使用 Docker 安装了 Pimcore,只需运行以下简单指令:

  1. 使用以下命令运行 Docker:

    docker-compose up
    
  2. 有可能,但不是必须的,通过运行以下命令来恢复本地安装设置:

    docker-compose exec php bash restore.sh
    

导航到localhost/admin并使用你的管理员/pimcore 凭据登录。

现在你可以将本章涉及的所有方面付诸实践了。

安装捆绑包

在本节中,我们将了解如何使用捆绑包向 Pimcore 添加功能。然后我们将了解捆绑包是什么,以及如何通过几个简单步骤来安装它。

Pimcore 已经预装了许多功能,并准备好使用,但尽管这些可能满足我们的需求,但可能还需要一些 Pimcore 中不可用的额外功能。没问题,因为这个框架提供了一个快速简单的方式来安装新功能。向框架添加功能是通过安装包来完成的,在 Pimcore 的世界里,它们被称为组件捆绑包,就像在其他系统中,它们可以被识别为插件、模块或附加组件一样。换句话说,捆绑包是一个包含额外组件或功能的包,这将增加 Pimcore 的功能性。

安装捆绑包是一个相对简单的操作;让我们一步步进行。

首先,我们需要根据我们的需求确定要安装的包。在官方 Pimcore 网站上有一个专门的页面,你可以在这里找到大量包,其中许多是由 Pimcore 开发团队创建的,其他则是由第三方开发者创建的。这是该页面的链接,被称为 Pimcore 市场页面:https://Pimcore.com/en/developers/marketplace。

我们可以在以下屏幕截图中看到市场的外观:

![图 7.1:Pimcore 市场页面]

![图片 7.01_B17073.jpg]

图 7.1:Pimcore 市场页面

如前一个屏幕截图所示,我们可以进行搜索并过滤搜索结果。

现在,我们只需查找我们需要的。对于本章,我们可以假设我们需要一个允许我们生成连续数字的包。即使我们将要安装的包不会给我们的 Pimcore 安装添加很多功能,但该过程对于我们将要安装的每个包都是有效的,无论其功能如何。

经过简单的搜索,我们找到了一个适合我们的包。这个包叫做 数字序列生成器,由 Pimcore 团队开发。在下一个屏幕截图中,我们看到搜索执行和结果的样子:

![图 7.2:执行搜索的 Pimcore 市场页面]

![图片 7.02_B17073.jpg]

图 7.2:执行搜索的 Pimcore 市场页面

如前一个屏幕截图所示,我们得到了搜索结果列表。搜索结果以卡片形式表示,我们可以阅读我们将通过安装包介绍的功能的简要描述。还有其他有用的信息,例如版本号、类别、开发者的名字、是否经过审查,以及最后一次审查的时间。

现在,只需点击包并转到详情页面。在页面上找到的所有附加信息中,点击 立即获取 按钮。这是一个链接,将带我们到包的源代码页面。

因此,让我们进一步深入,开始安装过程。这并不复杂,但与其他插件安装系统,如 WordPress 或其他类似系统相比,它需要一些额外的步骤。所以,准备好让你的手稍微脏一点,并遵循以下步骤:

  1. 在源文件仓库中定位并打开 composer.json 文件。在我们的例子中,文件看起来是这样的:

    {
         "name": "Pimcore/number-sequence-generator",
         "license": "GPL-3.0+",
         "type": "Pimcore-bundle",
         "config": {
              "sort-packages": true
         },
         …
    }
    

    虽然熟悉 composer.json 文件确实很有用,但在这种情况下,我们唯一感兴趣的是检索要安装的包名。我们可以通过向上滚动文件到 "name" 属性来找到它。

    现在我们知道了要安装的包的名称,我们需要执行一个简单的命令,compose 会为我们做所有的事情。为此,我们需要访问我们的命令行安装。如果您不使用 Docker,只需在 Pimcore 安装的机器上打开一个 shell。否则,您首先需要访问 Pimcore 运行的容器。

  2. 要做到这一点,输入以下命令:

    NAME, related to the Pimcore image. 
    
  3. 一旦您恢复了 Pimcore 运行的镜像的容器 ID,输入以下命令:

    xxxxxxxxxxxx is the container ID retrieved from the previous command. 
    
  4. 一旦进入,运行以下命令:

    composer downloads and installs the packages needed to add the new bundle. The output of the command can be longer or shorter, depending on the number of packages that need to be installed or whether they are already installed and need to be updated. At the end of the process, the last few lines in the console should look like this:
    
    

    …(之前的控制台日志行)

    尝试将资产作为相对符号链接安装。


    包                            方法 / 错误


    FOSJsRoutingBundle                relative symlink

    …(一些其他包)


    [OK] 所有资产已成功安装。

    
    

如果安装成功,我们将在 Pimcore 中安装一个新的包。我们只需去配置它。

通过遵循工具 | 包菜单,您可以访问包配置页面。在下一张截图中,我们看到这个页面的样子:

图 7.3:Pimcore 包管理页面

图 7.3:Pimcore 包管理页面

如前一个截图所示,我们已安装了两个包;第二行显示的是我们刚刚安装的包。

在完成包的安装之前,让我们停下来分析一下我们在图 7.3中看到的表格中的列。

我们可以看到有两种类型的列:

  • 信息列,包括ID名称版本描述

  • 操作列,其中包含操作按钮。特别是,我们感兴趣的列是启用/禁用安装/卸载列,以及它们的行为按钮。

首先,我们需要启用这个包。为此,点击启用/禁用列中的+图标,然后启用包。此操作将花费几秒钟,完成后,屏幕上会出现一个模态窗口,指示启用操作成功。

现在我们准备安装这个包。在继续此步骤之前,我们需要清除缓存。您可以通过点击右上角的按钮轻松完成此操作:清除缓存并重新加载。缓存清理操作是必要的,因为 Pimcore 广泛使用缓存来存储不同类型的数据,包括包文件及其配置。不推荐在不先清除缓存并重新加载页面的情况下完成此操作。

清除缓存并 Pimcore 重新加载后,我们可以返回包管理页面以验证包的正确状态。

现在我们已经启用了这个包,+ 图标出现在安装/卸载列中,如下截图所示:

![图 7.4:启用 Pimcore 包后的情况图片

图 7.4:启用 Pimcore 包后的情况

如前一个截图所示,现在可以点击新包的“安装/卸载”列中的+图标以启动安装过程。

关于启用操作,系统通过包含有关刚刚完成操作的一些信息的模态窗口通知我们操作的结果。

再次提醒,Pimcore 要求我们清除缓存并重新加载 Pimcore。让我们最后一次这样做,包安装完成。

现在我们已成功安装了新的包,我们可以利用其功能。我们为这一章选择的包允许我们生成连续的数字,例如,用于订单号或客户号。我们不会详细说明此功能的工作原理,因为本节的目的在于学习如何安装和管理包。

在下一节中,我们将看到如何创建用户和角色,以及如何配置用户以限制对内容的访问。

探索用户和角色

在本节中,我们将了解如何管理用户及其权限,以限制网站在管理和内容管理部分的功能。我们将了解角色和权限是如何创建的,以及它们是如何分配给用户的。

在创建网站的过程中,我们经常需要管理不同重要性不同的部分。此外,我们还可以区分我们在组织中的工作。网站的管理部分很重要,涉及内容的创建或编辑。

通常,与站点的维护和管理相关部分是管理员的职责。因此,如管理语言、配置路由规则或创建用户和安装包等任务由具有所需技能和知识以及执行此类操作权限的专家用户完成,而这些权限取决于管理员。另一方面,内容通常是其他人的责任,例如用户,通常定义为编辑者或发布者。一旦我们意识到站点的管理和维护需要通过多个用户,因此我们可以再迈出一步,定义一些关于“谁做什么”的基本概念。

正如我们已经提到的,有不同类型的用户:在我们的例子中,我们谈到了管理员,他们管理网站的配置部分,以及编辑者或发布者,他们输入内容。这种区分虽然有效,但却是有限的,因为就像在现实公司中,有很多人有很多不同的任务和责任一样,在网站上,也可以有很多人有很多不同的角色和责任。

那么,我们如何区分访问网站的用户,更重要的是,我们如何允许这些用户能够看到和修改我们希望他们工作的某些信息?这个问题的答案是简单的:通过角色。

但角色是什么?角色本质上是一组权限。如果我们想为出版商创建一个角色,参照前面的例子,我们必须在这个角色中放入创建和修改内容(如网页、商店的产品或博客的文章)的权限。一旦角色创建完成,就可以将这个角色分配给网站的一个或多个用户,从而有效地允许这些用户执行角色允许的操作。

设置用户和角色

在 Pimcore 中,以及几乎所有允许多人访问的系统,都可以创建用户和角色,并将这两个实体关联起来。为此,Pimcore 的设置菜单中有专门的章节:用户角色

按照以下设置 | 用户菜单,Pimcore 打开一个包含注册用户列表的页面。在这个页面上,我们可以删除、修改或创建新用户。要打开角色管理页面,只需点击设置 | 角色菜单中的链接。在这里,我们将找到系统中创建的角色列表,以及修改、删除或创建新角色的可能性。

点击一个用户,将打开配置标签页,在这里您可以添加或更改诸如电子邮件语言等信息,如图下所示:

![图 7.5 – 用户管理页面

![img/Figure_7.05_B17073.jpg]

图 7.5 – 用户管理页面

在前面的截图中,我们可以看到用户管理页面;通过右键单击左侧菜单,将出现一个弹出上下文菜单,您可以在其中创建或删除用户。角色管理页面与用户管理页面具有相同的布局和功能。

在 Pimcore 中,存在两个级别的用户权限:

  • 系统组件的权限

  • 数据元素(资产、对象和文档)的权限

权限可以授予角色或单个用户。使用角色不是强制性的;可以直接将权限授予用户。然而,如果需要管理较大的用户组,建议使用角色。在用户/角色设置标签页中,在权限部分,可以决定授予该用户或角色的哪些权限。与角色相比,单个用户有一些更多的通用设置。

那么,让我们看看如何为用户分配权限。看看用户配置页面是如何定义的。如您在图 7.5中看到的,页面分为四个标签页。详细描述它们将花费很长时间,并且超出了本章的范围。为了我们的目的,我们将重点关注设置工作空间标签页。

特别是,设置标签页被分为几个部分:

  • 常规:配置账户用户

  • 管理员:授予用户管理员角色

  • 权限:设置授予用户的系统角色

  • 允许创建的类型:选择允许创建的类

  • 编辑器设置:选择用户的语言

  • 共享翻译设置:管理共享翻译

因此,让我们从用户设置的配置开始。通过点击+图标,您可以发现每个部分的多种配置,如下面的截图所示:

图 7.6:用户管理页面:设置选项卡内的部分

图 7.6:用户管理页面:设置选项卡内的部分

如前一个截图所示,常规部分包含所有用户信息,如用户名和密码、图像和角色。另一方面,管理员部分只包含一个复选框,如果选中,将为用户授予管理员权限;也就是说,他们将拥有对 Pimcore 的完全控制权。第三个部分权限是一个长长的复选框列表,每个复选框都标识了在 Pimcore 上执行特定操作的权利。

让我们检查一些这些条目及其含义:

  • 资产:使资产树可见。

  • :使对象类编辑器可见(用户可以创建和修改对象类)。

  • 清除缓存:定义用户是否可以清除 Pimcore 缓存。

  • 清除临时文件:定义用户是否可以删除临时系统文件。

  • 文档:使文档树可见。

  • 文档类型:允许用户创建和修改预定义的文档类型。

  • 电子邮件:用户可以看到电子邮件历史记录。

  • 扩展:指定用户是否允许下载、安装和管理扩展。

  • 对象:使对象的树可见。

  • 回收站:用户可以访问回收站。

  • 重定向:用户可以创建和修改重定向。

  • 系统设置:用户可以访问系统设置。

  • 翻译:定义用户是否可以查看和编辑网站翻译。

  • 用户:定义用户是否可以管理其他用户的设置和系统权限。

  • 网站设置:用户可以创建和修改网站设置。

因此,通过选择这些复选框中的一些,可以根据需要配置用户的权限(或对于角色,配置部分是相同的)。这些权限是 Pimcore 系统权限。

此外,还可以从工作空间选项卡配置其他权限,其外观如下:

图 7.7:管理数据元素(资产、对象和文档)的用户权限

图 7.7:管理数据元素(资产、对象和文档)的用户权限

如前一个屏幕截图所示,用户的访问权限可以基于元素进行限制。这可以通过为用户或角色定义工作空间来实现。既然用户通常可以访问文档,就可以指定用户/角色可以对每个文档或工作空间执行的操作。对于对象和资产也是如此。

基于元素的基于用户的权限通过一列标识,如图 图 7.7 所示。我们可以总结其中的一些:

  • 列表:元素可以在树中列出。

  • 查看:元素可以被打开。

  • 保存:元素可以被保存(可见保存按钮)。

  • 发布:元素可以被发布(可见发布按钮)。

  • 创建:可以创建新的子元素(对于资产不存在)。

  • 删除:元素可以被删除。

  • 版本:使 版本 选项卡可用。

现在我们已经看到了配置和使用用户和角色所需的所有组件,让我们继续一个简单的实际例子。

使用用户和角色的实际例子

现在我们已经清楚地了解了如何配置用户和角色,让我们用一个简单的实际例子来说明。

对于这个例子,我们创建了两个用户,TomBob,以及两个角色,tomstuffbobstuff。让我们将 Tom 分配为 tomstuff 角色,将 Bob 分配为 bobstuff 角色。这可以通过进入 用户配置 菜单的 常规 部分 (图 7.6) 并在 角色 框中选择适当的角色来实现。

我们现在需要为每个角色选择权限。这可以通过在 设置 选项卡内的 权限 组内完成(见图 图 7.6):

  • 对于 tomstuff,我们选择了 笔记与事件 | 系统设置 | 用户 | 管理员翻译 | 对象

  • 对于 bobstuff,我们选择了 回收站 | 静态路由 | 清除缓存 | 对象

这些是与 Pimcore 配置和设置相关的权限。现在让我们设置内容的权限。我们创建了两个类:BookFilm。类创建在 第五章探索对象和类 中有详细描述。我们将 tomstuff 角色的权限分配给管理书籍,而将 bobstuff 分配给管理电影。这可以通过 工作空间 选项卡来完成,如图 图 7.7 所示。

现在配置完成后,让我们用这两个用户登录;在下一个屏幕截图中,我们可以看到以 Tom 登录时管理界面看起来是什么样子:

图 7.8 – Tom 的管理页面

图 7.8 – Tom 的管理页面

如前一个屏幕截图所示,Tom 在用户角色的权限下只能访问一些菜单项。我们还可以看到,Tom 只能管理我们在 tomstuff 角色的工作空间中指定的书籍对象。相反,在下一个屏幕截图中,我们可以看到 Bob 的管理界面:

![Figure 7.9: Bob 的管理页面]

![img/Figure_7.09_B17073.jpg]

![Figure 7.9: Bob 的管理页面]

再次,在这个屏幕截图中,我们可以看到鲍勃的菜单是如何受限的,以及如何仅管理电影对象。

从前面的屏幕截图中我们可以看到,Pimcore 管理界面中的上下文菜单根据用户及其角色而有所不同。特别是,我们可以验证只有与分配的权限相关的操作是可见的;其他一切都不可以访问。即使是内容,两个用户也仅能访问通过其角色可访问的类;特别是,汤姆可以管理书籍,而鲍勃可以管理电影。

在本节中,我们刚刚看到的是解决基于角色限制某些用户访问问题的一个可能解决方案,而且可以通过配置用户、角色和权限,无需编写代码,仅通过 Pimcore 管理页面即可实现这一点。

然而,Pimcore 提供了一个更完整的系统来创建特殊视图,这个系统比我们刚刚看到的要完整得多,可配置性也更强。这个 Pimcore 功能被称为视角,即专门为特定用户创建和配置的视图。那么,让我们看看如何创建一个视角,如何配置它,以及最终在 Pimcore 中的结果会是什么。

管理视角

如前一小节所述,可以通过配置用户和角色来限制对 Pimcore 功能的访问。我们也在前一小节的结尾提到,Pimcore 中有一个功能可以让你获得相同的结果,即视角。虽然前面的说法完全正确,但有一个重要的区别需要记住:使用用户和角色的权限来限制数据访问,而视角并不是用来限制数据访问的。因此,尽管最终结果可能看起来相似,但在安全性方面,它们是两件非常不同的事情。我们的建议是两者都使用,以便从管理后端以及安全性方面都得到完美的结果。

那么,让我们看看我们如何创建一个视角。最简单的方法是使用 Pimcore 开发团队开发的包。这个包提供了一个 Pimcore 编辑器,允许我们执行以下操作:

  • 添加/删除/编辑自定义视图

  • 添加/删除/编辑视角

它还允许我们直接在用户界面中配置大多数可能的配置选项。

可以通过以下地址访问包页面:https://github.com/pimcore/perspective-editor。

如本章“安装包”部分所述,要安装包,只需遵循几个简单的步骤即可。我们不会再次解释如何安装包,但正如我们已经看到的,我们需要让 composer 将包添加到解决方案中,使用以下命令:

composer require pimcore/perspective-editor

在 Pimcore 上安装并激活捆绑包后,我们就可以使用这个新功能了,从设置 | 视角/视图下找到的新菜单项开始,如以下截图所示:

![图 7.10:视角/视图菜单项和视角编辑页面图片

图 7.10:视角/视图菜单项和视角编辑页面

如前一个截图所示,有一个默认的视角,可以随意更改。但为了不修改默认视角,让我们去创建一个新的视角。通过点击MyFirstPerspective

正如您在图 7.10中也可以看到,在视角中我们有五个字段,如下所示:

  • 图标:可以为视角选择一个图标。

  • 元素树左侧:在这个元素中,可以添加以下一个或多个元素:文档资产对象自定义视图。添加的项目将在 Pimcore 管理界面的左侧列中显示。

  • 元素树右侧:这与前面描述的相同项目,但项目将在右侧列中显示。

  • 仪表板:通过选择此元素,可以决定哪些元素可以在仪表板上允许或禁止。还可以创建新的仪表板,并且对于每个仪表板,可以决定它由哪些元素组成。

  • 工具栏:通过一组按菜单分组的复选框,可以选择是否显示菜单,还可以决定哪些菜单项应该可见或不可见。换句话说,通过这个元素,可以启用或隐藏 Pimcore 管理中的菜单项,甚至可以隐藏整个菜单。

正如我们所见,在两个项目元素树右侧元素树左侧中,可以添加一个或多个文档、资产或对象元素。在下一个截图中,我们看到如何添加文档元素:

![图 7.11:视角菜单项:添加文档元素树左侧图片

图 7.11:视角菜单项:添加文档元素树左侧

如前一个截图所示,对于我们的视图,我们决定在左侧列中添加文档和资产元素,在右侧列中添加一个对象。一旦决定将哪些元素放在哪里,通过选择这些元素中的每一个,就可以通过复选框列表决定每个元素的上下文菜单中哪些元素应该可见。以下是一个例子,如以下截图所示:

![图 7.12:文档元素的上下文菜单定义图片

图 7.12:文档元素的上下文菜单定义

从前面的截图我们可以看到,可以选择显示哪些上下文菜单项。

就列元素而言,刚刚看到,通过工具栏元素,我们可以决定显示或隐藏哪些菜单,或者我们可以决定要隐藏的菜单或子菜单中的哪些项目。所有菜单都分组,在每个组中都有一个作用于菜单项的复选框列表,显示或隐藏它。为了更好地理解,让我们看一下以下截图,与设置菜单相关:

图 7.13:设置菜单中要显示的项目选择

图 7.13:设置菜单中要显示的项目选择

如前截图所示,每个菜单项都是一个组,可以展开,显示识别各种菜单项的复选框列表。每个复选框列表组的第一个条目是隐藏 xxx 菜单,其中xxx是菜单的名称。如果我们选择此项目,菜单将被隐藏,后续的勾选将不被考虑。

一旦定义了视角的所有部分,视角项将出现在文件菜单中,并且在其中可以选择我们的新视角,如下图所示:

图 7.14:包含视角列表的文件菜单

图 7.14:包含视角列表的文件菜单

如前图所示,在名为Perspectives的新菜单项中,文件菜单内有两个项目:默认视角和我们的新视角MyFirstPerspective

一旦我们的视角配置如我们所愿,我们就可以将其关联到用户或角色。这可以直接在用户或角色设置中完成,如以下图所示:

图 7.15:用户和角色的视角配置

图 7.15:用户和角色的视角配置

如前截图所示,用户和角色的视角选择非常简单:只需从列表中选择所需的视角并保存设置。因此,我们已经看到了如何在 Pimcore 中管理用户和角色,以及如何创建和配置与每个用户或角色关联的视角。在下一节中,我们将看到一个关于 Pimcore 维护的非常有用的功能:Pimcore 设置的导入/导出。

导入和导出 Pimcore 设置

在本节中,我们将看到如何导出 Pimcore 安装的设置并将它们导入到其他环境中,这是在必须在不同环境中工作时的基本功能,例如开发、测试或生产。

正如我们在第五章中看到的,探索对象和类,当我们谈论类和对象时,我们学习了如何创建新实体并用于我们的目的。我们所做的一切工作都在某种程度上被困在 Pimcore 中,就像在一个盒子中一样。这是完全正常的,当开发一个新网站时,我们习惯于参考各种环境,开发、测试、预发布等,我们在那里进行了更改。因此,疑问随之而来:如果我工作在开发环境中,例如,我如何将其他环境中完成的工作转移过来?

好吧,拥有一个允许我们将 Pimcore 安装中完成的工作导出,以便能够将其导入另一个安装的工具,这成为了一个必要,如果不是必不可少的益处。

为了澄清,让我们以我们最初创建的两个类BookFilm为例。如果我们想要导出这两个类中的一个,或者两个,以便能够将它们导入另一个环境中的另一个 Pimcore 安装,我们可以进入类编辑页面,点击底部按钮栏中的导出按钮,如下截图所示:

Figure 7.16 类编辑页面,带有导入/导出按钮

Figure 7.17: 批量导出

图 7.16 类编辑页面,带有导入/导出按钮

如我们所见,导出按钮正是我们所需要的。只需点击导出,Pimcore 将生成一个包含所有必要信息的 JSON 文件,以便能够在另一个 Pimcore 环境中稍后导入。一旦导出,我们只需访问我们想要导入类的 Pimcore 安装,创建它,然后使用导入按钮导入之前提取的文件,如图7.16所示。

但这仅仅是解决方案的一部分。让我们设想我们有成百上千个类;逐个导出和导入它们可能是一项漫长的工作,我们可能会在途中忘记一些类。为了解决这个问题,导航到设置 | 数据对象,我们会找到两个项目:批量导出批量导入。点击批量导出后,会出现如下模式:

![Figure 7.17: 批量导出Figure 7.17: Bulk export

图 7.17:批量导出

如我们所见,我们可以从类列表中选择我们想要导出的类。

此外,如果您创建了或编辑了BookFilm

一旦我们通过点击导出选择了我们想要提取的内容,Pimcore 将生成一个包含导入另一个环境中所有元素所需信息的 JSON 文件。最后,您可以使用批量导入命令重新加载包含所有导出实体的导出文件。

导入分为两个步骤,如下所示:

  1. 选择导出过程中生成的 JSON 文件。使用以下模式,加载在导出阶段生成的 JSON 文件,您现在想要导入:![Figure 7.18: 选择本地文件

    ![img/Figure_7.18_B17073.jpg]

    图 7.18:选择本地文件

  2. 决定从该文件中导入什么。在我们的例子中,我们从以下模式中选择了我们想要导入的两个类——BookFilm

![img/Figure_7.19_B17073.jpg]

![img/Figure_7.19_B17073.jpg]

![img/Figure_7.19_B17073.jpg]

如前一个屏幕截图所示,Pimcore 向我们显示了所有可以导入的对象列表,与已上传的文件相关。所以,让我们选择我们想要导入的内容。一旦我们决定,只需点击应用,Pimcore 就会完成剩余的工作。

在本章的这一部分,我们已经了解了如何安装一个包,如何管理用户和角色,以及如何在各种 Pimcore 安装之间转移我们的工作。我们都是从 Pimcore 为我们提供的网络管理界面中完成这些活动的。但还有一种方法可以修改 Pimcore,而无需通过管理页面:使用 Pimcore 控制台工具。

使用 Pimcore 控制台

在本节中,我们将对 Pimcore 控制台有一个初步的了解,这是一个强大且有用的工具,可以执行命令而无需访问网络管理面板。

Pimcore 控制台可以被描述为一个命令行界面,它允许你仅使用终端安装、配置和维护你的 Pimcore。主要目标是提供一个工具,用于执行通常可以通过管理区域执行的操作。

由于 Pimcore 的管理界面如此美丽且易于使用,一个自然的问题就是:为什么你应该使用命令行界面?主要有两个原因:

  • 键盘比鼠标快:对于高级用户来说,输入一个命令可能比在网页浏览器中按按钮快一个数量级。

  • 脚本化:你可以将多个命令放入一个文本文件中,并自动运行它。

使用控制台而不是使用网络界面要快得多,因为它消除了加载页面及其所有组件的所有死时间。控制台直接作用于 Pimcore 核心,使得命令执行更快。

因此,使用控制台的第一步是登录到 Pimcore 运行的机器,或者进入 Docker 容器(有关 Docker 的更多信息,请参阅本章的“安装一个包”部分以获取访问容器的命令),然后运行以下命令以获取可用命令列表:

./bin/console list

由于可以从控制台执行许多命令,因此该命令的输出非常长。让我们看看命令列表的部分输出:

![img/Figure_7.20_B17073.jpg]

![img/Figure_7.20_B17073.jpg]

图 7.20:Pimcore 控制台的部分输出

如前一个屏幕截图所示,输出的第一部分包含有关 Pimcore 控制台选项的有用信息,下面是可用命令的列表(为了方便,我们在图 7.20中将其截断)。即使列表非常长,执行命令的逻辑始终相同:我们只需要理解命令的结构以及如何执行它。

在命令前面的-vvv中。另一方面,如果我们不想将任何信息输出到控制台,只需在命令前添加-q参数。

所有命令都被划分到cache命名空间,Pimcore 核心命令将以pimcore命名空间开头,等等。

要查看每个命名空间的所有命令列表,你可以运行list命令后跟命名空间。例如,要获取所有与缓存相关的命令,我们运行list命令后跟cache命名空间:

./bin/console list cache

输出将是可以在 Pimcore 缓存上执行的所有可用命令列表。

一些命名空间由几个元素组成,通过冒号连接,因此如果我们想识别 Pimcore 捆绑包可用的命令列表,我们必须执行以下命令:

./bin/console list pimcore:bundle

现在我们已经熟悉了控制台命令,让我们尝试运行几个命令作为练习。在章节的开始,我们安装了一个捆绑包,然后我们从网页界面激活了它。现在让我们尝试使用控制台运行相同的命令。

首先,我们需要通过运行以下命令来识别我们 Pimcore 安装中可用的捆绑包:

./bin/console pimcore:bundle:list

此命令的输出显示在下述屏幕截图中:

图 7.21:获取我们 Pimcore 安装中可用的捆绑包的命令输出

图 7.21:获取我们 Pimcore 安装中可用的捆绑包的命令输出

如此屏幕截图所示,我们在章节开始时安装的捆绑包是启用的。现在让我们尝试通过运行以下命令来禁用它:

./bin/console pimcore:bundle:disable NumberSequenceGeneratorBundle

如我们所见,我们在命令底部添加了作为参数的捆绑包名称,即我们想要操作的NumberSequenceGeneratorBundle

我们现在再次执行命令:

./bin/console pimcore:bundle:list

输出现在看起来是这样的:

图 7.22:获取我们 Pimcore 安装中可用的捆绑包的命令输出

图 7.22:获取我们 Pimcore 安装中可用的捆绑包的命令输出

如我们所见,捆绑包现在已经被完全卸载。

因此,我们看到了如何简单地在 Pimcore 控制台中执行命令。控制台非常有用的另一个原因是执行计划脚本,其中可以按顺序执行多个命令。例如,你可以编写一个清理缓存和邮件日志的脚本,并通过调度程序,例如Unix 系统上的crontab,每天早上运行此脚本。

我们留给您尝试其他命令的自由,熟悉 Pimcore 控制台,并理解其潜力。

摘要

在本章中,我们学习了如何通过使用包来增强 Pimcore 的功能,以及它们如何容易被安装和管理。

我们学习了如何组织网站的用户及其权限,限制网站在管理和内容管理部分的功能,以及如何创建和配置视角,并将它们与用户或角色关联起来。

我们还学会了如何将我们的 Pimcore 安装的设置导入和导出到其他环境。

最后,我们学习了如何使用 Pimcore 控制台,这是一个强大且有用的工具,可以执行命令,而无需访问网络管理面板。

在阅读本章的过程中,我们获得的所有新技能将使我们能够以最佳方式配置我们的网站,实现创建一个满足我们所有需求,甚至一点点满足我们乐趣的网站的目标。

现在我们已经熟悉了 Pimcore 提供的所有工具,是时候动手实践了。在本章之后,我们将开始将之前章节中看到的一切付诸实践,目标是创建一个包含博客、静态页面和产品目录的网站。为此,在下一章中,我们将首先创建自定义 CMS 页面。

第八章:第八章:创建自定义 CMS 页面

在前面的章节中,我们学习了如何使用这些功能创建文档和对象,并实现非常简单的网站。

在本章中,我们将深入探讨自定义 CMS 页面的创建。实际上,如果你正在模板化文档或创建独立页面,你有许多工具可以使 Pimcore 的开发体验对你来说非常出色。本章将涵盖许多对于全面了解 Pimcore 的 CMS 功能至关重要的方面;这些功能是创建自定义网页的基本工具,我们将它们结合起来讨论用户输入和模板以创建内容。

本章的结构如下:

  • 使用 MVC 模型

  • 使用可编辑内容

  • 使用块

让我们看看 Pimcore 的实际应用!

技术要求

与前几章一样,你可以在我们的 GitHub 仓库中找到一个演示,你可以在这里找到:github.com/PacktPublishing/Modernizing-Enterprise-CMS-using-Pimcore

要运行与本章相关的演示,你需要克隆它,导航到8. 创建自定义 CMS 页面文件夹,并启动 Docker 环境。

要这样做,请遵循以下说明:

  1. 使用以下命令运行 Docker:

    docker-compose up
    
  2. 然后,要恢复本地机器上的所有设置,请输入以下命令:

    docker-compose exec php bash restore.sh
    
  3. 导航到localhost/admin并使用你的管理员/pimcore 凭据登录。

使用此设置,你将获得以下内容:

  • 一个名为MyObject的类定义

  • 该类的两个实例,My Item 1My Item 2

  • 可编辑内容页面,一个展示可编辑内容的示例页面(参见使用可编辑内容

  • 模板页面,一个展示模板辅助工具的示例页面(参见使用 MVC 模型

  • 一个名为MyThumbnails的缩略图预设

现在,你已经准备好玩本章相关的演示了!

使用 MVC 模型

在本节中,我们将学习 MVC(模型-视图-控制器)模型的工作原理以及如何使用它创建一个独立于文档范围的网页。这对于覆盖你在使用 Pimcore 作为内容管理系统过程中可能遇到的所有可能需求非常重要。

MVC 原则非常简单。当一个 URL 与一组规则匹配(路由)时,会激活一个控制器类,并使用某些业务逻辑(控制器)计算数据(模型)。然后,数据被发送到视图,该视图实现展示逻辑并向用户展示内容。

在本节中,我们将介绍使用 MVC 模式构建嵌入式网页的最重要概念:

  • 控制器

  • 视图(模板辅助工具)

  • 路由

让我们详细看看它们。

控制器

Pimcore 控制器实现了 MVC 模式中的 "C" 部分。控制器负责业务逻辑,或者说,它是你的源代码中读取、操作和准备数据以传递给表示层(视图)的部分。将所有可重用逻辑保留在服务类中是一种良好的实践,但连接表示层与业务层的实际点是控制器元素。

Pimcore 提供了一个抽象类(FrontendController),可以用作控制器实现的基类。这意味着你的所有控制器通常都会继承自前端控制器。你的文件命名约定将遵循通用的 Symfony 规则。在简单的场景中,如果你使用 Symfony 的标准来构建网站,你将遵循以下规则:

  • /src/Controller/[Controller].php

  • /templates/[Controller]/[action].html.twig

在控制器内部,你可以创建任何你想要的操作。每个操作负责单一的功能,并与一个 URL 相关联。我们通常为每个主题或同质组或功能(即 CustomerController,它管理所有客户功能)创建一个控制器。如果你省略了操作名称来调用控制器,将使用 default

正如我们在 第四章 中解释的,在 Pimcore 中创建文档,我们可以为每个文档选择一个控制器,Pimcore 提供了一个现成的控制器,称为 DefaultController。我们可以创建与文档无关的控制器,并简单地实现自定义网页。

在控制器内部,你可以访问一些特殊的变量,这些变量可以帮助你定义如何构建所需的输出:

  • $this->document: 如果你正在处理文档,这就是你正在操作的文档。

  • $this->editmode: 表示你是否处于编辑模式,并且可以根据情况用于多样化输出。这适用于你处理文档时。

在接下来的章节中,你将找到一些控制器操作的示例,这些示例涵盖了所有最常见的情况。

将数据传递给视图

以下示例是一个将变量添加到视图中的操作,其中的值只是文本,但想象一下,你可以使用 $request 的输入来计算数据,并添加一个更复杂的数据对象:

    public function dataAction(Request $request)
    {
        $input=$request->get('data');
      return array(
                'content' =>$input
            );     
    }

设置 HTTP 头部

我们可能还有另一个要求,即设置一些 HTTP 头部。如果这些值是固定的,你可以使用注解添加它们,或者你可以使用 addResponseHeader 辅助函数访问和程序化地修改响应对象:

    /**
     * @ResponseHeader("X-Foo", values={"123456", "98765"})
     */
    public function headerAction(Request $request)
    {   
        $response = new Response();
        // using code: 
        $response->headers->set('X-Foo', 'bar'); 
        return $response;
    }

之前的代码为相同的头部添加了三个值:前两个来自注解,另一个来自方法内部的代码片段。

指定模板路径

如果你担心模板的固定约定,我们将通过下一个示例来安慰你。在以下代码片段中,我们将通过手动设置来覆盖正常的模板路径:

    public function differentPathAction()
    {
        return $this->render("Default/default.html.twig", ["foo" => "bar"]); 
    }

或者,你可以手动指定@Template()注解的模板路径,然后只返回数据,如下面的代码片段所示:

/**
* @Template(Default/default.html.twig)
*/
public function differentPathAction()
{
   return return ["foo" => "bar"]; 
}

生成 JSON 输出

尽管 Pimcore 自带了一个强大的 API 引擎和json函数。在下一个示例中,你将看到如何从原始数据创建一个json响应:

    public function jsonAction(Request $request)
    {
        return $this->json(array('key' => 'value'));
    } 

这将输出数据的json序列化为响应的主体,并将内容类型设置为application/json

对于所有其他情况

作为最后的备选方案,如果你对 Pimcore 提供的所有标准解决方案都不满意,你可以选择手动创建一个 Symfony 响应对象,并将其返回给 MVC 引擎。使用此选项,你可以自由设置所有响应参数,包括mime类型到原始内容,没有任何限制。在下一个示例中,我们将返回固定的文本:

    public function customAction(Request $request)
    {
        return new Response("Just some text");
    }
}

之前的代码块返回了一个包含文本内容的响应作为示例。给定Request对象,你可以实现所有想要的代码,然后生成一个自定义的Response

所有的上述操作都旨在包含在一个controller类中,如下所示:

<?php
namespace App\Controller;
use Pimcore\Controller\FrontendController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Pimcore\Controller\Configuration\ResponseHeader;
class MyController extends FrontendController
{
   // Add your actions here
} 

这组示例并不全面,但包含了最重要的功能,是一个很好的起点。你可以在官方文档中找到更多详细信息:pimcore.com/docs/pimcore/current/Development_Documentation/MVC/index.html

视图

本节涵盖了 MVC 模式中的“V”组件。视图是接收数据并通过实现表示逻辑来渲染数据的组件。视图文件可以使用 Twig 或 PHP 模板编写,但正如我们在第四章中提到的,在 Pimcore 中创建文档,我们将只关注 Twig 解决方案,它允许更严格地分离业务和表示逻辑,使 Pimcore 成为一个真正的独立 CMS。这种解决方案的缺点是,你可以在 Twig 文件中实现的逻辑有限,因为它强迫你在控制器中实现所有业务逻辑。这种严格的分离在开始时可能看起来有限制,但当你对模式有信心时,你会同意它更干净、可重用且易于维护。除了所有平台特定的功能,称为助手之外,Pimcore 的 Twig 文件支持所有标准的 Twig 功能。

这里是 Pimcore 最重要的助手列表。

pimcore_object

在以下代码中,我们通过其id(在我们的案例中,2)加载了一个对象,并显示了Title属性:

{% set myObject = pimcore_object(2) %}
{{ myObject.getTitle() }}

我们的对象有一个Title属性,可以通过标准的getTitle 方法访问,因此值将被打印。

pimcore_document

在下一个代码片段中,我们加载了一个文档并打印了标题:

{% set myDoc = pimcore_document(3) %}
title: {{ myDoc.getTitle}} </br>
url: {{ myDoc}}

myDoc元素是 Pimcore 的文档,您可以访问其所有属性。

pimcore_asset

此辅助程序加载一个可用于模板的资产。在下一个例子中,我们加载了一个资产,并显示了filenameurl

{% set myDoc = pimcore_asset(2) %}
url: {{ myDoc}} <br>
filename: {{ myDoc.getFilename}}

或者,您可以使用以下快捷方式通过路径找到资产:

{% set asset = asset('/path/to/image.jpg') %}

如同往常,分配的变量可以在模板文件中用于实现任何展示逻辑。

渲染控制器输出

此函数调用一个任意动作并打印结果。在下一个例子中,我们使用了/custom/json示例,并渲染了输出,传递items=11作为参数:

{{ render(controller('App\\Controller\\CustomController::jsonAction', { items: 11 })) 
}}

参数顺序是动作、控制器、包和参数。

pimcore_cache

Pimcore 的缓存简单地实现了模板内的缓存功能。您可以直接在模板中缓存 HTML 页面的某些部分,而不依赖于其他全局可定义的缓存功能。这对于需要大量计算或需要大量对象(如导航等)的模板非常有用。在下一块代码中,我们将看到缓存的实际应用:

{% set cache = pimcore_cache("cache_key", 60, true) %}
{% if not cache.start() %}
    <h1>If you refresh the page this date will remain the     same</h1>
    {{ 'now'|date('y-m-d') }} v{{ 'now'|date('U') }}
    {% do cache.end() %}
{% endif %} 

参数顺序是键名、秒数超时以及可选的强制在管理员模式下缓存标志。

pimcore_device

pimcore_device函数在实现自适应设计时很有帮助。下一段代码显示了在模板片段中此辅助程序的使用:

{% if pimcore_device().isPhone() %}
    I'm a phone
{% elseif pimcore_device().isTablet() %}
    I'm a table
{% elseif pimcore_device().isDesktop() %}
    I'm a desktop device
{% endif %}

如果您在您的 PC 上运行此脚本,输出将是我是一个桌面设备

请求

从默认的 Symfony 对象中,您可以访问请求数据。这可以通过包含所有所需信息的app.request项来完成。在下一个例子中,我们使用了这种方法来获取页面预览中通常存在的"_dc" URL 参数:

{{ app.request.get("_dc") }}

这只是一个示例,您可以访问所有请求参数。您可以查看官方文档以获取更多信息,请参阅:symfony.com/doc/current/templates.html#the-app-global-variable

术语表

此辅助程序将术语替换为链接。术语表模块是一个强大的工具,使得内部和外部链接变得简单且智能,并且 Pimcore 提供的是即用型。例如,您可以将“Pimcore”这个词与官方网站连接起来,这样每次在 HTML 中使用它时,都会被替换为指向网站的链接。此pimcore_glossary辅助程序将由该辅助程序用于渲染链接。要测试此功能,请按照以下步骤操作:

  1. 前往工具 | 术语表

  2. 点击添加

  3. 文本列中输入术语PIMcore,然后在链接列中输入页面链接。在这个例子中,我们添加了 PIMcore 和 CMS 词及其相关链接。在下一张截图,您将找到结果:图 8.1:术语表项

    图 8.1:术语表项

  4. 现在,术语表已设置,我们可以在任何网页上使用 pimcoreglossary 助手使用它。我们可以通过在网页模板中放置以下代码片段来实现这一点:

    {% pimcoreglossary %}
    My content PIMCore loves CMS
    {% endpimcoreglossary %}
    

    在前面的代码片段中,我们用 glossary 函数包围了文本。因为我们定义了术语表中的单词 PIMcoreCMS,它们将在网页上转换为链接。这是最终结果:

![图 8.2:术语表助手在行动中图片

图 8.2:术语表助手在行动中

这是一个简单的示例,用于解释概念,但它展示了此功能是多么强大。

pimcore_placeholder

此助手将自定义占位符添加到模板中。下一个代码片段定义了一个名为 myplaceholder 的占位符,该占位符配置用于构建围绕 "My content" 值的 H3 标签:

{% do  pimcore_placeholder('myplaceholder')
.setPrefix("<h3>")
.setPostfix("</h3>")
.set("My content") %}
{# Print placeholder #}
{{ pimcore_placeholder('myplaceholder') }}

此输出的结果是 <h3>My content</h3>

此助手收集头部链接列表(样式表或任何其他 head link 标签)并在网页的头部区域打印它们。根据展示逻辑,链接被收集(您可能包括或不包括文件,基于某些特殊条件)然后一次性打印。

在以下示例中,代码片段将 favicon(收藏夹图标——您在浏览网站时在浏览器标签中看到的标志)添加到链接列表中:

{% do  pimcore_head_link({'rel' : 'icon', 'href' : '/img/favicon.ico'},"APPEND")  %}
{# Print head links#}
{{ pimcore_head_link()}}

在示例中,我们将 favicon 添加到列表中。使用正确的 pimcore_head_link 配置,我们还可以使用相对包含(例如,在文件 y 之后添加文件 x)来定义顺序。

pimcore_head_meta

此助手打印 HTTP 元标签。它可以收集一组将在头部区域打印一次的项目。在下一个代码块中,类似于 HeadLink 助手,数据通过最终调用收集并打印到函数中:

{% do pimcore_head_meta().appendName('description', 'My SEO description for my awesome page') %} 
{# adding addictional properties #}
{% do pimcore_head_meta().setProperty('og:title', 'my article title') %}
{# Print tags #}
{{ pimcore_head_meta() }}

pimcore_head_script

这与 HeadLinkStyle 相同,但用于 JavaScript 文件。下一个代码块将脚本添加到列表中,然后将其打印到页面上:

{% do pimcore_head_script().appendFile("/myscript.js") %}
{# Print tags #}
{{ pimcore_head_script()}}

pimcore_head_style

此助手管理内联样式。它类似于 HeadLink,但带有内联脚本。在下一段代码中,我们添加了一个名为 ie.css 的文件,该文件具有条件包装,在这种情况下,将 CSS 操作限制在版本 11 之前的 Internet Explorer 中:

{% do pimcore_head_style().appendStyle("ie.css", {'conditional': 'lt IE 11'}) %}
{# Print tags #}
{{ pimcore_head_style() }}

pimcore_head_title

创建并保存 HTML 文档的 <title> 以供以后检索和输出。以下脚本将特殊的 title 标签添加到页面中:

{% do pimcore_head_title('My first part') %}
{# Print tags #}
{{ pimcore_head_title() }} 

pimcore_inc

此助手在页面中包含 Pimcore 文档。在下一个代码片段中,我们看到 MySnippet 文档是如何渲染并添加到页面中的:

{{ pimcore_inc('/MySnippet') }}

pimcore_inline_script

此助手向页面添加内联脚本。用法与 HeadScript 非常相似,但旨在内联使用。下一个代码块将 myscript.js 添加到列表中,然后将其打印到页面上:

{% do pimcore_inline_script().appendFile("/myscript.js") %}
{# Print tags #}
{{ pimcore_inline_script() | raw }}

导航

此助手负责生成并添加导航菜单。在下一个代码块中,您将找到一个示例,该示例根据文档层次结构打印菜单:

{% set mainNavStartNode = document.getProperty('mainNavStartNode') %}
{% set navigation = pimcore_build_nav({
    active: document,
    root: mainNavStartNode
}) %}
{# Print tags #}
{{ pimcore_render_nav(navigation) }}

在片段中,它渲染了一个从mainNavStartNode(根文档)开始的菜单,并使用当前文档作为活动文档。

您可以参考官方文档以获取有关导航的更多信息:pimcore.com/docs/pimcore/current/Development_Documentation/Documents/Navigation.html.

include

此助手直接在页面中包含一个模板。看看以下脚本:

{{ include("Default/include.html.twig", {'par':'value'}) }}

此脚本包括Default/include.html.twig模板,您可以在其中使用作为输入传递的参数集。

翻译

这是在 Pimcore 引擎中集成的 Symfony 功能。使用管道过滤器,您可以使用翻译数据库转换文本,并用翻译版本替换原始文本。为此,请执行以下操作:

  1. 创建一个文档并将其分配给一个模板。

  2. 将以下片段添加到模板中:

    {% set message ="my-test-key" %} 
    {{ message|trans }}
    

    此脚本设置一个具有字符串值(my-test-key)的变量,然后使用trans过滤器打印它。

  3. 在第一次使用标签后,将在您的后端创建一个条目,并且您可以为每种语言设置一个值。转到工具 | 共享翻译。通过在表中输入数据为每种语言设置标签的值:![Figure 8.3: 共享翻译面板

    ![img/Figure_8.03_B17073.jpg]

    Figure 8.3: 共享翻译面板

  4. 打开网页并查看翻译后的文本。

翻译功能非常有用且易于管理,因为它具有直观的界面。

网站配置

Pimcore 有一组易于通过网页界面编辑的配置关键字。您可以从设置 | 网站设置中添加它们,然后可以将值插入模板或控制器中。为此,请执行以下操作:

  1. 创建一个文档并分配一个模板。

  2. 设置 | 网站设置打开网站设置管理。

  3. 在顶部编辑栏中输入设置的关键字并选择文本选项。

  4. 点击+按钮,值将在表中显示。您只需在网格中输入文本即可编辑它。在下一张屏幕截图中,您将看到最终结果。在这个例子中,我们添加了一个名为mykey的键,其值为My Value:![Figure 8.4: 网站设置面板

    ![img/Figure_8.04_B17073.jpg]

    Figure 8.4: 网站设置面板

  5. 现在将以下片段添加到模板中:

    {{ pimcore_website_config('mykey') }}
    

    使用前面的代码,您将得到助手的结果MyValue

可视化编辑设置非常有用,因为它允许我们创建可配置的模板和网站,这些模板和网站可以轻松集中管理。

instanceof

instanceof构造非常有用,可以检查一个对象是否为特定类型。在下一段代码中,我们将检查资产实例是否为Image类型:

{% if item is instanceof('\\Pimcore\\Model\\Asset\\Image') %}
    {# print the image #}
{% elseif is instanceof('\\Pimcore\\Model\\Asset\\Video) %}
    {# print the video #}
{% endif %} 

这个功能很重要,因为它可以改变代码流程,使其根据对象类型完成或未完成任务。在之前的例子中,我们获取了一个可能是视频或图像的对象,并且我们可以根据类型正确地显示它。

缩略图

当您处理图像时,以正确的大小打印它们是基本的。Pimcore 的缩略图功能在模板制作中非常有帮助。我们可以从管理界面定义资产缩略图;您应该已经在第五章**,探索对象和类中发现了这个主题。让我们通过几个简单的步骤来查看这个功能:

  1. 创建一个网页并将其分配一个模板。

  2. 前往设置 | 缩略图 | 图像缩略图

  3. 添加一个具有以下截图所示设置的缩略图配置:![图 8.5:缩略图设置 图 8.05_B17073.jpg

    图 8.5:缩略图设置

    我们使用了PNG格式,并将按高度缩放设置为200。现在我们将上传的图像将会有一个合适的缩略图。

  4. DAM部分上传一个图像。在菜单的资产部分右键单击并选择上传文件选项:![图 8.6:上传图像 图 8.06_B17073.jpg

    图 8.6:上传图像

  5. 演示示例已经包含了一个 ID 为 2 的 Pimcore 标志图像。要获取缩略图,您只需通过路径或 ID 获取资产,然后渲染它。下面的代码片段就是这样做。将代码片段复制到模板中:

    {% set asset = pimcore_asset(2) %}
    {{ asset.getThumbnail('MyThubnails').getHtml() | raw }}
    

    脚本获取图像的缩略图(第一次使用时生成的文件)并将图像标签打印到文档中。

  6. 下一个示例获取了一个没有配置定义的即时缩略图。将此代码复制到模板中并查看结果:

    {{ asset.getThumbnail({
        width: 50,
        format: 'png'
    }).getHtml() | raw }}
    

    这个例子与上一个例子非常相似,但使用了不是由缩略图配置预定义的设置。

整个函数列表涵盖了 Pimcore 为我们提供的开箱即用的功能集。此外,您还将拥有所有默认的 Symfony 函数,您可以通过官方文档来发现它们:https://symfony.com/doc/current/reference/twig_reference.html。

但如果你既没有使用 Pimcore 也没有使用 Symfony 实现你所需要的功能,你应该怎么办?如果我们谈论的是业务逻辑,那么一个更简单的解决方案是在控制器内部操作数据,并为视图生成干净的输出。在某些情况下,我们可能需要实现一些复杂的展示逻辑,这些逻辑很难用 Twig 语法来管理。此外,我们不想将这种逻辑移动到控制器中(那里很容易实现),因为这将在模板和控制器之间创建耦合,而这不是我们想要的(你还记得我们在第一章**,介绍 Pimcore)时讨论的分离解决方案的好处吗?在下一节中,我们将提供在模板中实现复杂展示逻辑的解决方案,我们将看到如何向模板引擎添加方法并为我们的项目实现可重用的助手。

实现你自己的模板助手

在上一节中,我们学习了如何使用模板助手来生成动态内容。现在,是时候学习如何扩展模板助手系统并在集合中添加自己的函数了。在下一个示例中,我们将创建一个模板助手,它将以指定的格式显示当前日期和时间。你可能会有异议,因为 Twig 模板已经提供了类似的功能,但请记住,这是一个解释模板助手扩展的示例,所以最好将我们的案例研究保持尽可能简单。现在,按照以下步骤操作:

  1. /src/Templating/Helper/Timestamp.php 中创建一个文件。

  2. 然后在 Timestamp.php 文件中复制以下代码段:

    <?php
      …
    class Timestamp  extends AbstractExtension
    {    
        public function getFunctions()
        {
            return [
                new TwigFunction('timestamp', [$this,             'timestamp']), 
            ]; 
        }    
        public function timestamp(String $format)
        {     
           echo date($format);
        }
    }
    

    getFunctions 是一个特殊函数,它列出了从这个扩展公开的所有助手扩展。在我们的例子中,我们有一个名为 timestamp 的函数。这个函数根据用户接收到的格式计算文本日期表示。这个函数映射到名为 timestamp 的命令,并可以在模板引擎中使用。为了简单起见,我使用了计算结果的函数作为助手名称,但你也可以选择自己的名称。

  3. 使用 YAML 配置注册代码片段。打开 / config/services.yml 文件并添加以下内容:

    Services: 
         …
        App\Templating\Helper\Timestamp:
            public: true
            tags:
                - { name: templating.helper, alias:             timestamp}
    
  4. 现在时间戳助手已注册在模板引擎中,因此我们可以在我们的 Twig 文件中调用它。复制以下代码段:

    {{ timestamp("Y-m-d") }}
    

    你将得到类似 2020-11-03 的结果。

在本节中,我们学习了如何向模板引擎添加功能。这对于代码重用和克服 Twig 语法限制是有益的。在下一节中,我们将学习如何掌握路由规则,将 URL 与控制器连接起来。

掌握路由和 URL

掌握自定义页面的最后一步是路由。我们在第四章在 Pimcore 中创建文档中了解到,每个文档都有一个路径,可以通过文档编辑界面进行更改。如果我们不是在处理文档,而是在处理自定义页面呢?在本节中,我们将了解 Pimcore 提供的选项,如下所示:

  • 固定路由,按照 Symfony 标准。

  • 静态路由,可由管理界面更改的可配置路由。

  • 重定向,可以使用友好的管理界面设置 HTTP 重定向。对于那些不熟悉重定向的人来说,想象一下它是一种将浏览器从一个 URL 重定向到另一个 URL 的方式。这在页面更改 URL 或我们需要将网站从一个域名迁移到另一个域名时非常常见。

让我们详细看看它们。

固定路由

要添加路由,没有比将其添加到配置更复杂的了。这些设置包含在routing.yml文件中,这些规则遵循你可以在这里找到的 Symfony 标准:https://symfony.com/doc/current/routing.html。

在接下来的代码片段中,我们可以看到一个规则的示例:

custom_rule:
    path:      /custom/actionname/{parameter}
    controller: App\Controller\CustomController:myaction
    defaults:
     parameter: "my default value"

对于我们的目的来说,最相关的设置如下:

  • name:规则有一个必须唯一的名称;在我们的例子中,它是custom_rule

  • path:这是规则正在监听的路径;它可以包含正则表达式和获取参数(在我们的例子中,parameter)。

controller:这是控制器,包括动作名称;它支持 Symfony 语法。如果你写下App\Controller\CustomController:myaction,你将在应用程序的CustomController控制器中激活myaction

  • 对于每个参数,如果参数是可选的,你可以为其提供一个默认值。

注意,即使我们使用了可理解的命名约定,你也可以定义任何规则。URL 内部(或查询路径)的参数将被解析并传递给动作。

如果你愿意,第二个选项是将路由作为控制器动作的注解。前一个规则的等效如下:

   /**
     * @Route("/custom/actionname/{parameter}", name="custom_     rule")
     */
    public function myaction(string $parameter)
    {
        // ...
    }

路由规则是双向的,因此它可以从参数值生成 URL,也可以从 URL 中获取参数值。例如,假设你有一个用于产品 URL 的/product/{id}规则。如果用户在浏览器中输入/product/5,路由引擎能够告诉你 ID 参数是 5。另一方面,你可以要求引擎为 ID 为 5 的产品生成 URL,你将得到/product/5。简单来说,你可以从规则名称和参数自动构建 URL。这可以通过路径助手轻松完成:

{{% pimcore_path('custom_rule', {'parameter': 67}); }}

这将生成完整的 URL,/custom/actionname/67

可配置路由

在上一节中使用的前置规则是一个很好的解决方案,但它是静态的,您需要访问源代码来理解或更改它们。Pimcore 提供的另一种解决方案是使用管理 UI 可视地定义它们。在设置 | 静态路由下,您可以找到一个表格,您可以输入路由规则的所有值(包括名称、模式、参数名称和构建规则)。这使得规则管理变得非常容易,您可以在不访问源代码的情况下监控您有多少规则以及它们的配置。

您可以按照以下步骤查看此方法的效果:

  1. 创建一个控制器调用者,CustomController

  2. 在控制器中添加一个名为data的操作,类似于以下内容:

    /**
         * @Template() 
         */    
        public function dataAction(Request $request)
        {
          $input=$request->get('data');
          $content = "data to show $input";       
          return array(
               'content' => $content,
          );    
        }
    

    此代码将从 URL 中获取data参数,并通过content变量将其传递给视图。

  3. 在控制器文件夹中创建一个名为data.html的视图。添加以下代码:

    {{ content }}
    

    此脚本将打印content变量。

  4. 打开custom

  5. /\/custom_data\/(.*)\//。请注意,\/用于在正则表达式中转义/字符,因此像/custom_data/anything/这样的 URL 将被匹配。由选择器(.*)匹配的参数是anything部分。

  6. CustomController

  7. data

  8. /custom_data/%data/。使用此值,路由引擎将能够生成 URL,/custom_data/value/,如果您使用可编辑的{{% pimcore_path('custom', {'data': 'value'}); }}

  9. data。这意味着(.*)的值将被命名为data

  10. empty。在这种情况下,如果省略了参数,参数数据将具有文本empty作为其值。

  11. 打开您的浏览器并导航到localhost/custom_data/myvalue。您将在页面上看到打印的myvalue参数。

与前面的示例类似,我们可以使用规则名称和参数通过模板助手生成 URL。

您通过管理 UI 编辑的设置保存在一个 PHP 配置文件中(var/config/staticroutes.php),因此也可以直接编辑代码或将它们提交到 Git 存储库。下一部分代码显示了通过添加前面的规则所获得的内容:

<?php 
return [
    1 => [
        "id" => 1,
        "name" => "custom",
        "pattern" => "/\\/custom_data\\/(.*)?\\//",
        "reverse" => "/custom_data/%data/",
        "module" => NULL,
        "controller" => "@App\\Controller\\        CustomController:dataAction",
        "variables" => "data,",
        "defaults" => "empty",
    ]
];

当您希望保持 URL 路由灵活,允许用户在运行时选择路径时,可配置的路由非常有用。这对于匹配客户关于 URL 的规格变更(可能是由于 SEO 需求的变化)至关重要,而无需修改任何一行代码。

重定向

重定向是 Pimcore 的一个有用功能,可以将用户引导到正确的页面——无论是用于营销 URL,还是用于网站重新发布后的重定向,或者是移动文档的重定向。

创建重定向的过程非常简单。只需遵循以下步骤:

  1. 导航到系统 | 重定向。此菜单将打开一个类似于这个的表格:图 8.8:重定向表格

    图 8.8:重定向表格

  2. 点击添加按钮。您将看到一个以下弹出窗口:![Figure 8.9:添加重定向 img/Figure_8.09_B17073.jpg

    图 8.9:添加重定向

    类型下拉菜单允许您选择重定向的类型,而目标允许您选择将源重定向到目标 URL 的映射规则。

  3. 目标框中输入 /\/redirect\/(.*)//custom_data/$1,就像在 图 8.9 中所示。

  4. 打开浏览器并导航到 localhost/redirect/xxx/。您将被重定向到 http://localhost/custom_data/xxx/。

在本节中,我们学习了如何使用 MVC 模型创建自定义网页。特别是,我们涵盖了所有最重要的主题:

  • 控制器:我们了解了控制器如何与请求参数交互并将数据传递给视图。在控制器内部,我们可以实现我们的业务逻辑而没有任何限制。

  • 视图:我们学习了模板引擎的工作原理以及我们如何使用助手来实现表示逻辑。

  • 路由和 URL:我们学习了如何正确管理页面的 URL。我们没有将自己限制在 Symfony 的标准路由上,还涵盖了静态路由和重定向选项。有了所有这些选项,我们可以根据我们的用例选择正确的解决方案。最重要的是要知道,这个广泛的选项集赋予我们解决我们可能遇到的任何 URL 问题的能力。

在下一节中,我们将深入探讨 Pimcore 可编辑,并学习如何将它们组合起来以获得结果,而无需编写大量的代码。

使用可编辑

正如我们在 第四章 在 Pimcore 中创建文档 中所介绍的,Pimcore 的可编辑是一组可视化组件,可用于在 CMS 页面上输入信息,并且能够渲染输出以准备网页。您应该记住 pimcore_inputpimcore_wysiwyg 组件;好消息是 Pimcore 有很多这样的组件,并覆盖了您的大部分用户需求。在本节中,我们将查看这些组件。

重要提示

可编辑列表中,我们应该有区域区域块组件,但在此章节中我们不会讨论这些。这些元素与砖块结合,是 Pimcore 中代码重用的支柱,将在 第十章 创建 Pimcore 砖块 中介绍。动机是,如果不了解砖块是什么,区域、区域块和块组件将难以理解。

在下一节中,我们将发现可用的可编辑列表。对于每一个,我们将添加一段代码片段来向您展示如何将其添加到您的代码中,对于更复杂的项,我们还有一些截图来解释交互。

在您的实时 Pimcore 环境中测试可编辑的过程如下:

  1. 将文档添加到你的 CMS 中,并将其链接到模板。这个过程在第四章**,在 Pimcore 中创建文档中有详细描述。

  2. 复制以下子节中的代码片段。

  3. 进入页面编辑器,看看组件的外观。

  4. 打开页面预览,查看保存在可编辑区域内的数据。记住,通过使用 {{ pimcore_xxx('name') }},你可以打印数据,但你也可以将其设置为变量,使用 {% set var = pimcore_xxx('name') %},然后实现自己的展示逻辑。

所有这些示例都包含在 editable.htm.twig 模板中,该模板用于可编辑页面,你可以在与本章相关的演示中找到。

复选框

以下可编辑内容添加了一个可以被页面编辑器勾选的复选框:

{{ pimcore_checkbox('myCheckbox') }} 

该值可用于实现一些渲染逻辑(即根据 myCheckbox 值显示或隐藏某些内容)。

日期

此代码片段向网页添加了一个 DateTime 选择器:

{{ pimcore_date('myDate', {
    'format': 'd.m.Y',
    'outputFormat': '%d.%m.%Y'
    })
}}

当编辑页面时,你将看到如这里所示的可编辑 DateTime 选择器:

![图 8.10:日期选择器操作界面图片

图 8.10:日期选择器操作界面

在页面渲染过程中,当你不在编辑模式时,该函数输出用户在编辑器中选择的值。此值可以显示或用于实现展示逻辑。

关系(多对一)

此可编辑内容提供了将 relation 添加到对象的机会。你可以选择你想添加哪些类型的元素(例如,assetobject)以及哪些子类型。在以下示例中,我们只允许 MyObject 类型的类:

{{ pimcore_relation("myRelation",{
    "types": ["asset","object"],
    "subtypes": {
        "asset": ["video", "image"],
        "object": ["object"],
    },
    "classes": ["MyObject"]
}) }}

此组件一旦添加到页面,就会显示为一个简单的编辑框,你可以拖动你想要显示的项目,如下面的截图所示:

![图 8.11:关系配置图片

图 8.11:关系配置

然后,名为 myRelation 的关系将包含你的选择值,你可以在模板中使用它来渲染数据。

在以下示例中,我们将添加一个链接按钮,用于导航到所选项目:

<a href="{{ pimcore_relation("myRelation").getFullPath() }}">{{ "Go to" }}</a>

之前的代码片段将在文本中显示一个链接。

关系(多对多关系)

这个可编辑内容类似于多对一关系,但允许你选择对多个其他元素的引用(例如文档、资产和对象)。以下代码片段与上一个用例相同,但由于这个可编辑内容有多个引用,我们使用了 for 循环来列出所有选定的选项:

{% if editmode %}
    {{ pimcore_relations("objectPaths") }}
{% else %}
<ul>
    {% for element in pimcore_relations("objectPaths") %}
        <li><a href="{{ element.getFullPath }}">{{  element.getTitle  }}</a></li>
    {% endfor %}
</ul>
{% endif %}

现在我们可以拖放多个项目:

![图 8.12:关系配置图片

图 8.12:关系配置

选择的结果如下表所示:

![图 8.13:编辑模式下的关系图片

图 8.13:编辑模式下的关系

在我们的沙盒数据中,我们将得到如下内容:

图 8.14:关系的输出

图 8.14:关系的输出

图片

此可编辑器为您提供了一个可以上传图片的小部件。如果您从资产文件夹中拖动一个文件并将其放在组件上,图片将被显示。与关系组件相比的优势在于图片更容易使用且与缩略图系统集成。

下一行代码允许您上传图片:

{{ pimcore_image("myImage", {
    "title": "Drag your image here",
    "thumbnail": "myThumbnails"
}) }}

您可以上传图片或将它们拖放到小部件中,如下面的屏幕截图所示:

图 8.15:图片配置

图 8.15:图片配置

输入

输入允许用户输入一行文本,我们可以使用输入来渲染 HTML:

{{ pimcore_input("myHeadline") }}

我们在*第四章**,在 Pimcore 中创建文档中使用过它;关于此可编辑器没有更多要添加的内容。

链接

这是一个用于渲染链接的组件:

{{ pimcore_link('blogLink') }}

以下屏幕截图显示了编辑模式中的链接:

图 8.16 – 编辑模式中的链接组件

图 8.16 – 编辑模式中的链接组件

组件包含两个按钮:打开所选链接的文件夹和打开设置表单的编辑按钮(铅笔图标)。下一个屏幕截图显示了弹出窗口和链接可用的参数:

图 8.17:链接配置

图 8.17:链接配置

完成后,结果是一个包含文本和目的地的 HTML 链接。

选择

此代码片段添加了一个选择组件,允许用户从一组项目中选择。以下代码片段显示了它是如何工作的:

{% if editmode %}
    {{ pimcore_select("myItem", {
            "store": [
                ["option1", "Option One"],
                ["option2", "Option 2"],
                ["option3", "Option 3"]
            ],
            "defaultValue" : "option1"
        }) }}
{% else %}    
    Your choice:{{ pimcore_select("myItem").getData() }}    
{% endif %}

store参数包含一个数组列表。每个项目由两个元素的数组组成:第一个是键,第二个是值。defaultValue设置配置了所选列表项的默认值。

这是在编辑模式中显示的内容:

图 8.18:选择配置

图 8.18:选择配置

多选

多选组件与选择组件非常相似,但它允许多项选择:

{{% pimcore_multiselect("categories", [
        "width" => 200,
        "height" => 100,
        "store" => [
            ["cars", "Cars"], 
            ["motorcycles", "Motorcycles"],
            ["accessories", "Accessories"] 
        ]
    ]) %}} 

这是在编辑模式中显示的内容:

图 8.19:多选配置

图 8.19:多选配置

数字

此可编辑器类似于输入,但专门用于数字:

{{ pimcore_numeric('myNumber') }}

这是在编辑模式中显示的内容:

图 8.20:数字编辑器

图 8.20:数字编辑器

在编辑模式下,它返回所选的数字。

Renderlet

Renderlet是一个特殊的容器,能够渲染一个对象。它使用控制器和操作来处理所选项目,并将生成的 HTML 提供给用户:

{{
     pimcore_renderlet('myGallery', {
          "controller" : "App\\Controller\\          CustomController::galleryAction",
          "title" : "Drag an asset folder here to get a           gallery",
          "height" : 400
     })
}}

在这种情况下,我们需要额外的步骤来测试它。按照以下步骤操作:

  1. /app/Resources/views/Default文件夹内添加一个名为gallery.php的模板文件,并添加以下代码以渲染您的数据:

    {% if assets %}
              {% for asset in assets %}
                   {% if asset is instanceof(
                   '\\Pimcore\\Model\\Asset\\Image') %}
                    <div style="border: 1px solid red; 
                    width:200px; padding 10px; 
                    margin:10px;">
                        {{ asset.getThumbnail(
                          'MiniIcons').getHTML()|raw}}
                    </div>
                   {% endif %}
              {% endfor %}
    {% endif %}
    
  2. 使用以下代码向默认控制器添加一个操作:

       /**
         * @Template() 
         */    
        public function galleryAction(Request $request)
        {
            $result=array();
            if ('asset' === $request->get('type')) {
                $asset = Asset::getById($request->get('id'));
                if ('folder' === $asset->getType()) {
                    $result["assets"] = $asset-                >getChildren();
                }
            }
            return $result;
        }
    
  3. 然后在页面中添加一个具有以下配置的Renderlet可编辑:

    {{
         pimcore_renderlet('myGallery', {
              "controller" : "App\\Controller\\          CustomController::galleryAction",
              "title" : "Drag an asset folder here to get a           gallery",
              "height" : 400
         })
    }}
    

    这个配置告诉 Pimcore 使用Default控制器中的galleryAction操作来渲染数据。

  4. 将一个文件夹拖放到Renderlet中;这就是编辑模式中显示的内容:

图 8.21:将文件夹拖放到 Renderlet 中

图 8.21:将文件夹拖放到 Renderlet 中

以普通用户查看页面,并查看你的模板的结果:

图 8.22:使用示例模板的输出

图 8.22:使用示例模板的输出

片段

这个组件用于在文档中包含一个文档或片段(一种特殊的文档类型);这对于在页面上重用脚本或网站的部分非常有用:

{{ pimcore_snippet("mySnippet", {"width": 250, "height": 100}) }} 

一旦你输入了代码,这就是如何在网页中添加一个片段的方法:

图 8.23:片段控制的配置

图 8.23:片段控制的配置

作为网站用户,你会看到以下内容:

图 8.24:片段控制输出

图 8.24:片段控制输出

在上一个截图中,文本我是默认模板来自片段。

表格

这个可编辑创建一个表格,并允许编辑器定义其中的数据。你可以指定默认的列数(cols)或行数(rows)。你还可以在data参数中添加数据矩阵(数组数组)。用户将能够自行添加行和列。以下是一个可编辑的示例:

{{ pimcore_table("productProperties", {
    "width": 700,
    "height": 400,
    "defaults": {
        "cols": 3,
        "rows": 3,
        }
    })
}}

这就是生成的编辑器界面:

图 8.25:表格控制的配置

图 8.25:表格控制的配置

这就是默认的渲染结果:

图 8.26:表格输出

前一个图看起来不太美观,因为组件输出的是一个没有样式的简单 HTML 表格。当然,基于你的 CSS 主题,你可以应用所有你想要的样式,使其与你的网站设计保持一致。

文本区域

这与输入可编辑非常相似,但使用的是Textarea组件:

{{ pimcore_textarea("myTextarea",
   {"placeholder": "My Description" }) 
}} 

视频

这个可编辑功能允许你将电影资产插入到你的页面内容中。它与图像组件非常相似,但用于视频。你需要添加以下代码片段来激活它:

  {{ pimcore_video('campaignVideo', {
        width: 700,
        height: 400
    }) }}

然后,你将能够定义源(本地资产或外部链接)并微调一些选项:

图 8.27:视频控制

图 8.27:视频控制

在网页上,你将看到它在一个视频播放器中,如下截图所示:

图 8.28:视频控制输出

图 8.28:视频控制输出

视频可编辑是一个非常强大的解决方案,允许用户在不上传和管理视频时无需寻求开发者的帮助。

WYSIWYG

这个所见即所得编辑器用于输入 HTML 内容。在下一段代码中,有一个可编辑使用的示例:

{{  pimcore_wysiwyg("specialContent")     }}

我们在第四章**,在 Pimcore 中创建文档中使用过它;没有更多要添加的内容。

在本节中,我们看到了最重要的可编辑内容的概述。使用它们作为我们创建的网页的基础组件,使我们能够完全自定义 HTML 的任何方面。此外,有了这个庞大的选项集,您需要比为用户添加输入并模板化收集到的数据更多的场合非常少。一般来说,您不需要编写代码来满足客户的需求,只需模板化页面即可。

关于可编辑的更多信息,您可以在以下 URL 的官方文档中进行咨询:pimcore.com/docs/pimcore/current/Development_Documentation/Documents/Editables/

在下一节中,我们将了解块的使用方法,这些是简单的工具,有助于创建动态页面。

使用块

Pimcore 块是一个非常聪明的系统,用于迭代页面的一部分。例如,如果您有一个由水平带或标题段落组成的标准页面,您可以定义一段 HTML 代码,说明每个项目应该如何看起来,并允许用户添加他们想要的任意数量的项目。作为另一个例子,您可以定义一个由 H2 标题和文本组成的块,这将为您网页创建许多标题段落。或者,您可以使用带有图像的块来创建一个画廊,迭代这些块。此外,您还可以通过安排发布来管理块的可视性。

正规块

pimcore_iterate_block可以返回块列表。在for循环内包装的所有代码都可以根据用户的意愿复制任意多次。

块迭代与常规for循环的区别在于,在块的情况下,用户定义他们想要多少项,并且所有在可编辑区域内的数据输入都将被持久化。

定义块的语法非常简单,我们可以在下一个片段中看到之前提到的函数的使用:

{% for i in pimcore_iterate_block(pimcore_block('block name')) %}
    My content
{% endfor %}

在下一个示例中,我们将看到在动作中的块,它遍历一个带有标题和文本的小型模板,构建一个带有标题段落的网页:

  1. 创建一个页面,并将页面与模板链接,就像我们之前多次做的那样。如果您有任何疑问,请参阅第四章**,在 Pimcore 中创建文档

  2. 将以下片段复制到模板中:

    {% for i in pimcore_iterate_block(pimcore_block('contentblock')) %}
        <h2>{{ pimcore_input('title') }}</h2>
        <p>{ pimcore_wysiwyg('content') }}</p>
    {% endfor %}
    
  3. 模板部分由一个title组成,被H2标签和paragraph包围。在下一张屏幕截图中,您将看到在添加块之前我们的代码在编辑模式下的结果:图 8.29:向列表添加块

    图 8.29:向列表添加块

  4. 前往页面编辑器,点击绿色+图标以将一个块添加到块列表中。现在块在编辑器中可见,您将能够输入数据。您可以添加任意多个块;您将能够在后端逐个编辑它们。

  5. 现在将数据输入到可编辑内容中。在这个例子中,我将我的第一个条目作为标题,放在长文本中。输出将类似于以下屏幕截图:图 8.30:在块列表中编辑元素

    图 8.30:在块列表中编辑元素

  6. 可以迭代任意多个块。

    最终结果在网页上看起来将如下所示:

图 8.31:添加更多元素后的结果

图 8.31:添加更多元素后的结果

计划块

计划块组件与块非常相似,但它有定义内容过期日期的选项。语法与下一片段中所示相同:

{% for i in pimcore_iterate_block(pimcore_scheduledblock('block')) %}
    <h2>{{ pimcore_input('blockinput') }}</h2>
    <p>{{ pimcore_image('myimage') }}</p>
{% endfor %}

测试此代码片段的过程与上一节中我们看到的标准块完全相同。

在下一张屏幕截图中,我们将看到计划块的编辑模式,其中靠近绿色+图标有一个DateTime选择器,允许用户定义内容何时过期:

图 8.32 – 编辑计划块

图 8.32 – 编辑计划块

块引擎是一个非常强大的系统,它允许用户轻松地将动态页面制作成易于编辑。当我们将在第十章“创建 Pimcore 砖块”中使用块与砖块结合来创建完全动态的模板时,我们将更加欣赏这个功能。无论如何,到目前为止我们所学的都是非常有趣的:我们可以通过一种结构化的方法给用户机会来管理重复的模板。

摘要

在本章中,我们学习了创建自定义 CMS 页面所需的所有信息。我们了解了 MVC 模型,并深入研究了 Pimcore 的模板引擎,发现了所有助手以及如何创建自己的助手。我们还学习了如何在控制器中编写后端代码,并通过定义路由规则使其工作。我们了解到在 Pimcore 中有许多管理 URL 的方法(硬编码、静态路由和重定向),并且它们涵盖了网站的所有用例。然后我们对可编辑内容进行了全面概述,这使得我们能够仅通过模板化来掌握任何自定义网页。最后,我们发现了允许通过给用户机会管理网页中的重复模式来迭代模板片段的块系统。

这是一个内容丰富的章节,为我们提供了关于自定义 CMS 页面的全面知识。在这里学到的内容将在下一章,第九章,配置实体和渲染数据中非常有用,我们将利用这些知识来渲染网页,以实现一个简单的博客引擎。

第九章:第九章:配置实体和渲染数据

在上一章中,我们学习了模型-视图-控制器MVC)开发模式的工作原理,然后学习了视图和模型控制器是什么。我们还看到了 Pimcore 路由系统的工作原理以及如何创建元素之间的关系。最后,我们看到了如何修改我们实体的内容,添加图片、文本和日期字段。

在本章中,我们将创建一个博客,我们将涵盖以下主题:

  • 定义博客类

  • 创建博客用户和角色

  • 路由

  • 编辑我们博客的控制器

  • 渲染博客视图

  • Pimcore 与 WordPress 之间的区别

到本章结束时,我们将使用 Pimcore 构建我们的第一个博客,文章按类别和作者分组。我们还将学习如何为每个页面创建合适的模板,并插入必要的代码以显示创建的内容。

技术要求

与前几章一样,有一个可以在我们的 GitHub 仓库中找到的演示,你可以在这里访问:

github.com/PacktPublishing/Modernizing-Enterprise-CMS-using-Pimcore/

要运行与本章相关的演示,你只需要导航到Full Demo文件夹并启动 Docker 环境。

要阅读本章,唯一的要求是拥有一个运行中的 Pimcore 安装,并且能够通过命令行访问它。

如果你使用 Docker 安装了 Pimcore,只需运行以下简单指令:

  1. 使用以下命令运行 Docker:

    docker-compose up
    
  2. 通过运行此命令恢复本地安装设置:

    docker-compose exec php bash restore.sh
    
  3. 导航到http://localhost/admin并使用你的管理员/pimcore 凭据登录。

现在,你已经准备好将本章相关的所有方面付诸实践。

定义博客类

正如我们所说,一个博客由文章和类别组成,因此我们首先需要做的步骤是创建两个与这些相关的类。除了这两个类之外,我们还需要创建第三个类:BlogAuthor

我们将在我们的类中使用的所有字段类型已经在第五章,“探索对象和类”中看到并详细描述,因此在本章中我们感兴趣的是用它们的名称和类型来定义它们。

我们唯一使用的新元素是slug字段,因此我们将简要描述它。

/slug

使用短横线(slug)因此允许我们通过一个可读性和可识别性更强的文本来识别一个页面,例如,与它的数字标识符ID)相比。此外,这也有助于提高搜索引擎对页面的索引,因为搜索引擎更喜欢基于文本的 URL 而不是数字 URL。

让我们看看我们现在计划创建的每个类。

定义 BlogArticle 类

BlogArticle 类是我们为博客生成文章的地方。这个类的创建已经在第四章中讨论过,即在 Pimcore 中创建文档;以下列表中的字段是任何文章的标准字段,但您可以根据需要添加更多:

  • Title:输入字段

  • Content:所见即所得(WYSIWYG)组件

  • CategoryBlogCategory类的多对一关系

  • Slug:别名字段

  • Author:与BlogAuthor类的多对一关系

  • Image:图像组件

让我们直接跳到我们创建的类将是什么样子。为了方便,我们将字段分组到标签页中,以便使数据输入更加线性。在下一个截图中,这里展示了新创建的类的样子:

图 9.1:BlogArticle 类

图 9.1:BlogArticle 类

如您从前面的截图中所见,所有字段都组织得很好,并且由于各自的图标,很容易识别。

定义 BlogCategory 类

类别类相对简单——正如我们所说的,它是一个文章的容器。它用于按主题分组文章,因此只需要几个简单的字段,如下所示:

  • Title:输入字段

  • Slug:别名字段

  • Description:文本区域字段

  • Image:图像组件

我们将在整合一切部分中看到如何将文章与类别链接起来。

定义 BlogAuthor 类

正如我们所说的,文章是由人——或者说是计算机术语中的用户——撰写的,因此,每篇文章都将有一个作者;也就是说,它必须与撰写它的用户相关联。实际上,在Article类中,我们创建了一个Author关系字段就是为了这个目的。

在 Pimcore 中,另一方面,用户管理是最基本的,不允许我们直接扩展用户。相反,它允许我们创建用户与一个或多个 Pimcore 对象之间的关系。这可以用来向用户添加信息,或者将一个或多个对象直接与系统用户关联。

为了做到这一点,我们随后创建了一个额外的类,BlogAuthor,这样我们就可以通过其他属性扩展 Pimcore 用户,例如FirstNameLastName、照片和传记。

BlogAuthor类由以下字段组成,字段名称已经具有自描述性:

  • FirstName:文本字段

  • LastName:文本字段

  • User:用户字段

  • Slug:别名字段

  • Bio:文本区域字段

  • Photo:图像组件

  • User:用户字段

对于User字段,应该进行一个小澄清。此字段使用 Pimcore 的一个组件——User类型。因此,在下一个截图中,我们可以看到User字段的外观:

图 9.2:用户类型字段

图 9.2:用户类型字段

如您从前面的截图中所见,配置并不特别复杂,实际上,我们唯一需要填写的是字段本身的名称和标题。

当创建成员类的对象实例时,您可以看到用户属性的输入小部件。这是一个组合框,用户可以从所有可用的 Pimcore 用户中选择。让我们看看如何将作者与 Pimcore 用户关联起来。以下截图说明了这个过程:

![图 9.3:将作者链接到 Pimcore 系统使用图片

图 9.3:将作者链接到 Pimcore 系统使用

在这个示例中,选择了用户Bob

现在我们已经为我们的博客创建了所有必要的类,我们仍然需要配置 Pimcore,使用必要的用户和角色来确保文章可以与相应的作者关联。

创建博客用户和角色

用户和角色的创建已经在第七章管理 Pimcore 站点中解释过了,所以我们只需要回顾一下那章中学到的概念来创建必要的用户和角色。

对于这个示例,我们可以创建两个用户,我们亲爱的BobTom(我们的作者),以及一个要分配给我们的用户的作者角色。

创建作者角色

首先,我们将为作者创建一个角色。角色配置在下一张截图中显示:

![图 9.4:博客作者角色配置图片

图 9.4:博客作者角色配置

如您从前一张截图中所见,我们已经为博客的三个类:BlogArticleBlogCategoryBlogAuthor分配了创建权限。这是因为我们需要允许属于此角色的用户管理这些对象。在权限部分(在图 9.4中由于空间原因被压缩),我们选择了以下项目:资产对象用户。这将允许用户上传文章的图片,并查看创建的分类和文章。

如您在下一张截图中所见,角色的最终配置是在工作空间选项卡中的权限:

![图 9.5:博客作者角色工作空间配置图片

图 9.5:博客作者角色工作空间配置

如您在前一张截图中所见,它代表了每个类的角色配置,将需要设置用户的权限——特别是创建文章、上传或选择图片或能够查看作者和分类列表的权限。

创建用户

现在配置完成后,我们可以继续创建实际的实体,基于我们创建的类。

首先,我们需要创建用户BobTom,并将作者角色分配给他们。我们已经学会了如何在第七章管理 Pimcore 站点中创建用户和角色,所以我们只需要重复之前已经完成的相同操作。

完成这些后,让我们创建作者。作者的创建,以及文章或类别的创建,都是在 Pimcore 界面的数据对象部分完成的。

为了方便起见,我们已经将创建的对象分组到文件夹和子文件夹中,如下一个屏幕截图所示:

![图 9.6:数据对象列表和作者 Bob 配置图片

图 9.6:数据对象列表和作者 Bob 配置

如您在前一个屏幕截图中所见,我们已经创建了三个文件夹,必须包含我们将要创建的对象。特别是,Blog/Authors文件夹将包含我们将创建的所有作者,Blog/Categories文件夹将包含所有博客类别,而Blog/Articles文件夹将包含作者所写的所有文章。

图 9.6中,我们还可以看到User字段是一个选择框,其中可以关联一个用户,在我们的案例中,我们选择了系统用户Bob。然后我们完成了FirstNameLastNameSlugPhoto字段的填写,并在Bio字段中完成了一段简短的传记。这些字段将在作者页面上显示。

整合所有内容

一旦我们为博客、用户和作者创建了类,我们就需要创建数据对象来在页面上表示:类别和文章。对象的创建已经在第四章**,在 Pimcore 中创建文档第五章**,探索对象和类中详细说明,因此在此场合不需要详细说明如何进行此操作。然而,对于我们的博客,我们已经创建了作者类别,并且还上传了类别和文章所需的图片。在下面的示例屏幕截图中,我们可以看到创建第一篇文章的过程,包括必要的信息和关系:

![图 9.7:创建我们的第一篇文章图片

图 9.7:创建我们的第一篇文章

如您在前一个屏幕截图中所见,所有元素都已创建,因此可以创建一篇文章并为其分配作者、类别和之前已加载到资产的图片。图 9.7中绘制的箭头标识了文章“类别”字段中的类别拖放操作。相同的拖放方法也可以用来将作者和图片链接到文章的相应字段。

您还可以看到我们如何将对象和资产分组到不同的文件夹中。组织目录结构不是强制性的,但它确实有助于按类型将创建的对象分组。如下一个屏幕截图所示,可以通过在主页或任何其他已创建的文件夹上右键单击来创建文件夹以组织我们的项目:

![图 9.8:创建我们的第一篇文章图片

图 9.8:创建我们的第一篇文章

在前面的屏幕截图中,您可以看到我们是如何从 Blog 文件夹开始组织文件夹的,并在其中创建文章、作者和分类的文件夹。

我们必须做的下一步是定义博客中导航的规则——换句话说,就是路由。

路由

路由是我们设置博客的关键部分,在上一章中已经详细讨论过,第八章创建自定义 CMS 页面。因此,我们将继续创建硬编码的路由,直接修改 routing.yml 文件。

让我们创建一组必要的规则,以便识别文章、分类和作者页面。此外,我们希望页面可以通过使用我们的 ID 或 slug 来访问。

例如,我们报告了与文章相关的两个路由规则,在下面的代码片段中:

blog_article_by_id:
    path:      /blog/article/{page}
    controller: BlogBundle\Controller\BlogController:articleAction
    requirements:
      path: '.*?'
      page: '\d+'
blog_article_by_slug:
    path:      /blog/article/{page}
    controller: BlogBundle\Controller\BlogController:articleAction
    requirements:
      path: '.*?'
      page: '[\w-]+'

正如您在前面的代码片段中所看到的,我们已经定义了一个显示文章的路径,我们还设置了控制器和识别文章所需的参数,无论是通过 ID (blog_article_by_id) 还是通过 slug (blog_article_by_slug)。

通过分析这两个规则,我们可以看到它们只在 path 参数上有所不同。在通过 ID 识别文章的规则中,在路径中我们必须搜索一个整数,即文章的 ID。这是通过使用 \d+ 实现的。在通过 slug 识别页面的规则中,我们必须识别一个字符串,为此我们使用定义为 [\w-]+ 的正则表达式。这个最后的正则表达式过滤了所有由单词组成并由连字符分隔的字符串。

重要提示

正则表达式,也称为 regex,是一种在文本中匹配模式的方法——例如,正则表达式可以描述电子邮件地址、URL、电话号码、员工识别号、社会保险号或信用卡号的模式,当然还有网站上的页面路由。在许多系统和脚本语言中,正则表达式的使用是标准做法。正则表达式可以是简单的,也可以非常复杂。关于这个主题有成百上千的指南,在互联网上很容易找到,只需在任何搜索引擎上搜索 regex 即可。

我们已经看到了文章规则的定义方式。routing.yml 文件还包含了针对分类和作者的路线规则,这些规则的定义方式完全相同,只是要在 BlogController 控制器上调用不同的操作。

现在我们已经完成了路由配置,我们必须在控制器上创建操作,以便我们的页面可以包含和显示我们感兴趣的数据。

让我们现在去看看 BlogController 及其操作是如何编写的,这些操作我们之前在路由规则中已经看到了。

编辑我们的博客控制器

关于控制器的内容在上一章中已经解释过,第八章创建自定义 CMS 页面,因此在本章中,我们只关注我们需要对博客进行哪些更改才能使其正常工作。

我们现在感兴趣的是创建与上一节中刚刚配置的规则相对应的操作。实际上,如果我们查看配置,我们可以看到Controller字段包含捆绑名称(BlogBundle),后面跟着Controller关键字,然后是控制器名称(BlogController)。最后一部分是当浏览器 URL 与路由规则匹配时要调用的操作名称(articleAction)。

为了阐明这些想法,想象我们在浏览器中写下这个 URL:myblog.com/blog/article/my-first-article。我们唯一地标识了一个blog_article_by_slug规则。这个规则在配置中编写,表明在BlogBundle捆绑的BlogController控制器中调用articleAction操作。因此,通过我们刚刚写下的 URL,我们已经标识了一个要调用的操作,即ArticleAction操作。所以,让我们看看这个操作是如何编写的。

文章操作(ArticleAction)

正如我们刚才提到的,当 URL 通过 ID 或别名标识出必须显示文章的路径时,将执行此操作。因此,首先要做的事情就是根据输入参数检索文章,如下面的代码片段所示:

/**
 *  Get detail of article. route: /blog/article/id|slug
 * @Template() 
 */   
public function articleAction(Request $request,$page) {
  if (intval($page)) { // by id
    $article = DataObject\BlogArticle::getById($page);
  }
  else { // by slug
    $slug = UrlSlug::resolveSlug("/$page");
    if ($slug instanceof UrlSlug) {
      $id = $slug->getObjectId();
      if (intval($id) && $id > 0) {
        $article =  DataObject\BlogArticle::getById($id);
      }
    }         
  }
  if ( !( $article instanceof DataObject\BlogArticle ||   $article->isPublished() ) ) {
    // article not found, redirect to blog
    return $this->redirect('/blog');
  }
  return $this->renderTemplate(
    '@Blog/Blog/article.html.twig',array(
        // get all categories for widget
        'categories' => $this->getAllCategories(), 
        'article' => $article
  ));
}

如您从前面的代码片段中看到的,articleAction函数接受两个参数:requestpage。我们感兴趣的参数是page,为了理解 URL 中是否有 ID 或别名。

首先,我们需要检查$page变量中的输入参数是否为整数类型,并检索它所代表的值。要从字符串中读取整数,我们可以使用 PHP 语言的intval函数,该函数获取变量的整数值。如果intval函数返回一个整数值,这意味着我们有一个 ID。要通过 ID 检索对象,可以使用 Pimcore 在所有对象中提供的getById函数。如果$page变量不是整数,那么在 URL 中输入了自由文本,这可能是文章的别名。然后我们必须通过别名检索对象 ID,一旦检索到,我们就可以通过其 ID 检索对象,就像我们刚才所做的那样。

一旦检索到对象,我们验证它是否是类型为article的对象。这是通过以下if语句完成的:

if ( !( $article instanceof DataObject\BlogArticle || $article->isPublished() ) ) {

第一部分,instanceof构造,用于检查一个对象是否为BlogArticle类型;if语句的第二部分使用一个特定的 Pimcore 函数isPublished(),该函数用于检查文档是否已发布。在此阶段,如果一切正常,我们只需调用RenderTemplate函数,这是一个接受两个参数的函数:首先,Twing 模板文件的路径,其次,传递给视图的对象数组。在我们的示例中,我们传递了文章页面模板的路径(@Blog/Blog/article.html.twig)以及一个包含渲染页面视图所需两个对象的数组:文章和类别列表(我们很快将看到如何在视图中使用这些变量)。有关 MVC 模式如何工作以及数据从路由到控制器再到视图的传递的更多详细信息,请参阅第八章创建自定义 CMS 页面

其他动作

我们刚刚看到了如何编写一个与路由规则链接的ArticleAction动作,routing.yml文件中存在的其他规则,用于识别类别和作者,将会有它们自己的动作,这些动作的编写方式与刚刚看到的article动作完全相同。

检查BlogController代码,我们可以很容易地看到所有动作具有相同的结构,因为它们执行相同的操作。这些操作的目的在于通过 ID 识别一个对象。唯一改变的是恢复的对象,在一个案例中是文章,在另一个案例中是类别,在另一个案例中是作者。

由于每个动作之间的代码非常相似,因此没有必要详细查看其他动作,我们只需报告控制器中必须存在的动作列表,如下所示:

  • blogAction

  • articleAction

  • categoryAction

  • authorAction

用于此演示的所有文件(如routing.ymlBlogController.php和所有视图的*.html.twig文件)都可以从与本书相关的 Git 仓库下载:github.com/PacktPublishing/Modernizing-Enterprise-CMS-using-Pimcore/

我们已经看到了如何在控制器中定义路由以及与之相关的动作。现在,让我们查看所需的文件和代码,以便查看本节中恢复的数据。

渲染博客视图

一旦我们通过之前看到的路由规则确定了访客请求的页面,并且数据已经被提取并通过控制器传递到视图后,剩下的工作就是正确地在页面上显示。在 Pimcore 中,这可以通过一个名为Twig的模板系统来完成,正如我们在第四章中提到的,在 Pimcore 中创建文档,这是 Pimcore 将业务逻辑与表示逻辑分离的解决方案。

简而言之,Twig 是 PHP 的现代模板引擎,由 Symfony(因此也是由 Pimcore)支持,它允许你通过其自己的语法在视图页面中直接处理代码。项目的官方页面,你可以从这里阅读完整的文档,可以访问:twig.symfony.com/

模板是有用且必要的,因为我们可以为不同的内容创建单个视图。换句话说,模板化允许我们创建一个 HTML 页面来查看我们博客的所有文章,无论它们是几篇还是数百万篇。页面的视图对每个人都是相同的——只有内容会改变。这使我们免去了为每篇文章创建页面的麻烦,那将是一项漫长且无用的工作。

因此,我们需要创建四个模板,如下所示:

  1. 博客: 这是博客的主页,其中将包含一系列分类。

  2. 分类: 这是分类页面,其中将包含该分类下的所有文章。

  3. 文章: 这是实际的文章页面,用户可以在这里阅读文章内容。

  4. 作者: 一个包含作者信息、姓名和照片以及他们文章列表的页面。

我们将很快讨论这四个模板;然而,首先,我们将提到这些页面是如何在 HTML 和层叠样式表CSS)中创建的。

使用 Bootstrap 对 HTML 页面进行样式化和布局

在讨论博客模板页面之前,我们需要了解页面是如何制作的。页面是用HTML编写的,其中包含一些 Twig 代码片段,同时使用 Bootstrap 进行图形样式和布局。Bootstrap是一组图形、样式和布局工具的集合,它允许你拥有大量可修改和根据需要调整的功能和样式。你可以在官方项目页面上了解更多关于这个框架的信息:getbootstrap.com/

Bootstrap 的主要组件是网格系统。该组件允许您创建布局,将空间分割成。这些布局将是构建我们模板的起点。除了用于创建布局的类之外,Bootstrap 还提供了一套 CSS 类,用于美化 HTML 元素,如标题、段落、表格、按钮等。然后,还有其他 JavaScript 组件——即下拉菜单、标签界面、工具提示、警报、手风琴菜单、滑块和导航横幅等元素。

在对 Bootstrap 进行简短但必要的介绍之后,让我们回到我们的博客。使用 Bootstrap 系统网格,我们创建了一些布局,将页面分割成列。在下一张屏幕截图中,您可以看到我们使用的三种布局类型:

图 9.9:模板布局

对于第二种布局,我们有以下内容:

]

如您所见,我们为页面设计了三种不同的布局,概述如下:

  • 在第一种布局中,内容尚未被分割,因此我们有一个占据空间十二分之一的列。

  • 在第二种布局中,内容已被分割成两列——一列占四分之一的空间,另一列占八分之一的空间。

  • 图 9.9:模板布局

我们使用了第一种没有分割的布局来制作主要博客页面,第二种布局在左侧有小列的作者页面,第三种用于文章和分类页面。

让我们看看这是如何在 HTML 页面中实现的。为了制作布局,我们使用了 Bootstrap 类来定义列的大小。对于第一种布局,我们有以下内容:

 <!-- Page Blog Content -->
  <div class="container">
    <div class="row">
      <!-- Post Content Column -->
      <div class="col-lg-12">… here the content
      </div>
    </div> <!-- row -->
  </div> <!-- container -->

在第三种布局中,与之前的布局一样,内容被分割成不同大小的两列,但与第二种布局的顺序相反。

<!-- Page Content -->
  <div class="container">
    <div class="row">
      <!-- Post Content Column -->
      <div class="col-md-4">… here the content
      </div>
      <!-- Sidebar Widgets Column -->
      <div class="col-lg-8">… here the content
      </div>
    </div> <!-- row -->
  </div> <!-- container -->

最后,对于第三种布局,我们有以下内容:

<!-- Page Content -->
  <div class="container">
    <div class="row">
      <!-- Post Content Column -->
      <div class="col-lg-8">… here the content
      </div>
      <!-- Sidebar Widgets Column -->
      <div class="col-md-4">… here the content
      </div>
    </div> <!-- row -->
  </div> <!-- container -->

在本节中,我们简要但清晰地了解了我们的模板布局是如何创建的。在下一节中,我们将看到如何编写构成模板的视图文件中的代码。

模板化

模板文件是*.html.twig文件,通过 Twig,我们能够插入来自控制器中的数据。布局和图形风格部分是通过 Bootstrap 完成的,正如我们在上一节中看到的。我们可以报告我们已定义的四个模板,如下所示,以及它们响应的路由和相应的模板文件:

  1. 博客:

    • 路径:/blog

    • Twig 文件路径:BlogBundle/Resources/views/Blog/blog.html.twig

  2. 分类:

    • 路径:/blog/category/{page}

    • Twig 文件路径:BlogBundle/Resources/views/Blog/category.html.twig

  3. 文章:

    • 路径:/blog/article/{page}

    • Twig 文件路径:BlogBundle/Resources/views/Blog/article.html.twig

  4. 作者:

    • 路径:/blog/author/{page}

    • Twig 文件路径:BlogBundle/Resources/views/Blog/author.html.twig

因此,让我们看看一个完整的模板是如何制作的。作为一个例子,我们将采用文章模板。

检查文章视图

为了理解模板是如何制作的,最好的办法是报告代码并逐部分描述各个部分。因此,让我们从 article.html.twig 文件的完整模板代码开始,如下所示:

{% extends '@Blog/Layout/layout.html.twig' %}
{% block content %}
  {% include '@Blog/Layout/header.html.twig' %}
  <!-- Page Content -->
  <div class="container">
    <div class="row">
      <!-- Post Content Column -->
      <div class="col-lg-8">
        <!-- Title -->
        <h1 class="mt-4">{{article.getTitle()}}</h1>
        <!-- Author -->
        <p class="lead">
          by <a href="/blog/author{{article.getAuthor().          getSlug()[0].getSlug()}}">{{article.getAuthor().          getFirstName()}}</a>
        </p>
        <hr>
        <!-- Date/Time -->
        <p>Posted on {{article.getModificationDate() | date("F         jS \\a\\t g:ia") }}</p>
        <hr>
        <!-- Preview Image -->
        <img class="img-fluid rounded" src="{{article.        getImage()}}" alt="">
        <hr>
        <!-- Post Content -->
        {{article.getContent() | raw}}  
        <hr>
      </div>
      <!-- Sidebar Widgets Column -->
      <div class="col-md-4">
         {% include '@Blog/Widget/widget.html.twig' %}
      </div>
    </div>
    <!-- /.row -->
  </div>
  <!-- /.container -->
{% endblock %}

让我们从第一行开始:extends 命令指示 Twig,页面扩展了由 @Blog/Layout/layout.html.twig 路径标识的页面。扩展一个页面就像说当前页面以某种方式包含在它扩展的页面中。在这种情况下,layout.html.twig 文件包含了我们在 article.html.twig 文件中分析时找到的 block content 的定义。我们已经在 第四章在 Pimcore 中创建文档 中讨论了块,因此我们可以进一步描述下一行。

在内容块开始后,我们还有另一个 include 语句,它用于加载 @Blog/Layout/header.html.twig 文件的内容。在这个文件中,我们找到了构建网站头部(即顶部图像和标题)的 HTML 代码。

滚动文件,我们看到主列中与文章相关的数据:这些数据是通过 getTitle()getAuthor()getModificationDate()getSlug()getImage() 函数检索的。这些元素使用 Twig 命令进行渲染,我们将在本章下一节中更详细地了解这些命令。然而,我们可以看到所有数据都是从 article 变量中提取的,正如我们回忆的那样,这个变量是在 RenderTemplate 命令中由控制器传递给视图的。

其他模板与刚刚看到的这个模板略有不同,因此我们不会对其进行描述,但所有相关文件都可在本书的仓库中找到,网址为github.com/PacktPublishing/Modernizing-Enterprise-CMS-using-Pimcore

渲染分类小部件

正如我们在 图 9.9 中看到的,我们创建了三种类型的布局,其中两种有两个不同大小的列。我们考虑在较窄的列中插入一个组件,称为 小部件,它将包含一个分类列表。在下一张屏幕截图中,你可以看到 分类 小部件如何在页面右侧显示:

图 9.10:模板布局

图 9.10:模板布局

如您从前面的屏幕截图中看到的,分类 小部件包含所有博客分类的列表,每个分类中的文章数量用括号表示。

Widget 文件夹。小部件的包含是通过 Twig 的 include 命令完成的。include 命令至少需要一个参数,即要包含的文件路径,如下面的代码片段所示:

<!-- Sidebar Widgets Column -->
<div class="col-md-4">
  {% include '@Blog/Widget/widget.html.twig' %}
</div>

获取分类列表的功能是在 BlogController 控制器中编写的,如下面的代码片段所示:

/**
 * get a complete list of categories for blog
 */
public  function getAllCategories() {
  $categories = new DataObject\BlogCategory\Listing();
  foreach ($categories as $category) {   
    $articles = new DataObject\BlogArticle\Listing();
    $articles->setCondition('Category__id = ' . $category-    >getId());       
    $category->ArticleCount = $articles->getTotalCount();
    if( !empty( $category->getSlug()[0]->getSlug()) ) {
      $category->link = $category->getSlug()[0]->getSlug();
   }
  }
  return $categories;
}

在小部件文件中,我们通过forTwig 语句创建了一个所有类别的项目符号列表,如下面的代码片段所示:

<ul class="list-unstyled mb-0">
     {% for cat in categories %}
     <li>
          <a href="/blog{{cat.link}}" >
               {{cat.getTitle()}} ({{cat.ArticleCount}})
          </a>
     </li>
     {% endfor %}
</ul>

为了获取数据,我们使用了getTitle()函数,并读取了我们在控制器中创建并传递到视图中的ArticleCount属性。我们没有使用类别描述字段,但我们将此作为一项练习留给你,以检索此字段并在页面上显示它。

理解 Twig 过滤器

过滤器是改变变量值的函数——例如,想想所有那些转换字符串值的 PHP 函数:strtoupperstrtolower等等。在 Twig 中,它们通过pipe, |(管道符)使用,并接受一些参数。以下是一些示例:

{{textWithsomeCharUpperCase | lower}}
{{arrayOfStrings | join (',')}}

第一个示例将字符串的值转换为小写,而第二个示例通过逗号分隔元素来打印arrayOfStrings数组的所有内容。您可以在官方文档中查看过滤器列表:twig.symfony.com/doc/

现在,让我们详细看看我们用来创建模板的过滤器。

使用日期过滤器格式化日期

date过滤器将日期格式化为指定的格式。以下是使用此过滤器的示例:

<p>Posted on {{article.getModificationDate() | date("F jS \\a\\t g:ia") }}</p>

如您从前面的代码片段中看到的,我们使用了F jS \\a\\t g: ia日期格式。F jS部分表示我们希望如何格式化日期,而g: ia表示时间格式。中间的文本\\a\\t只是用来在日期和时间之间写上"at"。对于日期和时间的所有可能的格式化类型,您可以在 PHP 在线指南中查看:www.php.net/manual/en/datetime.format.php

使用切片过滤器省略内容

在某些情况下,我们必须显示的文本太长,例如在文章列表中,我们只想显示文章的图片和内容的前两行或三行。我们希望截断文本,并用三个省略号替换被截断的文本,以便访客理解文章并不完整。为此,我们使用slice过滤器。slice过滤器从序列、数组或字符串中提取一段。以下是使用此过滤器的示例:

{% set content = cat.getContent() | length > 100 ? cat.getContent() | slice(0, 100) ~ ' ...' : cat.getContent()  %}
…
<div class="card-body">
  …
  <p class="card-text">{{ content | raw }}</p>
</div>

如您从前面的代码片段中看到的,我们设置了一个content变量,然后将其用于模板的内容中,其值为文章内容,对长度应用条件过滤。特别是,如果文本超过100个字符,我们应用slice过滤器并取前100个字符,并将三个省略号连接到字符串上。如果内容不超过100个字符,我们则完整地取它。我们还使用了length过滤器来获取字符串的字符长度。最后一个技巧:我们使用了波浪号字符(~)来连接字符串。

使用原始过滤器渲染文本

raw过滤器将值标记为“安全”,这意味着在自动转义启用的环境中,如果raw是应用到最后一个文本过滤器,则此变量不会被转义。正如我们刚才看到的,我们使用了raw过滤器来查看文章内容,如下所示:

<p class="card-text">{{ content | raw }}</p>

如果您想确切了解raw过滤器的工作方式,您可以尝试从文章内容中移除raw过滤器,并查看结果。

过滤器是非常有用的工具,因为它们允许我们在展示阶段直接修改数据。在本节中,我们看到了一些可用的过滤器以及如何使用它们。对于所有其他过滤器,您可以通过以下链接访问 Twig 项目的官方页面:twig.symfony.com/doc/.

Pimcore 与 WordPress 之间的差异

我们已经看到了如何使用 Pimcore 创建一个博客。然而,有些人可能会想知道使用 Pimcore 创建博客是否是正确的选择。已经有许多内容管理系统CMSes)可以完成这项工作——WordPress 最为著名。

我们提到 WordPress 是因为,对于那些还不了解它的人来说,这是一个强大的开源软件解决方案,您可以轻松自由地使用它来创建博客。它无疑是最受欢迎的 CMS,因为它的安装和配置简单。几乎所有的网站托管解决方案都提供在您的域名中预先安装 WordPress 的选项。甚至使用它也不需要任何特殊知识——它非常直观,并附带一个简单有效的管理页面。您还可以通过安装插件来扩展其功能,对于前端,您只需点击一下就可以下载和安装数千个图形主题。所有这些功能都使 WordPress 成为目前网络上 40%的网站的优先选择。

那么,为什么使用 Pimcore 来创建博客,而不是 WordPress 呢?如果我们说 WordPress 是参考博客 CMS,那么是什么原因让我们选择使用 Pimcore 呢?让我们尝试分析这个选择的优势和劣势(如果有)。

与 WordPress 不同,Pimcore 基于 MVC 开发模式,这允许业务逻辑与展示逻辑解耦。在视图部分,此外,Pimcore 使用一个渲染引擎(Twig),它简化了数据插入到页面中的过程,无需使用 PHP 代码。例如,这也简化了用户界面UI)的更改(开发成本大大降低),因为数据是由控制器传递到视图的,而不是在视图内部提取和处理。

Pimcore 的另一个优点是能够拥有结构化数据,而在 WordPress 中,与实体(文章、分类、用户等)关联的元数据是没有类型的。为了拥有类型化的数据,需要安装许多可用的插件之一。缺点是插件将数据及其类型配置存储在其元数据中,因此——例如——如果我们想更改或删除一个插件,我们也会丢失与之相关的数据。

在我们选择时需要考虑的另一件事是,Pimcore 是一个完整的框架,因此可以在其中创建功能。在 WordPress 上,一切也是可行的,但只能通过使用插件来实现。

有些人可能会正确地想:“但 WordPress 已经具备了创建博客的所有元素——文章、用户、分类、标签。” 确实如此。但同样真实的是,在本章中看到的在 Pimcore 中创建相同博客结构的努力是微不足道的。一旦你投入了创建博客所需的时间,回报就会变得丰厚,因为在这个时候,我们将拥有 WordPress 的功能,但能够随意自定义和修改每个方面,使其满足我们的需求。让我们举一个例子:如果我们想向用户添加工作字段,我们应该怎么做?嗯,在 Pimcore 上,就像我们创建其他字段一样,我们只需要添加一个,我们就做到了。在 WordPress 上?显然,在 WordPress 上也可以做到这一点,但需要安装一个插件。

我们已经多次讨论过 WordPress 的插件。我们不需要了解它们是如何工作的,但我们感兴趣的是指出,有数千种插件,适用于所有目的。其中许多是付费的,几乎所有的插件都会做比所需更多的事情,总的来说,在 WordPress 上安装插件需要注意插件之间的任何冲突,以及配置、更新和维护。由于是由第三方开发者创建的,插件不一定是最新的;也许它不兼容 WordPress 的最新版本,或者开发者可能决定放弃它。换句话说,直接在平台上进行开发总是更好、更有优势,而不是使用外部第三方工具。

现在,让我们看看 Pimcore 提供的附加功能。首先,可以创建多语言站点。WordPress 仍然不允许这样做,因此为了做到这一点,又需要安装一个插件。

Pimcore 允许你创建多站点——即在同一个 Pimcore 安装中管理多个站点和多个域名。即使在 WordPress 上,也可以创建多站点,但仅限于第三级,因此不是在不同的域名上。例如,在一个多站点 WordPress 安装中,可以管理mysite.domain.commysite2.domain.com,但无法在同一个 WordPress 安装中管理mysite.commysite2.com——这可能对管理拥有许多连接域的站点来说是一个令人烦恼的限制。

Pimcore 允许您轻松创建视角,根据访问它们的用户配置文件或角色限制对管理后端部分访问。在 WordPress 上,这是不可能的,并且通常用户必须通过专门视图来访问管理区域,因此无法重用 WordPress 后端。

无论我们是否将其用作博客,拥有 Pimcore 的优势都将大于使用 WordPress,因为使用 Pimcore,我们将拥有对诸如产品信息管理(PIM)等商业功能的支持,我们将在第十二章“实施产品信息管理”中看到,或者数字资产管理(DAM),在第第六章“使用数字资产管理”中看到。

我们这样说并不是说 Pimcore 比 WordPress 更好,我们只是在评估和比较这两个系统以及它们能做什么。这无疑将帮助最终用户选择最适合他们目的的平台。

摘要

在本章中,我们了解了如何构建一个博客,需要创建哪些类,如何为页面创建文件,它们应该如何以 HTML 的结构来组织,以及如何通过 Twig 框架渲染数据。我们还学习了如何构建网站的路线,以及如何通过使用routing.yml文件和BlogController控制器,根据请求选择要显示的内容。最后,我们学习了如何为我们的网站构建 Bootstrap 布局,以及如何使用 Bootstrap 框架创建模板。

在下一章中,我们将学习如何构建可重用的组件,称为砖块,这些组件可以放置在 CMS 或多虚拟存储(MVS)页面上,并且还可以通过包从项目转移到项目。

第十章:第十章: 创建 Pimcore 砖块

在上一章中,我们学习了如何使用 Pimcore 创建实体并渲染自定义网页。之前,在第八章 创建自定义 CMS 页面中,我们发现了如何使用 Web 界面或自定义模型视图控制器MVC)页面创建 CMS 页面。在两种情况下,我们都希望有一些可重用的组件,这些组件可以定义一次,并在每次使用时通过更改一些设置来使用。想想看,你可以将其拖放到任何网页上的联系表单小部件。嗯,在 Pimcore 中,这类可重用组件被称为砖块

在本章中,我们将学习如何构建可重用的组件,这些组件可以放置在 CMS 或 MVC 页面上,而且还可以通过包在不同的项目之间移植。

这是我们的路线图:

  • 创建一个包

  • 理解砖块的工作原理

  • 实现一个简单的砖块

  • 实现联系表单砖块

  • 实现幻灯片砖块

  • 使用砖块和块构建通用模板

到本章结束时,你将学会如何创建自定义交互式小部件来组合页面。这对于满足你网站上用户的所有需求非常重要。

让我们开始探索砖块!

技术要求

就像前面的章节一样,这里有一个可以在我们的 GitHub 仓库中找到的演示:https://github.com/PacktPublishing/Modernizing-Enterprise-CMS-using-Pimcore/

要运行与本章相关的演示,你需要克隆它,然后导航到Full Demo文件夹并启动 Docker 环境。

要这样做,只需遵循以下说明:

  1. 使用以下命令运行 Docker:

    docker-compose up
    
  2. 然后,为了从你的本地机器上恢复所有设置,请输入以下命令:

    docker-compose exec php bash restore.sh
    
  3. 导航到localhost/admin并使用你的管理员/pimcore 凭据登录。

使用此设置,你将获得以下内容:

  • 一个BlogBundle,在这里你可以找到本章产生的所有资源

  • 一个完全工作的 Pimcore 实例,已安装数据和配置

这个项目是一个很好的参考,但毕竟我们在 Pimcore 上已经有很多实践经验了,你也可以从头开始一个项目,并尝试自己复制所有步骤。

创建一个包

在我们开始砖块之旅之前,我们必须学习如何创建一个包。在第七章 管理 Pimcore 站点中,我们学习了如何安装来自供应商的包,但我们是怎样构建自己的呢?在本节中,我们将学习包的结构以及如何构建它。包对于创建一个可携带的功能集非常重要,你可以重用它或在网站之间分发。在我们的演示项目中,我们将创建一个自包含的博客包,你可以将其挑选并放置在你的任何网站上。

什么是包?

在前面的章节中,您已经使用了主应用程序的许多示例。这对于实现特定项目来说很好,但它并不便携。简单来说,一个包是一个包含源代码和模板的文件夹。您可以通过添加 composer 依赖项或使用本地文件夹来获取这个文件集。这使您可以将代码用于多个项目,或者简单地将复杂的应用程序划分为模块。为了简单起见,在这本书中,我们将使用 bundles 路径内的本地文件夹。每个子文件夹将托管不同的包。在本章中,我们将涵盖启动博客所需的所有内容,因此我们将创建一个 BlogBundle。这意味着我们将有一个包含所有与包相关的文件的 /bundles/BlogBundle 文件夹。这个文件集不是自动发现的;您必须在您的 composer.json 中添加特定的配置。在下一部分代码中,是博客包的配置:

"autoload": {
    "psr-4": {
      "App\\": "src/",
      "BlogBundle\\": "bundles/BlogBundle/",
      "Pimcore\\Model\\DataObject\\": "var/classes/DataObject",
      "Pimcore\\Model\\Object\\": "var/classes/Object",
      "Website\\": "legacy/website/lib"
    }
  },

如您在前面的代码片段中所见,博客文件夹被添加到 psr-4 定义中,紧随标准 src 之后,它映射到 App 命名空间。在我们的情况下,我们将 BlogBundle 命名空间映射到 bundles/BlogBundle/ 文件夹。当然,您可以玩转这个配置,创建自己的设置以适应您的需求。无论如何,我们建议将配置尽可能接近 Symfony 标准。

下面是一个包内文件夹和文件的列表:

  • /bundles/BlogBundle:这是包含所有包资源的包文件夹。包是自包含的,因此它包含所有资源(配置、主题等)和类。

  • DependencyInjection:此目录包含配置包的两个重要文件:BlogExtension.php(约定是去掉 Bundle 单词的包名称然后加上 Extension.php)和 Configuration.php

  • Document/Areabrick:此文件夹用于 Brick 类;我们将在下一节中详细探讨。

  • 控制器:此文件夹包含控制器。

  • 资源:此目录包含以下子目录:

    a) config:您的 YAML 文件构建于此。

    b) public:在这里,您可以加载所有将在 /bundles/{bundle name}/ 下发布的资源,因此如果您在这里添加一个名为 script.js 的文件,您将可以在 localhost/bundles/blog/script.js 找到它。

    c) 视图:您可以在其中创建一个包含每个控制器模板的子文件夹。此文件夹还包含 Areas 子文件夹,其中将包含所有的 Brick 模板。

现在是时候创建我们的第一个包了!

从命令行创建包

您可以通过使用命名约定手动创建文件和文件夹。这并不难,但在手动操作时很容易出错。幸运的是,我们有一个来自 Pimcore 的命令可以为我们完成这项工作。

在 Symfony 5 中,这不再是内置功能,因此我们必须从 Pimcore 安装一个包,然后我们可以使用控制台创建一个包骨架。

创建包非常简单,将在下一步骤中解释:

  1. 使用以下命令进入您的 Docker 实例:

     docker-compose exec php bash
    
  2. 使用以下命令安装包生成器:

    composer require pimcore/bundle-generator
    

    之前的命令将添加包并为其配置为常规控制台命令。

  3. 导航到config/bundles.php并使用以下代码注册包:

    <?php
    use Pimcore\Bundle\BundleGeneratorBundle\
    PimcoreBundleGeneratorBundle;
    return [
        PimcoreBundleGeneratorBundle::class => ['all' =>     true],
    ];
    
  4. 运行以下命令:

     bin/console pimcore:generate:bundle BlogBundle
    

    此操作将为您的包创建一系列文件夹和文件。运行此命令后的结果是创建包含所有基本子文件夹的包。

  5. 此外,为了使包内容对应用程序可用,我们需要通过添加命名空间映射来更改我们的 composer 定义,如下例所示:

    "psr-4": {
          "App\\": "src/",
          "BlogBundle\\": "bundles/BlogBundle/",
          …
        }
    

    在此步骤之后,您可能需要运行chmod -R www-data.以修复权限问题。在我们提供的 Docker 示例中,这是强制性的。

  6. 现在,该包对系统可用,可以按照第三章中所述的说明启用和安装,开始使用 Pimcore 管理 UI

在本节中,我们学习了如何组成一个包以及如何创建一个新的包。现在我们有了准备好的包,我们可以通过一些实际例子来开始讨论砖块。

理解砖块的工作原理

简而言之,砖块由一个类组成,该类取代了控制器和视图的位置。构建砖块与实现 MVC 页面没有太大区别。最重要的例外是,在这种情况下,我们没有路由部分,因为砖块被添加到现有页面中(不能独立运行)。在下图中,我们有一个解释砖块如何工作的架构图:

图 10.1:砖块的概念性架构

图 10.1:砖块的概念性架构

在前面的图中,我们可以看到页面(我的页面)可以托管许多砖块。每个砖块都由一个和两个模板(编辑查看)组成。

在接下来的章节中,我们将学习如何实现每个单独的组件,包括类和模板。

类的实现

砖块是Pimcore\Extension\Document\Areabrick\AreabrickInterface的一个实例,但为了方便起见,我们通常扩展AbstractTemplateAreabrick类,该类实现了接口并提供了一些有趣的方法。这些类可以手动加载或通过 YAML 文件自动加载。尽管将类添加到 YAML 文件中很简单,但这始终是一个额外的步骤。因此,我们通常更喜欢自动加载场景,这只需要我们使用默认文件夹(Document/Areabrick),我们将类放置在该文件夹中。您的类命名空间必须是namespace BlogBundle\Document\Areabrick

下面的类实现了一个简单的砖块:

class MyBrick extends AbstractTemplateAreabrick
{
    public function getName()
    {
        return 'The Brick Name';
    }
    public function getDescription()
    {
        return 'The Brick description';
    }
     public function getTemplateSuffix()
     {
          return static::TEMPLATE_SUFFIX_TWIG;
     }
}

正如您在前面的代码片段中所看到的,有一些方法必须实现,以提供您组件的信息。这些在代码中突出显示的方法如下:

  • getName:此方法返回砖块的名字(应该是唯一的)。

  • getDescription:此方法返回砖块的长描述,并在网页界面中显示,以使用户了解砖块的功能。

  • getTemplateSuffix:此方法用于定义模板扩展名(Twig 或 PHP)。要采用 Twig 模板而不是 PHP 模板,请使用static::TEMPLATE_SUFFIX_TWIG

现在类部分已经准备好了,我们可以在下一节中看到如何设置模板。

模板化

通常,对于砖块类,模板遵循一个命名约定。它们必须位于视图文件夹(Resources/views)内的Areas文件夹中。每个砖块都必须有自己的文件夹,但文件夹名称必须使用脊椎式命名法(所有字母小写,单词之间用连字符分隔,因此MyBrick需要一个名为my-brick的文件夹)。视图模板的名称必须是view.html.twig

一些砖块是完全所见即所得的,您只需输入数据就可以更改组件的行为。其他砖块将配置与渲染分离。在这些情况下,您可以配置一个编辑弹出窗口,它会提示输入数据。我们将在下一节的示例中详细说明配置。

在下一个方案中,我们总结了命名约定,并为每种情况添加了路径示例。全局场景是将砖块添加到主项目(应用文件夹)的选项,而场景是将砖块添加到特定的包中:

  • 视图路径:

    a) 全局:

    templates/views/Areas/{BrickID}/view.html.(php|twig)
    

    b) :

    {BundleLocation}/Resources/views/Areas/iframe/view.html.(php|twig)
    
  • :

    a) 全局:

    src/Document/Areabrick/{BrickID}
    

    b) :

    {BundleLocation}/Document/Areabrick/{BrickID}
    

在本节中,我们学习砖块由什么组成。这对于理解命名约定和使用原则很重要。现在,是时候通过一些例子深入了解!在下一节中,我们将涵盖从简单到复杂使用的重要用例。

实现一个简单的砖块

在本节中,我们将实现我们的第一个砖块。因为本书的精神是使用真实世界的例子来学习,所以我们不会将其限制在“你好,世界”的例子中。在我们的第一个例子中,我们将创建一个可以多次放置在页面上的小部件,并可以重复使用。这个小部件将允许添加文本,选择标题类型(h1、h2 等),并输入文本。

为了完成这个目标,我们必须遵循以下步骤:

  1. 创建一个文档并将其链接到控制器和模板文件。我们在第四章“在 Pimcore 中创建文档”和第九章“配置实体和渲染数据”中多次执行了这个步骤。这个文档将用于测试我们正在创建的砖块。

  2. /bundles/BlogBundle/Document/Areabrick中创建一个名为Heading.php的文件。文件内容应如下所示:

    class Header extends AbstractTemplateAreabrick
    {
        public function getName()
        {
            return 'Header';
        }
        public function getDescription()
        {
            return 'A component for rendering a Header';
        }
        public function getTemplateLocation()
        {
            return static::TEMPLATE_LOCATION_BUNDLE;
        }
    }
    

    提供的代码声明了一个名为Header的砖块,具有特定的描述。现在我们有了砖块定义,我们必须为它添加一个模板。这将是我们的下一步。

  3. /bundles/BlogBundle/Resources/views/Areas中添加一个名为view.html.twig的模板。

  4. 将以下代码添加到文件中:

    {% if editmode %}
    {{pimcore_select('style', {
                "store" : [
                    ['h1', 'H1'],
                    ['h2', 'H2'],
                    ['h3', 'H3']
                ],
                "defaultValue" : "h1"
    })}}
    {{pimcore_input('text')}}
    
    {% else %}
    <{{pimcore_select('style')}}>{{pimcore_input('text')}}<{{pimcore_select('style')}}>
    {% endif %}
    

    代码分为两个分支。第一个分支在编辑模式下被激活,显示一个选择组件,允许你选择标题类型(h1、h2 等)和文本;第二个分支的代码显示在标题中的数据包装文本。我们实现第一个砖块所需的所有工作已经完成;我们现在只需测试它。

  5. 步骤 1中创建的模板中,添加以下片段:

    {{ pimcore_areablock("header")}}
    

    在编辑模式下,此可编辑将显示以下组件:

    ![图 10.2:可编辑组件]

    ](https://github.com/OpenDocCN/freelearn-php-zh/raw/master/docs/mdn-entp-cms-pimcore/img/Figure_10.02_B17073.jpg)

    图 10.2:可编辑组件

    此组件只是一个占位符,将允许我们从砖块列表中选择一个砖块并将其放入页面中。我们将在下一步中这样做。

  6. 点击加号按钮。它将显示以下菜单:![图 10.3:Areablock 的菜单]

    ](https://github.com/OpenDocCN/freelearn-php-zh/raw/master/docs/mdn-entp-cms-pimcore/img/Figure_10.03_B17073.jpg)

    图 10.3:Areablock 的菜单

    如前一个屏幕截图所示,我们输入到类中的数据用于区分组件。实际上,我们选择了标题作为砖块名称,用于渲染标题的组件作为描述。

  7. 点击框中的My H1 text:![图 10.4:标题砖块编辑]

    ](https://github.com/OpenDocCN/freelearn-php-zh/raw/master/docs/mdn-entp-cms-pimcore/img/Figure_10.04_B17073.jpg)

    图 10.4:标题砖块编辑

  8. 现在点击预览按钮或导航到页面。输出将是以下内容:

![图 10.5:砖块输出]

](https://github.com/OpenDocCN/freelearn-php-zh/raw/master/docs/mdn-entp-cms-pimcore/img/Figure_10.05_B17073.jpg)

![图 10.5:砖块输出]

页面正确显示了我们所选择的文本。

这个第一个例子展示了在 Pimcore 中创建可重用组件是多么简单。实际上,我们可以在每个页面上使用标题砖块,使用户在需要时选择并配置它。你可以与结合使用,允许用户选择一系列自定义元素或将其硬编码在模板中。此外,我们还可以使用交互式砖块。我们将在下一节中了解所有这些功能。

实现联系表单砖块

在这个例子中,我们将了解如何创建一个用户可以插入数据的交互式组件。为此,我们将创建一个联系表单。当填写详细信息并点击按钮时,将向固定收件人地址发送电子邮件。此小节还将介绍打开砖块编辑器以获取视图中未显示的参数的工作示例。按照以下步骤实现示例:

  1. 首先,使用模板创建一个文档,并在可编辑的模板中放置一个 areabrick。在下一步中,我们将必须创建砖。

  2. /bundles/BlogBundle/Document/Areabrick/ 中创建 ContactForm.php 文件。内容如下:

    class ContactForm extends AbstractTemplateAreabrick
    {
        public function getName()
        {
            return 'ContactForm';
        }
        public function getDescription()
        {
            return 'ContactForm';
        }
        public function getTemplateLocation()
        {
            return static::TEMPLATE_LOCATION_BUNDLE;
        }
    }
    
  3. 现在我们需要要求用户为联系表单添加收件人地址。在复杂场景中,您可能需要添加更多参数并对其进行组织。这可以通过实现特殊的 EditableDialogBoxInterface 接口来实现。在下一段代码中,我们可以看到必须添加的代码:

    class ContactForm extends AbstractTemplateAreabrick implements EditableDialogBoxInterface
    {
      public function   getEditableDialogBoxConfiguration(Document\Editable   $area, ?Info $info): EditableDialogBoxConfiguration
        {
            $config = new EditableDialogBoxConfiguration();
    
            $config->setItems([
                'type' => 'tabpanel',
                'items' => [
                    [
                        'type' => 'panel',
                        'title' => 'Contact Form Settings',
                        'items' => [
                            [
                                'type' => 'input',
                                'label' => 'Email Recipient',
                                'name' => 'recipient'
                            ]
    
                ]
                ]
            ]]);
            return $config;
        }
    }
    

    实际上,配置是一个可以分组到容器中的项目数组。在我们的案例中,我们使用了选项卡面板,并将输入放置在其中。此数组将用于自动生成用户的输入表单。输入的数据将以常规可编辑的形式提供给用户,如下面的代码片段所示:

    $recipient=$this->getDocumentEditable($info->getDocument(), 'input', 'recipient')->getData();
    
  4. 创建 view.html.twig 文件。此文件将包含将显示给用户的全部内容。在下一个代码片段中,为了简洁,我们提供了一个简化的表单(完整的 bootstrap 示例在本书相关的源代码中):

    {% if alert is defined %}
      {{ alert }}
     {% endif%}
    
    <form id="contact-form" name="contact-form" method="POST">
       <input type="hidden" name="sendEmail" value="true"/>
       <input type="text" id="name" name="name" >
       <input type="text" id="email" name="email" >
       <input type="text" id="subject" name="subject" >
       <textarea type="text" id="message" name="message" >
       </textarea>
       <input type="submit" value="submit" />
    </form>
    

    模板包含一个警告消息,这是一个用于确认向用户发送电子邮件或显示错误的消息。表单包含从用户获取字段的输入和一个提交按钮。动作未指定,因此此表单将向页面本身提交数据。隐藏的输入 sendEmail 是一个将激活发送过程的标志。

  5. 现在是时候在后台指定读取 POST 数据和发送真实电子邮件的逻辑了。下一个代码片段显示了要添加到砖类中的方法:

    public function action(Info $info)
    {  
         $request=$info->getRequest();
         $id= $info->getEditable()->getName();
         $info->setParam('id', $id);
         $sendEmail=$request->get("sendEmail");
         if($sendEmail==$id)
         {
              $name=$request->get("name");
              $email=$request->get("email");
              $subject=$request->get("subject");
              $message=$request->get("message");
    
              //send an email here
              $sent= $this->sendEmail($name,$email,
              $subject,$message, $recipient);
              if($sent)
              {
                   $alert="the message is sent!";
              }
              else
              {
                   $alert="there was an error, try later";
              }
              $info->setParam('name',$name);
              $info->setParam('email',$email);
              $info->setParam('subject',$subject);
              $info->setParam('message',$message);
              $info->setParam('alert',$alert);
    
         }
         $recipient=$this->getDocumentEditable($info->
         getDocument(), 'input', 'recipient')->getData();
         $info->setParam('recipient',$recipient);        
    
    }
    

    之前的代码实现了获取参数并发送通知用户结果的逻辑。$request=$info->getRequest(); 用于获取包含提交数据的 HTTP 请求,并使用 get 方法获取 sendEmail 标志的值,该标志激活发送过程。您可以通过使用参数将变量传递给视图,如下面的代码片段所示:

    $info->setParam('recipient',$recipient);  
    

    现在所有组件都已就绪,可以测试我们的砖了。

  6. 按照从 实现简单砖 部分的 步骤 5-6 添加砖到页面。现在页面上将有一个工作状态的联系表单组件。

  7. 通过点击砖的工具栏中的铅笔图标打开设置:图 10.6:打开弹出窗口

    图 10.6:打开弹出窗口

  8. 点击铅笔图标,将显示一个弹出窗口:图 10.7:输入收件人的弹出窗口

    图 10.7:输入收件人的弹出窗口

    您可以输入用作联系表单收件人的电子邮件地址。

  9. 保存文档并打开本节 步骤 1 中创建的文档页面。将显示联系表单。

  10. 用数据填写表单(它是一个联系表单,所以字段含义应该是自解释的)并点击发送。您应该会看到一个确认警报,如下面的截图所示:

图 10.8:发送后显示确认信息的联系表单

](https://github.com/OpenDocCN/freelearn-php-zh/raw/master/docs/mdn-entp-cms-pimcore/img/Figure_10.08_B17073.jpg)

图 10.8:发送后显示确认信息的联系表单

如您从本例中学到的那样,实现交互式小部件,如联系表单,相当简单。无论如何,当您在同一页面上有多个组件时,有一些技巧需要了解以避免冲突。我们将在下一节中解释这一点。

避免冲突

对于联系表单的例子,我们必须提出一个关于在具有多个砖块的页面上提交数据的问题。使用帖子方法,我们向服务器发送数据并在后端管理请求。这个程序非常简单,但它可能导致一些问题。事实上,考虑一下您在同一页面上有多个组件的情况。

在我们的例子中,如果我们将两个联系表单小部件放在同一页面上,点击发送将会触发两个动作。类似的情况也可能发生在具有相似字段名称的不同组件上。

为了避免此类冲突,请遵循以下故障排除步骤:

  1. 为所有字段名称添加一个唯一的前缀(每个组件一个)。在我们的例子中,这可以是cf用于ContactForm,名称将是cf-namecf-sendEmail等等。

  2. 将实例名称作为触发值。这是使您的帖子独特所必需的。砖块类的动作方法(在实现联系表单砖块步骤 5中创建)的更改如下:

    …
    $id= $info->getEditable()->getName();
    $sendEmail=$request->get("cf-sendEmail");
    if($sendEmail==$id)
    {
    …
    

    现在只有当组件的名称与产生帖子的名称完全相同时,才会处理电子邮件发送过程。同一砖块的两种不同实例会产生不同的名称,因此您的动作只会被触发一次。

    最后一步是在视图模板文件中进行一个小改动(在实现联系表单砖块步骤 3中创建)。我们将添加一个具有cf-sendEmail名称属性和从动作方法计算出的 ID 作为value的隐藏输入。将以下片段复制到您的视图文件中:

    <input type="hidden" name="cf-sendEmail" value="{{id}}"/>
    

    此值将作为帖子参数发送回我们的动作方法,我们将将其与服务器端生成的值进行比较。如果它们不相等,帖子就不会与当前组件匹配,我们避免任何动作。

在本节中,我们学习了如何实现联系表单。我们刚刚完成的例子向我们展示了创建一个可重用的交互式砖块是多么简单。您不仅能够在您网站的任何页面上重用此组件,还可以将捆绑包复制到另一个网站,并免费获得此功能。在下一个例子中,我们将了解如何实现幻灯片,通过混合控制器和砖块来重用我们可能为 MVC 页面编写的代码。

实现幻灯片砖块

在本例中,我们将构建一个幻灯片小部件,可以用来显示图像轮播。这将非常简单,我们只需使用 bootstrap 和迄今为止学到的工具。实际上,我们将重用用于显示图像库的代码第九章配置实体和渲染数据,但我们将将其集成到一个砖块中。为此,请按照以下步骤操作:

  1. 首先,通过创建一个名为Slideshow的文件夹并上传一系列图像到其中来准备环境。我们应该使用宽图像(例如 1920x1080)。

  2. 为每个图像打开图像设置,并将图像的标题和描述作为元数据添加。我们将在模板中使用它。

  3. 通过单击工具栏上的属性选项卡按钮来访问属性面板。每个 Pimcore 实体(对象、文档和资产)都有一组键/值属性,可以用来动态扩展信息。我们将使用它们来为我们的图像添加元数据。在下一张截图中,我们可以看到一个有效的配置:![图 10.9:图像属性 图片

    图 10.9:图像属性

    上一张截图显示了属性表。我们添加了一个标题和副标题字段,并输入了一些值。

  4. 创建一个缩略图预设。我们必须配置缩略图引擎,以便将上传的图像调整大小以匹配幻灯片组件期望的格式。用户可能会上传过大或比例错误的图像(例如,横向而不是纵向),但我们需要确保所有图像具有相同的高度,以便正确显示图像。我们需要裁剪上传的图像并使它们具有相同的格式。在我们的示例中,我们可以使用一个裁剪转换,该转换将生成只有 400 像素高的图像。为此,只需输入以下截图中的宽度、高度X、Y设置:![图 10.10:缩略图配置 图片

    图 10.10:缩略图配置

  5. 通过在砖块类文件夹中添加SlideShow.php来创建一个名为SlideShow的砖块(例如,/bundles/BlogBundle/Document/Areabrick/SlideShow.php)。

  6. 在视图文件夹中创建一个模板文件(例如,/bundles/BlogBundle/Resources/views/Areas/slide-show)。请注意文件夹名称 - 它必须与砖块名称匹配,但要以小写形式呈现,单词之间用连字符分隔,因此slide-show将是Slideshow

  7. 现在将以下内容添加到模板中:

    {{
         pimcore_renderlet('myGallery', {
               "controller" : "BlogBundle\\Controller\\
               SlideShowController::galleryAction",
               "title" : "Drag an asset folder here to get 
               a gallery",
               "height" : 400
         })
    }}
    

    上述代码添加了一个 Pimcore renderlet,允许用户将其拖放到文件夹上,并使用控制器来实现渲染逻辑。在我们的情况下,我们将使用SlideShow控制器中的画廊操作。我们正在使用一个包中的控制器,因此我们必须指定包名称。

  8. SlideShow控制器添加到控制器文件夹中(例如,/bundles/BlogBundle/Document/Controller/SlideShowController.php)。初始内容应如下所示:

    <?php
    namespace BlogBundle\Controller;
    use Pimcore\Controller\FrontendController;
    use Symfony\Component\HttpFoundation\Request;
    use Symfony\Component\HttpFoundation\Response;
    use Symfony\Component\Routing\Annotation\Route;
    use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
    use Pimcore\Model\Asset;
    class SlideShowController extends FrontendController
    {
    }
    
  9. 现在我们必须实现渲染视图的动作。这个动作将获取用户添加的文件夹,并将图像列表加载到视图中。在下面的代码片段中,我们有动作实现;将其取走并添加到你的控制器中:

    public function galleryAction(Request $request)
    {
         $result=array();
         if ('asset' === $request->get('type')) {
              $asset = Asset::getById($request->
              get('id'));
              if ('folder' === $asset->getType()) {
                 $result['assets'] = $asset->
                  getChildren();
              }
         }
         return $result;
    }
    

    代码与我们在第九章配置实体和渲染数据中使用的代码相同,因此无需更多解释。

  10. 正确渲染的最后一步是创建一个名为gallery的视图,并将其放置在控制器相关的文件夹中(例如,/bundles/BlogBundle/Resources/views/slide_show/gallery.twig)。我们将使用的模板如下:

    <div id="carouselExampleControls" ...>
      ... omitted bootstrap tags  
      {% if assets %}
         {% set active ='active' %}
         {% for asset in assets %}
              {% if asset is instanceof('\\Pimcore\\
              Model\\Asset\\Image') %}
                   <div class="carousel-item  {{ active 
                    }}">
                      <img srcfor loop that prints images following the bootstrap carousel standard. The image thumbnail is extracted from the original image using the getThumbnail('SlideShow') function. The title and subtitle fields are read from the asset properties using the asset.getProperty method. 
    
  11. 将砖块添加到页面并将文件夹拖动到它上面:![Figure 10.11: Dragging the folder to the component

    ![img/Figure_10.11_B17073.jpg]

    图 10.11:将文件夹拖动到组件中

  12. 现在,你将看到下一个屏幕截图中的滑动轮播图:

![Figure 10.12: The slideshow in action]

![img/Figure_10.12_B17073.jpg]

图 10.12:幻灯片播放效果

在之前的屏幕截图中,我们突出显示了导航按钮和打印在图像上的字段。

在本节中,我们发现了如何集成控制器和砖块。通过使用第八章中提到的可编辑关系,创建自定义 CMS 页面,并在砖块内部实现模板,可以达到相同的结果。现在我们已经涵盖了所有与砖块相关的主题,是时候学习如何实现一个可以让我们创建任何类型的页面而不需要编写任何额外代码的布局了。

使用砖块和块构建通用模板

在本节中,我们想要找到一个解决方案来实现所有类型的布局,而无需花费数小时创建自定义模板。从理论上讲,我们可以有一组基础对象,然后将它们组合起来以创建所有类型的网站。在实践中,这就是我们应该如何使用 Pimcore 来做的事情:

![Figure 10.13: General-purpose template

![img/Figure_10.13_B17073.jpg]

图 10.13:通用模板

之前的图表显示了多功能布局的结构。我们有许多水平部分(Section 1,…,Section N),它们可以被划分为列(col1col2col3)。在每一个位置,你都将能够添加砖块以按照你想要的任何布局来组合页面。

从理论上讲,我们需要添加一个块迭代,它将在另一个块迭代内部打印行,该块迭代将打印列。这让我们能够创建一个元素矩阵,我们可以添加一个areablock来选择我们想要的任何砖块。这种布局在文字描述中相当简单,通过将我们在上一章中学到的知识付诸实践,它是可行的。

在本例中,我们将创建一个类似于以下图中所示的通用布局:

![Figure 10.14: Generic website layout]

![img/Figure_10.14_B17073.jpg]

图 10.14:通用网站布局

在前面的图中,我们可以注意到三个带(标题左侧带有描述的联系方式,然后是一个全宽的幻灯片)。这当然是一个非常简单的用例,但通过一些想象力,你应该能理解如何将其扩展到任何类型的网页。按照以下步骤创建自定义布局:

  1. 第一步是创建一个可以实现 Bootstrap 容器的区域砖。这个区域砖将允许用户选择列数和大小。因此,我们必须在 Document/AreaBrick/Container.php 中创建砖类。起始代码如下:

    <?php
    namespace BlogBundle\Document\Areabrick;
    class Container extends AbstractTemplateAreabrick implements EditableDialogBoxInterface
    {
        public function getName()
        {
            return 'Container';
        }
        public function getDescription()
        {
            return 'Container';
        }
    }
    
  2. 第二步是为组件配置以向用户公开列配置。在这个例子中,我们假设我们只能有三种布局选项(一列、两列 30%-70% 和大小相同的两列)。在现实世界的例子中,你可以准备任何可能的组合,包括列数和大小,以使用户能够真正自主地管理任何类型的布局。在下一段代码中,有创建包含所有布局的下拉列表的配置:

    public function getEditableDialogBoxConfiguration(Document\Editable $area, ?Info $info): EditableDialogBoxConfiguration
        {
            $config = new EditableDialogBoxConfiguration();
            $config->setWidth(600);
            $config->setItems([
                'type' => 'tabpanel',
                'items' => [
                    [
                        'type' => 'panel',
                        'title' => 'Column settings',
                        'items' => [
                            [
                                'type' => 'select',
                                'label' => 'Layout',
                                'name' => 'layout',
                                'config' => [
                                    'store' => [
                                        ['one.html.twig',                                     'One column'],
                                        ['two-50-50.html.                                    twig', 'Two column                                     50-50'],
                                        ['two-30-70.html.                                    twig', 'Tre column                                     30-70'],
                                    ]
                                ]
                            ]
    
                ]
                ]
            ]]);
            return $config;
        }
    

    注意,为了简单起见,我们使用了文件模板的名称作为选择项的值,这样项就可以简单地与内容相关联。

  3. 类中的最后一步是读取配置参数并将其传递到视图中。为此,你只需将以下代码中的 action 方法实现添加到你的类中:

    public function action(Info $info)
    {       
         $layout=$this->getDocumentEditable($info->
         getDocument(), 'select', 'layout')->getData(); 
         $info->setParam('layout',"@Blog/areas/
         container/templates/$layout");        
    }
    

    如从源代码中看到的,相对文件名被转换成完整路径并添加到属性包中。

  4. 现在我们必须实现主视图模板。只需将以下代码添加到 view.html.twig 文件中:

    <div class="container blog-container">
    {% include layout %}
    {% if editmode %}
        <div class="blog-container-footer">
                CONTAINER
        <div>
    {% endif %}
    </div>
    

    上一段代码包含了基于动作中设置的变量创建的模板,并且简单地将其包裹在 bootstrap 容器中。此外,当你处于编辑模式时,它会在底部添加一个栏来帮助用户识别布局。

  5. 现在我们必须实现砖模板。像往常一样,我们需要创建一个 view.html.twig 文件,但这次我们还将创建一个包含许多其他模板的文件夹,这些模板将被动态加载。因此,创建 one.html.twigtwo-50-50.html.twigtwo-30-70.html.twig 文件。最终结果如下:图 10.15:文件配置

    图 10.15:文件配置

  6. 现在我们必须实现三个模板。为了简洁,我们在这里只报告一个案例:其他案例非常相似,可以在代码库中找到。下一段代码展示了两列的实现:

    <div class="row">
        <div class="col-6 blog-col">
            {{ pimcore_areablock("content_50501")}}        
        </div>
         <div class="col-6 blog-col">
            {{ pimcore_areablock("content_50502")}}        
        </div>
    </div>
    

    正如你在前面的代码中看到的,有一个 bootstrap 行和两个列(col-6col-6 表示相同的宽度)。在每一列内部,areablock 组件将允许你选择要添加到其中的组件。现在我们准备好在现实世界的例子中使用我们的通用模板了!

  7. /bundles/BlogBundle/Layout中创建layout.html.twig文件,并添加以下代码片段:

    {# SETTING THE IMAGE URL#}
    {% set imageurl=null %}
    {% if not editmode %}
     {% set image =pimcore_relation("image")%}
      {% if  image.getElement() is defined and  image.  getElement() != null %}
        {% set imageurl= image.getElement().    getThumbnail("SlideShow") %}
      {% endif %} 
    {% endif %}
    {# PRINT HEADER#}
    <header class="masthead" style="background-image: url({{imageurl}})">
        <div class="overlay"></div>
        <div class="container">
          <div class="row">
            <div class="col-lg-8 col-md-10 mx-auto">
              <div class="site-heading">
                <h1> {{ pimcore_input('headline', {'width':             540}) }}</h1>
                <span class="subheading"> {{ pimcore_            input('subheading', {'width': 700}) }}</span>
              </div>
            </div>
          </div>
        </div>
      </header>
    {# IMAGE INPUT #}
    {% if editmode %}
    {{  pimcore_relation("image",{
        "types": ["asset"],
        "subtypes": {
            "asset": [ "image"],
        },
        "classes": ["person"]
    }) }}
    {% endif %}
    

    这段代码将渲染一个参数化标题,该标题将放置在所有我们的页面上。您不希望在所有页面上都有它?没问题。您总是可以将此代码转换为砖块,并仅将其放置在您真正需要的地方。

  8. 现在,创建一个模板。因为我们想创建一个带有水平带的标准化布局,所以我们只允许使用Container砖块。

  9. 要做到这一点,只需在默认文件夹内创建一个名为generic.html.twig的文件,并将其添加到以下代码片段中:

    {% extends 'BlogBundle:Layout:layout.html.twig' %}
    {% block content %}
     {% include 'BlogBundle:Layout:header.html.twig' %}
        {{ pimcore_areablock("content", {'allowed':['container']})}}
    {% endblock %}
    

    之前的脚本定义了一个带有标题和将托管页面布局容器的区域块的页面结构。

  10. 创建一个网页,并使用此过程第 6 步中创建的generic.html.twig模板。

  11. 以编辑模式打开您创建的网页。您应该看到以下结果:图 10.16:将容器添加到页面

    图 10.16:将容器添加到页面

  12. 完成此步骤后,组件将在页面上就绪。现在点击配置按钮,如图所示:图 10.17:打开设置

    图 10.17:打开设置

  13. 到目前为止,用户可以使用编辑框选择布局,就像我们在上一节中看到的联系表单示例一样。此配置的结果如下弹出窗口:图 10.18:选择布局

    图 10.18:选择布局

    以下截图显示了允许我们创建任意多带的区域砖块。完成此步骤后,您应该得到以下结果:

    图 10.19:页面上的容器组件

    图 10.19:页面上的容器组件

  14. 通过点击容器区域内的加号按钮(如图 10.19 所示)并选择列砖块,将列内容添加到其中。

  15. 通过点击加号按钮并从组件菜单中选择项目,在右侧添加一个联系表单。

  16. 在左侧列中添加一个标题组件,即我们在实现简单砖块部分创建的标题组件。然后在标题上方添加一个所见即所得编辑器。您应该得到以下截图所示的结果:图 10.20:带有联系表单和数据的网页

    图 10.20:带有联系表单和数据的网页

  17. 现在通过点击顶部向下箭头(如图 10.20 所示)在之前的容器之后添加另一个容器。在此组件上添加幻灯片砖块。通过拖放图片进行配置,就像我们在本章幻灯片示例中所做的那样。下一张截图总结了您在此页面部分的工作:

图 10.21:本例中要获得的结果

图 10.21:本例中要获得的结果

在本节中,我们学习了如何创建一个能够适应大多数情况的模板。这个例子为我们提供了一个在现实场景中测试通用布局的好机会。这个模板,结合你能够创建的所有砖块,将涵盖最常见的场景,并将节省大量时间。

摘要

在本章中,我们继续使用 Pimcore CMS,通过发现砖块引擎,另一个创建动态网站的重要工具。通过创建砖块,可以轻松准备可重复使用的组件,网页编辑人员可以使用这些组件来组合任何网站,而无需向开发者请求定制。这种新的处理方式对于减少开发工作量、保持高质量标准和提高实现用户所需功能的速度非常重要。

更具体地说,我们通过实施现实世界的例子发现了砖块的工作原理。联系表单和幻灯片是你在项目中一定会重复使用的组件。此外,我们还学习了如何创建一个通用模板,使我们能够不写一行代码就生成任何页面布局。

在下一章中,我们将学习如何通过发现一些日常 Pimcore 使用的重要细节和解决方案来最终确定我们的网站。最重要的几点包括,我们将学习如何创建安装包的安装程序,以便在设置后轻松重新创建我们的类和内容,以及我们将学习如何创建 Pimcore 的多站点实例。

第十一章:第十一章:完成网站

在上一章中,我们使用 Pimcore 完成了博客的建设。得益于 CMS 和数据管理引擎的能力,我们能够实现创建自定义非结构化内容(网站的页面)和结构化内容(博客文章)等复杂目标。这是一段愉快的旅程,使我们能够自主实现任何类型的网站或门户。此外,我们可能还需要采取许多其他步骤来使我们的工作可重用、可扩展且易于部署。正如标题所述,在本章中,我们将学习如何最终完成我们的网站。

我们将涵盖的要点如下:

  • 在 Pimcore 中创建多站

  • 使捆绑包可安装

  • 使用多环境配置

  • 使用环境变量

技术要求

就像之前的章节一样,在我们的 GitHub 仓库中有一个演示,您可以在以下链接找到:github.com/PacktPublishing/Modernizing-Enterprise-CMS-using-Pimcore

要运行与本章相关的演示,您只需克隆它并导航到完整演示文件夹以启动 Docker 环境。

要做到这一点,只需遵循以下说明:

  1. 使用以下命令运行 Docker:

    docker-compose up
    
  2. 然后,为了在您的本地机器上恢复所有设置,请输入以下命令:

    docker-compose exec php bash restore.sh
    
  3. 导航到localhost/admin并使用您的管理员/pimcore 凭据登录。

在 Pimcore 中创建多站

每次创建网站时,您都需要花费时间来创建环境、安装插件以及配置所有其他 Pimcore 设置。此外,我们还需要一个托管空间,这意味着额外的成本。这是我们每次创建网站时都必须进行的操作,但我们希望减少这种活动对每个网站创建的影响。

例如,考虑一个场景,一个客户有 10 个网站,可能每个品牌都有一个。考虑到如今每个公司都有的数字曝光度,这是一个合理的用例。即使我们可以创建一个可以用于迁移网站之间公共组件的捆绑包,拥有独立的网站仍然涉及额外的开销。从用户的角度来看,管理 10 个不同的网站是非常困难的。

对于这种常见情况,解决方案仍然是 Pimcore 本身。多站功能让我们能够在同一个实例中管理多个网站,降低托管成本,并在所有网站中使用相同的资源(主题、砖块、自定义代码)。借助云提供的扩展能力,我们预计不会出现服务器负载问题,并且我们可以无副作用地遵循这种方法。

为了覆盖您可能在与现实世界网站相关的所有可能情况,我们将实施一个测试案例,其中我们将网站树的一个分支转换为独立网站。这将使用户能够像浏览独立网站一样访问网页。这是让您能够在同一个 Pimcore 实例中管理多个网站(例如,product1.mywebsite.comproduct2.mywebsite.com)以及网站别名(例如,www.mywebsite.commywebsite.com)的基本原则。

在下一个示例中,我们将创建一个名为subsite1的通用子站点,并使用与默认域名不同的域名使其可用。此外,我们将使用不同类型的域名映射来覆盖所有最常见的情况(地址、别名和通配符):

  1. 将文档添加到页面树中。命名为subsite1。页面的名称不会影响网站的行为。在我们的案例中,我们使用了完整的演示设置,并得到了以下截图所示的网页:![图 11.1:用于测试的页面 图片 B17073_11_01.jpg

    图 11.1:用于测试的页面

  2. 在树形菜单中导航,并在subsite1项上右键单击。然后点击使用为站点:![图 11.2:用于将网页转换为网站的菜单 图片 B17073_11_02.jpg

    图 11.2:用于将网页转换为网站的菜单

    如果您点击使用为站点按钮,将弹出一个窗口:

    ![图 11.3:配置网站的表单 图片 B17073_11_03.jpg

    图 11.3:配置网站的表单

  3. 填写以下信息的表单:

    • subsite1.local

    • subsite1-alternative.local*.subsite1.local。这些值必须放在两行不同的地方。此设置适用于我们已选择的项及其所有子项。此配置告诉 Pimcore 使用我们在步骤 2中提升为站点的页面下的页面来处理请求。这意味着如果您导航到添加的域名之一,将提供此页面下的页面。因此,如果您导航到subsite1.localsubsite1-alternative.local,您将看到转换后的页面;如果您在域名内部查找路径(例如subsite1.local/xxx),将提供页面站点下具有相同相对路径的页面。对于subsite1.local的所有三级域名也是如此,例如mysubsite.subsite1.local,因为我们输入了通配符地址。

  4. 编辑您的 hosts 文件以访问这些虚拟 URL。打开 hosts 文件并添加以下行:

    127.0.0.1 subsite1.local
    127.0.0.1 subsite1-alternative.local
    127.0.0.1 test.subsite1.local
    
  5. 请访问以下网址:subsite1.local, http://subiste1-alternative.local,以及test.subsite1.local。您将始终得到相同的结果,这证明了多站点的配置良好。

在本节中,我们学习了如何将页面树的一部分转换为独立的网站。这对于托管多个网站和重用同一代码库的主题和组件非常有用。这对可重用代码非常有帮助,它可以与打包和共享源代码一起工作。在下一节中,我们将学习如何在包安装期间创建创建数据和设置的过程。

使包可安装

第十章**,创建 Pimcore 砖块中,我们创建了一个包含所有资产的单一包,使其自包含且可移植。通过安装一个包来开始我们的下一个 Pimcore 项目意味着我们不必重新执行某些任务,这使得这是一个有吸引力的选项。无论如何,有一些步骤我们通过用户界面手动执行,现在必须复制。回想一下第九章**,渲染数据,它们是手动创建的,但你不想在创建每个新博客时重复这一步骤。即使你只花几分钟创建它们,也总有可能输入错误的字段名或出错;它们将你的 5 分钟任务变成一个小噩梦。

但不必担心!Pimcore 的安装系统允许你添加一个特殊类来管理安装过程。以下是一些常见的用例:

  • 创建或更新类定义

  • 输入种子数据(例如标准分类)

  • 更新数据库模式(添加表、列、索引等)

  • 导入翻译

安装器实际上是在安装包时 Pimcore 使用的类。

这个主题有两种不同的方法:

  • 安装器:一个管理安装过程并赋予你自定义所有阶段(安装和卸载)的权限的类。

  • 迁移:这一部分是为了管理数据库变更,并支持升级和降级选项。

让我们在下一节中探讨这两个选项。

安装器

当安装器处理初始配置时,迁移保持数据库更新。当你安装包时,将运行一个安装过程。然后,在每次包更新时,你可以对数据库应用一些更改以实现数据迁移。

安装器类可以继承自 AbstractInstaller 并具有以下结构:

class MyInstaller extends AbstractInstaller
{    
    public function install()    {}
    public function uninstall()  {}
    public function isInstalled(){
        return true;
    }
    public function canBeInstalled(){
        return false;
    }
    public function canBeUninstalled(){
        return false;
    }
    public function needsReloadAfterInstall() {
        return false;
    }

AbstractInstaller 包含一个 BufferedOutput 实例,该实例与控制台工具和 Web UI 集成。这意味着如果你用它来记录日志,日志将会提示给用户。BufferedOutput 实例可以通过 getOutput() 方法访问。

现在我们将创建一个安装器,它可以自动安装与我们的项目相关的类。这非常简单,我们只需要完成以下步骤:

  1. 创建一个包含一个或两个字段的类定义。命名为test。为了保持简单,类的复杂性对我们目标来说并不重要。如果你对如何创建类有疑问,只需查看第五章**,探索类和对象,其中涵盖了这一主题。

  2. 通过点击类定义页面上的导出按钮下载类定义:图 11.4:类导出菜单栏

    图 11.4:类导出菜单栏

  3. 现在在/bundles/BlogBundle/Resources/install/中创建一个名为class_sources的文件夹,最终路径为/bundles/BlogBundle/Resources/install/class_sources

  4. 将你导出的 JSON 文件复制到这个文件夹中。

  5. 在你的包中创建一个名为Setup的文件夹,并在其中添加BlogInstaller类。内容应包括以下内容:

    <?php
    namespace BlogBundle\Setup;
    ... usages
    class BlogInstaller  extends AbstractInstaller
    {    
    }
    
  6. 现在我们必须注册安装器类,使其可用于依赖注入。将以下配置添加到service.yml文件中:

    services:
        BlogBundle\Setup\BlogInstaller:
            public: true
            autowire: true
    

    现在依赖注入知道你的安装器,并且可以创建其实例。

  7. 打开BlogBundle.php包文件,并添加以下方法:

    public function getInstaller() {        
         return $this->container->get(
         BlogInstaller::class);      
    }       
    

    此函数将告诉 Pimcore 你的包有自己的安装器,并将使用它。当你安装你的包时,会发生什么,你的安装器的事件将被触发,你将能够做所有你需要的事情。在接下来的步骤中,我们将实现初始配置。

  8. 下面的代码片段实现了类恢复,因此添加此函数(为了简洁,省略了日志和输出消息):

    public function install(){       
         $files = $this->getClassesToInstall();
         foreach ($files as $file) {
              $data = file_get_contents($file);
              $json= json_decode($data);
              $name= $json->id;
              $class = ClassDefinition::getById($name);
              if($class) continue; // do not overwrite
              $class = new ClassDefinition();
              $class->setName($json->id);
              $class->setId($json->id);
    Service::importClassDefinitionFromJson($class, $data, false, true);
         }
    }
    

    安装过程由几个简单的步骤组成。首先,我们读取文件系统,并获取classes文件夹中的所有文件(files = $this->getClassesToInstall();)。然后,对于每一个,我们检查类是否存在;如果不存在,我们创建并导入类。如果类存在并且我们用不同的定义覆盖它,我们可能会遇到数据丢失,我们不希望这样。

  9. 下一个片段包含getClassesToInstall过程。将其复制到安装器类中:

    protected function getClassesToInstall()
    {        
         $realpath = realpath(__DIR__."/../
         Resources/install/class_sources/");
         $files=glob($realpath.'/*.json');           
         return $files;
    }
    

    上述代码读取class_sources文件夹中的所有*.json文件,并将它们返回给调用者以进行安装。

  10. 现在是时候测试包了。为了进行严格的测试,我们应该创建一个新的环境,将包移动到该环境,并对其进行测试。然而,这种方法需要时间和精力,并且对于本说明来说并不相关,因此我们将使用快捷方式。

    由于我们没有数据库迁移或不可逆的操作,我们将使用当前安装。第一个操作是删除你导出的类。这是强制性的,因为否则我们的程序将跳过创建(参见步骤 7)。你可以通过右键单击类名然后点击删除来完成此操作,如图所示:

    图 11.5:如何删除一个类

    图 11.5:如何删除一个类

  11. 现在我们必须通过告诉 Pimcore 我们的包是可安装的来欺骗它。为此,在安装类中实现canBeInstalled方法,返回true(这意味着“是的,它可以安装!”)。复制以下代码片段并将其粘贴到您的文件中:

    public function canBeInstalled(){
            return true;
        } 
    

    下一个屏幕截图显示了方法实现前后的变化:

    图 11.6:比较更改标志前后的包设置

    图 11.6:比较更改标志前后的包设置

    前一个屏幕截图显示了当我们更改canBeInstalled方法时安装状态的变化。第一个标志矩阵是pimcore:bundle:list命令的输出,您可以看到该包被标记为不可安装。在安装类中的更改之后,可安装标志变为活动状态,Pimcore 将允许我们再次安装该包。

  12. 最后,是时候测试包的安装器了。从命令行进入bin/console pimcore:bundle:install BlogBundle图 11.7:扩展面板现在允许您再次安装包

    图 11.7:扩展面板现在允许您再次安装包

    如您在前一个屏幕截图中所见,UI 中可用的选项反映了从控制台收集的信息。

  13. 导航到类列表。您将在菜单中再次找到您删除的test类,因为它被安装过程重新创建:

图 11.8:创建的类

图 11.8:创建的类

在本节中,我们介绍了安装过程的工作原理。在下一节中,我们将使用迁移来处理模式更新和数据播种。

迁移

迁移的目的是管理数据迁移和模式更新。如果您正在使用自定义数据库结构,这将非常有用。迁移的基本概念是它从一个现有版本开始,可以通过应用更改的增量来递增。可以通过实现回滚函数来撤销迁移。更具体地说,Pimcore 中的迁移是一个类实现,它有两个方法:up(应用更改)和 down(撤销更改)。

以下图表解释了迁移过程:

图 11.9:迁移过程

图 11.9:迁移过程

如您在前一个图中所见,更新后,版本 1.0 更新到 1.1,但如果进行回滚,down 方法将将其恢复到初始版本。

将管理迁移的能力添加到您的应用程序的第一步是为迁移文件映射一个文件夹到您的命名空间。为此,只需打开/config/config.yml文件并添加以下片段:

doctrine_migrations:
      migrations_paths:
          'App\Migrations': 'src/Migrations'

上述代码片段将您的命名空间与相关文件夹映射。

创建迁移类时,最佳方法是调用console命令:

bin/console doctrine:migrations:generate --namespace=App\\Migrations

前一个命令在主应用程序的迁移文件夹内创建了一个文件。每个版本都有一个生成的名称,例如 /src/Migrations/Version20210227065641.php,其中文件名的Version前缀后面跟着一个时间戳。

创建的文件看起来可能如下所示:

<?php
namespace App\Migrations;
… uses
class Version20210227065641 extends AbstractMigration
{
    public function up(Schema $schema)    {
          //do things here
    }
    public function down(Schema $schema)    {
          //do things here
    }
} 

Schema对象是一个 doctrine 元素,它允许您操作数据库结构。以下示例显示了最重要的用例,例如创建一个表、添加字段和删除字段:

        $table = $schema->createTable('foo');
        $table->addColumn('title', 'string');
        $table->addColumn('description', 'string');
        $schema->dropTable('foo');

重要提示

要全面了解Schema对象的功能,请查看 Symfony 文档:www.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/schema-representation.html

在本节中,我们学习了如何创建一个安装程序来管理包的设置和数据迁移。当您想基于 Pimcore 创建一个可移植的包或产品时,这个主题非常有用。例如,考虑一个包含所有砖块和实用工具的包,您可以用它作为项目的基础。在下一节中,我们将介绍在同一个代码库中工作时的另一个重要主题。

使用多环境配置

在任何现代部署工作流程中,我们都有四个环境:localdevtestproduction。这些环境可能具有不同的配置和调整。您的生产环境可能需要在集群系统中面对大量的用户和沉重的负载,而您的本地环境只需与 RAM 的数量作斗争。我们看到的是,每个环境都有不同的需求,因此需要不同的配置。我们想要遵循的方法是保持所有数据在一个代码库中,并将所有设置放在同一个地方。如果您认为您将需要管理大量的文件和复杂的逻辑来切换它们,那您就错了。

幸运的是,Pimcore 基于 Symfony,并扩展了其非常强大的配置系统。Pimcore 原生支持devtestprod环境(而其他环境可以通过额外的配置添加)。要切换环境,您必须指定PIMCORE_ENVIRONMENT环境变量。由于我们的 Pimcore 实例运行在容器中,此设置对我们 PC 没有任何影响,因为配置仅限于容器。

一旦设置了变量,Pimcore 将按以下顺序加载文件:

  1. config/pimcore/system_{env}.yml

  2. var/config/system_{env}.yml

  3. config/pimcore/system.yml

  4. var/config/system.yml

配置文件可以包含其他配置文件并继承属性。全新 Pimcore 安装附带默认设置,config.yml 文件从 devprod 有增量配置(prod 包含 test,而 test 包含 dev)。这种机制对于共享设置并在需要时覆盖它们非常有用。

如果你省略了 PIMCORE_ENVIRONMENT,基础文件将按照以下升级顺序获取:

  1. config/pimcore/system.yml

  2. var/config/system.yml

当你在控制台运行 Pimcore 时,你可以将环境作为参数传递,如下例所示:

./bin/console --env=dev ...

在 Pimcore 环境中,拥有不同的 Pimcore 配置以匹配我们将要工作的不同环境规格非常重要。顺便说一句,出于安全原因,并非所有配置都可以保存到设置文件中。在下一节中,我们将学习如何使用 Pimcore 安全地管理敏感数据,例如密码和 API 密钥。

使用环境变量

使用容器作为现代方法时,会大量使用环境变量将值注入应用程序。这种方法非常方便,因为它使你的应用程序对部署的环境无关。这个过程意味着配置的一部分是从应用程序代码外部拉取的。

将所有配置移出应用程序会使开发者对内部发生的一切一无所知,当出现问题时,这会在开发者和运维团队之间造成误解。你有你的本地代码,你可以看到它运行,但你将无法了解在生产环境中应用其他设置时可能会发生什么。通常,负责运维的人对配置背后的含义知之甚少,因为他们不是应用程序的专家,而且通常不是开发者。开发者知道应用程序是如何工作的,并且了解设置更改的影响,但他们对基础设施了解不多,无法对应用程序可能存在的问题进行测试以修复问题(他们没有访问生产环境的权限)。

在本节中,我们将解释一种解决方案,它可以保持生产设置的安全,在开发者和运维之间共享配置,并且易于使用 Pimcore 实现。一个好的折衷方案是将所有配置保留在源代码中,但在部署期间移除注入的敏感信息。将敏感信息与配置分开,让我们能够与整个团队共享设置,并使每个人都了解选择的配置,但不会使我们面临安全问题。这种方法创建了一个清晰的职责划分,并使我们的存储库更安全。这样,开发者了解每个环境的配置,而运维可以独立管理系统设置。

这个解决方案有积极的一面,即开发者可以在他们的本地 PC 上测试不同的配置(但不会访问生产系统),结果更可预测。但是,如何配置 Pimcore 将配置与敏感数据分开?在下一个示例中,我们将创建一个适用于所有环境但不会将敏感数据添加到源代码文件的配置。

使用环境变量管理数据库连接

我们的目标是拥有一个本地、测试和生产环境配置相同的 Pimcore 实例。所有配置都将存储在 devtestprod 文件夹中。我们想要以这种方式管理的配置项是配置字符串。我们将移除 Pimcore 的硬编码连接字符串,使其参数化。这些数据通常在 config/local/database.yml 文件中设置,并在第一次安装时由 Pimcore 生成;通常不会提交。由于我们使用的是 Docker 化环境,所有下载源代码的开发者都在单独的环境中本地工作,因此不存在共享此信息的问题。

我们现在可以开始在这些设置下工作了:

  1. 删除或重命名 database.yml 文件(我们不再需要它了)。

  2. 将以下代码添加到 docker-compose.yml 文件中。此配置将设置作为 环境变量

    services:
     …
      php:
       …
       environment: 
        - PIMCORE_ENVIRONMENT=dev
        - PIMCORE_HOST=db
        - PIMCORE_DB=pimcore
        - PIMCORE_USERNAME=pimcore
        - PIMCORE_PASSWORD=pimcore
        - PIMCORE_PORT=3306 
    

    下一个图显示了同一文件中 MySQL 设置的裸拷贝:

    ![图 11.10:容器之间的字段映射

    ![img/B17073_11_10.jpg]

    图 11.10:容器之间的字段映射

  3. 现在我们必须告诉 Pimcore 使用此变量的配置。依赖链是 config_prod.yml 包含 config_test.yml,而 config_dev.yml 包含 config.yml。因此,将适当的配置添加到 configconfig_dev 文件中,将使其对所有环境可用。

  4. 打开 config.yml 文件。首先需要做的更改是禁用数据库配置的导入。只需注释掉以下行:

    # - { resource: 'local/' } removed... it users environments now!
    

    禁用了 local 资源集的导入(否则,您只需删除 database.yml 文件)。

  5. 然后将以下配置添加到文件中:

    doctrine:
        dbal:
            connections:
                default:              
                    host: '%PIMCORE_HOST%'
                    port: '%PIMCORE_PORT%'
                    dbname: '%PIMCORE_DB%'
                    user: '%PIMCORE_USERNAME%' 
                    password: '%PIMCORE_PASSWORD%'
    parameters:
        PIMCORE_ENVIRONMENT: '%env(PIMCORE_ENVIRONMENT)%'
        PIMCORE_HOST:  '%env(PIMCORE_HOST)%'
        PIMCORE_DB:  '%env(PIMCORE_DB)%'
        PIMCORE_USERNAME:  '%env(PIMCORE_USERNAME)%'
        PIMCORE_PASSWORD:  '%env(PIMCORE_PASSWORD)%'
        PIMCORE_PORT: '%env(PIMCORE_PORT)%'
    

    配置与 database.yml 相同,但具有参数化。我们定义内部参数,从容器中导入环境变量。我们使用 1:1 映射,为参数重用相同的环境变量名称。这使得配置更容易阅读。

    然后我们在文件的 doctrine\dbal\connection\default 部分使用该参数。这确保 Pimcore 将激活一个与此配置的连接,使用获取值的参数来形成主机环境(在我们的情况下是 docker-compose 文件)。

    在这一步之后,我们将配置与数据完全解耦,因此我们可以分别设置它们。您可以提交任何配置(devtestprod),而不用担心有人会窃取敏感数据,在部署期间,正确的值将被注入到环境中(虚拟机或容器)。

  6. 打开 Pimcore 并检查您是否可以登录。因为我们的更改是关于数据库的连接,如果我们能够登录,那么我们的新设置就成功了。

在本节中,我们学习了如何在 Pimcore 配置中管理敏感信息,以及如何创建变量而不复制设置。使用容器是一个有用的解决方案,因为容器可以被部署为独立的虚拟机、PC 或云服务,这意味着该解决方案涵盖了大多数用例。此外,将所有配置放在源代码中,使得开发人员可以访问,从而对平台在生产中的工作有更深入的了解。所有配置都可以轻松地在本地进行测试,然后提交。

摘要

在本章中,我们学习了 Pimcore 开发人员的一些重要细节,这对于最终完成我们的网站非常重要。

多站点配置允许我们仅使用一个 Pimcore 实例来管理公司的所有网站。这是一个节省时间和金钱的非常有趣的功能,只需使用一个 Pimcore 安装来管理所有公司网站。

安装程序赋予我们执行安装步骤以重新创建我们捆绑包所需配置的能力。我们可以创建数据资产并对它们进行更新。这意味着我们可以将我们的捆绑包安装到另一个 Pimcore 实例上,并添加捆绑包运行所需的所有类和数据。我们还学习了我们可以以低级别管理数据库更改。

多环境功能允许 UX 根据我们使用的环境指定不同的配置。这对于保持所有功能在一个代码库中非常有用。此外,我们还发现了配置强大的继承系统是如何工作的。

环境变量可以帮助使配置与环境无关,并且我们学习了如何从文件中移除敏感数据。

现在我们对 CMS 部分的旅程几乎完成,我们可以转向 Pimcore 开箱即用的企业解决方案。在下一章中,我们将学习如何正确地在 Pimcore 中收集和存储产品信息,并将信息传播到所有其他应用程序。这对于使公司能够将 Pimcore 用作 PIM 解决方案非常重要。

第十二章:第十二章:实施产品信息管理

在前面的章节中,你学习了在第一章介绍 Pimcore中介绍的 Pimcore 环境的一些关键特性。特别是,在第六章使用数字资产管理中,你发现了 Pimcore 的数字资产管理(DAM)特性和与图像及资产管理相关的所有方面。然后,在第四章在 Pimcore 中创建文档第八章创建自定义 CMS 页面中,你学习了内容管理系统(CMS)的概念以及如何创建文档和网站页面。

在本章中,我们将深入探讨产品实体的概念。本章的组织结构如下:

  • 什么是 PIM?

  • 定义产品实体

  • 创建产品变体

  • 创建捆绑产品

  • 管理不同的产品类型

  • 与工作流程一起工作

从解释 PIM 系统是什么开始,我们将实现一个产品类的示例。在定义了类属性之后,你将学习如何创建产品变体和捆绑产品,以及如何使用 Objectbricks 管理不同的产品类型。在章节的最后部分,你将学习如何定义一个工作流程来逐步填写产品信息。

技术要求

正如你在前面的章节中所做的那样,你所需要做的就是运行与本章相关的演示,通过导航到官方书库的12. 实施 产品 信息 管理文件夹,并启动一个 Docker 环境。

要做到这一点,只需遵循以下说明:

  1. 使用以下命令运行 Docker:

    docker-compose up
    
  2. 然后,为了恢复您本地机器上的所有设置,只需打开一个新的 shell,并输入以下命令:

    docker-compose exec php bash restore.sh
    
  3. 导航到localhost/admin,并使用您的管理员/pimcore 凭据登录。

你可以通过以下链接访问官方书库以获取源代码:

github.com/PacktPublishing/Modernizing-Enterprise-CMS-using-Pimcore/tree/main/12.%20Implementing%20Product%20Information%20Management

现在,你已经准备好通过演示来探索与本章相关的所有方面。

什么是 PIM?

第一章介绍 Pimcore中,我们简要介绍了产品信息管理(PIM)的概念。在本节中,我们将更好地解释这个概念,我们将在本章的后续部分将其付诸实践。

PIM(产品信息管理)的概念涵盖了一系列技术和流程,这些技术和流程允许对产品数据进行集中管理,并在不同的渠道间进行分发。在许多常见的场景中,与产品相关的信息可能来自多个来源,这些信息可能具有不同的数据结构,这既是因为它们在不同渠道的需求不同,也是因为同一公司内部不同区域提供的技术不同。

使用 PIM 可以使您将来自不同来源的信息整合到一个单一平台上,并对其进行连贯的组织,同时有可能以不同的方式重新分配这些信息到电子商务平台、网站、纸质目录等。它还允许对产品数据进行全面和动态的管理,包括定制和过滤与不同类型产品相关的信息,以管理价格和货币、不同的计量单位、多语言翻译、多媒体内容等等。

能够将所有这些信息集中在一个平台上,使您能够完全独立于任何分销渠道管理产品;PIM 将负责向每个渠道发送所需的信息。这种集中化管理使产品信息保持一致性,避免了在不同平台上复制数据的需求,并保持它们的一致性,减少了设计错误。这也为任何目录、价格表和在线平台的管理成本带来了好处。

对于需要在不同平台和媒体上销售或展示其产品的公司来说,使用 PIM 是必不可少的,但同样对于需要在不同部门或开发领域共享与产品相关信息的企业场景也是必要的,始终保持此类信息的生产集中化。随着需要管理的产品数量增加,拥有 PIM 的需求也会增加,因为管理和维护数据成本会大幅降低,限制在单一平台上。

PIM 技术还使得将产品相关的信息与它们的多媒体内容管理相结合成为可能,并将此类内容发送到各种分销渠道。

所有关于 PIM 概念及其用法的这些方面都在以下图中进行了总结:

![Figure 12.1: PIM Architecture]

![Figure 12.01_B17073.jpg]

图 12.1:PIM 架构

如您在前面的图中所见,产品可以通过上传文件或实施特定的流程与其他软件或数据库建立集成,从而导入到 PIM 系统中。产品也可以直接在 PIM 环境中创建和丰富,通过图形用户界面GUI)。

产品数据可以随后导出到电子商务或其他软件,或者正确地导出到文件中。在第十四章中,数据集成,你将学习在 Pimcore 中导入和导出产品的不同方法。

总结来说,在本节中,你学习了 PIM 的概念以及 PIM 系统在产品数据管理和分发方面的好处。在下一节中,我们将逐步构建Product实体,定义一个代表产品概念的 Pimcore 类。

定义产品实体

在前一节中,你学习了产品信息管理的概念。正如其名所示,在一个 PIM 系统中,创建一个代表产品的类是强制性的,这正是本节将要做的。

Pimcore 在产品概念方面没有设置任何约束,因此我们可以简单地创建一个名为Product的类,并定义所有反映我们需求的属性。所以,正如你在第五章中学习的,探索对象和类,只需通过Product即可。

如果你遵循了技术要求部分提供的说明,你应该找到一个已经定义好的Product类。请注意,这只是一个典型的产品概念示例,你可以根据你的需求添加或删除类属性。你可以在下面的屏幕截图中看到这个类的样子:

![Figure 12.2: 产品类

![img/Figure_12.02_B17073.jpg]

图 12.2:产品类

让我们描述前一个屏幕截图中显示的各种类组件。该类由五个面板组成,这些面板包围着代表产品常见概念的不同的属性,这些将在下面概述:

  • 产品信息:在这个面板中,你可以找到库存单位SKU),它是产品的唯一标识符以及产品价格。然后,我们添加了产品名称和描述作为本地化字段,以便你可以提供翻译。

  • brand属性是一个自定义的单选字段,具有常见的品牌作为选项;还有一个预定义的选项列表,可以选择产品制造的国家。最后一个属性是与另一个类的一个多对一关系,用于描述类别。

  • 组成:在这个面板中,你可以找到一个高级的多对多关系组件,用于将产品与构成产品的材料相关联。在这个关系中,你可以设置各种材料的百分比来定义组成。

  • colorsize。对于color属性,我们定义了一个与专用类的关系。

  • 图片:正如其名所示,这个面板旨在包含产品图片。特别是,我们使用了一个Fieldcollection来管理未定义数量的图片。

为了完整性,在下面的屏幕截图中,你将看到其他类定义:

图 12.3:类定义

图 12.3:类定义

在前一个屏幕截图中,您可以看到CategoryMaterialColor类的定义。对于Category类,我们定义了一个唯一的code属性和几个本地化字段,称为namedescriptionMaterial类采用了相同的结构,并增加了一个字段来定义材料类型。对于Color类,增加了一个设置十六进制hex)值的属性。

如前所述,您应该已经在本章技术要求部分的安装过程之后找到了这些类,但您可以在任何时间通过选择您可以在章节存储库的src/classes文件夹中找到的文件来导入它们,正如您在第七章中看到的,管理 Pimcore 站点

如您在第五章中学习的,探索对象和类,您可以轻松进行数据录入以创建产品和其它实体。在下面的屏幕截图中,您可以看到创建的产品示例:

图 12.4:产品实体

图 12.4:产品实体

如您在前一个屏幕截图中看到的,创建的产品的结构反映了类定义。为了更好地组织内容,各种类的对象被分到了相应的子文件夹中。

总结来说,在本节中,我们学习了如何定义Product实体。我们展示了一个产品概念的可能的实现,但这个概念在属性方面没有固定的定义,因此您可以选择创建更符合您需求的属性。除此之外,我们还定义了其他次要类来关联产品与其它概念,如类别、材料和颜色。这对于将此类信息与产品关联起来非常有用,无需在所有产品中重复它们。

在下一节中,您将学习如何创建产品变体以创建可配置产品。

创建产品变体

在上一节中,您已经了解了如何定义一个Product实体以及创建产品对象的示例。在本节中,您将学习如何为Product类启用继承以创建产品变体和定义可配置产品。在本节的后面部分,我们将看到一些PHP:超文本预处理器PHP)代码示例,这些示例将展示如何在开发过程中实际使用变体。

要为Product类启用继承,打开类定义并选择常规设置根元素。您可以通过选择以下屏幕截图中看到的复选框来启用类继承并允许创建变体:

图 12.5:启用继承

图 12.5:启用继承

如您在先前的屏幕截图中所见,可以启用以下三个复选框:

  • 允许继承:如果勾选此属性,则允许以树状结构在对象之间进行继承。子对象可以是同一类的实例,也可能属于不同的类。

  • 允许变体:如果勾选,则启用创建对象变体的可能性。变体定义是一种特定的继承。不能选择变体类,但强制类与父对象相同。

  • 在树中显示变体:如果启用,此属性允许您在对象树中查看变体。

一旦您勾选了这些复选框,就必须单击保存按钮以应用更改。在为类启用变体后,可以为产品创建变体。要创建变体,只需在先前创建的产品上右键单击,选择添加变体,并输入变体名称。

在以下屏幕截图中,您将看到一个具有定义变体的可配置产品的示例:

图 12.6:产品变体示例

图 12.06:示例图片

图 12.6:产品变体示例

如您在先前的屏幕截图中所见,启用相应的属性可以让产品变体在对象树中显示。您可以通过树结构中的不同特定图标识别产品变体。

变体继承父对象的所有属性值,但在每个变体中都可以覆盖这些属性。在具体示例中,我们使用了颜色属性来创建具有不同变体的可配置产品。

现在您已经学会了如何在 Pimcore 界面中创建产品变体,让我们看看如何在代码中实际使用变体,通过查看一些编码示例。

变体方面的一个关键方面是对象类型。这是一个为所有类的对象定义的系统属性;此属性不能手动填写,但在创建元素时自动定义。有三种不同的对象类型,如下所述:

  • 文件夹:当我们创建数据对象部分中的文件夹时,分配此类型。

  • 对象:当我们创建类的对象实例时,分配此类型。

  • 变体:当我们创建对象变体时,分配此类型。

在 Pimcore 中编码时,重要的是要知道,所有执行对象列表搜索的本地方法始终只考虑文件夹对象类型,因此需要明确指定您想要检索变体。通过以下示例,我们将看到如何做到这一点。

父 PHP 类

在这个第一个示例中,您将学习如何为Product类创建父 PHP 类以及如何创建检索产品变体的方法。创建此类与变体概念没有直接关系,但它是一个值得发现的功能,可能在不同的场景中很有用。

如我们在第五章创建和编辑类定义部分简要介绍的,在[探索对象和类]中,对于每个类,都有定义自定义父 PHP 类的可能性。这可以是任何直接或间接扩展Pimcore\Model\DataObject\Concrete类的 PHP 类。

Concrete类是一个 PHP 类,它是所有 Pimcore 类的原始扩展,并包含所有类的公共方法,例如savegetById操作,仅举两例。

在下面的代码片段中,您将看到一个定义了检索产品变体方法的product父类示例:

<?php
namespace App\Model;
use Pimcore\Model\DataObject;
class AbstractProduct extends DataObject\Concrete
{
    /**
     * @return self[]
     */
    public function getVariants(){
        $variantType = self::OBJECT_TYPE_VARIANT; //variant
        $variants = $this->getChildren(array($variantType));
        return $variants;
    }
}

如您在前面的代码片段中所见,这个类扩展了之前提到的Concrete类。在这个类中,我们创建了一个getVariants方法,该方法调用原始的getChildren方法,并指定需要检索类型为variant的对象。这是必要的,因为我们之前提到,所有列表方法在未直接指定类型时,只考虑对象和文件夹。

一旦创建了 PHP 类,我们必须在Product类中正确设置相应的属性,如以下屏幕截图所示:

![Figure 12.7: 配置父 PHP 类

![img/Figure_12.07_B17073.jpg]

图 12.7:配置父 PHP 类

如您在前面的屏幕截图中所见,您可以在父 PHP 类输入框中写入完整的类命名空间。一旦填写完毕,您必须点击保存按钮以应用更改。

在定义了父 PHP 类之后,您可以为每个产品对象实例调用getVariants方法,如以下代码片段所示:

<?php
    use Pimcore\Model\DataObject;
    $product = DataObject\Product::getById(1);
    $variants = $product->getVariants();
?>

在前面的代码片段中,您可以看到,由于Product类扩展了之前创建的AbstractProduct类,每个产品对象都可以使用定义的getVariants方法。

在本例中我们看到的getChildren 方法只是对象列表的一个特例。在下面的例子中,我们将看到如何检索常见列表方法中的变体。

对象列表

在前面的例子中,我们看到了如何使用检索产品子对象的方法来检索特定产品的变体。在这个例子中,我们将看到如何在通用列表方法中检索变体。

在下面的代码片段中,您可以查看如何在列表查询中检索产品变体:

<?php
    use Pimcore\Model\DataObject\Product;
    use Pimcore\Model\DataObject\AbstractObject;
    $list = new Product\Listing();
    $list->setObjectTypes([AbstractObject::OBJECT_TYPE_    VARIANT]);
    $variants = $list->load();
?>

在前面的代码片段中,您可以查看如何初始化产品列表。对于列表对象,有一个特定的方法来设置您想要检索的对象类型。这个方法就是您在前一个例子中看到的getChildren方法所使用的内部方法。load方法返回一个符合列表条件的对象数组。

在这两个第一个示例中,您已经学习了如何检索现有变体。在下面的示例中,您将看到如何创建一个新的变体。

创建新的变体

在前面的示例中,您学习了如何查询现有变体。在这个示例中,您将学习如何创建产品变体。

在下面的代码片段中,您将看到如何为现有产品创建一个变体:

<?php
    use Pimcore\Model\DataObject\Product;
    use Pimcore\Model\DataObject\AbstractObject;
    $tshirt = Product::getByName("Classic T-Shirt", "en", 1);
    $orange = new Product();
    $orange->setKey("Orange");
    $orange->setParent($tshirt);
    $orange->setType(AbstractObject::OBJECT_TYPE_VARIANT);
    $orange->save();
?>

如您在前面的代码片段中所见,首先您必须获取产品对象。检索到的产品必须声明为新产品变体的父级。然后,必须显式设置产品类型以声明创建的产品是一个变体。

在示例中,您会注意到getByName方法的使用。这种类型的方法在类定义保存时自动为每个类属性生成。第一个参数是要搜索的值,第二个参数是本地化字段(必须搜索值的语言),第三个参数是限制参数。如果限制为 1,则返回单个对象;否则,返回类型是类列表的实例。

总结来说,在本节中,您学习了如何为Product类启用变体以及如何创建产品变体。然后,通过一些代码示例,您学习了如何检索现有变体以及如何创建新的变体。

在下一节中,您将学习如何创建捆绑产品以及如何创建一个在执行某些操作后触发事件的监听服务——例如,在产品保存时自动计算一个或多个产品字段值。

创建捆绑产品

在前面的章节中,您学习了如何启用和创建产品变体,以及如何在代码示例中实际使用它们。在本节中,您将学习如何定义捆绑产品。

在市场营销中,产品捆绑的概念是将一组单独的产品或服务作为一个组合产品或服务包一起提供。通常,捆绑产品旨在作为套件或更普遍地,一组协调一致的产品,如果一起购买而不是单独购买,则具有折扣价格的优势。

通过本章,我们将首先看到如何修改之前创建的Product类以定义捆绑产品。然后,我们将发现如何在产品保存后自动执行操作来计算捆绑价格。

定义捆绑产品

在本节中,您将学习如何修改Product类以能够定义捆绑产品。最简单的解决方案是创建一个与Product类自身相关的自引用关系属性。这将让您能够从之前创建的产品中选择将构成捆绑的产品。

要添加此属性,您需要执行以下操作:

  1. 打开Product类定义。

  2. 右键单击产品信息面板,然后选择添加数据组件 | 关系 | 多对多对象关系

  3. 将属性名称写为bundle_products,属性标题为Bundle Products

  4. Product类中。

  5. skuname中。

  6. 点击保存按钮以应用更改。

在以下屏幕截图中,您可以看到这些操作后Product类应该是什么样子:

图 12.8:Bundle_Products 属性

图 12.8:Bundle_Products 属性

如您在前一个屏幕截图中所见,新属性被添加到面板的底部,并且选定了所需的可见字段。

现在我们已经创建了此属性,我们可以创建一个捆绑产品。为此,只需创建一个新的产品对象,然后使用之前创建的关系属性选择几个将组成捆绑产品的产品。一旦选择了这些产品,它们将出现在关系中,如以下屏幕截图所示:

图 12.9:捆绑产品关系

图 12.9:捆绑产品关系

如您在前一个屏幕截图中所见,只有之前选定的产品字段在关系属性中可见。

现在我们已经定义了组成我们捆绑产品的产品,我们可能希望根据所选产品的价格自动计算捆绑价格。因此,我们需要打开类定义并添加一个新的数值属性来存储捆绑价格,如以下屏幕截图所示:

图 12.10:捆绑价格属性

图 12.10:捆绑价格属性

在前一个屏幕截图中,您可以看到此属性被标记为不可编辑,这意味着我们需要一个方法来计算捆绑价格。

总结来说,在本节中,您学习了如何修改Product类以定义捆绑产品。在下一节中,您将学习如何创建一个监听器类,该类监听由产品保存操作触发的事件,这将允许您自动计算捆绑价格。

创建事件监听器

在前一个章节中,您学习了如何定义捆绑产品。在常见场景中,捆绑产品的价格可能低于其组成的单个产品的总价。自动使用预定义的规则计算捆绑产品的价格可能很有用,而不是手动插入此值。

在本节中,您将学习如何创建一个事件监听器以捕获产品保存后触发的事件。对象的保存只是 Pimcore 中可以监听的事件之一,它包括对对象、资产和文档的所有创建、读取、更新和删除CRUD)操作,对用户的操作,搜索或网格列表的打开,以及其他许多操作。

要创建一个事件监听器,你首先需要在app/config/services.yml文件中注册一个新的类,如下面的代码片段所示:

services:
App\EventListener\DataObjectListener:
        tags:
            - { name: kernel.event_listener, event: pimcore.            dataobject.postUpdate, method: onObjectPostUpdate }

如前一个代码片段所示,可以通过添加类命名空间来定义一个新的服务。在tags属性中,我们必须定义我们的服务的一个或多个标签。每个标签由以下三个属性组成:

  • 名称:标签的名称。我们必须提供kernel.event_listener固定值,以便服务能正确识别为事件监听器。

  • 事件:用于指定我们想要监听的事件。在我们的例子中,我们感兴趣的是监听对象的postUpdate事件。正如其名所示,该事件在对象保存后触发。

  • 方法:在这个属性中,我们必须放入我们的类中将被自动调用的方法名称。

对于事件监听器,每个定义的标签代表一个特定的事件,因此你必须为每个你希望你的服务监听的事件添加一个标签。

现在我们来看如何实现定义的服务来计算我们捆绑产品的价格。在下面的代码片段中,你会看到一个可能的实现:

<?php
namespace App\EventListener;
use Pimcore\Event\Model\DataObjectEvent;
use Pimcore\Model\DataObject\Product;
class DataObjectListener 
{
    public function onObjectPostUpdate (DataObjectEvent $e) 
    {
        $obj = $e->getObject(); 
        if($obj instanceof Product)
        {
            $bundleProducts = $obj->getBundle_products();
            $currentPrice = $obj->getBundlePrice();
            if(count($bundleProducts) >0)
            {
                $bundlePrice = 0;
                foreach($bundleProducts as $product)
                {
                    $price = $product->getPrice()
                        ->getValue();
                    $bundlePrice += $price;
                }
                //substract the 20% of the sum
                $bundlePrice = round($bundlePrice*0.8,2);
                //Add this check to avoid circular saves
                if($bundlePrice != $currentPrice)
                {
                    $obj->setBundlePrice($bundlePrice);
                    $obj->save();
                }
            }
        }
    }
}

让我们分析前面的代码片段,以了解关键方面。首先,你可能注意到我们定义了一个名为onObjectPostUpdate的方法,这是在services.yml文件中定义的名称。

此方法将触发事件作为参数,并从该事件中提取触发事件的本身对象。正如你可能注意到的,只有当对象是产品时,我们才必须检查对象类以执行操作部分。

对于构成捆绑的每个产品,我们将产品价格相加,最后从这个总和减少 20%。请注意,这只是一个示例,你可以定义自己的规则。

为了避免产品保存时的循环,我们只在新的计算价格与之前的价格不同时保存产品。如果我们省略这个检查,对这个服务进行的保存操作将再次触发事件。

总结来说,在本节中,你了解了产品捆绑的概念以及如何通过添加允许你定义捆绑产品的属性来更改Product类。后来,你学习了如何创建事件监听器服务来捕获由对象操作(如产品保存)触发的事件。在提供的示例中,你看到了如何自动计算捆绑产品的价格。

在以下部分,你将学习如何扩展Product类来管理不同类型的产品,而无需为每个产品创建一个特定的类。

管理不同产品类型

在上一节中,你学习了如何定义捆绑产品。在本节中,你将学习如何管理不同类型的产品,而无需为每种产品类型创建一个不同的类。如果你需要管理一个异构的产品集,例如衬衫和鞋子,你可能需要特定的属性来更好地表示这些概念。

当然,我们可以为衬衫和鞋子创建两个不同的类,但我们需要为这两个类定义冗余字段来描述它们之间共享的属性——例如,标题、价格、描述等。

第五章,“探索对象和类”,我们介绍了Objectbricks的概念。使用 Objectbricks,我们只需要创建一些属性的小集合来描述特定的字段,并允许我们的类动态地添加这些砖块。正如其名所示,类对象可以由一个或多个添加到公共属性中的砖块组成。

在创建 Objectbrick 定义之前,我们需要在Product类中创建一个属性来容纳各种砖块。要创建此属性,只需在类定义内部右键单击面板组件,然后选择添加数据组件 | 结构化 | Objectbricks,填写属性名称,然后单击保存按钮以应用更改。在下面的屏幕截图中,你可以看到一个示例:

图 12.11:Objectbricks 属性

图 12.11:Objectbricks 属性

如前一个屏幕截图所示,我们已创建了一个Objectbricks类型的属性。作为一个可选属性,我们可以设置每个对象可以附加的最大砖块数。

现在我们已经在Product类中定义了属性,我们可以定义一个或多个 Objectbricks。要做到这一点,只需通过设置 | 数据对象 | Objectbricks。要添加新的 Objectbricks 定义,只需单击添加按钮,写下你的砖块名称,然后单击确定按钮。在下面的屏幕截图中,你可以看到一个创建的 Objectbrick 的示例:

图 12.12:Objectbrick 定义

图 12.12:Objectbrick 定义

如前一个屏幕截图所示,Objectbricks 定义面板与类创建面板相同。此外,对于 Objectbricks,我们可以选择要附加 Objectbrick 的类和特定属性。在这个例子中,我们将 Objectbrick 附加到了Product类,并选择了之前创建的属性。

一旦定义了 Objectbricks,我们就可以将它们附加到产品对象上。在下面的屏幕截图中,你可以看到 Objectbrick 在产品对象中的样子:

图 12.13:Objectbrick 实例

图 12.13:Objectbrick 实例

如前一个截图所示,在产品对象中,Objectbricks 以一个特定的部分出现。由于已达到定义的限制,您可以给每个对象附加一个或多个 Objectbricks,并且每种类型的 Objectbrick 都可以在同一对象中附加一次。

总结来说,在本节中,您学习了如何使用 Objectbricks 管理不同类型的产品。Objectbricks 可以被视为可以附加到类上以扩展类概念的属性子集。例如,对于 Product 类,我们可以考虑为衬衫、鞋子等创建特定的属性。

在下一节中,您将学习如何配置一个工作流,这将让您逐步控制产品信息的完整性。

与工作流一起工作

工作流由一系列代表达到共同目标必须完成的工作的过程和任务组成。通常,我们可能会将工作流视为一个图。

Pimcore 工作流管理提供了对资产、文档、数据对象上的多个工作流的配置,以支持数据维护过程、元素生命周期以及各种其他过程。Pimcore 工作流基于 Symfony 工作流组件,并扩展了其特定功能。在开始配置 Pimcore 工作流之前,让我们描述以下 Symfony 工作流组件的基本概念:

  1. 工作流类型 'Workflow':这是默认的工作流类型,允许您建模一个作为 Petri 网子类的工作流网。对于此类工作流,一个元素可以在工作流的几个状态中同时存在。

  2. 工作流类型 '状态机':状态机是工作流的一个子集,其目的是保持模型的状态。状态机不能同时在多个地方存在。

  3. 位置:位置是工作流中的一个步骤,描述了元素的特征或状态。根据位置,元素可能出现在特定的视图中——例如,仅关注翻译。在下一节中,我们将探讨如何为 Pimcore 类创建自定义布局。

  4. 标记存储:标记存储存储每个元素的当前位置(s)。

  5. 过渡:过渡描述了从一处移动到另一处所执行的操作。过渡可能允许或不允许,这取决于额外的标准,并且可能需要用户输入的额外注释和信息。

  6. 过渡守卫:定义了一个标准,用于确定是否允许当前进行过渡。

通过阅读以下章节,您将学习如何正确配置 Pimcore 工作流。我们将首先定义 Product 类的定制布局,然后我们将看到如何设置一个将指导产品信息完成的工作流。

配置自定义布局

如前所述,在工作流程的各个地方,我们可以为元素显示自定义视图。这是通过在相应的类上配置自定义布局来实现的。

要创建自定义布局,只需打开类定义并点击配置自定义布局按钮。当点击该按钮时,将打开一个新的对话框,您可以在其中添加一个新的自定义布局或加载之前创建的一个。要创建新布局,只需点击添加按钮。在将打开的对话框中,您可以写下新的布局名称和标识符ID),如以下屏幕截图所示:

图 12.14:创建自定义布局

图片

图 12.14:创建自定义布局

如您在前面的屏幕截图中所见,要添加新的自定义布局,只需填写名称唯一标识符字段,然后点击确定按钮进行确认。

一旦您初始化了自定义布局,您就可以指定您想在布局中显示哪些属性。在以下屏幕截图中,您可以查看如何进行此配置:

图 12.15:自定义布局配置

图片

图 12.15:自定义布局配置

如您在前面的屏幕截图中所见,配置对话框由两个主要面板组成。在左侧面板中,您将找到之前定义的类结构,而在右侧面板中,您可以从左侧面板拖放您想在自定义布局中显示的属性。

对于每个属性,您可以决定更改一些属性,例如是否可以编辑该属性本身。一旦您配置了自定义布局,您就可以点击保存按钮来应用更改。

现在您已经看到了如何配置自定义布局,让我们看看如何在工作流程配置中使用它们。

配置 Pimcore 工作流程

在上一节中,您学习了如何为 Pimcore 类配置自定义布局。在本节中,您将学习如何配置 Pimcore 工作流程以及如何使用之前创建的自定义布局。

与许多其他服务一样,Pimcore 工作流程必须在 Pimcore 项目的config.yaml文件或特定包的相同文件中定义。在本节中,您将学习如何正确配置工作流程。

在下面的代码片段中,您将看到如何初始化工作流程配置:

pimcore:
    workflows:
        product_workflow:
            label: 'Product Workflow'
            type: 'state_machine'
            supports:
                - 'Pimcore\Model\DataObject\Product'
            marking_store:
                type: single_state
                arguments:
                    - marking

如您在前面的代码片段中所见,要初始化工作流程,您必须在pimcore关键字下添加workflows关键字。然后,您必须为工作流程添加一个唯一的 ID,在我们的例子中是product_workflow

在较低级别,您可以定义一些参数,这些参数在此提供:

  1. label:工作流程标题。

  2. type:工作流程类型,可以是workflowstate_machine,如章节介绍中所述。

  3. supports:工作流程应用到的一个或多个类。

  4. marking_store:对于state_machine工作流程,您可以指定必须使用类的哪个属性来存储工作流程状态。如果该属性是选择列表属性,您可以通过定义选项提供者,通过读取工作流程状态来让类动态创建选择列表选项,就像您在下面的屏幕截图中所看到的那样:

![图 12.16:工作流程状态选项提供者图 12.16

图 12.16:工作流程状态选项提供者

正如您在之前的屏幕截图中所看到的那样,您可以填写places关键字,就像您在下面的代码片段中所看到的那样:

pimcore:
    workflows:
        product_workflow:
            places:
                base_data:
                    label: 'Base Data'
                    color: '#ffd700'
                    permissions:
                        - objectLayout: basedata

正如您在之前的代码片段中所看到的那样,您可以在places关键字后面添加一个或多个状态。对于每个状态,您必须指定一个唯一的 ID 并定义一个标签和颜色,该颜色将用于突出显示标签文本。如果您想限制特定状态的可见类属性,您可以在permissions关键字后面的objectLayout关键字中指定一个先前定义的自定义布局。

工作流程配置的最后一步是定义不同状态之间的过渡。您可以在下面的代码片段中查看如何定义过渡:

pimcore:
    workflows:
        product_workflow:
            transitions:
                product_images:
                    from: [ translations, enrichment ]
                    to: images
                    guard: subject.checkTranslationsCompleted()
                    options:
                        label: 'Edit Images'
                        notes:
                            commentEnabled: true
                            commentRequired: false
                        iconClass: 'pimcore_icon_image'

正如您在之前的代码片段中所看到的那样,过渡必须在transitions关键字后面定义。对于每个过渡,您必须定义一个唯一的 ID;然后,您必须指定一个或多个起始状态和一个目标状态。在下面的屏幕截图中,您可以查看如何调用过渡:

![图 12.17:调用工作流程过渡图 12.17

图 12.17:调用工作流程过渡

正如您在之前的屏幕截图中所看到的那样,一个分组按钮会自动注入到对象编辑器中,以便您选择可用的过渡。

如果需要,您还可以指定一个guard函数,当工作流程放置在from状态之一时,该函数会自动调用。如果guard函数未通过,则无法应用过渡并移动到目标状态。在这个特定示例中,您可以让用户在过渡完成后仅编辑图像。过渡守卫必须是对象的一个函数,因此最好的解决方案是在本章创建产品变体部分提到的父 PHP 类中创建此函数。

可选地,您还可以在过渡上指定一些额外选项,例如为过渡设置自定义图标或让用户在调用过渡时写下注释,就像您在下面的屏幕截图中所看到的那样:

![图 12.18:过渡说明图 12.18

图 12.18:过渡说明

正如您在之前的屏幕截图中所看到的那样,当用户点击过渡操作时,会打开一个模态窗口,用户可以写下将被存储在对象内部的笔记与事件部分的注释,然后点击执行操作按钮来完成过渡。

总结来说,在本节中,你学习了如何配置 Pimcore 工作流。通过定义自定义布局,你可以强制用户逐步填写产品信息,以确保数据完整性。特别是,你学习了如何定义工作流的位置以及如何配置工作流转换。

摘要

在本章中,你了解了Product实体的概念,并通过实际示例进行了介绍。在章节的第一部分,你学习了 PIM 是什么以及它的主要特性。然后,你学习了如何根据你的需求创建和配置Product类。

在定义了Product类之后,你学习了如何为该类启用继承以及如何为现有产品定义产品变体。通过实际代码示例,你还学习了如何在列表中检索变体以及如何创建新的产品变体。

在本章的后面部分,你学习了产品捆绑的概念以及如何向Product类添加新字段以定义捆绑产品。然后,你学习了如何创建事件监听服务来监听由对象触发的事件——例如,当产品被保存时。特别是,你看到了一个代码示例,展示了如何计算捆绑产品的价格。

之后,你学习了如何使用 Objectbricks 扩展Product类,附加一组有助于定义特定概念的属性。如果你想要表示不同种类的产品而不为每种产品创建一个类,以避免常见属性的冗余,这非常有用。

在最后一节中,你学习了如何为 Pimcore 类配置自定义布局以及如何在 Pimcore 工作流配置中使用它们。通过一个具体示例,你学习了如何配置一个工作流以逐步填写产品信息。

在下一章中,你将学习如何通过 Pimcore Datahub 捆绑将产品和其他实体暴露给外部,以及如何将 Pimcore 转变为主数据管理MDM)平台。

第十三章:第十三章:实施主数据管理

在上一章中,您学习了 产品信息管理(PIM)的概念,以及如何正确创建 Pimcore 类来表示产品。通过一些编码示例,您学习了如何创建产品变体和捆绑产品,以及如何通过扩展定义的类使用 Objectbricks 来定义不同类型的产品。

在本章中,我们将介绍 主数据管理(MDM)的概念,以及如何使用 Datahub Pimcore 扩展将 Pimcore 对象暴露给第三方应用程序。本章的组织结构如下:

  • 将 Pimcore 转换为 MDM

  • 激活 Pimcore Datahub 扩展包

  • 暴露实体

  • 使用突变查询

  • 创建自定义突变

  • 定义自定义报告

主数据管理的定义开始,我们将看到如何将 Pimcore 转换为 MDM。然后,我们将介绍 Pimcore Datahub 扩展包并解释如何安装它。之后,我们将看到如何暴露创建的对象,如何使用突变查询创建新对象,以及如何创建自定义突变。最后但同样重要的是,我们将看到如何定义自定义报告。

技术要求

如您在之前的章节中所做的那样,要运行与本章相关的演示,您只需导航到官方书籍仓库中的 13\. 实施主数据管理 文件夹并启动 Docker 环境。

要这样做,只需遵循以下说明:

  1. 使用以下命令运行 Docker:

    docker-compose up
    
  2. 然后,为了恢复您本地机器上的所有设置,只需打开一个新的 shell 并输入以下命令:

    docker-compose exec php bash restore.sh
    
  3. 导航到 http://localhost/admin 并使用您的 admin/pimcore 凭据登录。

您可以通过以下链接访问官方书籍仓库以获取源代码:

github.com/PacktPublishing/Modernizing-Enterprise-CMS-using-Pimcore/tree/main/13.%20Implementing%20Master%20Data%20Management

现在,您已经准备好导航演示,以发现与本章相关的所有方面。

将 Pimcore 转换为 MDM

第一章介绍 Pimcore 中,我们简要介绍了主数据管理(MDM)的概念。MDM 是一个基本流程,用于根据公司的销售、营销和运营策略来管理、集中、组织、分类、定位、同步和丰富关键数据。在本节中,我们将更好地解释这个概念,以便您了解如何轻松地将前几章的学习应用到将 Pimcore 转换为 MDM 系统中。

我们已经在 第十二章实施产品信息管理 中看到了 Pimcore 在数据管理方面的潜力,但它有一个很大的限制:它与产品的概念紧密相关。

在许多公司场景中,产品并不是唯一需要通过公司用户定义、管理和共享,或在不同渠道分发的数据类型。例如,如果我们从电子商务的角度来考虑,我们可能希望存储订单和客户信息,或者定义我们实体店铺的详细信息,以便在电子商务网站上创建一个店铺定位页面。

为了提供一个完全不同的例子,第九章配置实体和渲染数据中创建的类,用于存储文章和分类,在某种意义上可以被视为 MDM 的可能实现。

话虽如此,我们将 Pimcore 转变为 MDM 系统的第一步是创建一个代表每个概念的类,我们可以通过 Pimcore 类定义界面轻松地做到这一点。仅此还不够,但想想通过即插即用的界面创建 Pimcore 类是多么容易,正如你在第五章探索对象和类中学习到的,以及这如何在不写一行代码的情况下产生一个强大且易于维护的结构。

由于你已经在上一章中学习了如何创建 Pimcore 类,所以我们不会在本章中重复这个过程。如果你遵循了技术要求部分提供的说明,你应该会找到一些已经定义好的类。

一旦定义了结构,我们就可以利用 Pimcore 的潜力来实现数据管理流程,其中我们可以引用以下内容:

  • 数据验证:对于类属性,我们可以定义一些验证规则——例如,我们可以决定每个属性是否对类是必需的,对于文本属性,我们可以添加一个正则表达式来验证内容。这可能很有用,但它不允许定义复杂的验证场景,例如(例如)跨属性验证。这可以通过实现事件监听器来完成,正如你在上一章中学到的。

  • 数据质量:数据质量包括一组工具和流程,用于为我们提供数据的质量和数量一致性——例如,我们可能想检查我们的对象翻译是否完整。我们可以通过创建特定类型的属性来实现这一点,这些属性是计算值动态文本标签属性(我们将在下一节中看到这些属性的示例)。

  • 版本控制:PIM、DAM 和 MDM 的主要特征之一是共享对象的可能性。任何具有写权限的用户都可以编辑产品和其它对象,不同的用户可能访问并保存相同的对象。因此,跟踪对象版本以清楚地了解哪个用户进行了更改是很重要的。

现在我们已经定义了 MDM 系统的主要特征,让我们看看一个数据质量实现的例子。

实现数据质量

在前节中,我们介绍了主数据管理的定义,并学习了 MDM 系统的主要特征。

在本节中,通过一个示例,我们将看到如何实现数据质量。正如我们在前节中提到的,我们可以使用两种不同的属性来完成这项工作,即计算值动态文本标签属性。

这些特定的属性需要开发一个PHP:超文本预处理器PHP)类,其方法在对象打开时自动调用。一旦这个类开发完成,我们必须在属性配置中写入类命名空间,如下面的截图所示:

![图 13.1:计算值配置图片

图 13.1:计算值配置

如前一个截图所示,我们可以在属性配置中将类命名空间放入计算器类输入框中。一旦输入完成,你可以点击保存按钮将更改应用到类上。同样的配置也可以应用于动态文本标签属性。

现在我们已经看到了如何配置属性,在接下来的代码片段中,我们将看到如何实现Calculator类:

<?php
namespace App\CalculatedValue;
use Pimcore\Model\DataObject\ClassDefinition\CalculatorClassInterface;
use Pimcore\Model\DataObject\Concrete;
use Pimcore\Model\DataObject\Data\CalculatedValue;
use Pimcore\Model\DataObject\Product;
use Pimcore\Tool;
class DataQualityCalculator implements CalculatorClassInterface
{
    public function compute(Concrete $object, CalculatedValue     $context): string
    {
        return $this->getCalculatedValueForEditMode($object,         $context);
    }
    public function getCalculatedValueForEditMode(Concrete     $object, CalculatedValue $context): string
    {
        if ($object instanceof Product) {
            $language = $context->getPosition();
            if(empty($object->getName($language)) 
                || empty($object->getShort_                description($language))
                || empty($object->getDescription($language))){
                return "no";
            }
            return "yes";
        }
        return '';
    }
}

在前面的代码片段中,你可以看到如何实现一个适合CalculatorClassInterface接口的 PHP 类,这涉及到实现以下两个方法:

  • 在对象保存时调用compute方法,以将计算值存储在数据库中。

  • getCalculatedValueForEditMode方法被调用以在对象编辑模态中显示值。

这两个函数通常预期返回相同的值,因此最佳实践是让一个函数返回另一个函数的值,以避免代码重复。

这些函数接受对象实例和包含有用信息的属性上下文作为输入,例如fieldname属性。对于本地化字段,当前语言定义在上下文的position属性中。

在这个特定示例中,我们首先检查对象是否是产品,这是我们为它设置了计算值属性的那个类。然后,我们检查对于每种语言,所有本地化字段是否都为空。

在下面的代码片段中,我们将看到如何实现渲染动态文本标签所需的方法:

<?php
namespace App\CalculatedValue;
use Pimcore\Model\DataObject\ClassDefinition\Layout\DynamicTextLabelInterface;
use Pimcore\Model\DataObject\Concrete;
use Pimcore\Model\DataObject\Data\CalculatedValue;
use Pimcore\Model\DataObject\Product;
use Pimcore\Tool;
class DataQualityCalculator implements DynamicTextLabelInterface
{
    public function renderLayoutText($data, $object, $params)
    {
        if ($object instanceof Product) {
            $htmlTable = '<table style="border: 1px solid             black">';
            $htmlTable .= '<thead><tr>
<td style="border: 1px solid black">Language</td>
<td style="border: 1px solid black">Translation Status</td>
</tr></thead>';
            foreach (Tool::getValidLanguages() as $language) {
                $htmlTable .= '<tr>';
                $htmlTable .= '<td style="border: 1px solid                 black">'.$language.'</td>';
                $htmlTable .= '<td style="border: 1px solid                 black">'.($object-                >getTranslationCompleted($language) == "yes" ?                 "completed" : "not completed").'</td>';
                $htmlTable .= '</tr>';
            }
            $htmlTable .= '</table>';
            return "<h2 style='margin-top: 0'>Translations             Summary</h2>" . $htmlTable;
        }
        return '';
    }
}

如前一个代码片段所示,该类与之前创建的类相似。为了渲染动态文本标签,该类必须实现DynamicTextLabelInterface接口。该接口提供了renderLayoutText方法,我们必须实现它。

renderLayoutText方法中,我们可以返回将在标签中渲染的超文本标记语言HTML)文本。在这个特定示例中,我们实现了一个简单的 HTML 表格,显示了每种语言本地化字段是否已完成,使用了之前创建的计算值。

在以下屏幕截图中,您可以查看这些属性的外观:

图 13.2:计算值结果

图 13.2:计算值结果

如您在上一张屏幕截图中所见,动态文本标签显示了每种语言的完整性状态,而计算值显示了所选语言字段是否已完成。

总结来说,在本节中,您了解了主数据管理MDM)的概念,以及如何利用 Pimcore 潜力来实现数据管理流程,将 Pimcore 转变为 MDM 系统。稍后,您学习了如何实现计算值以实现数据质量。

在下一节中,您将学习如何激活 Pimcore Datahub Bundle,该 Bundle 可用于将 Pimcore 对象公开给第三方应用程序。

激活 Pimcore Datahub Bundle

在上一节中,您学习了如何实现数据管理流程,如数据质量流程。这些流程,名称?不清楚,是 MDM 概念的关键方面。MDM 系统的另一个基本功能是向第三方应用程序和站点公开实体。

在本节中,您将学习如何激活 Pimcore Datahub Bundle,以及如何正确配置该 Bundle。在本章的后面部分,您将学习如何使用此 Bundle 公开 Pimcore 对象,并允许外部应用程序创建新对象。

如您在第七章“安装 Bundle”部分所学的,管理 Pimcore 站点,Pimcore Bundle 可以通过composer包管理器下载;要下载 Datahub Bundle,您只需遵循以下说明:

  1. 打开一个 shell 并指向书籍源代码的章节文件夹。

  2. 运行以下命令以进入 Docker 容器:

    docker-compose php bash
    
  3. 运行以下命令以下载 Datahub Bundle:

    composer require pimcore/data-hub
    

下载完 Bundle 后,必须启用并安装才能使用。您可以通过工具 | Bundle菜单来完成此操作,如下面的屏幕截图所示:

图 13.3:Datahub Bundle 安装

图 13.3:Datahub Bundle 安装

如您在上一张屏幕截图中所见,必须首先启用 Datahub Bundle,然后才能安装。Bundle 的安装将在数据库结构内部创建额外的表。

这些操作可以通过以下 Bash 命令以不同的方式完成:

php bin/console pimcore:bundle:enablePimcoreDatahubBundle
php bin/console pimcore:bundle:installPimcoreDatahubBundle

请注意,运行这些命令只是通过扩展管理器界面进行的操作的一个替代方案;应只使用一种方法。

现在你已经学会了如何安装 Datahub 包,让我们看看如何创建 Datahub 配置模型。

创建 Datahub 配置

在前面的章节中,你学习了如何安装和激活 Pimcore Datahub 包。在本节中,你将学习如何为 Datahub 创建配置。这些配置将决定第三方应用程序如何与 Pimcore 交互以检索、创建或更新对象。

要打开 Datahub 配置面板,只需在 Pimcore 菜单中通过 Settings(设置)| Datahub Config(Datahub 配置)进行。要创建新的配置,只需遵循以下说明:

  1. 点击 Add Configuration(添加配置)按钮。

  2. 在出现的窗口中写下配置名称。

  3. 点击 OK 按钮以确认创建。

在下面的屏幕截图中,你可以看到前述指令的表示:

图 13.4:创建 Datahub 配置

图 13.4:创建 Datahub 配置

如前一个屏幕截图所示,一旦配置创建完成,它就会在左侧菜单中可见。如果您点击创建的配置,配置将以编辑模式打开。配置的设置可以通过三个不同的面板进行,正如我们即将看到的。

General(通用)面板包含有关配置的一般信息,例如配置名称。我们可以在下面的屏幕截图中看到这个面板的样子:

图 13.5:通用面板

图 13.5:通用面板

现在我们将描述在前面的屏幕截图中看到的每个属性,如下所述:

  • Active: 如果启用,配置是激活的,并且可以被外部应用程序访问。

  • Type: 配置类型。在当前版本中,只有 GraphQL 类型存在。

  • Name: 配置名称,在配置创建期间定义。这可能无法更改。

  • Description: 这允许你为配置编写文本描述。

  • SQL Condition: 在这个属性中,你可以添加一个 Structured Query Language(结构化查询语言,SQL)条件,该条件将用于对所有查询进行预过滤。

Schema Definition(模式定义)面板中,我们可以定义哪些类被启用用于查询和突变。我们可以在下面的屏幕截图中看到这个面板的样子:

图 13.6:Schema Definition 面板

图 13.6:Schema Definition 面板

现在我们将描述在前面的屏幕截图中看到的每个属性,如下所述:

  • Query Schema: 在这个部分,我们可以选择一个或多个类,其中包含可用于查询的对象。对于每个选定的类,可以定义在查询中必须公开哪些属性。我们将在 Exposing entities(公开实体)部分看到这个概念。

  • 突变模式:类似于 查询模式 部分,在本节中我们可以选择可能用于突变查询的类。对于每个类,我们可以定义是否可以创建、更新和删除对象。我们将在本章后面的 使用突变查询 部分了解更多关于突变查询的内容。

  • 通用类型:在这里,我们可以定义是否必须公开资产、文档和文件夹以进行查询和突变。例如,如果我们为对象文件夹启用 读取 选项,我们就可以检索一个文件夹中包含的所有对象。

安全定义 面板中,我们可以管理身份验证规则并限制实体对特定文件夹的可见性。我们可以在以下屏幕截图中看到这个面板的外观:

![图 13.7:安全定义面板]

![img/Figure_13.07_B17073.jpg]

图 13.7:安全定义面板

现在让我们描述在前面的屏幕截图中看到的每个属性,如下所示:

  • 方法:身份验证方法。在当前版本中,只有通过 应用程序编程接口API)密钥进行身份验证的方式可用。

  • Datahub API 密钥:用于身份验证所需的 API 密钥。可以通过点击右侧的闪电图标来生成。

  • 跳过权限检查:如果启用,则在执行突变查询时将跳过对必填字段的完整性的检查。

  • 工作空间:在本节中,我们必须指定特定的 文档资产对象 文件夹,我们希望公开查询和突变。

完成配置后,点击 保存 按钮以应用更改。

在配置保存后,可以通过两种不同的方式测试查询,如下所示:

  • 通过集成的 Iframe(可以通过点击 Pimcore 界面中的 在 Iframe 中打开 按钮在新面板中打开)

  • 在新的浏览器标签页中,可以通过点击 在新标签页中打开 按钮打开

对于第三方应用程序,可以通过对以下端点执行 超文本传输协议HTTP)调用来进行查询:

/pimcore-graphql-webservices/{configurationname}?apikey={yourApiKey}

在前面的端点中,你可以看到配置名称和 API 密钥是变量,因此你必须用配置中定义的值替换占位符。

所有的定义配置都存储在 var/config/Datahub-configurations.php 文件中。如果你想在不同的环境中共享相同的配置,可以将此文件提交到代码库,并运行以下 Bash 命令来重建 Datahub 配置:

php bin/console Datahub:graphql:rebuild-definitions

总结来说,在本节中,你学习了如何下载和激活 Pimcore Datahub 包以及如何为该包创建配置。在下一节中,你将学习如何公开实体以及如何在 Datahub 上执行查询,并通过集成的 Iframe 进行测试。

公开实体

在上一节中,您学习了如何激活 Datahub 捆绑包以及如何创建新的配置。在本节中,您将学习如何设置配置以公开实体以及如何在 Datahub 上执行查询。

正如我们在上一节中提到的,在 Datahub 配置的模式定义面板中,我们必须选择哪些类应该可用于查询,并在查询模式部分添加它们。

对于每个类,我们必须定义哪些字段可以公开用于查询。这可以通过点击每个添加的类的设置图标来完成。在下面的屏幕截图中,您可以查看如何选择要公开的字段:

图 13.8:查询模式字段

图 13.8:查询模式字段

正如您在上一张屏幕截图中看到的,在左侧您可以找到一个类字段的列表。如果您双击这些字段之一或将在右侧列中的字段拖放到右侧,该字段将被公开并可用于查询。一旦您选择了所有要公开的字段,只需点击应用按钮确认您的选择。

现在我们已经学习了如何配置查询模式,在接下来的部分,您将看到如何在 Datahub 上执行 GraphQL 查询。

执行 GraphQL 查询

在上一节中,您学习了如何公开类和字段以使它们可查询。在本节中,您将学习如何为您创建的配置执行查询,并查看一些查询示例。

正如我们在创建 Datahub 配置部分之前提到的,唯一支持的配置类型是 GraphQL。GraphQL 是构建 API 的查询语言和用于用真实数据提供这些 API 的工具。GraphQL 提供了对 API 数据的完整和可理解的描述,使客户端能够请求他们所需的数据,而不需要其他数据。这允许轻松集成外部软件,并允许您轻松维护和随着时间的推移发展 API。

GraphQL 查询总是返回可预测的结果,因此使用 GraphQL 的应用程序快速且可靠,因为它们控制着所需的数据,而不是服务器。

除了访问资源的数据外,GraphQL 查询还可以跟随其他实体的引用。这最终允许您在单个调用中检索应用程序所需的所有数据,与典型的表示状态传输REST)API 不同,后者通常需要多个调用才能获取数据。

因此,GraphQL API 是根据类型而不是端点组织的;所有数据都可以通过单个端点访问,使用类型确保外部应用程序只能请求允许的内容,这允许您提供清晰且有用的错误信息。

现在我们已经介绍了什么是 GraphQL,让我们看看 Pimcore Datahub Iframe 环境。在下面的屏幕截图中,您可以查看这个环境的外观:

![图 13.9:Datahub Iframe 环境图 13.9:Datahub Iframe 环境

图 13.9:Datahub Iframe 环境

如前一个屏幕截图所示,Iframe 被分为两个面板。在左侧面板中,我们可以编写我们想要运行的查询,而在右侧面板中,则显示查询结果。如您所见,在左侧面板中,当我们编写字段名时,会显示建议,提供了自动完成的可能。一旦查询准备就绪,您可以通过点击播放按钮来运行它。

现在我们已经看到了如何执行查询,让我们看看一些涵盖各种字段类型的查询示例。

获取对象列表

在本例中,您将学习如何执行对象列表操作。在下面的代码片段中,您可以查看如何形成列表查询:

{
    getProductListing(first: 10, after: 0, filter: "{\"o_    type\": \"object\"}") {
        edges {
            node {
                id
                name
                short_description
                    }
                }
        totalCount
    }
}

如前一个代码片段所示,查询语句由get前缀、类名和Listing后缀组成。列表函数具有以下输入属性:

  • first:要检索的结果数量。

  • after:要跳过的对象数量。与前面的参数结合使用,这可以用于执行分页。

  • ids:要检索的对象的标识符ID)列表。如果省略,则检索所有符合其他过滤条件的商品。

  • fullpaths:类似于前面的属性,我们可以指定要检索的对象的路径。

  • filter:一个或多个将应用于过滤要检索对象的组合过滤器。

  • published:指定查询是否必须包含未发布对象。

  • defaultLanguage:指定本地化字段的默认语言。

  • sortBy:用于排序结果的字段。

  • sortOrder:指定字段的排序顺序。

查询内容由一个edges组件组成,其中您可以指定为每个node检索的字段列表,以及一个totalCount组件,它总是检索总结果数,而不考虑当前页面的参数。

在以下示例中,我们将看到如何检索单个对象以及如何检索不同类型字段的值。

检索单个对象

在本例中,我们将看到如何检索单个对象。您可以在下面的代码片段中查看如何执行此查询:

{
getProduct(id: 162, defaultLanguage: "en"){
    name
    name_it: name(language: "it")
    price{
        value
        unit{
            abbreviation
        }
        toString
    }
  }
}

如前一个代码片段所示,查询语句由get前缀和类名组成。在查询函数中,我们必须定义对象的id或对象的fullpath

然后,我们可以可选地定义本地化字段的默认语言。在查询内容中,您可以看到对于本地化字段,我们可以定义与默认语言不同的语言。

在本例中,您还可以看到如何查询QuantityValue字段。如前一个代码片段所示,您可以通过toString属性要求字段值、度量单位以及值和单位的组合。

在以下示例中,您将学习如何检索对象关系的详细信息。

获取关系详情

在以下代码片段中,您可以查看如何获取标准关系和高级关系的详情:

{
    getProduct(id: 162){
        category{
            ... on object_Category{
                id
                name
      }
    }
    materials{
        element{
            id
            name
      }
      metadata{
          name
          value
      }
    }
  }
}

如前一个代码片段所示,对于标准关系,作为第一类,我们必须指定相关类。在 GraphQL 语法中,这可以通过添加三个点,然后是on object_关键字和类名来实现。对于相关类,您可以指定要检索的字段。

对于高级关系,在element组件中,您可以指定要检索相关对象的字段,而在metadata组件中,您可以检索每个关系元数据的名称和值。

在以下示例中,您将学习如何检索 Fieldcollections 的值以及如何要求图像详情。

获取图像详情

在本例中,我们将看到相同的语法可以用于Fieldcollections,您将学习如何检索图像详情。在以下代码片段中,您可以查看如何执行此类查询:

{
    getProduct(id: 162){
        images{
            ... on fieldcollection_ImageInfo {
                image{
                    id
                    filename
                    fullpath
                    filesize
                    data
               }
           }
       }
    }
}

如前一个代码片段所示,语法与之前我们看到的对象关系语法相当相似。对于每个图像,我们可以要求图像详情,如文件名和文件大小,但也可以通过data属性获取 Base64 图像内容。

获取对象变体

在本例中,您将学习如何获取对象变体。在下面的代码片段中,您可以查看如何获取对象子项:

{
getProduct(id: 162){
    children(objectTypes:["variant"]){
        ... on object_Product{
            id
            color{
                ... on object_Color{
                    name
                }
             }
          }
       }
    }
}

如前一个代码片段所示,您可以使用getChildren函数检索对象变体。要获取变体,您必须通过使用objectTypes属性指定您需要它们。

总结来说,在本节中,您学习了如何公开实体以供 Datahub 配置。在看到集成 Iframe 的外观后,通过一些查询示例,您学习了如何执行查询以检索不同类型属性的列表和详情。

在以下部分,您将学习如何执行突变查询以创建、更新和删除对象。

使用突变查询

在上一节中,您学习了如何公开实体以供 Datahub 配置,以及如何执行查询以检索对象数据。在本节中,您将学习如何公开实体以供突变,以及如何执行查询以创建、更新和删除对象。

正如我们在激活 Pimcore Datahub 捆绑包部分提到的,在 Datahub 配置的模式定义面板中,我们必须选择哪些类应该可用于突变,并将它们添加到突变模式部分。

正如我们在查询模式部分对类所做的,我们可以通过点击每个添加的类的设置图标来定义哪些字段可以公开用于突变查询。此外,对于每个类,我们可以决定我们是否希望使其可用于创建、更新或删除。

在本节中,我们将学习如何执行创建、更新和删除对象的突变查询。

创建对象

在本节中,你将学习如何执行突变查询来创建新对象。在以下代码片段中,你将看到突变查询的查询语法,以及创建新对象的特定查询:

mutation{
    createProduct(path:"/Products", key:"Running Shoes",     input:{
        sku: "0003"
        name: "Runner Shoes"
        category: {id: 177}
        }){
        success
        message
        output{
            id
            sku
            name
        }
    }
}

如前一个代码片段所示,所有突变查询都必须以mutation关键字开头。然后,查询函数由作为前缀的所需操作组成,这可以是createupdatedelete之一,后跟类的名称。

在函数参数中,你可以指定以下属性:

  • key: 对象的键。这将在对象树中显示。

  • path: 对象创建的路径。这可能是一个文件夹或父产品。

  • parentId: 这可以用来作为path参数的替代,以定义父文件夹或对象。

  • published: 如果为false,则产品将在未发布状态下创建。

  • omitMandatoryCheck: 如果设置为true,即使所有必填字段没有填写,也会创建一个对象。

  • type: 我们可以指定创建的对象必须是对象还是变体。

  • input: 在此属性中,我们可以指定我们想要创建的对象的字段值。

查询内容由三个部分组成,具体如下:

  • success: 一个布尔标志,如果查询成功运行则为true,否则为false

  • message: 如果查询成功运行,将显示成功消息。

  • output: 如果对象创建成功,这将显示查询中请求的对象字段。

运行之前定义的查询将返回以下结果:

{
  "data": {
    "createProduct": {
      "success": true,
      "message": "object created: 178",
      "output": {
        "id": "178",
        "sku": "0003",
        "name": "Runner Shoes"
      }
    }
  }
}

如前一个代码片段所示,如果对象创建正确,将返回对象id。这可以用来执行更新或删除对象的查询。

现在我们已经看到了如何创建一个新对象,让我们看看如何执行一个查询来更新之前创建的对象。

更新对象

在上一节中,你学习了如何使用突变查询来创建新对象。在本节中,你将学习如何更新之前创建的对象。

在以下代码片段中,你可以看到更新突变查询的语法:

mutation{
        updateProduct(id:178, input:{
            short_description: "The classic model of low             sneakers is certainly very comfortable and             practical and defines a personal style"
        }){
            success
            message
            output{
                   id
                   sku
                   name
                   short_description
            }
      }
}

如前一个代码片段所示,突变查询函数以update关键字开头。必须将对象id作为函数参数传递,如果提供的id不存在,将返回错误消息。

现在我们已经看到了如何更新之前创建的对象,让我们看看如何执行一个查询来删除该对象。

删除对象

在上一节中,你学习了如何使用突变查询来更新对象。在本节中,你将学习如何删除一个对象。

在以下代码片段中,你可以看到删除突变查询的语法:

mutation{
    deleteProduct(id:178){
        success
        message
    }
}

正如你在之前的代码片段中看到的,突变查询函数以 delete 关键字开始。必须将对象 id 作为函数参数传递,如果提供的 id 对象不存在,将返回错误信息。

总结来说,在本节中,你学习了突变查询的语法。特别是,我们看到了如何通过特定的查询创建、更新和删除对象。在下一节中,你将学习如何创建自定义突变查询函数。

创建自定义突变

在上一节中,你学习了如何使用突变查询来创建、更新和删除对象。这类查询在简单场景下效果良好,但在可以更新的属性类型或多个属性之间的相互依赖性方面存在一些限制。例如,在标准突变查询中,无法填写 QuantityValue 字段。

在本节中,你将学习如何创建自定义突变函数,以及如何使用它来更新标准突变查询中无法更新的值。

要创建一个新的自定义突变函数,我们需要向 Datahub 配置模式中添加一个函数定义。这可以通过实现 pimcore.Datahub.graphql.mutation.preBuild 事件监听器来完成。

第十二章实现产品信息管理 中,你学习了如何实现 EventListener。在下面的代码片段中,你将看到一个示例,展示如何实现一个将影响 Datahub 配置模式的监听器:

<?php
namespace App\EventListener;
class DatahubListener {
    public function onMutationEventsPreBuild (MutationTypeEvent $event) {
        $config = $event->getConfig();
        $opName = "updateProductPrice";
        $inputType = new \GraphQL\Type
        \Definition\InputObjectType([
            'name' => "priceType",
            'fields' => [
                'priceValue' => ['type' =>Type::float()],
                'unit' => ['type' =>Type::string()]
            ]
        ]);
        $operation = [
            'type' =>Type::string(), 
            'args' => [
                'id' => ['type' =>
                 Type::nonNull(Type::int())],
                'input' => ['type' => $inputType],
            ], 'resolve' => function ($source, $args, $context,             ResolveInfo $info) {
                $id = $args['id'];
                $product = Product::getById($id);
                if(empty($product)){
                    throw new \Exception("Product with id '$id'                     does not exists.");
                }
                $value = $args['input']['priceValue'];
                $uom = $args['input']['unit'];
                $unit = Unit::getByAbbreviation($uom);
                if(empty($unit)){
                    throw new \Exception("Unit of measure                     '$uom' does not exists.");
                }
                $price = new QuantityValue();
                $price->setValue($value);
                $price->setUnitId($unit->getId());
                $product->setPrice($price);
                $product->save();
                return "Price updated for product with id                 '$id'";
            }
        ];
        $config['fields'][$opName] = $operation;
        $event->setConfig($config);
    }
}

在之前的代码片段中,我们实现了一个简单的函数,用于设置产品价格。正如你在示例中看到的,监听函数有一个类型为 MutationTypeEvent 的输入参数。该事件变量有一个 config 属性,它包含 Datahub 配置模式。要添加一个新的突变函数,我们必须向这个配置中添加一个新的操作。

第一步是创建一个类型为 InputObjectType 的对象。该对象必须包含一个 fields 属性,它必须是一个数组,必须定义在突变查询函数的 input 参数中必须填充的每个属性的名称和类型。

然后,我们必须创建一个数组来定义一个新的操作。这个数组必须包含操作参数,例如对象 id 和之前定义的 input 参数,并定义一个 resolve 函数,在我们的情况下,将根据价格值和单位设置产品价格。

一旦定义了这个操作,你必须将其添加到配置属性中。结果,创建的函数将在 Iframe 中可选,正如你在下面的屏幕截图中所看到的:

![Figure 13.10: Custom Mutation Query]

![Figure 13.10_B17073.jpg]

![Figure 13.10: Custom Mutation Query]

如您在之前的屏幕截图中所见,在左侧面板中,您可以选择之前定义的函数并填写产品价格的价值和单位。在右侧面板中,您可以查看为突变查询定义的结果消息。

总结来说,在本节中,您学习了如何创建自定义突变查询。这可以用于设置复杂场景的对象属性。例如,您学习了如何实现事件监听器以创建一个自定义突变查询,该查询将设置产品价格。

在下一节中,您将学习如何定义自定义报告以创建具有过滤和导出功能的表格或图表报告。

定义自定义报告

自定义报告是直接集成到 Pimcore 中的报告引擎。这些报告基于对数据库的直接 SQL 查询,并且可以将它们作为表格和图表呈现。要定义或生成一个新的自定义报告,请按照以下步骤操作:

  1. 要创建一个新的报告,请转到营销菜单并点击自定义报告菜单选项。

  2. 然后,点击添加按钮并插入报告名称。在创建报告后,您可以开始配置它。在下面的屏幕截图中,您可以查看如何设置报告的一般设置:图 13.11:一般设置

    图 13.11:一般设置

    如您在之前的屏幕截图中所见,报告名称是之前插入的那个。

  3. 然后,添加一个用户友好的标签,并将报告最终分组到文件夹中。

  4. 点击在菜单中创建快捷方式复选框,报告将直接在营销菜单中可用。

  5. 在配置了一般设置后,下一步是配置数据源。这可以通过直接定义一个 SQL 查询来完成,如下面的屏幕截图所示:图 13.12:源定义

    图 13.12:源定义

    如您在之前的屏幕截图中所见,您可以将直接 SQL 查询作为源定义添加。这为您提供了设计复杂场景的可能性,但需要具备数据库结构的先进知识。在这个特定示例中,我们想要按类别统计产品数量。

  6. 在定义数据源后,定义如何呈现数据。您可以在下面的屏幕截图中查看如何管理列配置:图 13.13:管理列配置

    图 13.13:管理列配置

    如您在前面的屏幕截图中所见,如果查询格式正确,列将自动检测。对于每一列,我们可以指定该列是否必须在报告中显示,以及该列是否可以导出和排序。然后,我们还可以定义每一列是否可以过滤,以及应用哪种过滤类型,然后指定它们的宽度和标签。如果列包含一个对象id,我们还可以指定一个打开对象操作。正如我们将在下一步中看到的,这将添加一个按钮,允许您通过报告表打开相应的对象。

    在定义了列配置之后,您可以定义图表类型,从饼图柱状图折线图中选择。对于饼图,您必须指定哪个列必须用于定义值列表,以及哪个列包含数据计数。

  7. 一旦完成配置,请转到营销 | 报告菜单以查看报告的渲染方式。您可以在下面的屏幕截图中看到定义示例的外观:

图 13.14:报告可视化

图 13.14:报告可视化

如您在前面的屏幕截图中所见,报告以我们定义的饼图形式显示,包括类别名称、不同值的列表以及构成饼图的产品的计数。

在底部,您可以看到报告的表格版本。特别是,您可以看到打开按钮,它允许您打开链接的分类对象。如果您没有指定图表类型,则只显示表格版本。报告表可以导出为逗号分隔值CSV)文件。

总结一下,在本节中,您学习了如何使用自定义报告引擎配置和渲染报告。从一般设置开始,您学习了如何配置数据源以及如何在报告中正确渲染数据。

摘要

在本章中,您学习了主数据管理(Master Data Management)的概念以及如何使用 Datahub Pimcore 捆绑包将 Pimcore 对象暴露给第三方应用程序。

在定义了该概念之后,您已经看到了如何实现数据质量概念的一个示例,这是 MDM 系统的一个关键特性。

在本章的后面部分,您学习了如何激活 Datahub Pimcore 捆绑包以及如何为该捆绑包创建配置,以及如何设置配置以将对象和其他实体暴露给外部应用程序。

在介绍了 GraphQL 查询语言之后,您学习了如何通过一些查询示例执行查询以检索对象数据,以及如何通过突变查询创建、更新和删除对象。然后,您学习了如何实现自定义突变查询函数,这对于定义复杂场景非常有用。

在最后一节中,您学习了如何配置和渲染自定义报告,这使您能够展示和导出数据。

在下一章中,你将学习如何在 Pimcore 中执行数据集成,特别关注如何导入和导出对象,以及何时应该使用标准功能,以及在其他情况下,当它们存在限制需要实施自定义解决方案时。

第十四章:第十四章:数据集成

在上一章中,你学习了关于主数据管理MDM)的概念,以及如何使用Datahub Pimcore 插件将 Pimcore 对象暴露给第三方应用程序。在定义了如何安装和激活该插件以及如何配置它之后,你学习了如何执行 GraphQL 查询以检索对象数据以及创建、更新或删除对象。

在本章中,你将学习如何在 Pimcore 中通过标准导入和导出功能进行数据集成,当这些标准应该被使用时,以及当需要实现自定义解决方案时。

本章的组织结构如下:

  • 导入数据

  • 导出数据

  • 标准功能的限制

  • 实现自定义解决方案

  • 配置数据导入器

我们将从展示如何使用标准解决方案进行简单的 CSV 数据导入和导出开始。然后,我们将解释在使用这些标准解决方案进行导入和导出时可能遇到的限制,并解释如何实现一个自定义数据操作符,该操作符可以用于导入配置。在本章的后面部分,我们将展示如何实现导入和导出的自定义解决方案。

技术要求

如同你在前面的章节中所做的那样,你所需要做的就是通过导航到官方书库中的14\. 数据集成文件夹并启动 Docker 环境来运行与本章相关的演示。

要这样做,只需遵循以下说明:

  1. 使用以下命令运行 Docker:

    docker-compose up
    
  2. 然后,为了在本地机器上恢复所有设置,只需打开一个新的 shell 并输入以下命令:

    docker-compose exec php bash restore.sh
    
  3. 导航到localhost/admin并使用你的 admin/pimcore 凭据登录。

你可以通过以下链接访问官方书库以获取源代码:

github.com/PacktPublishing/Modernizing-Enterprise-CMS-using-Pimcore/tree/main/14.%20Data%20Integration

现在,你已经准备好导航到演示,以发现与本章相关的所有方面。

导入数据

在本节中,你将学习如何通过标准 Pimcore CSV 导入来导入数据。我们将查看如何配置简单 CSV 文件的导入,查看配置的每个步骤的详细信息,以及如何保存此配置以供将来导入使用。

虽然这个功能在 PimcoreX 中已被弃用,但我们必须考虑到 Pimcore 6 版本仍然被广泛使用,因此这个功能的解释仍然非常重要。因此,在本章的配置数据导入器部分,我们将解释如何配置新的 Pimcore 数据导入器。

要开始新的 CSV 导入,只需在您想要导入对象的文件夹上右键单击,选择CSV 导入,并选择您想要导入的对象类。此操作将打开一个上传对话框,您可以通过该对话框上传 CSV 文件以进行导入。

文件上传后,将打开一个新的模态窗口,您可以从配置导入开始。在接下来的章节中,我们将分析配置的每个步骤。

CSV 文件预览

在导入配置的第一个面板中,显示了上传的 CSV 文件的预览。在下面的屏幕截图中,您可以看到这个面板的样式:

![图 14.1:CSV 文件预览图片

图 14.1:CSV 文件预览

如您在之前的屏幕截图中所见,CSV 文件行被渲染为表格。如果顶部的复选框被启用,则第一行 CSV 包含标题。

在下一节中,我们将看到如何进行列配置,将每个 CSV 列与相应的类属性关联。

列配置

列配置面板中,我们可以将每个 CSV 列关联到相应的类属性,这样对于每次 CSV 导入,我们只能影响类字段的一个子集。您可以在下面的屏幕截图中看到这个面板的样式:

![图 14.2:列配置图片

图 14.2:列配置

如您在之前的屏幕截图中所见,在这个面板中有两个不同的区域。在左侧区域,您将找到类属性,并且可以将每个属性拖放到右侧区域对应的 CSV 列中。

在左侧区域,您还可以看到操作符部分。这些操作符可以用来改变数据处理的方式。让我们描述每个操作符是如何工作的:

  • 操作符 Base64:这个操作符对 CSV 数据进行 Base64 编码或解码。

  • 操作符忽略:这个操作符只是让导入器跳过相应的 CSV 列。

  • 操作符迭代器:这个操作符允许您通过将属性作为操作符子节点拖放,将相同的 CSV 单元格导入多个类属性。

  • 操作符区域切换器:这个操作符对于选择每个本地化字段的区域语言非常有用,允许在同一个 CSV 文件中导入不同语言的文本。

  • 操作符 ObjectBrick 设置器:这个操作符允许您导入ObjectBrick的特定属性。

  • 操作符 PHP 代码:这种操作符类型本身不执行任何操作。它需要您开发一个 PHP 类来管理 CSV 数据,并将类命名空间作为操作符的参数。您将在本章的创建自定义操作符部分学习如何创建自定义 PHP 操作符。

  • 操作符发布:这个操作符只是允许您根据 CSV 列值发布或取消发布导入的对象。

  • 操作符拆分器:此操作符可以用于根据分隔符字符将 CSV 列的值拆分为多个属性。

现在我们已经定义了如何映射每个对象属性,在下一节中,我们将展示允许我们解析每一行、识别每个对象是否已经存在的标准。

解析器设置

在下面的屏幕截图中,您可以查看 解析器设置 面板的外观:

图 14.3:解析器设置

图 14.3:解析器设置

正如您在前面的屏幕截图中看到的,有一组属性可以配置,我们将在这里进行描述:

  • 跳过标题行:定义是否必须跳过第一行。如果 CSV 的第一行包含列标题,则必须勾选此选项。

  • 语言:导入的语言。将导入指定语言的所有本地化字段值。如果您需要在同一 CSV 导入中导入不同语言的本地化值,您必须使用 区域设置切换器 操作符。

  • Pimcore\DataObject\Import\Resolver\AbstractResolver 类,并将类命名空间作为属性传递。

  • :此属性允许您选择包含解析器策略必须使用的值的 CSV 列。

  • 类型:此属性允许您定义导入的行必须是对象还是变体。可以强制此类型,让导入器保持当前类型,或为每一行动态设置类型,指定 类型列 属性。

  • 按需创建:如果选中,将创建不存在的对象。

  • 创建父级:如果选中,如果对象路径上不存在子文件夹,则将创建它们。

  • 如果存在则跳过行:如果选中,如果对象已存在,则跳过该行。

现在我们已经看到了如何设置解析器策略,在下一节中,我们将看到如何更改 CSV 设置。

CSV 设置

在这里,您可以查看 CSV 设置 面板的外观:

图 14.4:CSV 设置

图 14.4:CSV 设置

正如您在前面的屏幕截图中看到的,在这个面板中,您可以更改 CSV 解析设置,包括 分隔符引号字符等。这些设置在文件上传期间自动检测,但您可以手动更改它们。更改这些值后,您必须单击 重新加载列配置 按钮以应用更改。

在下一节中,我们将看到如何保存和分享定义的配置。

保存 & 分享

在下面的屏幕截图中,您可以查看 保存 & 分享 面板的外观:

图 14.5:保存 & 分享

图 14.5:保存 & 分享

如前一个截图所示,你可以设置配置名称,然后点击保存按钮将配置保存在数据库中。所有保存的配置都可以通过点击加载按钮并选择所选配置来恢复。导入配置可以全局共享给所有用户,或者共享给一组受限的用户和角色。

一旦完成配置,你可以通过点击导入按钮来运行导入。在下面的截图中,你可以看到导入报告面板:

![图 14.6:导入报告图片

图 14.6:导入报告

如前一个截图所示,对于每一行,我们可以看到该行是否成功导入,如果没有,则会显示该行的错误消息。对于每一行导入的对象,都可以打开。

总结来说,在本节中,你学习了如何配置和运行 CSV 导入。在下一节中,你将学习如何在 Pimcore 中导出数据。

导出数据

在上一节中,你学习了如何配置和运行 CSV 导入。在本节中,你将学习如何导出数据。与上一节中关于数据导入的内容类似,我们可以设置并保存导出配置。

开始数据导出的第一步是通过点击对象文件夹来打开对象网格。当网格打开时,网格将只包含在类配置中标记为在网格视图中可见的类属性,正如你在第五章,“探索对象和类”中所学到的。

要添加或删除在网格中显示的字段,你必须点击网格选项按钮来打开配置模式。你可以在下面的截图中看到这个配置模式的外观:

![图 14.7:网格选项配置图片

图 14.7:网格选项配置

如前一个截图所示,配置模式结构与我们在导入配置的列配置面板中看到的是相当相似的。

在左侧区域,你可以找到类属性列表和一些用于格式化、渲染和转换对象数据以及从对象关系提取值的操作符集合。我们可以将类属性和操作符从右侧区域拖放到网格中,以便这些属性在网格中显示。

在前一个截图中,你可能注意到我们使用了任何获取器操作符来从一个关系中提取特定的属性。为此,我们只需要将关系属性作为操作符的子项拖放到操作符中,并指定我们想要从该关系提取的属性。

一旦完成网格配置,你可以点击应用按钮来确认更改,你也可以通过点击保存副本并共享按钮将配置保存以供将来重用。

在下面的截图中,你可以看到更改后的对象网格看起来如何:

![图 14.8:对象网格图 14.08_B17073.jpg

图 14.8:对象网格

如您在前一个屏幕截图中所见,在对象网格中显示了之前定义的列。在屏幕截图中,您还可以看到,如果我们打开网格选项子菜单,我们可以切换到不同的配置,保存当前配置的副本,将该配置设置为收藏夹,或者删除当前配置。

对象网格显示了在打开的文件夹内以及最终在现有子文件夹内创建的所有对象和变体。如果您想限制显示的对象仅限于层次结构的第一个级别,您可以通过启用仅直接子项复选框来实现,正如您可以在以下屏幕截图中看到的那样:

![图 14.9:对象网格图 14.09_B17073.jpg

图 14.9:对象网格

如您在前一个屏幕截图中所见,仅显示直接子项对象。网格中的对象可以导出为 CSV 和 XLSX 文件。对于 CSV 导出,您将被要求选择分隔符字符。

总结来说,在本节中您学习了如何配置对象网格以及如何执行数据导出。在下一节中,您将发现使用标准导入和导出功能可能会遇到哪些局限性,以及如何创建用于导入的自定义运算符。

标准功能局限性

在前面的章节中,您学习了如何通过标准功能执行数据导入和导出。如您所知,这些功能易于配置,并且对于简单场景工作良好。

在本节中,您将了解这些标准功能的主要局限性,以及您将学习如何实现一个自定义 PHP 运算符,用于 CSV 导入。让我们首先介绍之前看到的导出功能局限性。

数据导出局限性

导出数据部分,您学习了如何配置对象网格以导出对象数据。当使用这些配置时,您可能会遇到以下局限性:

  • Fieldcollections属性。Fieldcollections可以为每个对象类提供不同的基数,并且很难在像 CSV 或 XLSX 文件这样的平面结构中表示这些类型的属性。

  • 父子关系 冗余:文件格式给出的另一个局限性是,由于每个对象变体将放置在不同的行中,因此无法在不避免数据冗余的情况下解释父子关系,在导出的文件中不会有任何关于一行代表对象或变体的信息。

  • 排除变体:在前一节中,在数据过滤方面,您了解到可以使用仅直接子项复选框来过滤对象并排除对象变体。这仅在所有对象都直接在打开的文件夹内创建的情况下有效,因为如果对象是在子文件夹中创建的,则点击复选框时会跳过它们。仅过滤对象的唯一方法是添加直接 SQL 条件,如下一个截图所示:

![图 14.10:直接 SQL 查询图片

图 14.10:直接 SQL 查询

如前一个截图所示,点击直接 SQL 查询图标将打开一个文本输入框,在其中您可以编写有效的 SQL 条件。这非常有用,但需要了解数据库结构。

  • 服务器超时:最后但同样重要的是,可能存在与时间相关的問題。导出操作是通过 HTML 调用控制器来完成的,因此对于要导出的成千上万的对象,此操作可能需要很长时间,并且可能会根据服务器设置出现超时。

现在您已经了解了标准数据导出的限制,让我们看看在数据导入过程中您可能会遇到哪些限制。

数据导入限制

导入 CSV 文件的主要问题是不同类型属性所需的标准格式。例如,对于以下类型的字段,我们有以下限制:

  • 数量值:要导入此类字段的值,您必须在 CSV 单元格中放置数值,后跟计量单位。

  • 选择:CSV 单元格必须包含选择的有效值,而不是选项标签。这在创建的选择具有数字 ID 或通常不是记忆值的情况下可能是一个问题。

  • 多选:多选字段上的不同值必须仅由逗号字符分隔。

  • object:/前缀,后跟相关对象的完整路径。

  • 高级关系:高级关系的元数据无法导入。

  • Fieldcollection:Fieldcollection 的值无法导入。

  • 媒体:无法通过 CSV 导入将图片和视频附加到对象上。

这些限制使得 CSV 文件的编译相当复杂,因为非专家用户很难创建一个符合所有格式规则的 CSV 文件。这些限制可以通过创建自定义 PHP 运算符来规避,我们将在下一节中看到,但当然,我们将失去无需编写任何代码即可导入数据的优势。

与 CSV 文件相关的另一个限制是格式本身。尽管 CSV 格式是一个广泛的标准,但可能存在过时的外部应用程序无法以 CSV 格式生成导出。话虽如此,要导入任何其他类型的文件,必须开发自定义解决方案。

至于导入过程本身,整个过程不能作为后台进程运行。一旦开始导入,导入模态直到导入过程结束都不能关闭,因为关闭模态会导致导入停止。对于每条导入的行,前端界面都会刷新,对于要导入的数千行,整个过程可能需要数小时。

由于这些时间限制,无法在外部软件和 Pimcore 之间安排自动导入流程,因为如前所述,导入不能作为后台进程运行,需要保持浏览器长时间开启。

现在你已经了解了标准数据导入的限制,让我们看看如何创建一个用于 CSV 导入的自定义 PHP 操作符。使用这些 PHP 操作符可以绕过之前提到的一些限制。

创建自定义操作符

在前一个章节中,你学习了在标准数据导入过程中可能会遇到哪些限制。这些限制之一是某些属性类型所需的严格格式。通过创建自定义操作符来管理 CSV 单元格数据,可以绕过这种限制。

在本节中,你将学习如何创建这些自定义操作符,以及如何在 CSV 导入中使用它们。特别是,我们将看到一个示例操作符,该操作符将根据选项标签而不是其值搜索选择字段的选项。在下面的代码片段中,你可以看到如何创建此操作符:

<?php
namespace App\Import\Operators;
use Pimcore\DataObject\Import\ColumnConfig\Operator\AbstractOperator;
use Pimcore\Model\DataObject\ClassDefinition;
class SelectOperator extends AbstractOperator{
protected $additionalData;
    public function __construct(\stdClass $config, $context = null){
parent::__construct($config, $context);
        $this->additionalData = json_decode($config->additionalData, true);
    }
    public function process($element, &$target, array &$rowData, $colIndex, array &$context = array()) {  
        $value = $rowData[$colIndex];
        $field = $this->additionalData["field"];
        $target->set($field, $this->getValueByDisplayName($target->getClass(), $field, $value));
    }
    public function getValueByDisplayName(ClassDefinition $class, $field, $displayName){
        $fieldDefinition = $class->getFieldDefinition($field);
        if(in_array($fieldDefinition->getFieldtype(), array("select", "multiselect"))){
            $options = $fieldDefinition->getOptions();
            $option = array_search(strtolower($displayName), array_map('strtolower', array_column($options, "key")));
            return $option !== false ? $options[$option]["value"] : null;
        }
        return null;
    }
}

如前一个代码片段所示,操作符必须扩展 AbstractOperator 类。在类构造函数中,我们可以解析在操作符配置中定义的附加数据,并且业务逻辑的实现必须在 process 函数中完成,该函数将由导入流程自动调用。

在这个特定的例子中,我们使用对象的类中的 getFieldDefinition 方法来检索字段定义。如果字段是一个选择或多项选择属性,我们可以使用 getOptions 函数来检索选择选项并搜索与给定标签对应的值。

一旦创建操作符,我们必须在 CSV 导入配置中使用它。为此,只需将 操作符 PHP 代码 操作符拖放到你想要应用操作符的 CSV 列中。在操作符配置面板中,你必须放置操作符命名空间,如以下屏幕截图所示:

![图 14.11:操作符 PHP 代码图 14.11:操作符 PHP 代码

图 14.11:操作符 PHP 代码

如前一个屏幕截图所示,在操作符配置中,我们必须在 PHP 类 输入中放置 PHP 类命名空间。然后,在 附加数据 文本区域中,我们可以放置一些要传递给操作符的数据。在我们的例子中,我们以 JSON 格式传递这些附加信息,该信息将由操作符解析。

总结来说,在本节中,您学习了在执行标准导入和导出过程中可能遇到的限制。然后,您学习了如何创建自定义 PHP 操作符,这些操作符可以在 CSV 导入过程中使用。在下一节中,您将学习如何实现导入和导出的自定义解决方案。

实现自定义解决方案

在上一节中,您学习了标准导入和导出功能性的限制。然后,您学习了如何创建一个自定义操作符,用于 CSV 导入过程。

在本节中,您将学习如何实现导入和导出的自定义解决方案。特别是,您将学习如何向 Pimcore 后端界面中的对象和文件夹编辑器添加额外的按钮,这些按钮在点击时将调用自定义控制器,以及如何创建可以计划并作为后台进程运行的命令。

添加自定义按钮

在本节中,您将学习如何向 Pimcore 后端界面添加自定义按钮,以及如何让这些按钮调用自定义控制器以执行导入和导出。

要添加这些按钮,我们需要在之前创建的 Pimcore 包的 Resources/js/Pimcore/startup.js 文件中实现 postOpenObject 函数。在下面的代码片段中,您可以看到一个如何创建两个按钮来上传和下载文件的示例:

postOpenObject: function (object, type) {
    if (object.data.general.o_type === 'folder') {
object.toolbar.add({
            text: t('Export'),
iconCls: 'pimcore_icon_download',
            scale: 'medium',
            handler: function (obj) {
pimcore.helpers.download("/admin/export-objects?folderId=" + object.id);
}.bind(this, object)
        });
object.toolbar.add({
            text: t('Import'),
iconCls: 'pimcore_icon_upload',
            scale: 'medium',
            handler: function (obj) {
pimcore.helpers.uploadDialog("/admin/import-objects?folderId=" + object.id, "Filedata", function (response) {
pimcore.layout.refresh();
object.reload();
}.bind(this), function () {
Ext.MessageBox.alert(t("error"), t("error"));
                });
}.bind(this, object)
        });
pimcore.layout.refresh();
    }
}

如您在前面的代码片段中所见,我们首先检查打开的对象是否为文件夹,以便在文件夹编辑工具栏中添加两个不同的按钮。对于每个按钮,handler 函数是在对象被点击时被调用的函数。

在第一个按钮中,我们使用 pimcore.helpers.download 函数让浏览器下载响应中返回的文件。在第二个按钮中,使用 pimcore.helpers.uploadDialog 将渲染一个上传模态框;上传的文件将被传递到控制器。

让我们现在看看如何实现将被创建的按钮调用的控制器动作。在下面的代码片段中,您可以看到一个控制器实现的示例:

<?php
namespace App\Controller;
use Pimcore\Bundle\AdminBundle\Controller;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\ResponseHeaderBag;
/** @Route("/admin") */
class AdminController extends Controller\AdminController {
    /** @Route("/export-objects") */
    public function exportObjectsAction(Request $request) {
        $folderId = $request->get("folderId");
        //Add business logic here
        $response = new Response();
        $response->setContent($jsonResponse);
        $disposition = $response->headers->makeDisposition(
ResponseHeaderBag::DISPOSITION_ATTACHMENT,
            "export_".date("YmdHis").".json";
        );
        $response->headers->set('Content-Type', 'application/json');
        $response->headers->set('Content-Disposition', $disposition);
        return $response;
    }
    /** @Route("/import-objects", methods={"POST"}) */
    public function importObjectsAction(Request $request) {
        $folderId = $request->get("folderId");
        $tmpName = $_FILES['Filedata']['tmp_name'];
        $fileContent = file_get_contents($tmpName);
        //Add business logic here
        $response = $this->adminJson(['success' => true]);
        $response->headers->set('Content-Type', 'text/html');
        return $response;
    }
} 

如您在前面的代码片段中所见,为每个控制器动作创建了一个特定的函数。每个动作都将 HTTP 请求对象作为输入参数传递,并且可以通过 get 函数访问请求属性值。

exportObjectsAction 函数中,我们已通过正确设置响应头来配置响应以接受 JSON 文件的下载。所选的文件格式只是一个示例,可以更改为所需的格式。在 importObjectsAction 函数中,我们从 $_FILES 全局变量中读取上传文件的文件内容,这样根据业务逻辑,我们可以导入对象。

总结来说,在本节中,你学习了如何向 Pimcore 后端界面添加自定义按钮,以及如何具体实现导入和导出文件的控制器。在下一节中,你将学习如何创建可以通过 Pimcore 控制台调用的命令,并且最终可以将其安排为后台进程执行。

创建 Pimcore 命令

在上一节中,你学习了如何通过在 Pimcore 后端界面中添加额外的按钮来创建自定义控制器,以执行任何类型的文件导入和导出。在本节中,你将学习如何创建可以通过 Pimcore 控制台调用的命令。

要创建一个新的命令,你只需创建一个扩展 Pimcore\Console\AbstractCommand 类的类,如下面的代码片段所示:

<?php
namespace App\Command;
use Pimcore\Console\AbstractCommand;
use Pimcore\Console\Dumper;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
class ImportCommand extends AbstractCommand
{
    const IMPORT_FOLDER = PIMCORE_PROJECT_ROOT."/var/imports";
    protected function configure() {
        $this->setName('import-file')
            ->setDescription('Import a file in background');
        $this->addOption("filename", null, InputOption::VALUE_REQUIRED, "The name of the file to import");
    }
    protected function execute(InputInterface $input, OutputInterface $output) {
        $this->dump("The execution is starting!",  Dumper::NEWLINE_AFTER);
        $filename = $input->getOption("filename");
        $fileContent = file_get_contents(self::IMPORT_FOLDER."/".$filename);
        //Add business logic here
        $this->writeError('Please implement this command with business logic...');
    }
}

如你在前面的代码片段中看到,在命令配置中,你可以指定命令的名称和描述,以及命令的列表可选或必需的参数和选项。

命令的业务逻辑必须在 execute 函数中实现。我们可以使用命令原生函数,如 dumpwriteError,在控制台中打印消息。

一旦开发完成命令,它必须像以下代码片段所示那样声明为服务:

services:
App\Command\ImportCommand:
        tags:
            - { name: 'console.command', command: 'import-file' }

你可能会注意到,在前面的代码片段中,command 标签报告了创建的命令名称。要调用命令,你只需运行以下指令:

php bin/console import-file --filename=my-import-file.csv

当运行命令时,必须指定文件名作为属性。你可以在下面的屏幕截图中看到命令结果:

Figure 14.12: Command execution

img/Figure_14.12_B17073.jpg

图 14.12:命令执行

如你在前面的屏幕截图中所见,消息和错误被输出到控制台。

总结来说,在本节的第一个部分,你学习了如何向 Pimcore 后端界面添加自定义按钮,以及如何让这些按钮调用控制器动作来上传和下载文件。然后,你学习了如何通过 Pimcore 控制台创建和运行 Pimcore 命令。

在下一节中,你将学习如何配置新的 Pimcore 数据导入器,这将允许你从不同的来源导入数据并在后台安排导入。

配置数据导入器

在上一节中,你学习了如何实现自定义解决方案,特别是如何向对象界面添加自定义按钮以及如何创建可执行命令。

在本节中,你将学习如何安装和配置新的 Pimcore 数据导入器,在 PimcoreX 版本中将取代我们在 导入数据 部分描述的标准 CSV 导入。

数据导入器插件是 Datahub 包的扩展,我们在 第十三章实现主数据管理 中进行了描述。要安装数据导入器,你只需运行以下脚本:

docker-compose exec php bash
composer require pimcore/data-importer
./bin/console pimcore:bundle:enable PimcoreDataImporterBundle

如前一个脚本所示,数据导入器可以通过 Composer 下载,并且可以像其他 Pimcore 捆绑包一样启用,使用 pimcore:bundle:enable 命令。

一旦您启用了捆绑包,您可以通过访问 Pimcore 菜单中的 设置 | 数据集配置 选项来打开 Datahub 配置面板。要创建新的导入配置,您只需单击 添加配置 按钮即可,如以下屏幕截图所示:

图 14.13:添加导入配置

图 14.13:添加导入配置

如前一个屏幕截图所示,除了 GraphQL 配置外,您还可以选择 数据对象导入器 选项并填写配置名称。

要配置和运行导入,您必须遵循以下步骤:

  1. 常规 选项卡中,启用 激活 复选框并添加可选的描述,如以下屏幕截图所示:图 14.14:常规设置

    图 14.14:常规设置

    如前一个屏幕截图所示,定义的配置名称显示在设置中。

  2. 在生成的 URL 的 POST 调用中。

    一旦您已定义数据源,您可以选择文件格式,从 CSV、JSON、XLSX 和 XML 中选择,并填写具体的配置。

  3. 导入设置 面板中,为上传文件中的每个字段配置解析器和映射。在以下屏幕截图中,您将看到如何配置解析器:图 14.16:导入解析器

    图 14.16:导入解析器

    如前一个屏幕截图所示,您可以定义参与导入的类和加载策略,从 路径ID属性不加载 中选择。最后一个选项将使导入器始终创建新对象,而不会查看这些对象的存在。然后,您可以通过定义现有的文件夹路径来选择创建和更新的对象必须位于的位置,以及如何影响发布状态。

    处理设置 选项卡中,您可以定义配置的导入是否可以并行运行多次,或者每次导入运行是否必须是顺序的。

  4. 映射 选项卡中,为要导入的每个上传文件的属性定义一个映射。在下面的屏幕截图中,您将看到如何添加新的映射以及如何映射一个简单的文本字段:图 14.17:导入映射

    图 14.17:导入映射

    如前一个屏幕截图所示,您可以通过单击 添加 按钮添加新的字段映射。要映射一个简单的文本字段,您只需从自动检测的源属性中选择正确的字段,并在 字段名称 列表中选择相应的类字段。

    对于不同类型的字段,您可能需要使用转换管道添加一个或多个转换。您可以在以下截图中看到一个示例:

    图 14.18:导入映射

    图 14.18:导入映射

    如前一个截图所示,对于数量值属性,我们可以添加一个特定的转换。这需要选择两个源属性,一个包含值,另一个包含度量单位。

    这些管道可以用于导入日期和数字字段,或者更复杂的字段,例如,例如图像和其他类型的资产,或者与其他对象的关联。

    在左侧面板中,您可以看到已定义的字段被突出显示。

  5. 执行面板中,运行您已配置的导入操作。您可以通过点击开始按钮手动运行导入,如下截图所示:图 14.19:导入执行

    图 14.19:导入执行

    如前一个截图所示,导入状态显示在进度条中,您可以在任何时候停止导入。

    如果您想计划在后台运行导入,只需填写Cron 定义规则。

  6. 要启用cron执行,您只需按照以下脚本计划执行命令:

    cron execution, as shown previously, will let Pimcore check which import configurations must be run every minute. These configurations will be run according to the cron definition of every single configuration.
    

总结来说,在本节中,您学习了如何安装和启用数据导入器插件。通过逐步配置,您学习了如何创建和执行导入配置。

摘要

在本章中,您学习了如何使用标准 Pimcore 功能导入和导出数据,这些功能允许您在定义相应的导入和导出配置后导入和导出 CSV 文件。

在描述了如何正确设置这些配置之后,您学习了在执行这些标准功能时可能遇到的限制,以及如何实现一个用于 CSV 导入过程的自定义操作符。

在本章的后面部分,您学习了如何实现导入和导出的自定义解决方案。特别是,您学习了如何向 Pimcore 后端界面添加自定义按钮,让您可以上传和下载文件,以及如何创建可以通过 Pimcore 控制台调用并最终计划为后台进程的命令。

在最后一节中,您最终学习了如何启用数据导入器插件,从不同类型的源创建导入配置,您可以手动执行或计划在后台执行。

由于这是最后一章,让我们尝试总结整本书的内容。在书的第一个部分,我们讨论了 Pimcore 基础知识,介绍了 Pimcore 及其功能,展示了如何设置开发环境,如何在 Pimcore 菜单和功能中导航,以及如何管理 Pimcore 站点。

在第二部分,你学习了如何逐步使用 Pimcore CMS 引擎实现一个博客,从学习如何创建自定义 CMS 页面以及如何为博客渲染数据开始,然后是如何创建可重用组件以及如何最终完成网站。

在最后一章中,我们描述了如何使用 Pimcore 进行企业解决方案,重点关注 PIM 和 MDM 的 Pimcore 功能以及数据集成过程,提供了如何将 Pimcore 连接到外部系统的具体示例。

现在你已经读完了这本书的结尾,我们希望它对你来说是一次鼓舞人心的阅读,并且这本书将成为你使用 Pimcore 开发项目的有用指南。

Packt.com

订阅我们的在线数字图书馆,全面访问超过 7,000 本书和视频,以及领先的行业工具,帮助你规划个人发展并推进你的职业生涯。更多信息,请访问我们的网站。

第十五章:为什么订阅?

  • 通过来自 4,000 多位行业专业人士的实用电子书和视频,节省学习时间,多花时间编码

  • 通过为你量身定制的技能计划提高你的学习效果

  • 每月免费获得一本电子书或视频

  • 完全可搜索,便于轻松访问关键信息

  • 复制粘贴、打印和收藏内容

你知道 Packt 为每本书都提供电子书版本,包括 PDF 和 ePub 文件吗?你可以在 packt.com 升级到电子书版本,并且作为印刷书客户,你有权获得电子书副本的折扣。有关更多信息,请联系我们 customercare@packtpub.com。

www.packt.com,你还可以阅读一系列免费的技术文章,订阅各种免费通讯,并享受 Packt 书籍和电子书的独家折扣和优惠。

你可能还会喜欢的其他书籍

如果你喜欢这本书,你可能还会对 Packt 出版的以下书籍感兴趣:

Drupal 9 模块开发 - 第三版

Daniel Sipos

ISBN: 978-1-80020-462-1

  • 为你的应用程序开发定制的 Drupal 9 模块

  • 掌握不同的 Drupal 9 子系统和 API

  • 模型、存储、操作和处理数据以实现有效的数据管理

  • 使用主题系统以干净和安全的方式展示数据和内容

  • 测试你的业务逻辑以防止回归

使用 Microsoft Power Automate 进行工作流程自动化

Aaron Guilmette

ISBN: 978-1-83921-379-3

  • 掌握 Power Automate 的构建块、其服务和核心功能

  • 在 Power Automate 中探索连接器以自动化电子邮件工作流程

  • 发现如何创建在两个云服务之间复制文件的流程

  • 理解创建审批流程的业务流程、连接器和操作

  • 使用流程将 Microsoft Forms 提交到数据库中的响应保存

  • 了解如何将 Power Automate 与 Microsoft Teams 集成

Packt 正在寻找像你这样的作者

如果你有兴趣成为 Packt 的作者,请访问 authors.packtpub.com 并今天申请。我们已经与成千上万的开发者和技术专业人士合作,就像你一样,帮助他们将见解与全球技术社区分享。你可以提交一般申请,申请我们正在招募作者的特定热门话题,或者提交你自己的想法。

嗨!

我们是丹尼尔、马可和弗朗西斯科,这本书的作者。我们真心希望您喜欢阅读这本书,并觉得它对掌握 Pimcore 平台和交付现代企业解决方案很有用。

如果您能在亚马逊上留下一个评价,分享您对《使用 Pimcore 现代化企业 CMS》的看法,这将对我们(以及其他潜在读者!)真的有很大帮助!

B17073_QR

您的评价将帮助我们了解这本书中哪些内容做得好,哪些内容需要改进以供未来版本使用,所以您的评价真的非常受重视。

祝好,

丹尼尔·丰塔尼 马可·古吉奇 弗朗西斯科·米纳
丹尼尔·丰塔尼 马可·古吉奇 弗朗西斯科·米纳
posted @ 2025-09-07 09:18  绝不原创的飞龙  阅读(14)  评论(0)    收藏  举报