Concrete5-秘籍-全-

Concrete5 秘籍(全)

原文:zh.annas-archive.org/md5/3403bb6d7fb37c17ae37d3478cb76929

译者:飞龙

协议:CC BY-NC-SA 4.0

前言

concrete5 是一个越来越受欢迎的开源内容管理系统。concrete5 通过其易于使用的点选界面和众多功能,将自己与其他 CMS 应用程序区分开来。网络开发者喜爱 concrete5,因为它非常容易定制,并且可以在相对较短的时间内构建额外的功能。本书旨在以易于阅读的食谱格式解释 concrete5 开发者常见的各种编程任务。

本书涵盖内容

第一章, 页面和页面类型, 帮助我们学习如何使用 concrete5 API 处理页面和页面类型。

第二章, 使用块, 创建自定义块类型并将块集成到您的网站中。

第三章, 文件和文件集, 开发存储在 concrete5 优秀文件管理器中的文件。

第四章, 使用核心助手, 发现 concrete5 内置的众多核心助手文件。

第五章, 使用数据库和模型, 通过数据库访问学习如何使用模型,探索自定义 concrete5 开发的核心。

第六章, 创建 CRUD 界面, 通过一系列有用的食谱创建界面,以管理 concrete5 中的自定义数据。

第七章, 使用用户和权限, 利用 concrete5 的用户和权限模型在自己的应用程序和网站上。

第八章, 使用主题和插件, 帮助我们学习如何创建自定义主题和插件,进一步扩展您的 concrete5 开发技能。

第九章, 系统事件和高级配置, 通过高级配置设置和挂钩到系统事件,揭示 concrete5 强大的开发者功能。

附录 A, 蓝图 – 创建图片库插件, 从零开始构建一个显示存储在文件管理器中的图片的插件。

附录 B, 蓝图 – 创建事件日历插件, 结合前几章学到的所有知识,创建一个功能齐全的日历插件,包括 CRUD 界面和自定义块类型。

附录 C, 将插件包提交到 concrete5 市场 place, 帮助我们了解开发者必须遵循的过程,以便将他们的插件包含在 concrete5 市场 place 中。

您需要为此书准备的东西

读者需要一份在开发(非生产)服务器上运行的 concrete5 的副本。这将允许读者在不干扰正常网站操作的情况下,实验 concrete5 API 的许多不同元素。

读者还需要一个能够编辑 PHP 文件的代码编辑器。这可以是一个高级编辑器,如 Adobe Dreamweaver,或者一个基本文本编辑器,如 Vim。

一些章节也涉及浏览和查询 MySQL 数据库,因此推荐使用查询浏览工具。HeidiSQL(在 Windows 上)、Sequel Pro(在 OS X 上)和 MySQL Workbench(所有平台)是一些提供高级功能的同时浏览数据库的优秀工具。

本书面向对象

本书面向初学者到中级 PHP 开发者,他们希望更好地了解 concrete5,或者对于希望拥有 concrete5 API 便捷参考手册的 concrete5 老手。

规范

在本书中,您将找到许多不同风格的文本,以区分不同类型的信息。以下是一些这些样式的示例及其含义的解释。

文本中的代码单词如下所示:“例如,左侧边栏页面类型将有一个left_sidebar的句柄。”

代码块设置如下:

function my_debug($var) {
  echo '<pre>';
  print_r($var);
  echo '</pre>';
  exit;
}

新术语重要词汇以粗体显示。您在屏幕上看到的单词,例如在菜单或对话框中,在文本中显示如下:“点击下一步按钮将您带到下一屏幕”。

注意

警告或重要提示以如下框的形式出现。

小贴士

小贴士和技巧如下所示。

读者反馈

我们始终欢迎读者的反馈。告诉我们您对这本书的看法——您喜欢什么或可能不喜欢什么。读者反馈对我们开发您真正从中获得最大收益的标题非常重要。

要向我们发送一般反馈,只需发送一封电子邮件到<feedback@packtpub.com>,并在邮件的主题中提及书名。

如果您在某个主题上具有专业知识,并且您对撰写或为书籍做出贡献感兴趣,请参阅我们的作者指南www.packtpub.com/authors

客户支持

现在您已经是 Packt 书籍的骄傲拥有者,我们有一些事情可以帮助您从您的购买中获得最大收益。

下载示例代码

您可以从您在www.packtpub.com的账户下载您购买的所有 Packt 书籍的示例代码文件。如果您在其他地方购买了这本书,您可以访问www.packtpub.com/support并注册,以便将文件直接通过电子邮件发送给您。

错误

尽管我们已经尽最大努力确保内容的准确性,但错误仍然可能发生。如果你在我们的书中发现错误——可能是文本或代码中的错误——我们非常感谢你向我们报告这一点。通过这样做,你可以帮助其他读者避免挫败感,并帮助我们改进本书的后续版本。如果你发现任何勘误,请通过访问 www.packtpub.com/submit-errata,选择你的书籍,点击勘误提交表单链接,并输入你的勘误详情来报告。一旦你的勘误得到验证,你的提交将被接受,勘误将被上传到我们的网站,或添加到该标题的勘误部分下的现有勘误列表中。任何现有的勘误都可以通过从 www.packtpub.com/support 选择你的标题来查看。

盗版

互联网上版权材料的盗版是一个跨所有媒体的持续问题。在 Packt,我们非常重视我们版权和许可证的保护。如果你在网上遇到任何我们作品的非法副本,无论形式如何,请立即提供位置地址或网站名称,以便我们可以寻求补救措施。

请通过 <copyright@packtpub.com> 与我们联系,并提供疑似盗版材料的链接。

我们感谢你在保护我们的作者和为我们提供有价值内容的能力方面的帮助。

询问

如果你在本书的任何方面遇到问题,可以通过 <questions@packtpub.com> 联系我们,我们将尽力解决。

第一章. 页面和页面类型

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

  • 获取当前页面对象

  • 通过 ID 获取页面对象

  • 通过路径获取页面对象

  • 通过 ID 获取页面类型

  • 通过句柄获取页面类型

  • 获取页面类型的 ID

  • 获取页面类型的名称

  • 获取页面类型的句柄

  • 获取页面类型的图标

  • 获取属于页面类型的页面列表

  • 创建页面类型

  • 更新页面类型

  • 删除页面类型

  • 创建页面类型

  • 更新现有页面

  • 设置页面属性

  • 获取页面属性

  • 获取页面的 ID

  • 获取页面的路径

  • 获取页面的句柄

  • 获取页面的名称

  • 获取页面的描述

  • 获取页面页面的 ID

  • 获取页面页面的句柄

  • 获取页面的主题对象

  • 获取页面下的子页面

  • 移动页面

  • 删除页面(及其子页面)

  • 获取页面列表

  • 将页面选择字段添加到表单中

简介

几乎任何内容管理系统都围绕着页面的概念。concrete5页面包含可重用的内容部分,称为。块可以包含您自己输入的格式化文本内容,到照片幻灯片,到视频,到您开发的包含特殊功能的自定义表单。concrete5 页面是内部Collection对象的扩展,其名称来源于它包含构成页面的块集合。

由于网站上的页面通常包含重复的信息区域(可能是一个带有一些持久小部件的侧边栏),concrete5 包括页面类型的概念。页面类型允许您为在 concrete5 中创建新页面定义不同的模板。它们用于指定添加到该类型新页面上的默认块集、内容和特殊属性,以及通过 concrete5 网站创建不同的视觉布局。

一个常见的页面类型是左侧边栏,它包含侧边栏中的链接列表,以及一个在右侧添加内容块的区域。标准的 concrete5 安装默认包含一些页面类型,包括左侧边栏和全宽。在代码中,页面类型可以通过数据库中唯一的数值 ID 或更常见的人类可读标识符(称为句柄)来引用。例如,左侧边栏页面类型将有一个句柄left_sidebar

介绍

当通过用户界面向 concrete5 网站添加页面时,你可能会注意到第一步是选择页面类型。页面类型也由 concrete5 的 Composer 功能使用,这可以帮助创建同一类型的多个页面(如博客文章)。

concrete5 中有两种页面类型,第一种是标准页面,它会被添加到网站地图中并分配一个页面类型,第二种是单页,它处理方式略有不同,不会分配页面类型。本章将处理第一种类型的页面。

关于本章代码的说明

通常,您将在 concrete5 应用程序的块、控制器或模型中编写与页面和页面类型交互的代码。为了演示目的,您可以将代码放置在 concrete5 允许您执行任意 PHP 代码的任何位置。

一个很好的做法是将site_process.phpsite_post.php文件添加到您网站的根目录/config中。concrete5 将在所有核心类和库加载完毕后执行该文件中的所有代码(site_post在当前页面加载之前执行,site_process在当前页面设置之后执行)。我们将使用经典的 PHP 调试技术来验证我们的代码是否正常工作。通常,我们将使用 PHP 的var_dumpprint_r函数来导出一个变量的内容,然后跟一个exit命令。

由于本书中使用的调试技术可能会中断 concrete5 网站的常规功能,建议您在 concrete5 的开发副本上执行这些练习。

完成后,请确保注释掉或删除调试代码,以恢复您 concrete5 网站的正常功能。

创建一个自定义调试函数

为了帮助变量导出,我们可以创建一个简单的调试函数,该函数将我们的输出包裹在<pre>标签中,并自动为我们exit

将以下代码放置在/config/site_post.php的顶部(如果不存在,则创建该文件):

function my_debug($var) {
  echo '<pre>';
  print_r($var);
  echo '</pre>';
  exit;
}

小贴士

下载示例代码

您可以从您在www.packtpub.com的账户中下载所有已购买 Packt 书籍的示例代码文件。如果您在其他地方购买了这本书,您可以访问www.packtpub.com/support并注册,以便将文件直接通过电子邮件发送给您。

现在,当我们希望检查一个变量或其他对象的内容时,我们可以简单地调用my_debug($variable),并得到一个格式良好、易于阅读的响应。

当然,您完全可以使用自己的调试变量技术。

获取当前 Page 对象

对于 concrete5 开发者来说,从当前显示的页面中检索信息是一个非常常见的任务。您会遇到这种情况,无论是需要更新当前页面的某些信息(如页面标题),检查当前用户在此页面的权限,还是仅显示页面标题。幸运的是,这相当简单。

如何做到这一点...

获取当前Page对象的步骤如下:

  1. 如果不存在,创建/config/site_process.php

  2. 在你偏好的文本编辑器中打开/config/site_process.php

  3. 我们可以通过调用Page类的getCurrentPage静态函数来获取当前的Page对象。

    $currentPage = Page::getCurrentPage();
    
  4. 如果我们检查$currentPage变量的内容,我们可以看到它是一个Page对象,现在我们可以对它执行进一步的操作。在这个例子中,我们使用在章节介绍中创建的自定义调试函数。

    my_debug($currentPage);
    

它是如何工作的...

Page类上调用静态的getCurrentPage函数将会在 concrete5 的Request对象中查找当前页面。如果未设置,concrete5 将使用全局变量$c。注意使用site_process.php来输出当前页面变量。我们使用这个文件是因为它在 concrete5 设置当前Page对象之后被读取。使用site_post.php会导致返回一个空对象。

还有更多...

你可能已经注意到,有时开发者会在他们的代码中使用全局变量$c来获取当前的CollectionPage对象。这通常工作得很好,但最佳实践是使用getCurrentPage函数来为你处理这个问题。

参见

  • 通过 ID 获取页面对象的配方

  • 通过路径获取页面对象的配方

通过 ID 获取页面对象

在许多情况下,你需要使用数据库中页面的唯一数字 ID 来加载Page对象。如前所述,页面实际上是Collection对象的扩展,所以你实际上是通过集合 ID 来加载页面的。

准备工作

我们需要知道你试图加载的页面的数字 ID。通常这个 ID 会存储在其他对象中,可能甚至是你存储在数据库中的自定义实体。例如,假设你在数据库中有一个食谱表,每个食谱在 concrete5 网站上都有自己的页面。你为每个食谱存储页面 ID,这样你就可以在需要时加载相关的Page对象。

如何做到这一点...

首先,你必须获取你试图加载的Page对象的页面 ID。在这个例子中,我们将直接硬编码我们正在加载的页面 ID。步骤如下:

  1. 在你喜欢的代码编辑器中打开/config/site_post.php

  2. 首先,让我们将我们正在加载的页面 ID 存储到一个变量中。在实际应用中,你可能会在数据库表中存储这个 ID,或者从你运行的其他代码中获取。在 concrete5 中,主页的 ID 默认为1,所以我们将使用这个 ID 作为我们页面的 ID:

    $pageId = 1; // load the home page
    
  3. 现在我们已经得到了需要加载的页面 ID,使用getByID函数来获取所需的Page对象:

    $page = Page::getByID($pageId);
    
  4. 我们可以检查$page变量并验证它是否包含一个Page对象。

    my_debug($page);
    

它是如何工作的...

页面 ID(也称为集合 ID)在数据库中是唯一的,所以调用getByID函数将加载正确的页面数据并返回一个你可以与之交互的Page对象。

参见

  • 获取当前页面对象的配方

  • 通过路径获取页面对象 的配方

通过路径获取页面对象

concrete5 也支持通过在网页浏览器中显示的路径来加载 Page 对象。这是一种方便的加载页面方式,而无需知道它们的数字 ID。在这个练习中,我们将通过路径加载一个关于我们的页面。

准备工作

我们将加载路径为 /about-us 的页面。如果此页面在您的 concrete5 网站中不存在,请在尝试此练习之前将其添加到网站地图中。

如何操作...

使用静态函数 getByPath,我们可以轻松获取 Page 对象,而无需知道其 ID。步骤如下:

  1. 在您的代码编辑器中打开 /config/site-post.php 文件。

  2. 声明您要加载的页面的路径。

    $path = '/about-us';
    
  3. 我们可以通过传递路径字符串到 getByPath 函数来加载位于 http://example.com/about-us 的页面。

    $aboutPage = Page::getByPath($path);
    
  4. 为了确保我们获取了正确的页面,我们将输出 $aboutPage 变量以验证我们有一个完全加载的 Page 对象。我们将使用我们在章节介绍中创建的自定义调试函数。

    my_debug($aboutPage);
    

它是如何工作的...

concrete5 将查询数据库以获取分配了指定路径的页面。在通过路径加载页面时,您需要明智地判断,因为该数据可以通过 concrete5 界面轻松更改。想象一下,您正在为一个有 15 个编辑者的网站工作,任何一位编辑者都有权编辑页面的路径。concrete5 默认会在更改新路径时保存旧页面路径,但这不是必需的。在您的自定义应用程序中硬编码页面路径仅应在适当的情况下使用。在可能的情况下,通过 ID 加载页面是一个更好的主意,因为该 ID 不会更改。

更多内容...

您可以使用此技术加载网站上的任何页面。要加载位于我们刚刚加载的“关于”页面之下的“职业”页面,您会编写以下内容:

$careersPage = Page::getByPath('/about-us/careers');

您应该知道,concrete5 会缓存与每个路径相关的页面 ID,所以如果您在使用此功能时遇到意外结果,请确保通过访问 concrete5 网站的 /dashboard/system/optimization/clear_cache/ 来清除您的网站缓存。

相关内容

  • 获取当前页面对象 的配方

  • 通过 ID 获取页面对象 的配方

通过 ID 获取页面类型

在 concrete5 开发中创建和编辑页面时,您不可避免地需要加载将被分配给页面的所需页面类型对象。请注意,页面类型实际上是代码中 CollectionType 对象的实例。为了保持一致性,我们将在代码之外继续将它们称为页面类型。

准备工作

我们将继续在 /config/site-post.php 文件中执行这些示例,因为这是一个快速且易于运行任意代码的地方。我们还将继续使用我们在章节介绍中定义的自定义 my_debug 函数。

在这个菜谱中,我们将加载 ID 为4的页面类型。请确保此页面类型存在于您的 concrete5 实例中,否则将 ID 更改为适合您环境的内容。

如何做...

与加载页面类似,您需要在CollectionType类上调用一个静态函数。步骤如下:

  1. 打开文本编辑器中的/config/site_post.php

  2. 首先,我们需要知道页面类型的数字 ID。在这种情况下,我们将假设存在一个名为“Left Sidebar”的页面类型,并且它具有数字 ID 4

    $leftSidebarId = 4;
    
  3. 既然我们已经有了我们想要加载的页面类型的 ID,我们可以调用CollectionType类的getByID函数。

    $leftSidebarPageType = CollectionType::getByID($leftSidebarId);
    
  4. 我们可以通过检查$leftSidebarPageType变量并验证它是否是CollectionType类的实例来验证我们是否加载了正确的页面类型。

    my_debug($leftSidebarPageType);
    

它是如何工作的...

getByID函数执行一个简单的数据库查询以找到属于该 ID 的页面类型。在成功查找时返回一个CollectionType对象。

参见

  • 通过句柄获取页面类型的菜谱

通过句柄获取页面类型

如章节介绍中所述,页面类型也有人类可读的句柄,这为在不了解它们的数字 ID 的情况下加载页面类型提供了一个方便的方法。句柄总是由单词之间带有下划线的字母数字字符串组成,不包含任何文件扩展名,如.php。例如,名为“Left Sidebar”的页面类型的句柄很可能是left_sidebar,但 concrete5 允许用户为句柄指定任何字母数字字符串,因此 Left Sidebar 的句柄也可能是left

通过句柄获取页面类型

您可以通过访问 concrete5 仪表板的页面类型区域来找到页面类型的句柄,该区域位于您的 concrete5 网站上的/dashboard/pages/types/

准备工作

在这个菜谱中,我们将加载句柄为left_sidebar的页面类型。请确保该页面类型存在于您的 concrete5 安装中,否则您可以添加一个新的页面类型并使用该句柄,或者调整菜谱以适应您的环境。

如何做...

这是我们如何通过句柄left_sidebar加载页面类型的方法。这与通过路径加载页面类似。步骤如下:

  1. 在您的首选代码编辑器中打开/config/site_post.php

  2. 声明您要加载的页面类型的句柄。

    $handle = 'left_sidebar';
    
  3. 使用我们刚刚定义的句柄加载页面类型。

    $pageType = CollectionType::getByHandle($handle);
    
  4. 您可以通过输出$pageType变量来验证您是否已加载页面类型。

    my_debug($pageType);
    

它是如何工作的...

执行一个简单的数据库查询,如果成功,将返回一个CollectionType对象。

更多内容...

就像加载页面路径时的警告一样,当通过处理器加载页面类型时,您也需要进行相同的良好判断。由于这些处理器只是可以通过 concrete5 界面编辑的字符串,您需要确保您编写的代码不会因为网站编辑更改页面类型的处理器而损坏。

相关内容

  • 通过 ID 获取页面类型配方

获取页面类型的 ID

一旦页面类型被加载,我们可以从中获取不同的信息。有时,如果页面类型是通过其处理器加载的,或者是从另一个函数调用中提供的,开发者将需要从现有的页面类型对象中获取页面类型的 ID。在这个练习中,我们将通过处理器加载页面类型,然后找出页面类型的 ID。

准备工作

在这个例子中,我们将加载一个处理器为right_sidebar的页面类型。如果该页面类型在您的 concrete5 系统中不存在,请根据您的具体情况调整此配方。

如何操作...

获取页面类型 ID 的步骤如下:

  1. 在您的代码编辑器中打开/config/site_post.php

  2. 通过路径加载页面类型:

    $pageType = CollectionType::getByHandle('right_sidebar');
    
  3. 从页面类型获取 ID。

    $id = $pageType->getCollectionTypeId();
    
  4. 输出页面类型 ID(我们使用本章引言中解释的自定义调试器)。

    my_debug($id);
    

工作原理...

一旦页面类型对象被加载,开发者可以调用多个函数来从其中检索数据,包括数字 ID。

相关内容

  • 通过处理器获取页面类型配方

获取页面类型的名称

页面类型对象还包含检索页面类型名称的方法。在这个练习中,我们将通过处理器加载页面类型,然后检索页面类型的名称。

准备工作

我们将加载一个具有right_sidebar处理器的页面类型,所以如果该页面类型在您的 concrete5 实例中不存在,请根据您的需求调整此配方。

如何操作...

获取页面类型名称的步骤如下:

  1. 在您首选的代码编辑器中打开/config/site_post.php

  2. 通过处理器加载页面类型:

    $pageType = CollectionType::getByHandle('right_sidebar');
    
  3. 获取页面类型的名称。

    $name = $pageType->getCollectionTypeName();
    
  4. 使用我们的自定义调试器输出名称。

    my_debug($name);
    

工作原理...

getCollectionTypeName函数简单地返回页面类型名称的字符串值。

相关内容

  • 通过处理器获取页面类型配方

获取页面类型的处理器

如果页面类型已经通过其 ID 加载或以其他方式提供,开发者可能希望从现有的页面类型对象中检索页面类型的处理器。在这个例子中,我们将加载一个 ID 为4的页面类型,并使用 concrete5 API 获取其处理器。

准备工作

我们将加载一个 ID 为 4 的页面类型,所以请确保它在您的 concrete5 网站上存在。您可以根据您的 concrete5 实例更改此配方中的 ID 为适当的值。

如何操作...

获取页面类型处理器的步骤如下:

  1. 在您首选的代码编辑器中打开/config/site_post.php

  2. 通过 ID 加载页面类型。

    $pageType = CollectionType::getByID(4);
    
  3. 获取页面类型的处理程序。

    $handle = $pageType->getCollectionTypeHandle();
    
  4. 使用我们的自定义调试函数输出处理程序。

    my_debug($handle);
    

它是如何工作的...

页面类型对象的getCollectionTypeHandle函数返回页面类型的处理程序字符串。

参见

  • 通过 ID 获取页面类型的配方

获取页面类型的图标

在 concrete5 仪表板界面中,页面类型与图标相关联。在某些高级应用中,您可能希望检索页面类型的图标。在这个配方中,我们将通过处理程序加载页面类型并获取其图标。

准备工作

我们将加载一个处理程序为right_sidebar的页面类型。如果right_sidebar不存在,请随意将其更改为适合您的 concrete5 实例的适当处理程序。

如何操作...

获取页面图标步骤如下:

  1. 在您最喜欢的代码编辑器中打开/config/site_post.php,因为这是一个尝试随机代码的好地方。

  2. 通过路径加载页面类型。

    $pageType = CollectionType::getByHandle('right_sidebar');
    
  3. 获取图标图像。

    $icon = $pageType->getCollectionTypeIconImage();
    
  4. 输出图像。您应该看到图标图像出现。

    echo $icon;
    exit;
    

    如何操作...

它是如何工作的...

concrete5 返回一个包含集合类型图标的实际 HTML 图像标签的字符串。

更多内容...

如果您想获取包含页面类型图标的文件的数字 ID,您可以简单地调用此函数:

$iconId = $pageType->getCollectionTypeIcon();

数字 ID 在处理 concrete5 文件管理器时很有用,这在本书第三章(第三章。文件和文件集)中详细讨论。

参见

  • 通过 ID 获取页面类型的配方

获取属于页面类型的页面列表

在许多高级 concrete5 应用中,开发者可能需要找到属于给定页面类型的所有页面的列表。在这个例子中,我们将获取具有right_sidebar处理程序的页面类型的页面数组。

准备工作

如果您的 concrete5 实例没有名为right_sidebar的页面类型,请随意调整配方以满足您的需求。我们将继续使用/config/site_post.php作为我们的沙盒来运行随机代码片段,以及我们在本章引言中创建的自定义调试函数。

如何操作...

获取属于页面类型的页面列表的步骤如下:

  1. 在您的代码编辑器中打开/config/site_post.php以尝试以下代码。

  2. 通过处理程序加载页面类型。

    $pageType = CollectionType::getByHandle('right_sidebar');
    
  3. 获取Page对象数组。

    $pages = $pageType->getPages();
    
  4. 输出数组以查看其内容。

    foreach ($pages as $page) {
      echo $page->getCollectionTitle().'<br />';
    }
    exit;
    

它是如何工作的...

concrete5 简单地使用关系型 MySQL 数据库来查找与页面类型相关的所有页面。请注意,当调用此函数时,concrete5 会忽略权限设置,因此这实际上仅应用于内部目的。

参见

  • 通过处理程序获取页面类型的配方

创建页面类型

您可以通过 concrete5 用户界面轻松添加新的页面类型,但有些情况可能需要您使用 PHP 代码动态创建页面类型。

准备工作

首先,你需要创建一个包含你正在创建的页面类型数据的关联数组。

数组可以包含以下字段:

属性 是否必需? 描述
ctHandle 集合类型处理程序:单词之间用下划线分隔的字母数字字符串。
ctName 集合类型名称:将在 concrete5 界面中显示的字符串。
ctIcon 如果你想要为此页面类型指定一个图标,请传递来自文件管理器的图标数值 ID。
ctIsInternal 一个布尔值,表示此页面类型是否为内部页面类型。内部页面类型不会在 concrete5 界面的页面创建对话框中显示。
akID 要添加到新页面类型中的属性键 ID 数组。

如何操作...

我们将只使用所需的字段:ctHandlectName 来创建页面类型。步骤如下:

  1. 在你喜欢的代码编辑器中打开 /config/site_post.php

  2. 声明要创建的新页面类型的处理程序。

    $handle = 'page_type_handle';
    
  3. 声明包含 ctHandlectName 字段数据的数组。

    $data = array(
      'ctHandle' => $handle,
      'ctName' => 'Page Type Name'
    );
    
  4. 通过加载新的处理程序来检查页面类型是否已存在。

    $pageType = CollectionType::getByHandle($handle);
    
  5. 如果页面类型不存在,则创建它。

    if (!$pageType) {
      $newPageType = CollectionType::add($data);
    }
    
  6. 如果它存在,将现有页面类型分配给新页面类型变量。

    else {
      $newPageType = $pageType;
    }
    
  7. 输出新页面类型变量以确保它已成功。

    my_debug($newPageType);
    

它是如何工作的...

concrete5 将会接收你传递的数据数组,并使用它来在数据库中创建一个新的 CollectionType 记录。concrete5 还会自动在数据库中生成一个主集合页面。主集合是一个模板页面,concrete5 将将其用作该类型所有页面的基础。任何分配给主集合的块、属性或其他数据将自动添加到使用该页面类型创建的任何新页面中。

更多...

如果你在一个自定义包中创建此页面类型,你需要将你的包对象传递给 add() 函数,这样 concrete5 就知道此页面类型属于你的包。这样,当用户卸载你的包时,他们将有选择删除它创建的所有页面类型的选项。

假设你知道你的包的处理程序,使用以下代码来创建一个带有它的页面类型:

$data = array(
  'ctHandle' => $handle,
  'ctName' => 'Page Type Name'
);
$pkg = Package::getByHandle('my_package');
$newPageType = CollectionType::add($data, $pkg);

参见

  • 创建自定义插件包 的配方

  • 更新页面类型 的配方

更新页面类型

更新页面类型与之前配方中讨论的创建页面类型非常相似。

如何操作...

首先,你需要加载一个现有的页面类型。在更新页面类型时,你需要传递与创建时相同的数据数组。步骤如下:

  1. 在你的代码编辑器中打开 /config/site_post.php

  2. 声明旧处理程序和新处理程序变量。

    $handle = 'page_type_handle';
    $newHandle = 'new_handle';
    
  3. 使用新的处理程序和新的名称定义新的 $data 数组。

    $data = array(
      'ctHandle' => $newHandle,
      'ctName' => 'New Name'
    );
    
  4. 如果页面类型存在,则更新它。

    $pageType = CollectionType::getByHandle($handle);
    if ($pageType) {
      $pageType->update($data);
    }
    
  5. 通过访问 concrete5 网站的 /dashboard/pages/types 来验证页面类型是否已更新。如何操作...

它是如何工作的...

concrete5 将更新数据库中加载的页面类型的记录。当调用此函数时,主收藏页面不会被更新。您也不能将包装对象传递给更新函数,因为这只有在首次创建页面类型时才是必要的。

相关链接

  • 创建页面类型 的食谱

  • 删除页面类型 的食谱

删除页面类型

除了添加和编辑页面类型外,您还可以删除它们。

准备工作

由于删除页面类型是一个破坏性的不可逆操作,因此为这次练习创建一个句柄为 delete_me 的虚拟页面类型是个好主意。我们还将继续使用 site_post.php 来执行任意代码。

如何操作...

删除页面类型的步骤如下:

  1. 在您偏好的代码编辑器中打开 /config/site_post.php

  2. 定义要删除的页面的句柄。

    $handle = 'delete_me';
    
  3. 通过其句柄加载页面类型。

    $pageType = CollectionType::getByHandle($handle);
    
  4. 现在,删除页面类型。

    $pageType->delete();
    

它是如何工作的...

delete() 函数删除页面类型、主收藏以及所有使用它的页面。请谨慎使用此函数,因为一旦数据被删除,就无法恢复(除非您有网站的数据库备份副本)。

相关链接

  • 通过 ID 获取页面类型 的食谱

创建页面类型

动态创建页面是 concrete5 开发的一个核心概念,并且可以在自定义应用程序中解锁许多强大的功能。想象一个拥有食谱数据库的 concrete5 网站。您可以使其每次将食谱添加到数据库时,都会在网站地图中添加一个新的食谱页面,从而立即提高您网站的内容深度、可用性,甚至搜索引擎性能。

在这个例子中,我们将创建一个“关于我们”页面并将其添加到网站地图中。

准备工作

我们继续将代码放在 /config/site_post.php 中进行演示和测试。在实际应用中,您的动态页面创建将在控制器文件或附加包中发生。

我们将分配一个具有句柄 right_sidebar 的新页面类型。如果这在您的 concrete5 安装中不存在,请根据您的需求调整此食谱。

如何操作...

创建页面的步骤如下:

  1. 在您的代码编辑器中打开 /config/site_post.php

  2. 加载新页面将使用的页面类型。我们将使用句柄(在这种情况下为 right_sidebar)加载页面类型。

    $pageType = CollectionType::getByHandle('right_sidebar');
    
  3. 创建一个包含您希望为新页面指定的字段的关联数组。在这个例子中,我们只指定页面的名称和句柄。

    $data = array(
      'cName' => 'About Us',
      'cHandle' => 'about'
    );
    
  4. 加载新页面将放置其下的父页面。在这种情况下,我们正在加载主页,因为新页面将在顶级可用。

    $parent = Page::getByID(1);
    
  5. 通过将$pageType对象和$data数组传递给父Page类的add()函数来添加页面。

    $newPage = $parent->add($pageType, $data);
    
  6. 输出消息并退出进程。

    echo 'done!';
    exit;
    
  7. 访问你的网站主页以执行site_post.php中的代码。

  8. 如果你看到成功消息,请注释掉site_post.php中的代码,这样你就可以访问新创建的页面。否则,每次将网站加载到浏览器中时,concrete5 都会创建一个新页面。

  9. 访问新创建的页面http://example.com/about

它是如何工作的...

add()函数是Collectionadd()函数的包装器。调用它将在数据库中创建一个新的Collection记录,并创建一个新的待批准的CollectionVersion记录(如果cvIsApproved变量设置为true或留空,则将予以批准)。然后新页面将继承必要的权限,并从相关页面类型的 Master Collection 中获取所有块和其他属性。

还有更多...

你需要向add()函数提供两个参数,一个CollectionType对象(我们在本章前面已经使用过),以及包含创建页面所需所有数据的关联数组。关联数组可以包含以下字段。

属性 是否必需 描述
cName 这是页面的名称。这将是整个网站中引用页面的方式,并且将自动用于页面的<title>标签(除非被元标题属性覆盖,你可以在页面创建后指定。)
cHandle 这是页面的处理程序,即页面标题将如何在页面 URL 中显示。如果你省略此字段,concrete5 将根据cName字段生成一个处理程序。这有点令人困惑,因为 concrete5 允许在页面处理程序中使用破折号("-"),但似乎在其他地方不支持它们。不过,这很好,因为网页路径的典型约定是使用破折号而不是下划线。
cDescription 这是页面的内部描述。它只是一个描述页面目的的字符串。一些主题可能会在主题的某个地方使用这些数据,但这不是必需的。concrete5 的旧版本会在仪表板中显示页面的描述,但自更新到 5.5 版本后,这一功能已经取消。
uID 这是一个整数 ID,用于表示页面的作者。将任何用户在 concrete5 的Users表中的 ID 传递进去,可以将该用户设置为页面作者。如果省略,则当前登录用户将被注册为页面作者。
pkgID 这是创建此页面的包的整数 ID。如果你是从包中创建页面,请确保包含此字段。如果你省略了此字段,但附加的页面类型属于一个包,则页面类型的包 ID 将附加到该页面上。这将帮助用户在卸载你的包时可选地删除由你的包创建的任何页面。
cDatePublic 这是页面应在网站上公开可见的 MySQL 格式日期字符串(YYYY-MM-DD)。如果省略,则使用来自 Web 服务器的当前日期和时间。
cvIsApproved 这是一个布尔值,表示初始页面版本是否应该被批准。如果没有指定,默认为 true。当页面被批准时,它们将立即对所有有权访问该页面的网站用户可见。对页面的任何后续编辑都需要在用户可以看到更改之前批准页面的新版本。

参考以下内容

  • 更新现有页面的配方

  • 通过 ID 获取页面类型的配方

  • 通过句柄获取页面类型的配方

更新现有页面

更新页面与创建页面类似,你必须首先传递一个包含你希望在页面上更新的所有数据的关联数组。

准备工作

在这个配方中,我们将修改路径为/about的页面。我们在上一个配方中创建了该页面,但如果它在你系统中不存在,请根据你的需求调整代码。

如何做到这一点...

在此示例中,我们将更新About页面的名称。步骤如下:

  1. 首先,我们需要通过其路径加载Page对象。

    $page = Page::getByPath('/about');
    
  2. 创建一个包含你希望更新的数据的关联数组。

    $data = array(
      'cName' => 'About Our Company'
    );
    
  3. 将数据数组传递给$page对象的update函数。

    $page->update($data);
    
  4. 输出成功消息并退出进程。

    echo 'done!';
    exit;
    

它是如何工作的...

update函数更新数据库中必要的表以包含新指定的信息。concrete5 还将重新扫描此页面及其所有相关页面路径的所有权限。当函数完成后,将触发on_page_update事件,你可以编写自定义代码来监听并在页面更新时执行自定义操作。监听系统事件将在后面的章节中介绍。

还有更多...

就像创建页面一样,你需要传递一个关联数组到update()函数以更新现有页面。你可以使用上一个配方中指定的所有字段来添加页面,以及这些其他可选字段。

属性 描述
ctID 这是更改页面类型的页面类型的数值 ID。提供此字段以更改给定页面的页面类型。
cCacheFullPageContent 一个布尔值,指定页面是否应支持完整页面缓存(某些块类型不支持完整页面缓存,因此仅在页面上提供的块支持完整缓存支持时使用)。
cCacheFullPageContentOverrideLifetime 一个字符串,告诉 concrete5 缓存寿命应该如何执行。可能的值是 defaultcustomforever
cCacheFullPageContentLifetimeCustom 当覆盖模式设置为 custom 时,缓存应持续多长时间的分钟设置。

相关内容

  • 创建页面类型 食谱

设置页面属性

页面,像 concrete5 中的大多数对象一样,可以附加任何类型的自定义属性。这提供了极大的灵活性,但使用原始 SQL 读写这些属性可能很困难。concrete5 API 使设置和读取页面属性变得简单。

准备工作

您至少需要知道要分配给页面的属性键句柄。一个常见的设置属性是 Meta Title 属性,它更新出现在 HTML <title> 标签中的文本。

如何操作...

在本例中,我们将设置 Meta Title 属性到关于我们页面。步骤如下:

  1. 在您首选的代码编辑器中打开 /config/site_post.php

  2. 加载您希望设置属性的 Page 对象。

    $page = Page::getByPath('/about');
    
  3. $page 对象上调用 setAttribute 函数,传入两个参数:属性句柄(键)和值。

    $page->setAttribute('meta_title', 'New Page Meta Title');
    
  4. 输出成功消息并退出进程。

    echo 'done!';
    exit;
    

工作原理...

setAttribute 函数是 Collection 类的一个成员,该类由 Page 类扩展。它要求您提供两个参数,一个属性键(可以是表示属性键句柄的字符串(我们在这里提供),或者实际的 AttributeKey 对象),以及值。

更多内容...

setAttribute 函数对于设置任何类型的页面属性数据非常方便。可以更新页面的元信息(如描述、关键词和标题),还可以为页面提供各种选项,例如,将其排除在导航之外(如之前所见)或从搜索引擎查找的 sitemap.xml 文件中。

您可以更新 concrete5 系统中安装的任何属性。要查看所有可用的页面属性或创建新的属性,请访问您网站仪表板的 页面属性 区域(位于 /dashboard/pages/attributes/)。

相关内容

  • 通过路径获取页面 食谱

  • 获取页面属性 食谱

获取页面属性

除了能够设置页面属性外,开发者还可以轻松检索属性。在本练习中,我们将获取关于页面的 Meta Title 属性。

准备工作

在本食谱中,我们假设存在一个路径为 /about 的页面。如果该页面不存在,您可以创建它,或者修改本食谱中的代码以适应您的环境。

如何操作...

获取页面属性的步骤如下:

  1. 在您首选的编辑器中打开 /config/site_post.php。这是一个运行一些任意代码的好地方。

  2. 加载 Page 对象。

    $page = Page::getByPath('/about');
    
  3. 获取 meta_title 属性。

    $title = $page->getAttribute('meta_title');
    
  4. 使用我们在章节介绍中创建的自定义调试函数输出变量。

    my_debug($title);
    

...工作原理...

concrete5 使用属性处理字符串来在数据库中找到相应的记录并返回其值。concrete5 以 EAV 格式(实体属性)存储属性,这使得直接使用 SQL 查询读取这些值变得困难。concrete5 API 简化了这一过程,方便开发者使用。

相关内容

  • 通过路径获取页面的教程

  • 设置页面属性的教程

获取页面 ID

开发者通常会需要知道页面的 ID,尤其是在将页面与其他数据库对象(如博客文章或日历事件)相关联时。在本例中,我们将加载我们一直在处理的/about页面,并获取其 ID。

准备工作

请确保在您的 concrete5 实例中存在/about页面。如果该页面不存在,您可以自由修改本教程中的代码。

如何操作...

获取页面 ID 的步骤如下:

  1. 在您的代码编辑器中打开/config/site_post.php

  2. 通过路径加载Page对象。

    $page = Page::getByPath('/about');
    
  3. 获取页面的 ID。

    $id = $page->getCollectionId();
    
  4. $id变量的内容输出,以查看 ID 是什么。

    my_debug($id);
    

相关内容

  • 通过路径获取页面的教程

获取页面的路径

除了能够获取页面的 ID 之外,开发者还可以检索页面的路径。在本教程中,我们将通过页面的 ID 来加载页面,然后检索其路径。

如何操作...

获取页面路径的步骤如下:

  1. 在您首选的代码编辑器中打开/config/site_post.php

  2. 通过 ID 加载页面。这里我们将使用4的 ID,它应该属于仪表板上的一个页面。

    $page = Page::getByID(4);
    
  3. 获取页面的路径。

    $path = $page->getCollectionPath();
    
  4. 使用自定义调试函数输出路径。

    my_debug($path);
    

相关内容

  • 通过 ID 获取页面的教程

获取页面的处理程序

页面,就像页面类型和其他 concrete5 中的对象一样,除了路径外还有处理程序。处理程序在其他内容管理系统中的 slug 类似。在本练习中,我们将通过 ID 加载页面,然后检索其处理程序。

如何操作...

获取页面处理程序的步骤如下:

  1. 在您的代码编辑器中打开/config/site_post.php

  2. 通过 ID 加载页面。

    $page = Page::getByID(4);
    
  3. 获取页面的处理程序。

    $handle = $page->getCollectionHandle();
    
  4. 输出处理程序变量以查看其内容。

    my_debug($handle);
    

相关内容

  • 通过 ID 获取页面的教程

获取页面的名称

页面名称通常在 concrete5 中用作事实上的标题。在本练习中,我们将通过路径加载页面,然后获取其名称。

如何操作...

获取页面名称的步骤如下:

  1. 在您的代码编辑器中打开/config/site_post.php

  2. 通过路径加载页面。

    $page = Page::getByPath('/about');
    
  3. 获取页面的标题。

    $name = $page->getCollectionName();
    
  4. 输出标题变量的内容。

    my_debug($name);
    

相关内容

  • 通过路径获取页面的教程

获取页面的描述

页面描述在 concrete5 中并不广泛使用。一些主题会将它们视为内容摘录,而其他插件会将描述用作通用属性存储区域。无论如何,它们仍然内置在 concrete5 中,在这个配方中,我们将通过路径加载页面并检索其描述。

准备工作

concrete5 中的许多页面都没有描述。如果您愿意,可以编辑页面以添加描述,如下面的截图所示:

准备工作

如何操作...

获取页面描述的步骤如下:

  1. 在您的代码编辑器中打开/config/site_post.php文件。

  2. 通过路径加载页面。

    $page = Page::getByPath('/about');
    
  3. 获取页面的描述。

    $description = $page->getCollectionDescription();
    
  4. 输出描述变量的内容。

    my_debug($description);
    

参见

  • 通过路径获取页面 的配方

获取页面页面类型 ID

如我们在本章前面所讨论的,页面被分配了一个页面类型。在这个配方中,我们将从Page对象中获取页面类型 ID。

如何操作...

获取页面页面类型 ID 的步骤如下:

  1. 在您的代码编辑器中打开/config/site_post.php,以便我们可以运行一些任意代码。

  2. 通过路径加载页面。

    $page = Page::getByPath('/about');
    
  3. 获取此页面的页面类型 ID。

    $pageTypeId = $page->getCollectionTypeID();
    
  4. 使用我们的自定义调试函数输出页面类型 ID。

    my_debug($pageTypeId);
    

参见

  • 通过路径获取页面 的配方

获取页面页面类型句柄

除了能够检索页面页面类型的 ID 之外,开发者还可以获取句柄。

如何操作...

获取页面页面类型句柄的步骤如下:

  1. 在您的代码编辑器中打开/config/site_post.php,因为我们只是要运行一些任意代码。

  2. 通过路径加载页面。

    $page = Page::getByPath('/about');
    
  3. 获取页面类型句柄。

    $handle = $page->getCollectionTypeHandle();
    
  4. 输出句柄变量以查看其内容。

    my_debug($handle);
    

参见

  • 通过路径获取页面 的配方

获取页面主题对象

在 concrete5 中,每个页面都可以有自己的独立主题。虽然对于大多数网站来说,只使用一个全局主题是典型的,但 concrete5 确实允许开发者为每个页面设置独立主题。在这个配方中,我们将获取页面的主题对象,这可以用来查看给定页面上激活的主题。

如何操作...

获取页面主题对象的步骤如下:

  1. 在您首选的代码编辑器中打开/config/site_post.php

  2. 通过路径加载页面。

    $page = Page::getByPath('/about');
    
  3. 获取主题对象。

    $theme = $page->getCollectionThemeObject();
    
  4. 输出主题对象以检查其类。

    my_debug($theme);
    

参见

  • 通过路径获取页面 的配方

获取页面下方的子页面

如果您需要访问页面的子项,您可以要求 concrete5 返回一个数字 ID 数组。然后,可以使用这些 ID 分别加载每个Page对象。

如何操作...

获取页面下方子页面的步骤如下:

  1. 在您首选的代码编辑器中打开/config/site_post.php

  2. 通过 ID 加载父页面。

    $page = Page::getByID(1);
    
  3. 获取子 ID 数组。

    $children = $page->getCollectionChildrenArray();
    
  4. 遍历子 ID 数组并输出每个页面的名称。

    foreach ($children as $childId) {
      $child = Page::getByID($childId);
      echo $child->getCollectionName().'<br />';
    }
    
  5. 退出进程。

    exit;
    

工作原理...

concrete5 将为父页面下的每个页面返回一个数字 ID 数组。在这个例子中,我们加载了主页,所以结果应该是网站上每个页面的列表。这个函数忽略权限,如果有很多页面要加载,可能会对数据库造成压力。使用PageList类遍历页面会更好,这个类在本章后面会进行描述。

移动页面

concrete5 的网站地图是一个管理网站页面层次结构的强大工具。它允许你安排页面的顺序,甚至可以将页面拖放到网站的不同区域。幸运的是,你不仅限于使用图形界面来移动页面。你还可以在你的自定义 concrete5 应用程序中动态地重新排列页面。

准备工作

在这个例子中,我们将把职业页面移动到“关于我们”页面之下。在我们能够移动页面之前,我们需要有新父页面的Page对象,我们将把当前页面移动到这个新父页面。

这个练习假设在你的 concrete5 网站上存在/about/careers这两个页面。你可以通过 concrete5 界面创建这些页面,或者修改这个配方中的代码以适应你自己的网站。

如何做到...

移动页面的步骤如下:

  1. 打开/config/site_post.php,因为那是一个安全的地方来尝试一些随机的代码。

  2. 首先,加载“关于我们”页面,这是职业页面将要移动到的位置。

    $newParent = Page::getByPath('/about');
    
  3. 现在,我们需要加载我们要移动的职业页面。

    $careersPage = Page::getByPath('/careers');
    
  4. 最后,在职业页面上调用move函数,传递新父页面和一个可选的布尔值,告诉 concrete5 我们是否希望同时保存旧页面路径和新页面路径。

    $careersPage->move($newParent, true);
    

它是如何工作的...

移动函数非常容易使用。你只需要提供一个参数,即你将页面移动到其下的新父页面的Page对象。还有一个可选的第二个参数,表示你是否希望保留旧页面路径以及当前路径。该参数默认为 false。

页面移动后,它将继承新父页面的权限(如果页面没有明确设置自己的权限)。

页面移动后,将触发on_page_move事件。

参见

  • 在第九章中监听系统事件系统事件和高级配置

  • 通过路径获取页面对象的配方

删除页面(及其子页面)

concrete5 还使得从网站地图中删除页面变得容易。

准备工作

删除页面是一个永久性的破坏性操作。在尝试这段代码时,创建一个路径为/delete-me的虚拟页面会是一个好主意。

如何做到...

我们将永久删除“关于我们”页面及其所有子页面。步骤如下:

  1. 首先,加载你想要删除的页面。我们将删除一个虚拟页面。

    $page = Page::getByPath('/delete-me');
    
  2. Page对象上调用delete()函数。

    $page->delete();
    

它是如何工作的...

concrete5 在实际删除之前将触发 on_page_delete 事件。事件触发后,页面(及其所有子页面)将从数据库中删除。此操作是永久的,因此确保您只在确定不再需要页面时删除页面非常重要。

更多...

如果您不想永久删除页面,可以将它移动到回收站。截至 concrete5 版本 5.5,页面可以被“临时”删除并移动到称为回收站的特殊内部页面。

$page->moveToTrash();

参考信息

  • 通过路径获取页面的菜谱

获取页面列表

许多应用程序将需要获取页面列表并在列表上执行各种过滤和排序函数。为此,存在 PageList 类,它公开了许多方便的辅助函数,以帮助处理大量页面列表。

准备工作

在此示例中,我们将查找 /blog 页面下的所有页面。这是页面列表模型的一个常见用途。PageList 类不是由 concrete5 自动加载的,因此我们需要使用 Loader 类来使其对我们可用。

如果您的网站没有位于 /blog 的页面,创建该页面以及其下的几个子页面将很有帮助。否则,请随意根据您的需求调整此菜谱中的代码。

如何做...

在此菜谱中,我们将获取 /blog 在网站地图下存在的 20 个页面列表。步骤如下:

  1. 首先,我们必须使 PageList 类对我们可用。

    Loader::model('page_list');
    
  2. 创建 PageList 类的新实例。我们将将其分配给一个名为 $list 的变量。

    $list = new PageList();
    
  3. 过滤列表,只包括 /blog 页面下的页面。

    $list->filterByPath('/blog');
    
  4. 限制页面列表,只包括前 20 个结果。

    $list->setItemsPerPage(20);
    
  5. 执行数据库查询并获取第一个“页面”的结果,这将返回一个包含 20 个 Page 对象的数组。

    $pages = $list->getPage();
    
  6. 将页面变量的内容输出以查看数组。

    foreach ($pages as $page) {
      echo $page->getCollectionTitle().'<br />';
    }
    exit;
    

它是如何工作的...

PageList 类扩展了核心的 DatabaseItemList 类,该类本身就有许多有用的函数。get() 函数接受两个参数,即要检索的记录数和偏移量。

更多...

页面列表类实现了“魔法方法”,这允许我们通过任何页面属性来过滤列表。我们只需创建一个基于属性处理程序驼峰式命名的函数名,并在其前加上“filterBy”。因此,要过滤所有具有 exclude_nav 属性的页面,我们会编写以下函数:

$list->filterByExcludeNav(true);

或者,如果您只想获取前 99 个 Page 对象的数组并忽略分页,请使用 get() 函数。

$pages = $list->get(99);

自从 5.5 版本以来,concrete5 使用 Twitter 的开源 Bootstrap CSS 框架来处理许多内部样式。你可以通过打印/输出以下函数的结果(最好在视图或模板文件中使用此函数)来获取格式良好的 HTML(带有相关的 Bootstrap CSS 类)的分页控件:

echo $list->displayPagingV2();

DatabaseItemList 类和 PageList 类有多个函数,使得处理页面集合变得更容易。你可以通过关键字、集合类型、父页面以及任何属性使用魔法方法进行筛选。我们将在 第五章 中进一步介绍 DatabaseItemList 类,与数据库和模型一起工作

在表单中添加页面选择器字段

在表单中添加页面选择器字段很容易。当点击时,网站地图将在模态窗口中显示,允许轻松浏览和选择页面。这允许用户友好的自定义应用程序,可以允许用户将页面附加到任何类型的自定义对象,例如博客文章或烹饪食谱。

准备工作

我们需要使用 FormPageSelectorHelper 类,我们需要使用 Loader 库来加载它。

此配方需要写入你网站中的某个 HTML 表单内。我们为此创建了一个基本的单页,可以从本书的网站上下载代码。要安装单页,将此配方的代码复制到你的 concrete5 网站目录中,并访问 /dashboard/pages/single。添加一个路径为 /example 的新单页。

如何做到...

concrete5 包含一个生成显示网站地图选择器小部件所需的必要 JavaScript 和 HTML 文本的辅助工具。我们将使用 Loader 类来包含并返回 PageSelectorHelper 类,然后它将返回我们需要的整个 HTML。步骤如下:

  1. 使 pageSelector 辅助类可供我们使用。当辅助工具被加载时,Loader 类将自动实例化并返回实例化的辅助对象。

    $pageSelector = Loader::helper('form/page_selector');
    
  2. 输出所需的 HTML 和 JavaScript,以便用户可以选择一个页面。

    echo $pageSelector->selectPage('page_id');
    

它是如何工作的...

selectPage 函数返回生成页面选择器字段所需的 HTML 和 JavaScript。只需要一个参数,即表示字段名称的字符串。concrete5 将在表单中添加一个隐藏的 <input> 元素,允许从 POST 请求中读取选定的页面 ID。

在这个例子中,一旦表单提交,你可以通过查看 $_POST 超全局变量来检索选定的页面 ID。

$pageId = $_POST['page_id'];

还有更多...

你可以在可选的第二个参数中指定页面 ID,这将用现有页面填充页面选择器。

$page = Page::getByCollectionPath('/about-us');
echo $pageSelector->selectPage('page_id', $page->getCollectionID());

pageSelector 辅助工具还有一个函数可以在模态窗口中显示网站地图。

$args = array(
'display_mode' => 'full'
);
$pageSelector->sitemap($args);

注意,sitemap() 函数加载一个元素,该元素会自动打印到屏幕上,因此不需要回显或打印结果。

第二章. 与块一起工作

在本章中,我们将介绍以下食谱:

  • 创建自定义块类型

  • 使用块控制器回调函数

  • 从控制器向视图发送变量

  • 从块控制器向页面页眉和页脚添加项目

  • 创建自定义块模板

  • 在块表单中包含 JavaScript

  • 在块视图中包含 JavaScript

  • 在块视图中包含 CSS

  • 通过其句柄加载块类型

  • 将块添加到页面

  • 从区域获取块

简介

concrete5 中的块是小型、模块化的视觉展示组件,可以几乎添加任何类型的内容到您的网站。块可以包含文本内容、HTML 代码、图片、视频、交互式地图或您能想到的任何其他内容。当您编辑 concrete5 网站的页面内容时,您正在编辑内容块类型的一个实例。块被添加到页面的特殊区域,这些区域在主题布局中指定。concrete5 默认附带了许多不同的块类型,并且创建您自己的自定义块类型很容易,这使您能够为您的网站添加无限的可能性。

在本章中,我们将从头开始创建一个自定义块类型。此块类型将仅显示一些用户可以通过 CMS 界面编辑的文本,并将作为一个基本的 "Hello World" 示例。

创建自定义块类型

创建块类型是向网站添加自定义功能的好方法。这是添加像日历、经销商定位器或任何其他在网站前端可见且可重复的内容的首选方式。

准备工作

该食谱的代码可以从本书的网站上免费下载。我们将创建一个完全功能性的块类型,该类型将在我们的网站上显示内容。

如何操作...

创建自定义块类型的步骤如下:

  1. 首先,您需要在您网站的根目录 /blocks 中创建一个目录。目录的名称应该是下划线,并且将在整个代码中用来引用块。在这种情况下,我们将创建一个名为 /hello_world 的新目录。如何操作...

  2. 一旦您创建了 hello_world 目录,您需要创建以下文件:

    • controller.php

    • db.xml

    • form.php

    • add.php

    • edit.php

    • view.php

    • view.css

  3. 现在,我们将为每个文件添加代码。首先,我们需要设置 controller 文件。controller 文件是驱动块的动力所在。由于这是一个非常基础的块,我们的控制器将只包含一些信息,以告诉 concrete5 关于我们块的一些细节,例如它的名称和描述。

  4. 将以下代码添加到 controller.php 文件中:

    class HelloWorldBlockController extends BlockController {
      protected $btTable = "btHelloWorld";
      protected $btInterfaceWidth = "300";
      protected $btInterfaceHeight = "300";
      public function getBlockTypeName() {
        return t('Hello World');
      }
      public function getBlockTypeDescription() {
        return t('A basic Hello World block type!');
      }
    }
    
  5. 注意,类名是HelloWorldBlockController。concrete5 约定规定,你应该使用与block目录相同的名称来命名你的块控制器,并以驼峰式(例如:CamelCase)形式,后面跟BlockControllerbtTable类变量很重要,因为它告诉 concrete5 应该使用哪个数据库表来处理此块。重要的是,这个表在数据库中尚未存在,所以给它取名为bt(代表“块类型”)加上块名称的驼峰式版本是一个好主意。

  6. 现在控制器已设置,我们需要设置db.xml文件。此文件基于 ADOXMLS 格式,该格式在phplens.com/lens/adodb/docs-datadict.htm#xmlschema有文档说明。此 XML 文件将告诉 concrete5 应该为新的块类型创建哪些数据库表和字段(以及当您的块类型更新时,哪些表和字段应该更新)。

  7. 将以下 XML 代码添加到您的db.xml文件中:

    <?xml version="1.0"?>
    <schema version="0.3">
      <table name="btHelloWorld">
        <field name="bID" type="I">
          <key />
          <unsigned />
        </field>
          <field name="title" type="C" size="255">
          <default value="" />
        </field>
          <field name="content" type="X2">
          <default value="" />
        </field>
      </table>
    </schema>
    
  8. concrete5 块通常都有add.phpedit.php文件,这两个文件通常做同样的事情:显示包含块设置的表单。由于我们不希望重复代码,我们将我们的表单 HTML 输入到第三个文件form.php中,并在add.phpedit.php中包含该文件。

    <?php 
      $form = Loader::helper('form');
    ?>
    <div>
      <label for="title">Title</label>
      <?php echo $form->text('title', $title); ?>
    </div>
    <div>
      <label for="content">Content</label>
      <?php echo $form->textarea('content', $content); ?>
    </div>
    
  9. 一切准备就绪后,将以下代码行添加到add.phpedit.php中,以便在用户添加和编辑块时显示此 HTML 代码:

    <?php include('form.php') ?>
    
  10. 将以下 HTML 添加到您的view.php文件中:

    <h1><?php echo $title ?></h1>
    <div class="content">
       <?php echo $content ?>
    </div>
    
  11. 最后,为了增加一点视觉吸引力,将以下代码添加到view.css中:

    content {
      background: #eee;
      padding: 20px;
      margin: 20px 0;
      border-radius: 10px;
    }
    
  12. 现在所有文件都已填充了使我们的 Hello World 块工作的代码。现在我们需要在 concrete5 中安装此块,以便我们可以将其添加到我们的页面上。

  13. 要安装新块,您需要登录到您的 concrete5 网站,并导航到/dashboard/blocks/types/。如果您在这里遇到 PHP 致命错误,请通过访问/dashboard/system/optimization/clear_cache来清除您的 concrete5 缓存(在 concrete5 中开发时禁用缓存总是一个好主意)。

  14. 块类型屏幕的顶部,您应该看到您的Hello World块,准备安装。点击安装按钮。如何操作...

  15. 现在块已安装并准备好添加到您的网站中!

它是如何工作的...

让我们一步一步地回顾一下我们刚才编写的代码。

controller.php中,类顶部有几个受保护的变量。$btTable变量告诉 concrete5 数据库中哪个表包含此块类型的数据。$btInterfaceWidth$btInterfaceHeight变量确定当用户将您的块添加到他们网站上的页面时出现的对话框窗口的初始大小。

我们将块描述和名称放入特殊的getter函数中,原因之一是为了支持未来的翻译。将任何出现在 concrete5 中的字符串包装在全局t()函数中是最佳实践。

db.xml文件告诉 concrete5 在安装此块时应创建哪些数据库表。此文件使用 ADOXMLS 格式生成表和字段。在此文件中,我们告诉 concrete5 创建一个名为btHelloWorld的表。该表应包含三个字段,一个ID字段,一个title字段和一个content字段。应记录这些字段的名称,因为 concrete5 将需要它们与 HTML 表单中的字段名称匹配。

form.php中,我们正在设置用户将填写以保存块内容的设置表单。我们使用表单助手生成各种字段的 HTML。注意我们如何能够在变量尚未声明的情况下使用$title$content变量。concrete5 会自动将这些变量暴露给表单,无论何时添加或编辑块。然后我们在add.phpedit.php文件中包含这个表单。

view.php文件是一个模板文件,其中包含最终用户将在网站上看到的 HTML。我们只是在<h1>标签中包装标题,并在具有.content类的<div>中包装内容。

如果它们存在于你的块目录中,concrete5 将自动包含view.css(如果存在,还包括view.js)。此外,如果你包含一个auto.js文件,它将在块处于编辑模式时自动包含。我们向.content类添加了一些基本样式,concrete5 会负责将此 CSS 文件添加到你的网站的<head>标签中。

参见

  • 从控制器向视图发送变量的食谱

  • 从块控制器添加项目到页面页眉和页脚的食谱

  • 在块视图中包含 CSS 的食谱

  • 在块视图中包含 JavaScript 的食谱

使用块控制器回调函数

块控制器类包含一些在页面加载过程中的不同点自动调用的特殊函数。你可以查看这些回调来为你的块类型提供不同的功能。

准备工作

要开始,你需要创建并安装一个块类型。查看前面的食谱,了解创建自定义块类型的课程。我们将向controller.php添加一些方法。

如何做到这一点...

使用块控制器回调函数的步骤如下:

  1. 打开你的块的controller.php文件。

  2. 添加一个名为on_start()的新函数:

    public function on_start() {
    }
    
  3. 编写一个在控制器加载时触发的die语句。

    die('hello world');
    
  4. 刷新包含块类型的任何页面。页面应该在完成之前停止渲染,显示你的调试信息。

  5. 一定要删除die语句,否则你的块将不再工作!

它是如何工作的...

concrete5 会在页面加载过程中的不同点调用各种回调函数。on_start() 函数是第一个被调用的。这是一个在块渲染之前放置你想要发生的事情的好地方。

下一个被调用的函数取决于你如何与块交互。如果你只是在页面上查看它,则调用 view() 函数。如果你正在添加或编辑块,则将根据情况调用 add()edit() 函数。这些函数是向视图发送变量的好地方,我们将在下一个菜谱中展示如何做到这一点。save()delete() 函数也会在这个时候自动调用,如果块正在执行这些功能之一。

之后,concrete5 将调用 on_before_render() 函数。这是一个在 concrete5 为页面渲染 HTML 之前添加页面页眉和页脚的好时机。我们将在本章后面做这件事。

最后,调用 on_page_view() 函数。这实际上是在页面渲染后运行的,所以这是你在块控制器中执行代码的最后一个地方。当向页面添加 HTML 项目时,这很有帮助。

更多内容...

以下函数可以添加到你的控制器类中,它们将在块加载过程中的不同点自动被调用。

  • on_start

  • on_before_render

  • view

  • add

  • edit

  • on_page_view

  • save

  • delete

要获取可用回调函数的完整列表,请查看位于 /concrete/core/libraries/block_controller.php 的块控制器库的源代码。

参见

  • 从控制器向视图发送变量 菜谱

  • 从块控制器向页面页眉和页脚添加项目 菜谱

从控制器向视图发送变量

MVC 编程中的一个常见任务是控制器到视图设置变量的概念。在 concrete5 中,块遵循相同的原理。幸运的是,将变量设置到视图相当简单。

准备工作

这个菜谱将使用本章第一个菜谱中创建的块类型。你可以自由地调整这段代码以在任何块控制器中工作。

如何做到...

在你的块控制器中,使用 controller 类的 set() 函数将变量和值发送到视图。注意,视图不一定是你的块的 view.php 模板。你也可以将变量发送到 add.phpedit.php。在这个菜谱中,我们将向 view.php 发送一个变量。步骤如下:

  1. 打开你的块的 controller.php 文件。

  2. 如果不存在,添加一个名为 view() 的函数:

    public function view() {
    }
    
  3. 将一个名为 name 的变量设置到视图中。

    $this->set('name', 'John Doe');
    
  4. 在你的块的目录中打开 view.php

  5. 输出名称变量的值。

    <div class="content">
      <?php echo $name ?>
    </div>
    

参见

  • 使用块控制器回调函数 菜谱

从块控制器向页面页眉和页脚添加项目

块开发的一个重要部分是能够在适当的位置向页面添加 JavaScript 和 CSS 文件。考虑一个使用 jQuery 插件创建幻灯片小部件的块。为了使其工作,您需要包含插件的 JavaScript 和 CSS 文件。

在此配方中,我们将向页面<head>元素添加一个 CSS <link>标签,并在页面底部(在关闭</body>标签之前)添加一个 JavaScript <script>标签。

准备工作

此配方将继续使用本章第一个配方中创建的块。如果您需要下载该块的副本,它包含在此书的网站上的代码示例中。

此配方还引用了 CSS 文件和 JavaScript 文件。这些文件可以在本书的网站上提供的代码中下载。

如何操作...

从块控制器向页面页眉和页脚添加项的步骤如下:

  1. 打开你的块的controller.php文件。

  2. /css目录下创建一个名为test.css的 CSS 文件。

  3. 设置规则以将网站的背景颜色更改为黑色。

    body {
      background: #000 !important;
    }
    
  4. /js目录下创建一个名为test.js的 JavaScript 文件。

  5. 在 JavaScript 文件中创建一个警告消息。

    alert('Hello!');
    
  6. controller.php中创建一个名为on_page_view()的新函数。

    public function on_page_view() {
    }
    
  7. 加载 HTML 辅助工具:

    $html = Loader::helper('html');
    
  8. 将 CSS 文件添加到页面页眉:

    $this->addHeaderItem($html->css('testing.css'));
    
  9. 将 JavaScript 文件添加到页面页脚:

    $this->addFooterItem($html->javascript('test.js'));
    
  10. 访问包含此块的网站页面。你应该能看到你的 JavaScript 警告以及黑色背景。

它是如何工作的...

如在使用块控制器回调函数配方中所述,将项添加到页眉(页面的<head>标签)和页脚(在关闭</body>标签之前)的理想位置是on_before_render()回调函数。addHeaderItemaddFooterItem函数用于在 Web 文档的这些位置放置文本字符串。我们不会在 PHP 中键入<script><link>标签,而是将使用内置的 HTML 辅助工具生成这些字符串。这些文件应位于网站的根目录/css/js目录中。

由于通常最佳实践是首先加载 CSS 文件,最后加载 JavaScript 文件,因此我们将每个项目放置在页面中最合理的位置。

相关内容

  • 第四章,使用核心辅助工具

  • 使用块控制器回调函数配方

创建自定义块模板

所有块都附带一个默认视图模板,view.php。concrete5 还支持替代模板,用户可以通过 concrete5 界面启用这些模板。您也可以通过自定义 PHP 代码启用这些替代模板。

准备工作

您需要已经创建并安装了一个块类型。在此配方中,我们将向本章开头创建的块类型添加一个模板。

如何操作...

创建自定义块模板的步骤如下:

  1. 打开你的块目录。

  2. 在您的块目录中创建一个名为templates/的新目录。

  3. templates/中创建一个名为no_title.php的文件。

  4. 将以下 HTML 代码添加到no_title.php

    <div class="content">
      <?php echo $content ?>
    </div>
    
  5. 通过访问包含此块的页面来激活模板。

  6. 在页面上进入编辑模式并点击块。

    Click on "Custom Template".
    

    如何操作...

  7. 选择“无标题”并保存您的更改。

更多...

您可以直接在块控制器中指定替代模板,因此您可以根据某些设置、条件或几乎任何您能想到的东西自动渲染不同的模板。只需在视图渲染之前被调用的回调中使用render()函数即可。

public function view() {
  $this->render('templates/no_title');
}

这将使用no_title.php文件而不是view.php来渲染块。请注意,添加.php文件扩展名不是必需的。就像块的常规view.php文件一样,开发人员可以在他们的模板目录中包含view.cssview.js文件,以便自动将这些文件包含在页面上。

相关内容

  • 使用块控制器回调函数 的配方

  • 创建自定义块类型 的配方

在块表单中包含 JavaScript

在添加或编辑块时,通常希望以客户端 JavaScript 的形式包含更高级的功能。concrete5 使自动将 JavaScript 文件添加到块的编辑表单变得极其简单。

准备工作

我们将使用本章第一个配方中创建的块进行工作。如果您需要赶上进度,请随时从本书的网站上下载代码。

如何操作...

在块表单中包含 JavaScript 的步骤如下:

  1. 打开您的块目录。

  2. 创建一个名为auto.js的新文件。

  3. 将基本警报函数添加到auto.js

    alert('Hello!');
    
  4. 访问包含您的块的页面。

  5. 进入编辑模式并编辑块。

  6. 您应该会看到您的警报消息如以下截图所示:如何操作...

工作原理...

concrete5 在进入块的添加或编辑模式时会自动查找auto.js文件。开发人员可以利用这一点来包含块编辑模式特有的客户端功能。

相关内容

  • 在块视图中包含 JavaScript 的配方

  • 在块视图中包含 CSS 的配方

在块视图中包含 JavaScript

除了能够在块的添加和编辑表单中包含 JavaScript 之外,开发人员还可以在块在前端查看时自动包含一个 JavaScript 文件。在这个配方中,我们将创建一个简单的 JavaScript 文件,每当块被查看时都会创建一个警报。

准备工作

我们将继续使用本章第一个配方中创建的块进行工作。

如何操作...

在块视图中包含 JavaScript 的步骤如下:

  1. 打开您的块目录。

  2. 创建一个名为view.js的新文件。

  3. 将警报添加到view.js

    alert('This is the view!');
    
  4. 访问包含您的块的页面。

  5. 你应该看到新的警告出现。如何操作...

它是如何工作的...

就像在先前的配方中讨论的 auto.js 文件一样,如果存在,concrete5 将自动包含 view.js 文件。这允许开发者非常容易地将 jQuery 插件或其他客户端逻辑嵌入到他们的块中。

参见

  • 在块表单中包含 JavaScript 的配方

  • 在块视图中包含 CSS 的配方

在块视图中包含 CSS

开发者和设计师在自定义 concrete5 块类型上工作时,可以自动包含一个 CSS 文件。在这个配方中,我们将自动包含一个 CSS 文件,将我们的背景变为黑色。

准备工作

我们仍在处理本章早期创建的块。请确保该块存在,或者根据你的 concrete5 环境调整此配方。

如何操作...

在块视图中包含 CSS 的步骤如下:

  1. 打开你的块目录。

  2. 如果不存在,创建一个名为 view.css 的新文件。

  3. 添加一个规则来更改网站的背景颜色为黑色:

    body {
      background: #000 !important;
    }
    
  4. 访问包含你的块的页面。

  5. 背景现在应该是黑色的!

它是如何工作的...

就像对 JavaScript 所做的那样,如果存在于你的块目录中,concrete5 将自动在页面的头部包含 view.css。这是一个节省时间的好方法,因为只有你的块需要这些样式。

参见

  • 在块表单中包含 JavaScript 的配方

  • 在块视图中包含 JavaScript 的配方

通过其句柄加载块类型

块类型在 concrete5 中是对象,就像大多数事物一样。这意味着它们在数据库中有 ID,以及可读的句柄。在这个配方中,我们将加载我们在本章第一个配方中创建的块类型的实例。

准备工作

我们需要一个运行一些任意代码的地方。我们将再次依靠 /config/site_post.php 来执行一些随机代码。这个配方还假设在你的 concrete5 网站中存在一个句柄为 hello_world 的块。请随意根据需要调整该句柄。

如何操作...

通过句柄加载块类型的步骤如下:

  1. 在你偏好的代码编辑器中打开 /config/site_post.php

  2. 定义要加载的块的句柄:

    $handle = 'hello_world';
    
  3. 通过句柄加载块:

    $block = BlockType::getByHandle($handle);
    
  4. 输出块的内容以确保它已正确加载:

    print_r($block);
    exit;
    

它是如何工作的...

concrete5 将在提供句柄时简单地查询数据库。然后,它将返回一个包含几个在开发中可能有用的方法和属性的 BlockType 对象。

将块添加到页面中

用户可以使用直观的 concrete5 界面将块添加到网站页面的各个区域。你还可以使用 concrete5 API 以编程方式将块添加到页面。

准备工作

本章中的代码可以在你想要创建块的地方运行。为了保持简单,我们将使用 /config/site_post.php 文件来运行一些任意代码。

此示例假设在你的 concrete5 网站上存在一个路径为 /about 的页面。你可以自由创建该页面,或者根据你的需求调整此菜谱。同样,此菜谱假设 /about 有一个名为 content 的内容区域。再次根据你自己的网站配置进行调整。

我们将使用本章开头创建的块。

如何操作...

将块添加到页面的操作步骤如下:

  1. 在你的代码编辑器中打开 /config/site_post.php

  2. 加载你想要添加块的页面:

    $page = Page::getByPath('/about');
    
  3. 通过句柄加载块:

    $block = BlockType::getByHandle('hello_world');
    
  4. 定义将发送到块的 数据:

    $data = array(
      'title' => 'An Exciting Title',
      'content' => 'This is the content!'
    );
    
  5. 将块添加到页面的内容区域:

     $page->addBlock($block, 'content', $data);
    

它是如何工作的...

首先,你需要获取目标页面。在这个菜谱中,我们通过其路径获取它,但你可以在任何 Page 对象上使用这个函数。接下来,我们需要加载我们正在添加的块类型。在这种情况下,我们使用本章早期创建的一个。块类型句柄与块的目录名相同。

我们使用 $data 变量传递块的配置选项。如果没有选项,你需要传递一个空数组,因为 concrete5 不允许该参数为空。最后,你需要知道内容区域的名称;在这种情况下,内容区域名为 "content"。

相关内容

  • 创建自定义块类型 菜单

  • 通过句柄加载块类型 菜单

  • 第一章中的 通过路径获取页面 菜单,页面和页面类型

从区域获取块

concrete5 页面可以有多个不同的区域,可以在其中添加块。开发者可以编程方式获取一个区域中所有块对象的数组。在这个菜谱中,我们将加载一个页面并获取其主内容区域中所有块列表。

准备工作

我们将使用 /config/site_post.php 在这里运行一些任意代码。尽管如此,你可以将此代码放置在认为合适的位置。

此示例假设存在一个路径为 /about 的页面,并且有一个名为 content 的内容区域。根据需要,在代码中进行必要的调整。

如何操作...

从区域获取块的操作步骤如下:

  1. 在你的代码编辑器中打开 /config/site_post.php

  2. 通过路径加载页面:

    $page = Page::getByPath('/about');
    
  3. 获取页面内容区域中的块数组。

    $blocks = $page->getBlocks('content');
    
  4. 遍历数组,打印每个块的句柄。

    foreach ($blocks as $block) {
      echo $block->getBlockTypeHandle().'<br />';
    }
    
  5. 退出进程。

    exit;
    

它是如何工作的...

concrete5 将为每个包含在内容区域内的块返回一个块对象数组。开发者可以遍历这个数组来操作或读取块对象。

第三章。文件和文件集

在本章中,我们将涵盖以下内容:

  • 通过 ID 加载文件

  • 获取文件的路径

  • 获取文件列表

  • 将文件上传到文件管理器

  • 通过 ID 加载文件集

  • 将文件添加到文件集中

  • 从文件集中移除文件

  • 检查文件是否属于文件集

  • 获取文件集中的所有文件

  • 复制文件

  • 删除文件

  • 重新索引文件的搜索属性

  • 在文件对象上设置密码

  • 在文件上设置权限

  • 获取文件的下载 URL

  • 获取文件的下载统计信息

  • 在表单中添加文件选择器

简介

除了强大的内容编辑功能外,concrete5 还附带了一个强大的工具来管理网站上的静态文件,称为 文件管理器。文件管理器是您可以存储任何类型的静态文档的地方,包括图片、视频、PDF、文档和音频文件。文件管理器允许您创建文件的下载链接,将图片嵌入到网站内容中,等等。您甚至可以分配文件管理器内文件的权限,以便在决定用户可以下载哪些文件时拥有更大的控制权。

通过 concrete5 接口处理文件是一种乐趣,但有时你可能希望将文件管理器的强大功能集成到你自己构建在 concrete5 中的自定义应用程序中。在本章中,我们将展示如何与文件交互、上传新文件,甚至将新文件上传到文件管理器。

关于本章代码的说明

本章中展示的大部分代码几乎可以在 concrete5 应用程序的任何地方使用。由于我们只是将要尝试简单的代码片段,所以在沙盒区域进行实验是有意义的。在 concrete5 中有几个地方适合这样做,但我们将使用 /config/site_post.php 来测试我们的代码。

在每个菜谱之后删除 site_post.php 中的任何实验性和任意代码是个好主意,这样您的网站就为下一个练习做好了准备。

此外,我们有时还需要转储变量的内容。每个 PHP 开发者都有自己的方式来做这件事,但本章我们将使用自定义的调试函数。您可能已经从 第一章,页面和页面类型 中认出了这个函数。我们在这里将继续使用它,因为它使得输出易于阅读,并在开发过程中节省了一些时间。

将以下 PHP 函数放置在 /config/site_post.php 的顶部:

function my_debug($var) {
   echo '<pre>';
   print_r($var);
   echo '</pre>';
   exit;
}

现在,我们可以通过调用 my_debug($variableName) 来转储变量内容,并看到变量内容的格式化输出。您可以使用 print_rvar_dump 作为替代。

site_post.php 中放置调试代码对于实验和尝试 concrete5 API 非常好,但它会干扰 concrete5 网站的正常操作。建议在本章中执行的所有菜谱都在 concrete5 的测试副本上执行。

通过文件 ID 加载文件

对于大多数 concrete5 开发者来说,最常见的文件交互是加载文件并与它们交互。为此,我们必须通过 ID 加载文件。此配方中的代码可以放置在你需要加载文件并检索或修改其属性的地方。

准备工作

我们需要知道我们正在加载的文件的 ID。在这个配方中,我们将加载 ID 为17的文件。如果你的 concrete5 网站没有 ID 为17的文件,请上传一个新的文件到文件管理器,并将此配方中的ID更改为与新上传文件的ID相匹配。你可以通过访问文件管理器,点击一个文件,并选择属性来获取文件的ID

准备工作

如何操作...

查看以下步骤:

  1. 在你的代码编辑器中打开/config/site_post.php,或者将此代码放置在你自己的应用程序中适当的位置。

  2. 声明要加载的文件的 ID,并确保将其设置为对你系统相关的内容:

    $fileId = 17;
    
  3. 加载文件:

    $file = File::getByID($fileId);
    
  4. 输出文件变量的内容:

    my_debug($file);
    

它是如何工作的...

concrete5 将使用此函数根据你传入的数字 ID 从数据库中加载相关文件。静态getByID函数将返回一个完全加载的file对象,你可以进一步操作。

获取文件的路径

一旦你加载了文件对象,你可以调用多种不同的方法,以获取与该文件相关联的所有不同属性。其中最常见且重要的属性是文件的路径。

准备工作

在这个配方中,我们将获取一个文件的路径,并使用它来显示存储在文件管理器中的图像。

再次强调,我们将引用 ID 为1的图像。请确保将此配方中的代码修改为加载你 concrete5 安装中实际存在的图像。

如何操作...

查看以下步骤:

  1. 在你的编辑器中打开/config/site_post.php

  2. 声明要加载的文件的 ID:

    $fileId = 1;
    
  3. 通过文件 ID 加载文件:

    $file = File::getByID($fileId);
    
  4. 获取文件的路径:

    $path = $file->getRelativePath();
    
  5. 将路径输出到屏幕:

    echo $path;
    exit;
    

它是如何工作的...

文件管理器通过 concrete5 网站将文件存储在多个位置,通常位于files/文件夹下,该文件夹被分割成几个由整数组成的机器可读文件夹。由于这些路径难以定期确定和预测,文件对象 API 允许我们通过简单的函数调用获取这些路径。

更多...

如果你正在使用 PHP 的fopen函数处理图像,你需要文件的实际绝对路径。为此,你将使用getPath函数:

$fullPath = $file->getPath();

相关内容

  • 通过文件 ID 加载文件的方法

获取文件列表

许多时候,你需要一次性获取多个文件。例如,如果你正在构建一个相册,你将想要获取要在相册中显示的文件列表。

在这个菜谱中,我们将获取文件管理器中存储的前一百个图像的列表,并输出它们的文件路径。

准备工作

这个菜谱假设 concrete5 的文件管理器中至少存储了一个图像。请确保您的 concrete5 版本中至少存储了一个或多个图像。

如何操作...

  1. 在您偏好的代码编辑器中打开 /config/site_post.php

  2. 加载文件列表模型:

    Loader::model('file_list');
    
  3. 创建 FileList 类的新实例:

    $list = new FileList();
    
  4. 过滤列表以仅显示图像:

    $list->filterByType(FileType::T_IMAGE);
    
  5. 获取图像数组。

    $images = $list->get();
    
  6. 遍历图像数组并输出每个图像的路径。

    foreach ($images as $img) {
       echo $img->getRelativePath().'<br />';
    }
    exit;
    

工作原理...

与在 concrete5 中列出页面和其他对象类似,我们加载了一个扩展核心 DatabaseItemList 类的 FileList 对象。这为我们提供了一种面向对象的方式来过滤、搜索和检索文件数组。

我们调用了 get() 函数来返回文件管理器中找到的图像。

更多内容...

concrete5 在 FileType 类中存储了一些文件类型常量,您可以在 concrete/libraries/file/types.php 中查看。以下常量可用于根据不同的文件类型进行过滤:

  • FileType::T_APPLICATION

  • FileType::T_AUDIO

  • FileType::T_DOCUMENT

  • FileType::T_IMAGE

  • FileType::T_TEXT

  • FileType::T_UNKNOWN

  • FileType::T_VIDEO

FileList 类上提供了许多函数来搜索和过滤文件列表。以下是一些您可以使用的更多函数:

  • 通过文件扩展名过滤列表(不要在扩展名参数中提供点):

    $list->filterByExtension('mp3');
    
  • 通过关键词短语过滤列表(通过文件标题、文件名和一些其他属性进行搜索):

    $list->filterByKeywords('guacamole');
    

对于 FileList 类,还有一些更具体的过滤器可用。您可以通过浏览 FileList 类的源代码或查看在线 concrete5 开发者文档 www.concrete5.org/documentation/developers/files/searching-and/ 来深入了解这些过滤器函数。

参见

  • 获取文件集中的所有文件 的菜谱

将文件上传到文件管理器

有时您可能需要在文件管理器中存储用户提供的文件,或者可能想要将服务器上现有的文件迁移到文件管理器。在处理用户生成内容时,您总会遇到明显的安全问题,但有许多合法的理由想要通过编程方式将文件添加到文件管理器中。

准备工作

这个菜谱要求我们创建一个基本的 HTML 表单,其中包含文件上传输入。我们将 HTML 表单放置在位于 /single_pages/upload.php 的单个页面上。确保通过访问 /dashboard/pages/single 并添加一个路径为 /upload 的新页面来安装单页。

由于这个菜谱稍微复杂一些,因此查看本书网站上这一章的免费代码下载可能很有用。

我们还将使用我们在章节介绍中讨论的自定义调试函数。

如何操作...

请看以下步骤:

  1. /single_pages/upload.php 创建一个新的单页。

  2. 通过访问 /dashboard/pages/single 并输入路径 /upload 将单页添加到 concrete5 网站。

  3. upload.php 文件中创建一个基本的 HTML 表单,包含文件输入:

    <form method="POST" enctype="multipart/form-data">
       File to upload: <input type="file" name="example_file"><br />
       <input type="hidden" name="file_upload" value="yes">
       <input type="submit" value="Upload!">
    </form>
    
  4. 如果不存在,请创建 /config/site_process.php

  5. site_process.php 中,检查是否有文件已上传:

    if ($_POST['file_upload'] == 'yes') {
    }
    
  6. if 语句内部,加载 FileImporter 库:

    Loader::library('file/importer');
    
  7. 然后,创建 FileImporter 类的新实例:

    $importer = new FileImporter();
    
  8. $_FILES 超全局变量中获取上传的文件:

    $file = $_FILES['example_file'];
    
  9. 获取文件名:

    $name = $file['name'];
    
  10. 获取文件的当前临时位置:

    $path = $file['tmp_name'];
    
  11. 将文件添加到文件管理器:

    $newFile = $importer->import($path, $name);
    
  12. 如果 $newFile 是一个整数,concrete5 遇到了错误。输出错误信息:

    if (is_numeric($newFile)) {
       die(FileImporter::getErrorMessage($newFile));  
    }
    
  13. 否则,文件上传成功。

  14. 访问网站的文件管理器 /dashboard/files/search/ 以查看新上传的文件。

工作原理...

FileImporter 类接受上传文件的临时路径(从 $_FILES 超全局变量中获取)和文件名。然后,文件被添加到文件管理器,在整个 concrete5 网站上都可以使用。

参见

  • 将文件选择器添加到表单 的配方

通过 ID 加载文件集

concrete5 允许您将文件分组到集合中。一些开发者认为文件集类似于在您的计算机上使用文件夹,只不过一个文件可以同时属于多个集合(或没有任何集合),因此一个更恰当的描述可能是,这些是文件类别。

文件集非常适合组织 concrete5 网站上用于不同目的的文件。例如,您可能有一个用于主页幻灯片的文件集,同时还有一个用于员工照片的文件集,还有一个用于内部文件。

在本配方中,我们将使用其数字 ID 加载文件集。

准备工作

在本节中,我们假设存在一个 ID 为 1 的文件集。请根据您的 concrete5 环境调整本配方中的代码。

如何操作...

我们将假设我们想要加载一个 ID 为 1 的文件集。请看以下步骤:

  1. 首先,确保您知道要加载的文件集的 ID:

    $id = 1;
    
  2. 加载文件集:

    $fileSet = FileSet::getByID($id);
    
  3. 如果您愿意,可以通过输出 $fileSet 变量来验证文件集是否正确加载:

    my_debug($fileSet);
    

工作原理...

concrete5 将查询数据库以找到具有您提供的 ID 的文件集。一旦找到合适的记录,它将返回一个 FileSet 对象,您可以与之交互。

更多...

您还可以通过提供它们的名称来检索文件集,如下面的代码片段所示:

$fileSet = FileSet::getByName('File Set Name');

参见

  • 将文件添加到文件集 的配方

  • 获取文件列表 的配方

将文件添加到文件集

与文件集一起工作的一个有用方面是能够使用 PHP 代码将文件添加到指定的集合中。幸运的是,这是一个非常简单的任务。

准备工作

您需要知道您要添加的文件 ID,或者已经加载了 File 对象。本菜谱将假设存在一个 ID 为1的文件和一个 ID 也为1的文件集。

如何操作...

以下是一些步骤:

  1. 在您的代码编辑器中打开 /config/site_post.php

  2. 声明要加载的文件 ID。

    $fileId = 1;
    
  3. 声明要加载的文件集 ID:

    $fileSetId = 1;
    
  4. 通过其 ID 加载文件:

    $file = File::getByID($fileId);
    
  5. 通过其 ID 加载文件集:

    $fileSet = FileSet::getByID($fileSetId);
    
  6. 将文件添加到文件集:

    $fileSetFile = $fileSet->addFileToSet($file);
    
  7. 输出结果 FileSetFile 对象:

    my_debug($fileSetFile);
    

它是如何工作的...

concrete5 将在完成后将文件与文件集之间创建关联,并返回一个 FileSetFile 对象。

更多内容...

或者,如果您不想加载文件对象,只需提供您要添加的文件 ID。请查看以下代码片段:

$fileSet = FileSet::getByID($filesetID);
$filesetFile = $fileSet->addFileToSet($fileId);

相关内容

  • 从文件集中删除文件 菜单

  • 检查文件是否属于文件集 菜单

从文件集中删除文件

除了能够将文件添加到文件集外,开发者还可以从他们的文件集中删除文件。

准备工作

在本菜谱中,我们将再次假设存在一个 ID 为1的文件,以及一个 ID 也为1的文件集。请确保根据您的 concrete5 实例调整代码。

如何操作...

以下是一些步骤:

  1. 在您的代码编辑器中打开 /config/site_post.php,以便我们可以玩一些任意代码。

  2. 声明文件 ID:

    $fileId = 1;
    
  3. 声明文件集 ID:

    $fileSetId = 1;
    
  4. 通过其 ID 加载文件:

    $file = File::getByID($fileId);
    
  5. 通过其 ID 加载文件集:

    $fileSet = FileSet::getByID($fileSetId);
    
  6. 从文件集中删除文件:

    $fileSet->removeFileFromSet($file);
    

它是如何工作的...

concrete5 简单地破坏了文件与文件集之间的关系。

相关内容

  • 将文件添加到文件集 菜单

  • 检查文件是否属于文件集 菜单

检查文件是否属于文件集

开发者有时可能想知道一个文件是否是某个特定文件集的成员。在本菜谱中,我们将加载一个文件,加载一个文件集,然后找出该文件是否是给定文件集的成员。

准备工作

如往常一样,在本菜谱中,我们将假设存在一个文件和一个文件集。我们将使用文件和文件集的 ID 1,所以请确保对代码进行必要的调整,以便在您的 concrete5 系统中运行。

如何操作...

以下是一些步骤:

  1. 打开 /config/site_post.php 并清除任何现有代码。

  2. 声明要加载的文件 ID:

    $fileId = 1;
    
  3. 声明我们将要处理的文件集 ID:

    $fileSetId = 1;
    
  4. 通过其 ID 加载文件:

    $file = File::getByID($fileId);
    
  5. 通过其 ID 加载文件集:

    $fileSet = FileSet::getByID($fileSetId);
    
  6. 如果文件是文件集的成员,输出一条 yes 消息:

    if ($file->inFileSet($fileSet)) {
       echo 'yes!';
    }
    
  7. 如果文件不是集的成员,输出 no

    else {
       echo 'no';
    }
    

它是如何工作的...

concrete5 将执行查询数据库的繁重工作,以确定文件是否是给定集的成员。

相关内容

  • 将文件添加到文件集 菜单

  • 从文件集中删除文件 菜单

获取文件集中的所有文件

现在我们知道了如何加载文件集并将文件添加到其中,我们可以学习如何从文件集中获取所有文件。我们将使用 FileList 类,这是我们在此章中较早描述过的。

准备工作

我们将继续假设在 concrete5 中至少安装了一个文件和一个文件集,它们的 ID 都是 1。请根据您的需求调整此配方中的变量。

如何操作...

请查看以下步骤:

  1. 在您的代码编辑器中打开 /config/site_post.php,移除其中可能存在的任何现有代码。

  2. 加载 FileList 模型:

    Loader::model('file_list');
    
  3. 创建 FileList 模型的新实例:

    $list = new FileList();
    
  4. 声明要过滤的文件集的 ID:

    $fileSetId = 1;
    
  5. 加载文件集:

    $fileSet = FileSet::getByID($fileSetId);
    
  6. 通过加载的文件集过滤列表:

    $list->filterBySet($fileSet);
    
  7. 获取文件集中的文件数组:

    $files = $list->get();
    
  8. 遍历数组,将每个文件的路径打印到屏幕上:

    foreach ($files as $file) {
      echo $file->getRelativePath().'<br />';
    }
    exit;
    
  9. 刷新您的网站以查看结果。

它是如何工作的...

在此示例中,我们只是实例化 FileList 类,这将公开几个用于过滤文件的方法。我们感兴趣的方法是 filterBySet

我们必须传递一个 FileSet 对象给此函数,然后我们可以调用 get 函数,该函数将返回属于该文件集的文件数组。

参见

  • 获取文件列表的配方

  • 通过 ID 加载文件集的配方

复制文件

正如传统的文件系统一样,concrete5 允许开发人员复制文件;在此配方中,我们将通过 ID 加载一个文件,然后创建一个副本。

准备工作

请确保在此配方中调整文件 ID 以匹配您 concrete5 数据库中存在的 ID。

如何操作...

请查看以下步骤:

  1. 在您首选的代码编辑器中打开 /config/site_post.php

  2. 声明要复制的文件的 ID:

    $fileId = 1;
    
  3. 通过 ID 加载文件:

    $file = File::getByID($fileId);
    
  4. 复制文件:

    $newFile = $file->duplicate();
    
  5. 使用我们在章节简介中创建的自定义调试函数,转储新副本的内容:

    my_debug($newFile);
    

它是如何工作的...

concrete5 将创建原始文件的碳副本,并在函数完成后返回新文件。

删除文件

concrete5 允许开发人员通过 PHP API 删除文件。在此配方中,我们将通过 ID 加载一个文件,然后永久删除它。

准备工作

一旦文件被删除,就无法恢复。在此配方中尝试使用临时或虚拟文件是一个好主意,这样您就不会删除任何重要的内容。此配方将使用 1 作为要删除的文件的 ID,但请确保将其更改为您愿意删除的任何内容。

如何操作...

请查看以下步骤:

  1. 在您的代码编辑器中打开 /config/site_post.php

  2. 声明要删除的文件的 ID:

    $fileId = 1;
    
  3. 通过 ID 加载文件:

    $file = File::getByID($fileId);
    
  4. 删除文件:

    $file->delete();
    

它是如何工作的...

concrete5 将从您的服务器文件系统中删除文件,并从 MySQL 数据库中删除对它的引用。

重新索引文件的搜索属性

当以编程方式更改文件属性时,有时 concrete5 搜索引擎需要知道新的更改。在这个练习中,我们将重新索引文件的搜索属性。

准备工作

我们将假设在您的 concrete5 安装中存在一个 ID 为 1 的文件。请将本菜谱中的 ID 调整为存在的文件。

如何操作...

看看以下步骤:

  1. 在您的代码编辑器中打开 /config/site_post.php 文件。

  2. 声明要重新索引的文件 ID:

    $fileId = 1;
    
  3. 通过 ID 加载文件:

    $file = File::getByID($fileId);
    
  4. 重新索引搜索属性:

    $file->reindex();
    

工作原理...

concrete5 将查询数据库并更新给定文件的搜索索引。这将确保内部搜索引擎能够根据文件最新的属性找到文件。

在文件对象上设置密码

concrete5 支持向单个文件添加密码,因此网站管理员可以限制只有拥有共享密码的人才能下载这些文件。

准备工作

本菜谱将继续假设有一个 ID 为 1 的文件。请确保调整此 ID 以匹配您自己的 concrete5 网站中存在的某个文件。

如何操作...

看看以下步骤:

  1. 打开 /config/site_post.php 文件,以便我们有一个地方来尝试这段代码。

  2. 声明文件 ID:

    $fileId = 1;
    
  3. 通过 ID 加载文件:

    $file = File::getByID($fileId);
    
  4. 声明密码:

    $password = 'secret';
    
  5. 在文件上设置密码:

    $file->setPassword($password);
    

工作原理...

concrete5 将以纯文本形式将密码存储在数据库中。由于此密码打算与多个人共享,因此它本质上是不安全的。因此,concrete5 不会在数据库中对文件密码进行散列或加密。一旦设置密码,就会触发 on_file_set_password 事件。

更多内容...

可以通过在文件上调用 getPassword 函数来简单地检索文件的密码:

$password = $file->getPassword();

相关内容

  • 通过 ID 加载文件 菜谱

在文件上设置权限

在上一个菜谱中,我们讨论了如何在文件上设置共享密码。不过,有时人们希望有更健壮的安全性。为此,我们可以挂钩到 concrete5 权限模型以提供更高级的访问控制。

在本菜谱中,我们将给用户赋予文件的读取权限。

准备工作

此示例将假设存在一个 ID 为 1 的文件和一个 ID 为 1 的用户。根据需要调整这些 ID。

如何操作...

看看以下步骤:

  1. 在您的代码编辑器中打开 /config/site_post.php 文件。

  2. 声明我们将应用权限的文件 ID:

    $fileId = 1;
    
  3. 加载文件:

    $file = File::getByID($fileId);
    
  4. 声明将获得这些权限的用户 ID:

    $userId = 1;
    
  5. 加载用户:

    $user = UserInfo::getByID($userId);
    
  6. 在文件上设置权限:

    $file->setPermissions($user, FilePermissions::PTYPE_MINE);
    

更多内容...

concrete5 使用静态常量来设置权限模式(无、我的和所有)。这些常量如下:

  • FilePermissions::PTYPE_NONE

  • FilePermissions::PTYPE_MINE

  • FilePermissions::PTYPE_ALL

相关内容

  • 第七章, 与用户和权限一起工作

获取文件的下载 URL

concrete5 可以通过将所有下载请求通过一个特殊 URL 来过滤,对文件执行权限控制以及跟踪下载统计数据。这也有额外的优势,即向用户计算机发送正确的 HTTP 头,强制下载。

准备工作

如往常一样,我们必须假设文件管理器中存在一个 ID 为1的文件。请随意将此 ID 更改为适合您自己网站的适当 ID。

如何操作...

看看以下步骤:

  1. 在您喜欢的代码编辑器中打开/config/site_post.php

  2. 声明要加载的文件 ID:

    $fileId = 1;
    
  3. 加载文件:

    $file = File::getByID($fileId);
    
  4. 获取下载 URL:

    $url = $file->getDownloadURL();
    
  5. 将下载 URL 输出到屏幕:

    echo $url;
    exit;
    

它是如何工作的...

concrete5 通过一个能够跟踪权限、下载并能够发送正确 HTTP 头部的特殊 URL 来传递下载请求。

参见

  • 通过 ID 加载文件的菜谱

获取文件的下载统计数据

如果您使用前面菜谱中描述的下载函数提供文件服务,那么下载次数将被存储在数据库中。您只需几行代码就可以获取这些统计数据。

准备工作

我们将假设文件管理器中存在一个 ID 为1的文件。根据您自己的 concrete5 网站需要,相应地更改此变量。

如何操作...

看看以下步骤:

  1. 在您首选的代码编辑器中打开/config/site_post.php

  2. 声明我们想要获取统计数据的文件 ID:

    $fileId = 1;
    
  3. 加载文件:

    $file = File::getByID($fileId);
    
  4. 获取统计数据数组:

    $stats = $file->getDownloadStatistics(false);
    
  5. 将数组内容导出:

    my_debug($stats);
    

它是如何工作的...

当我们调用文件对象的getDownloadStatistics方法时,concrete5 默认将只返回最近的 20 次下载。通过将false作为参数提供,我们告诉 concrete5 返回所有结果。

在表单中添加文件选择器

在 concrete5 中构建应用程序时,您经常会发现自己需要在仪表板上创建CRUD(创建、读取、更新、删除)界面,以便网站编辑和管理员管理自定义内容。在某些情况下,您可能需要在这些后端表单上处理文件上传。在这样的表单上,提供一个用于浏览文件管理器的界面将是一个有用的工具,而不是使用标准的 HTML 文件输入。concrete5 使用资产库小部件来为我们提供这种便利。

准备工作

在这个菜谱中,我们将创建一个基本的 HTML 表单,该表单将发送来自文件管理器的所选文件 ID,以及表单提交。此菜谱的完整代码可以从本书的网站上下载。

如何操作...

看看以下步骤:

  1. /single_pages/upload.php中创建一个新的单页(如果尚未存在)。

  2. 如果需要,通过访问/dashboard/pages/single并输入upload作为页面路径,将单个页面添加到网站地图中。

  3. upload.php中,加载资产库助手:

    <?php $assetLibrary = Loader::helper('concrete/asset_library'); ?>
    
  4. 创建一个输出文件选择器的 HTML 表单:

    <form method="POST" enctype="multipart/form-data">
       <?php echo $assetLibrary->file('file_id', 'file_id', 'Select a file...') ?>
       <input type="hidden" name="file_upload" value="yes">
       <input type="submit" value="Upload the file!">
    </form>
    
  5. 如果尚不存在,则创建 /config/site_process.php

  6. 检查是否有文件上传发生:

    if ($_POST['file_upload'] == 'yes') {
    }
    
  7. if 语句内部,获取所选文件的文件 ID:

    $fileId = $_POST['file_id'];
    
  8. 将所选文件 ID 输出到屏幕:

    echo 'You have chosen file #'.$fileId;
    exit;
    

它是如何工作的...

资产库助手将输出所有必要的 HTML 和 JavaScript,为用户提供一个优雅的模式界面,以便从文件管理器中选择文件(或上传新文件到文件管理器)。一旦用户选择了一个文件,文件 ID 将被添加到一个隐藏的输入框中,该输入框的名称与您在 file() 函数的第二参数中提供的名称相同。

一旦用户提交了围绕文件选择器的表单,文件 ID 将包含在 $_POST 数组中(在这个例子中,它将在 $_POST['file_id'] 中),然后您可以在服务器端进行进一步存储或处理。

更多内容...

您还可以调出一个仅限于图像的文件管理器窗口。使用以下代码来完成此操作:

<form action="save" method="POST">
  <p>Choose a file...</p>
  <?php 
    $assetLibrary = Loader::helper('concrete/asset_library'); 
    $assetLibrary->image('file_id', 'file_id', 'Select a file...');
  ?>
</form>

您可能会注意到这里唯一的改变是,我们不是在 asset library 类上调用 file(),而是调用 image()。这将与 file() 做完全相同的事情,但会将模式窗口限制为仅包含图像。

参见

  • 上传文件到文件管理器 菜单

第四章。使用 Core 辅助工具

在本章中,我们将涵盖以下内容:

  • 加载辅助类

  • 使用 Date 辅助工具

  • 使用 Encryption 辅助工具

  • 使用 Feed 辅助工具加载 RSS 源

  • 使用 File 辅助工具管理文件和目录

  • 使用 Form 辅助工具创建自定义表单

  • 在表单上包含 WYSIWYG 编辑器

  • 使用 HTML 辅助工具生成 HTML 代码

  • 使用 Image 辅助工具生成和缓存缩略图

  • 使用 JSON 辅助工具进行 JSON 编码和解码

  • 使用 Mail 辅助工具发送电子邮件

  • 使用 MIME 辅助工具确定文件扩展名的 MIME 类型

  • 使用 Navigation 辅助工具获取页面 URL 和面包屑

  • 使用 Text 辅助工具处理字符串

  • 使用 URL 辅助工具生成 URL

  • 使用 Validation 辅助工具验证输入数据

  • 使用 Captcha 辅助工具防止垃圾邮件

  • 获取国家的列表

  • 获取州和省的列表

  • 在表单上显示颜色选择器

  • 在表单上显示日期/时间选择器

  • 在表单上显示评分小部件

  • 使用禁止使用的单词列表

  • 读取和写入系统缓存

  • 将信息写入调试日志

  • 读取和写入配置注册表

简介

在开发 concrete5 内容管理系统中的自定义应用程序的过程中,您可能会发现自己需要多次执行某些任务。例如,创建自定义表单、发送电子邮件或解析 RSS 源等任务都可以通过使用 concrete5 内置的 Core 辅助类来加速。

concrete5 中的辅助工具概念可能对之前在其他流行的 MVC 框架中工作过的开发者来说很熟悉。辅助工具是提供各种杂项、可重复功能的类,可以在代码的任何地方使用。我们将首先展示如何加载辅助类。

关于本章代码的说明

正如我们在前几章中所做的那样,我们将使用 /config/site_post.php 文件来运行一些任意代码。concrete5 没有一个很好的地方来尝试 API,所以我们将使用 site_post 作为我们的游乐场。在开始新的食谱之前,请确保清空任何实验性代码,并在开发服务器上执行所有这些课程。

我们将继续使用我们在第一章中创建的自定义调试函数,即“页面和页面类型”。如果您也想跟随,请将以下函数放置在 site_post.php 的顶部:

function my_debug($var) {
   echo '<pre>';
   print_r($var);
   echo '</pre>';
   exit;
}

当然,您完全可以替换我们的自定义调试器,使用您喜欢的任何工具。

加载辅助类

concrete5 中的 Loader 类在加载 concrete5 中多种不同类型的文件时非常有用。我们将使用 Loader 类来包含和实例化 Form 辅助工具。

如何做到...

  1. 在您的代码编辑器中打开 /config/site_post.php

  2. 确保你知道你想要加载的助手的 "handle"。handle 是包含助手类的文件名,不带 .php 扩展名。由于我们想要加载存在于 /concrete/helpers/form.php 的表单助手,因此 handle 将是 form

    $handle = 'form';
    
  3. 使用 handle 加载助手:

    $formHelper = Loader::helper($handle);
    
  4. 让我们通过输出 $formHelper 变量的内容来检查助手是否正确加载:

    my_debug($formHelper);
    

它是如何工作的...

Loader 类包含 PHP 脚本,使其可用于使用。此外,当加载助手时,包含的文件也将被实例化并返回,使其立即可用于你的代码中。

更多...

如果你需要加载一个包含在附加包中的助手,只需在加载助手时提供一个包处理程序作为第二个参数:

$helper = Loader::helper($handle, $packageHandle);

使用日期助手

使用日期助手可以简化许多与日期相关的任务。我们将探讨使用日期助手来协助处理自定义代码中的日期的几种方法。

准备工作

在本菜谱中,我们将探索日期助手的一些功能。

如何操作...

  1. 在你的编辑器中打开 /config/site_post.php

  2. 加载日期助手:

    $date = Loader::helper('date');
    
  3. 获取用户的时间:

    $userTime = $date->getLocalDateTime();
    
  4. 获取系统时间:

    $systemTime = $date->getSystemDateTime();
    
  5. 获取时区数组:

    $timezones = $date->getTimezones();
    
  6. 将这些值输出到屏幕上:

    echo 'User time: ' . $userTime . '<br />';
    echo 'System time: ' . $systemTime . '<br />';
    my_debug($timezones);
    

它是如何工作的...

concrete5 通过包装 PHP 和 Zend 框架的函数来创建单行任务,这些任务通常需要几行代码。

使用加密助手

concrete5 使得开发者可以使用包含的加密助手轻松地对字符串进行加密和解密。在本菜谱中,我们将使用加密助手来加密和解密一些字符串。

准备工作

大多数 Web 服务器都内置了它,但确保你的 Web 服务器已安装 mcrypt 非常重要,因为它是此助手正常工作所必需的。

如何操作...

  1. 在你的代码编辑器中打开 /config/site_post.php

  2. 加载助手:

    $eh = Loader::helper('encryption');
    
  3. 加密基本字符串:

    $encrypted = $eh->encrypt('hello');
    
  4. 输出加密的字符串:

    echo $encrypted . '<br />';
    
  5. 解密加密的字符串:

    $decrypted = $eh->decrypt($encrypted);
    
  6. 输出解密后的字符串:

    echo $decrypted;
    exit;
    

它是如何工作的...

加密助手包装 mcrypt PHP 扩展,并将加密文本编码为 Base64 编码的字符串。

参见

  • 加载助手类 菜谱

使用 Feed 助手加载 RSS 源

concrete5 随附一个名为 SimplePie 的第三方库,该库有助于解析 RSS 源。Feed 助手围绕 SimplePie 库提供了一种更方便的加载 RSS 源的方法。

如何操作...

  1. 加载 Feed 助手:

    $rss = Loader::helper('feed');
    
  2. 定义要加载的 RSS 源的 URL。我们将加载 Packt Publishing 的新闻源:

    $url = 'http://www.packtpub.com/rss.xml';
    
  3. 加载源:

    $feed = $rss->load($url);
    
  4. 将源对象的内容输出以验证它是否正确加载:

    my_debug($feed);
    

它是如何工作的...

load 函数简单地创建 SimplePie 类的新实例并加载参数中指定的源。然后 load 函数返回一个基于加载的源的 SimplePie 对象。

更多...

您可以通过访问simplepie.org了解更多关于SimplePie以及如何使用 feed 对象的信息。

使用文件助手管理文件和目录

在网络服务器上处理已存在的文件和目录有时可能是一项繁琐的任务。concrete5 文件助手提供了便利的方法,使得处理文件和目录变得更加简单。

准备工作

这个练习将大量涉及假设的文件和文件名。这更多的是作为一个对文件助手 API 的探索,所以您可以随意将这里的一些文件名替换为您系统中的实际文件。

如何操作...

  1. 加载文件助手:

    $fh = Loader::helper('file');
    
  2. 清理文件名,使其适合保存:

    $filename = 'Make This Eligible!';
    $cleanName = $fh->sanitize($filename);
    echo $cleanName; // outputs 'make_this_eligible'
    
  3. 获取文件名扩展名:

    $ext = $fh->getExtension('image.png');
    echo $ext; // outputs 'png'
    
  4. 修改文件的扩展名:

    $newFilename = $fh->replaceExtension('image.png', 'jpeg');
    echo $newFilename; // outputs 'image.jpeg' 
    
  5. 获取文件的全部内容:

    $contents = $fh->getContents('data.txt');
    
  6. 强制文件下载到用户的计算机:

    $fh->forceDownload('/path/to/file.zip');
    
  7. 将目录的内容复制到另一个目录:

    $fh->copyAll('/source', '/target');
    
  8. 删除目录中的所有文件:

    $fh->removeAll('/directory/to/delete');
    

它是如何工作的...

文件助手利用了 PHP 的许多内置函数,例如file_get_contentsunlinkcopy。助手通过将这些函数包装在额外的逻辑中,使得大多数这些操作只需要一行代码。

更多...

文件助手还提供了一些其他功能,您可以通过查看concrete/core/helpers/file.php文件中的源代码来发现它们。

参见

  • 加载助手类食谱

使用表单助手创建自定义表单

创建表单是网络开发者经常面临的最常见任务之一。concrete5 提供了表单助手来简化创建表单的过程。在本食谱中,我们将使用表单助手创建一个反馈表单。

准备工作

本食谱中的代码将被插入到我们网站上的<form>元素中。请参阅此书的网站上的完整示例代码。我们的表单将包含以下字段:

  • 名称(文本输入)

  • 电子邮件地址(文本输入)

  • 联系原因(选择框)

  • 消息(文本区域)

如何操作...

  1. 通过添加位于/single_pages/example_form.php的新文件来创建一个新的单页。

  2. 通过访问 concrete5 网站的/dashboard/pages/single来安装单页。将新页面的路径输入为example_form

  3. 加载表单助手:

    $form = Loader::helper('form');
    
  4. 输出名称输入字段:

    echo $form->text('name');
    
  5. 输出电子邮件地址输入字段:

    echo $form->email('email');
    
  6. 创建一个包含将出现在联系原因选择框中的选项的关联数组:

    $options = array(
       'general' => 'General Feedback',
       'support' => 'Technical Support',
       'return' => 'Returns / Refunds'
    );
    
  7. 输出联系原因选择框:

    echo $form->select('reason_for_contacting', $options);
    
  8. 显示消息文本区域:

    echo $form->textarea('message');
    

它是如何工作的...

表单助手的函数返回可以直接插入到网站表单中的 HTML。如果您向这些函数提供额外的参数,您可以用您喜欢的任何内容预先填充字段的值(除非该值存在于 HTTP 请求参数中,在这种情况下,concrete5 将用该值填充字段)。以这种方式创建表单有许多好处,并且可以通过遵循这里提出的简单约定节省大量时间。

还有更多...

可以使用表单助手生成许多表单元素。单选按钮、复选框、选择元素、文本输入等。请参阅concrete/core/helpers/form.php中的表单助手类或访问www.concrete5.org/documentation/developers/forms/的 concrete5 开发者文档。

参见

  • 加载助手类菜谱

在表单中包含一个 WYSIWYG 编辑器

concrete5 作为一个内容管理系统,内置了所见即所得WYSIWYG)编辑器,具体来说,是一个流行的开源编辑器,称为TinyMCE。开发者可以将此编辑器包含在他们的自定义 HTML 表单中。在这个菜谱中,我们将向我们在前一个菜谱中创建的表单添加一个 WYSIWYG 编辑器。

准备工作

我们将在前一个菜谱中创建的表单基础上进行构建。如果您需要赶上进度,本书网站上的免费代码下载将为您提供一个良好的起点。

如何做...

  1. 打开/single_pages/example_form.php

  2. 在文件顶部,包含初始化编辑器的 JavaScript 元素:

    Loader::element('editor_init');
    
  3. 在下面,包含默认的 TinyMCE 配置元素:

    Loader::element('editor_config');
    
  4. 在现有的文本区域输出上方,加载包含编辑器控制元素的元素:

    Loader::element('editor_controls');
    
  5. 用新的文本区域替换现有的输出:

    echo $form->textarea('content', '', array('style' => 'width:100%;', 'class' => 'ccm-advanced-editor'));
    

    如何做...

它是如何工作的...

concrete5 使用的修改后的 TinyMCE 编辑器需要在网页上包含大量的 JavaScript 之前才能使用。concrete5 元素包含可重复的 HTML 块(或以<style><script>标签形式存在的 CSS 和 JavaScript)。在我们的表单顶部,我们包括包含 TinyMCE JavaScript 和配置设置的元素。

这不是必需的,但将编辑器的控制元素放在将成为 WYSIWYG 编辑器的文本区域上方是一个好主意。这些控件具有 concrete5 特定的功能,例如在网站地图中插入页面链接或从文件管理器中包含图片。请注意,由于这些控件主要提供与网站编辑器相关的功能,因此这些控件更适合用于后端表单,而不是供最终用户使用。

最后,我们输出一个普通的文本区域元素,但带有ccm-advanced-editor类,这告诉 TinyMCE 将其转换为所见即所得编辑器。

参见

  • 使用表单助手创建自定义表单菜谱

使用 HTML 助手生成 HTML 代码

在许多情况下,您会希望避免在 PHP 服务器端代码中编写 HTML 字符串,因为它真的会弄乱您的代码并使其更难阅读。concrete5 中的 HTML 助手可以通过提供一种优雅的面向对象的方式来生成 HTML 代码,帮助您避免这种情况。

准备工作

此配方假定/css/example.css/js/example.js/images/icon.png都存在于您的网站上。即使这些文件不存在,您也可以执行此配方,concrete5 将简单地输出这些不存在文件的路径。

如何操作...

  1. 使 HTML 助手可用于使用:

    $html = Loader::helper('html');
    
  2. 输出一个 CSS <link>标签,链接到存储在/css/example.css的 CSS 文件:

    echo $html->css('example.css');
    
  3. 输出一个 JavaScript <script>标签,将src属性设置为位于/js/example.js的文件:

    echo $html->javascript('example.js');
    
  4. 输出一个图像<img>标签,显示存储在/images/icon.png的图像:

    echo $html->image('icon.png');
    exit;
    

它是如何工作的...

concrete5 会递归地查找几个目录以找到所需的文件。然后,它会将源路径包裹在适当的标签中,无论是脚本、CSS 链接还是图像。

相关内容

  • 加载助手类的配方

使用 Image 助手生成和缓存缩略图

许多类型的应用程序使用缩略图来显示大图像的表示。这使用户能够在不等待多个大文件大小的图像加载的情况下,在一页上查看多个图像。

准备工作

Image 助手的缩略图生成器接受一个File对象,因此请确保参考第三章,了解如何加载这些文件。

如何操作...

  1. 在您的代码编辑器中打开/config/site_post.php

  2. 加载 Image 助手:

    $ih = Loader::helper('image');
    
  3. 加载我们想要创建缩略图的File对象。这应该是一个图像(JPEG、PNG 或 GIF),并且应该存在于文件管理器中。我们将使用示例图像的 ID 为1

    $fileId = 1;
    $image = File::getByID($fileId);
    
  4. 生成一个高度和宽度为 100 像素的缩略图,并裁剪图像以适应:

    $thumbnail = $ih->getThumbnail($image, 100, 100, true);
    
  5. 回显缩略图的源位置:

    echo $thumbnail->src;
    exit;
    

它是如何工作的...

Image 助手将获取File对象(或文件路径字符串),首先检查是否已创建该大小的缩略图。如果已创建,它将从缓存中提供该缩略图。如果缩略图不存在,concrete5 将使用gdPHP 扩展来调整图像大小和裁剪(如果第四个参数指定并设置为true),然后将新副本保存到缓存中。

助手返回一个具有几个属性的标准类对象,包括srcheightwidth。在这个例子中,我们关注的是src属性。

更多内容...

您可以通过调用以下代码使 Image 助手应用输出已包裹在<img>标签中的缩略图:

echo $ih->outputThumbnail($image, 100, 100);

相关内容

  • 第三章中关于“通过 ID 加载文件”的配方,文件和文件集加载文件

  • 加载助手类的配方

使用 JSON 助手进行 JSON 编码和解码

大多数 PHP 安装都包括方便的 JSON 函数,如 encode_jsondecode_json,这允许开发者轻松生成 JSON 数据以传递给用户的浏览器。concrete5 包含 JSON 助手,允许你在没有这些函数的系统中进行编码和解码 JSON。这对于开发将在多个不同环境中运行的插件尤其有用。

如何做...

  1. 加载 JSON 助手:

    $json = Loader::helper('json');
    
  2. 创建一个将被转换为 JSON 字符串的数组:

    $data = array(
       'name' => 'John Doe',
       'age' => '31'
    );
    
  3. 将数组编码为 JSON 字符串:

    $jsonStr = $json->encode($data);
    
  4. 将 JSON 字符串解码回对象:

    $newObject = $json->decode($jsonStr);
    

它是如何工作的...

如果存在本机 JSON 函数,这些助手函数将简单地围绕它们包装。在 JSON 编码和解码函数不可用的环境中,concrete5 将使用第三方 JSON 库来促进 JSON 字符串的编码和解码。

参见

  • 加载助手类 的配方

使用邮件助手发送电子邮件

从您的网络应用中发送电子邮件的能力可以为最终用户添加一层强大的功能。在这个配方中,我们将使用简单的主题和正文发送电子邮件。

如何做...

  1. 加载邮件助手:

    $mail = Loader::helper('mail');
    
  2. 指定我们希望发送电子邮件的地址:

    $mail->to('test@example.com');
    
  3. 指定此电子邮件的发送地址(以及收件人可以回复的人):

    $mail->from('noreply@example.com');
    
  4. 设置电子邮件的主题行:

    $mail->setSubject('Hello from your concrete5 website!');
    
  5. 设置邮件正文:

    $mail->setBody('This email was sent from your webserver!');
    
  6. 发送电子邮件:

    $mail->sendMail();
    

它是如何工作的...

邮件助手围绕 Zend_Mail 对象,这是 concrete5 构建在之上的 Zend 框架的一部分。邮件助手将遵守 concrete5 安装设置,通过使用 PHP 内置的邮件函数或使用外部 SMTP 服务器来发送邮件。

还有更多...

您可以使用邮件助手发送带有模板、HTML 文本等电子邮件。邮件模板可以存储在您的 concrete5 网站的 /mail 目录中。以下是一个示例模板,它将存在于 /mail/test.php

$subject = 'Hello from your website!';
$body = 'This is the body! Hello, '.$name;

注意在这个模板中,我们引用了一个名为 $name 的变量。要将该变量传递到模板中,请调用邮件助手的 addParameter 函数:

$mail->addParameter('name', 'John Doe');

为了加载模板并应用额外参数,请在发送前调用 load 函数。请记住,我们的模板位于 /mail/test.php

$mail->load('test');

参见

  • 加载助手类 的配方

使用 MIME 助手确定文件扩展名的 MIME 类型

concrete5 可以轻松地使用 MIME 助手确定文件的 多用途互联网邮件扩展MIME)类型。

如何做...

  1. 加载 MIME 助手:

    $mime = Loader::helper('mime');
    
  2. 确定 JavaScript 文件的内容类型:

    $jsMime = $mime->mimeFromExtension('js');
    
  3. 验证 MIME 类型是否正确:

    echo $jsMime; // outputs 'application/x-javascript'
    exit;
    

它是如何工作的...

MIME 助手包含一个常见 MIME 类型及其相关扩展的数组。当你给 MIME 助手一个扩展来查找时,它将简单地找到相关的 MIME 类型并将其返回给你。

还有更多...

MIME 助手还可以返回给定 MIME 类型的文件扩展名:

$jsExt = $mime->mimeToExtension('application/x-javascript');
echo $jsExt;

参见

  • 加载助手类配方

使用导航助手获取页面 URL 和面包屑

导航助手可以协助执行两个非常重要的功能:获取准确的页面 URL 和为给定的Page对象生成面包屑路径。

准备工作

我们需要加载一个Page对象并将其传递给导航助手,所以请确保您熟悉这一点。

如何操作...

  1. 加载导航助手:

    $nav = Loader::helper('navigation');
    
  2. 加载我们将要处理的Page对象。在这个示例中,我们将使用位于example.com/about-us的页面:

    $page = Page::getByPath('/about-us');
    
  3. 获取页面的 URL:

    $url = $nav->getCollectionURL($page);
    
  4. 获取给定页面的面包屑项数组(作为Page对象):

    $breadcrumbs = $nav->getTrailToCollection($page);
    

它是如何工作的...

导航助手检查您的配置设置,并将任何基本 URL 或重写逻辑附加到页面集合路径上。对于面包屑,助手会从给定页面开始递归遍历网站地图,以找到其上方的所有父页面。

相关内容

  • 加载助手类配方

  • 在第一章的通过路径获取页面对象配方中,页面和页面类型

使用文本助手处理字符串

concrete5 提供的另一个有用助手是文本助手。文本助手允许您使用非常少的代码在字符串上执行几个常见(有时复杂)的操作。

如何操作...

  1. 加载文本助手:

    $text = Loader::helper('text');
    
  2. 创建一个用于示例的字符串:

    $str = 'This is a test';
    
  3. 将字符串转换为驼峰式命名(CamelCase):

    $camelCased = $text->camelcase($str);
    echo $camelCased; // outputs "ThisIsATest"
    
  4. 将字符串转换为非驼峰式命名:

    $uncamelcased = $text->uncamelcase($camelCased);
    echo $uncamelcased; // outputs 'this_is_a_test'
    
  5. 创建一个带有短横线的 URL 友好字符串:

    $url = $text->urlify($str);
    echo $url; // outputs 'this-is-a-test'
    
  6. 创建一个下划线命名的处理程序:

    $handle = $text->handle($str);
    echo $handle; // outputs 'this_is_a_test'
    
  7. 删除所有非字母数字字符:

    $alphaNum = $text->alphanum($str);
    echo $alphaNum; // outputs 'This is a test'
    Truncate a string and append an ellipsis at the end.
    $trunc = $text->short$trunc = $text->short$trunc = $text->short
    echo $trunc; // outputs 'This...'
    exit;
    

它是如何工作的...

文本助手围绕几个内置的 PHP 函数以及一些第三方库,提供方便的、一行代码的函数,允许您快速轻松地修改文本。

还有更多...

文本助手还有一些其他有用的函数,这些函数超出了本配方的作用范围,例如自动从字符串中的任何 URL 创建链接,甚至自动链接到 Twitter 账号。建议开发者探索文本助手的源代码,以了解它提供的更多特定功能。

相关内容

  • 加载助手类配方

使用 URL 助手生成 URL

URL 助手可以使用一些简单的函数生成 URL。

如何操作...

  1. 加载 URL 助手:

    $uh = Loader::helper('url');
    
  2. 创建一个包含我们想要传递的 URL 参数的数组。我们将在这个示例中随意创建一些内容:

    $params = array(
       'page' => '1',
       'filter' => 'events'
    );
    
  3. 构建 URL:

    $url = $uh->buildQuery('http://example.com', $params);
    
  4. 输出 URL 以查看结果:

    echo $url; // outputs http://example.com?page=1&filter=events
    exit;
    

它是如何工作的...

此函数使用了 PHP 的http_build_query函数,该函数可以在给定参数数组时生成有效的 URL。

还有更多...

URL 助手还有一个使用 TinyURL 服务创建短 URL 的函数。

$short = $uh->shortenURL('http://example.com');
echo $short; // outputs http://tinyurl.com/123abc

相关内容

  • 加载助手类配方

使用验证助手验证输入数据

当构建接受用户数据的应用程序时,确保用户填写了表单上的所有必需字段绝对是一个好主意。

准备工作

考虑一个包含以下字段的评论表单:姓名、电子邮件、网站和评论内容。姓名、电子邮件和内容字段是必需的,但网站字段是可选的。我们将使用验证助手来确定用户是否填写了所有必需的字段。

如何操作...

  1. 加载验证助手:

    $val = Loader::helper('validation/form');
    
  2. 让我们创建一个数组来模拟 POST 请求(通过 $_POST 超全局变量)中包含的数据。我们将故意留空 email 以查看验证助手在测试失败时的行为:

    $data = array(
       'name' => 'Jane Doe',
       'email' => '',
       'website' => 'http://example.com',
       'content' => 'Great post!'
    );
    
  3. 将数组传递给验证助手,以便它知道要验证什么:

    $val->setData($data);
    
  4. 指定必需的字段,并为每个字段提供错误信息:

    $val->addRequired('name', 'Please enter a name.');
    $val->addRequiredEmail('email', 'Please enter an email address.');
    $val->addRequired('content', 'Please enter some content.');
    
  5. 测试数组以查看它是否满足要求。

    $passed = $val->test();
    Output the list of errors so the user knows what fields are missing.
     if ($passed === false) {
       foreach ($val->getError()->getList() as $error) {
          echo $error . '<br />';
       }
     }
    exit;
    

它是如何工作的...

在功能方面,验证助手相当基础,它基本上检查数据数组中是否存在某个变量,并确保它具有某种类型的值。注意步骤 4 中的 addRequiredEmail 的使用。这个函数确保电子邮件地址存在,并验证它是一个有效的电子邮件地址(而不仅仅是任何字符串)。

验证助手上的 getError 函数返回一个 ValidationErrorHelper 对象,该对象有一个名为 getList 的函数,可以提供一个易于使用的错误信息数组。

还有更多...

除了测试常规字符串和电子邮件,你还可以测试整数值:

$val->addRequiredInteger('age', 'Please enter your age.');

参见

  • 加载助手类 的配方

使用验证码助手防止垃圾邮件

如大多数曾经在线发布表单的网页开发者所知,垃圾邮件对网站所有者来说是一个令人烦恼且可能造成损害的问题。concrete5 可以通过内置的验证码助手帮助减轻这个问题,该助手可以验证表单提交是否来自人类,而不是自动化脚本。

准备工作

这个配方将解释如何使用验证码助手。通常,你将在你的最终用户会看到的 HTML 视图中使用这个助手(单页视图、块视图等)。书中代码下载中包含了这个助手在单页上下文中的一个示例。

如何操作...

  1. 加载验证码助手:

    $captcha = Loader::helper('validation/captcha');
    
  2. 在表单底部显示 CAPTCHA 图像和输入,以便用户解决它:

    <?php echo $captcha->display(); ?> <br />
    <?php echo $captcha->showInput(); ?>
    
  3. 在处理表单提交的服务器端代码中,验证 CAPTCHA 是否正确解决:

    if ($captcha->check()) {
       // User passed, continue processing.
    }
    

它是如何工作的...

验证码助手利用名为 SecureImage 的第三方库来生成 CAPTCHA 图像和相关逻辑。如果用户正确地输入了图像中的单词,check 函数将返回 true,然后你可以继续处理表单提交。

参见

  • 加载助手类 的配方

获取国家列表

许多时候,网络开发者发现自己需要向用户提供国家列表。而不是寻找这些数据或甚至手动组装数据,concrete5 提供了一个辅助器来生成世界上所有国家的列表。在这个菜谱中,我们将使用国家列表并创建一个可以放置在表单中的 <select> 元素,允许用户选择一个国家。

如何做...

  1. /single_pages/example_form.php 创建一个单个页面。

  2. 通过访问 /dashboard/pages/single 并在路径输入中键入 example_form 来安装单个页面。

  3. 在你的代码编辑器中打开 /single_pages/example_form.php

  4. 在文件顶部加载国家列表辅助器:

    $list = Loader::helper('lists/countries');
    
  5. 获取可用国家的数组:

    $countries = $list->getCountries();
    
  6. 加载 Form 辅助器:

    $form = Loader::helper('form');
    
  7. 创建一个包含所有国家的 <select> 元素的 HTML 表单:

    <form>
       <?php echo $form->select('country', $countries); ?>
    </form>
    

它是如何工作的...

concrete5 承担了组装和维护国家列表的重任,并将其构建到核心列表辅助器中。国家的两位字符代码作为数组键提供,完整名称字符串作为值。

相关链接

  • 加载辅助类 菜单

  • 使用 Form 辅助器创建自定义表单 菜单

获取州和省的列表

除了提供国家列表之外,concrete5 还可以提供适用于有此类列表的国家列表、州、省和县。

在这个菜谱中,我们将获取英国所有县的列表并将它们呈现为 <select> 输入。

如何做...

  1. 如果它还不存在,在 /single_pages/example_form.php 创建一个单个页面。

  2. 加载 List 辅助器:

    $list = Loader::helper('lists/states_provinces');
    
  3. 获取英国的县列表:

    $counties = $list->getStateProvinceArray('UK');
    
  4. 加载 Form 辅助器:

    $form = Loader::helper('form');
    
  5. 创建一个包含县列表的 <select> 元素的 HTML 表单:

    <form>
       <?php echo $form->select('county', $counties); ?>
    </form>
    

它是如何工作的...

状态/县/省列表辅助器与国家辅助器的工作方式非常相似,因为 concrete5 团队为各种国家组装了一个州/县/省列表,可以通过提供两位字符代码来访问。

更多内容...

如果你想获取存储在辅助器中的所有州和省,可以使用以下代码:

$allProvinces = $list->getAll();

相关链接

  • 加载辅助类 菜单

  • 使用 Form 辅助器创建自定义表单 菜单

在表单上显示颜色选择器

concrete5 提供辅助器来生成标准的 HTML 表单元素,但对于需要允许用户选择颜色的应用程序怎么办?对于这些应用程序,concrete5 也包含一个颜色选择器辅助器!

准备工作

颜色选择器依赖于 jQuery UI,除非你以管理员身份登录,否则它不会自动包含在 concrete5 中。如果你在网站的前端使用颜色选择器,请确保在页面上包含 jQuery UI 的 JavaScript 和 CSS 文件。

如何做...

  1. 如果它还不存在,在 /single_pages/example_form.php 创建一个单个页面。

  2. 如果需要,在仪表板上安装此单个页面。

  3. 在文件顶部加载颜色选择器辅助器:

    $color = Loader::helper('form/color');
    
  4. 在 HTML 表单元素中输出颜色选择器小部件:

    <form>
       <?php echo $color->output('color', 'Choose a color...') ?>
    </form>
    

工作原理...

concrete5 将生成必要的 HTML 和 JavaScript,以提供交互式颜色选择器小部件。传递给 output 函数的第一个参数是字段的名称,这是表单提交后访问值的方式。第二个参数是将在颜色选择器旁边的 <label> 元素中出现的文本。

参见

  • 加载辅助类 菜谱

在表单上显示日期/时间选择器

使用需要日期输入的 Web 应用程序时,一个非常常见的用户体验是让用户在交互式日历中选择日期,而不是输入完整的日期。concrete5 提供一个辅助工具,可以轻松生成此类小部件。在这个菜谱中,我们将生成一个日期选择器,它将显示迷你日历来允许用户选择日期。

准备工作

concrete5 仅在用户以管理员身份登录时自动包含 jQuery UI 的 JavaScript 文件。如果您希望在非管理员可以使用的网站区域使用日期选择器,请确保在页面中包含 jQuery UI JavaScript 和 CSS 文件。

如何操作...

  1. 如果单个页面 /single_pages/example_form.php 还不存在,请创建一个。

  2. 请确保通过访问 /dashboard/pages/single 来在仪表板上安装单个页面。

  3. 加载日期/时间辅助工具:

    $datePicker = Loader::helper('form/date_time');
    
  4. 将日期选择器输出到 HTML 表单中:

    <form>
       <?php echo $datePicker->date('date') ?>
    </form>
    

工作原理...

concrete5 使用 jQuery UI 库生成创建交互式日期选择器所需的 JavaScript 和 CSS。日期/时间辅助工具生成所有必要的样板 HTML 和 JavaScript,这使得使用日期选择器变得非常简单。

更多内容...

有时开发者需要为用户提供一个界面,以便同时选择与日期一起的时间。这只是一个在日期/时间辅助工具上调用不同函数的问题:

echo $datePicker->datetime('date')

参见

  • 加载辅助类 菜谱

在表单上显示评分小部件

现代网络应用程序提供一组星形图标供用户点击,为给定项目提供“评分”。在 concrete5 应用程序中使用评分辅助工具包含这些类型的 UI 组件非常简单。

如何操作...

  1. 如果单个页面 /single_pages/example_form.php 还不存在,请创建一个。

  2. 通过访问 /dashboard/pages/single 并输入 example_form 作为页面位置来安装单个页面。

  3. 加载评分表单辅助工具:

    $rh = Loader::helper('form/rating');
    
  4. 输出评分小部件:

    <form>
       <?php echo $rh->rating('rating', 60) ?>
    </form>
    

工作原理...

评分辅助工具利用第三方 jQuery 插件提供交互式评分选择器。辅助工具将负责生成使用此小部件所需的所有 HTML 和 JavaScript。

输出函数需要两个参数:输入名称和初始值(一个整数,可以是 20、40、60、80 或 100)。

更多内容...

如果您只想简单地提供一种只读方式来显示评分,评分辅助工具可以做到这一点:

$rating = Loader::helper('rating');
$rating->outputDisplay(84);

简单地调用 outputDisplay 方法并提供一个介于 0 和 100 之间的值。

参见

  • 加载辅助类食谱

使用禁止单词列表

concrete5 附带了一系列粗俗和不恰当的英文单词列表,网站管理员可以使用这些单词从他们的网站上移除不适当的内容。在这个例子中,我们将检查一个单词,看看它是否在禁止单词列表中。

如何做到这一点...

  1. 加载禁止单词助手:

    $bannedWords = Loader::helper('validation/banned_words');
    
  2. 检查一个单词,看看它是否在禁止单词列表中:

    $isBanned = $bannedWords->isBannedWord('friendly');
    
  3. 如果单词在禁止单词列表中,则$isBanned将等于true

    var_dump($isBanned);
    exit;
    

它是如何工作的...

concrete5 会检查禁止单词列表(存储在/concrete/config/banned_words.txt),以查看它是否包含参数中提供的单词。

还有更多...

网站管理员可以通过将其复制到/config/banned_words.txt并添加或删除条目来自定义和编辑禁止单词列表。

参见

  • 加载辅助类食谱

读取和写入系统缓存

负责任的开发者会采取额外措施确保他们的应用程序针对最佳性能进行了优化。concrete5 内置了一个缓存 API,开发者可以将其挂钩以缓存自己的自定义数据并提高性能,尤其是在大型数据库查找中。

准备工作

我们将从数据库中加载大量行(这可能会以负面方式影响性能),然后将结果数组存储在缓存中,以防止未来的资源密集型数据调用。这个食谱将从包含数千行的假设表Customers中加载。

如何做到这一点...

  1. 从数据库中加载大量记录,这将消耗服务器的资源。我们将使用一个假设的表Customers

    $db = Loader::db();
    $customers = $db->getAll('SELECT * FROM Customers');
    
  2. 将结果存储在系统缓存中:

    Cache::set('customerList', false, $customers);
    
  3. 从缓存中读取结果,防止进行另一个密集的数据库查询:

    $cachedCustomers = Cache::get('customerList', false);
    

它是如何工作的...

concrete5 的缓存库是对Zend_Cache库的定制实现,该库与 Zend 框架一起提供,而 concrete5 就是基于这个框架构建的。调用set函数时,您将指定要保存的项目类型(在这种情况下,我们称之为customerList),以及要保存的项目 ID(如果您正在保存多个相同类型的对象,这将很有用——在这种情况下我们不是,所以我们只需将此变量设置为false)。

还有更多...

您可以通过发送已保存到缓存的项目类型和 ID 来删除您已保存到缓存中的项目。要删除我们之前保存的客户列表,您将编写以下内容:

Cache::delete('customerList', false);

您还可以刷新整个缓存,删除存储在其中的所有项目:

Cache::flush();

参见

  • 加载辅助类食谱

  • 在第五章的加载数据库对象食谱中,与数据库和模型一起工作加载数据库对象食谱

  • 在第五章的从数据库检索数据食谱中,与数据库和模型一起工作从数据库检索数据食谱

写入调试日志

记录日志是应用程序开发中的常见做法,但有时你可能想要将 concrete5 应用程序中的错误与特定于 PHP 或 Apache 的错误分开。为此,你可以写入 concrete5 的内部日志,该日志可以通过仪表板由网站管理员查看。在这个菜谱中,我们将简单地写入几个基本字符串到网站的内部日志。

如何操作...

  1. 想出一个你想要写入日志的消息字符串:

    $message = 'Hello, log!';
    
  2. 将消息写入日志:

    Log::addEntry($message);
    

读取和写入配置注册表

在数据字典中存储键值对是任何现代编程语言中的常见任务。concrete5 允许你使用 Config 类来存储配置设置,而不是在数据库或其他地方存储键/值设置。在这个菜谱中,我们将写入一个配置首选项,表示网站管理员是否希望允许在网站上允许评论。

如何操作...

  1. 将首选项写入系统配置字典:

    Config::save('allow_comments', true);
    
  2. 读取首选项项的值:

    $allowComments = Config::get('allow_comments');
    

它是如何工作的...

concrete5 将键值对存储在数据库的 Config 表中。Config 类提供了一个干净且简单的 API,使得写入和读取配置值尽可能容易。这些配置键在 concrete5 中持续存在,因此开发者应该格外小心,以防止与同名的其他配置值冲突。在这种情况下,给配置键加上一些你自己的代码中独特的名称,例如 cookbook_allow_comments 是一个好主意。

第五章:与数据库和模型一起工作

在本章中,我们将涵盖以下内容:

  • 配置数据库凭据

  • 加载数据库对象

  • 从数据库中检索数据

  • 将数据写入数据库

  • 使用预处理语句防范 SQL 注入

  • 创建自定义模型类

  • 使用活动记录从数据库读取

  • 使用活动记录向数据库写入

  • 使用活动记录更新数据库记录

  • 使用活动记录搜索数据库

  • 使用活动记录和模型类删除对象

  • 使用活动记录定义关系

简介

网络应用程序从连接到数据库中获得了许多功能。concrete5 是一个 LAMP 应用程序(在 Linux、Apache、MySQL 和 PHP 上运行)。MySQL 是 concrete5 使用的数据库,它是世界上最受欢迎的开源数据库。

在本章中,我们将探讨在 concrete5 中与数据库交互的方法,包括使用原始 SQL 查询和更面向对象的 active record 方法。我们将学习如何防范 SQL 注入攻击,创建自定义模型类,并使用对象和 active record 查询数据库。

本章将使用一些基本的 SQL 查询,因此建议您对编写数据库查询有一定的了解。

配置数据库凭据

在我们能够读取和写入数据库之前,我们需要确保 concrete5 有正确的数据库凭据。通常这些凭据是在安装期间设置的,但如果您将 concrete5 移动到另一个服务器或更改 concrete5 用户的用户名或密码,了解如何配置数据库访问是很重要的。

在这个菜谱中,我们将假设我们从零开始指定凭据。这将使我们能够探索数据库中存储的每个值。

如何操作...

查看以下步骤:

  1. 在您首选的代码编辑器中打开 /config/site.php

  2. 指定数据库服务器的名称。在许多情况下,这仅仅是 localhost

    define('DB_SERVER', 'localhost');
    
  3. 设置 concrete5 连接到数据库时使用的用户名:

    define('DB_USERNAME', 'user');
    
  4. 为该用户设置密码:

    define('DB_PASSWORD', 'password');
    
  5. 最后,指定 concrete5 将连接到的数据库名称:

    define('DB_DATABASE', 'concrete5');
    

它是如何工作的...

当网站被访问时,site.php 文件会被 concrete5 自动加载。开发者可以使用 PHP 的 define 函数在这里定义配置常量。define 函数的第一个参数是常量的名称,不要更改此参数。然而,第二个参数应包含特定设置的相应值。

确保您为 concrete5 选择的用户有足够的数据库访问权限,并且允许执行所有必要的查询。

此文件中配置不当的数据库设置将导致网站显示错误。

加载数据库对象

在 concrete5 中执行数据库查询的核心是数据库对象。数据库对象公开了几个方法,允许开发者对数据库执行查询。

如何操作...

看看以下步骤:

  1. 我们需要一个地方来测试一些测试代码。打开/config/site_post.php,这将很好地服务于你的代码编辑器。

  2. 编写以下代码片段以加载数据库对象:

    $db = Loader::db();
    
  3. 现在数据库对象已加载,看看它公开的一些方法:

    $methods = get_class_methods($db);
    
  4. 将方法数组输出到屏幕:

    var_dump($methods);
    exit;
    

工作原理...

concrete5 将使用配置文件中的数据库设置(可能位于/config/site.php)并连接到数据库,返回一个包含与数据库交互的几个有用方法的对象。

更多内容...

如果你想连接到site.php中指定的数据库以外的数据库,你可以将新的数据库凭据作为参数传递给数据库加载器,如下所示:

$db = Loader::db('host', 'user', 'password', 'database');

从数据库中检索数据

一旦加载了数据库对象,你就可以对其执行查询。在这个菜谱中,我们将选择Users表的内容,并输出每个用户名。

准备工作

在深入编写 concrete5 中的手动查询之前,请确保你理解如何使用 SQL 编写数据库查询。网上和印刷品中有成百上千的 MySQL 资源,远远超出了本书的范围!

如何操作...

看看以下步骤:

  1. 加载数据库对象:

    $db = Loader::db();
    
  2. 编写查询以从Users表中选择:

    $query = 'SELECT * FROM Users';
    
  3. 执行查询:

    $results = $db->getAll($query);
    
  4. 遍历结果并输出每个用户的用户名:

    foreach ($results as $user) {
       echo $user['uName'].'<br />';
    }
     exit;
    

工作原理...

这个函数按预期工作,但它减少了使用 PHP 和 MySQL 执行原始数据库查询时的繁琐。在数据库对象上调用getAll函数会返回一个包含所有结果的数组。每个结果也是一个数组,其键对应于行中的每一列。

更多内容...

如果你正在执行只选择一个列并期望一个结果的查询(例如,一个COUNT查询),你可以使用getOne方法来获取你需要的确切值,如下面的代码片段所示:

$count = $db->getOne('SELECT COUNT(*) FROM Users');

相关内容

  • 将数据写入数据库 菜谱

将数据写入数据库

当然,在 MySQL 数据库上可以执行的查询中,大多数不会返回任何数据。如果开发者需要向表中插入一行怎么办?为此,我们可以使用数据库对象的execute方法。

在这个菜谱中,我们将向名为CustomTable的表中插入一行新数据。

准备工作

我们将在这里向数据库中插入一些行,但我们不想在正常的 concrete5 数据库表中搞乱任何东西。通过在你的 MySQL 数据库上执行以下语句创建一个虚拟表来运行一些查询(此 SQL 文件也包含在此书的免费代码下载中):

CREATE TABLE `CustomTable` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  `country` varchar(255) DEFAULT '',
  PRIMARY KEY (`id`)
);

如何操作...

查看以下步骤:

  1. 在您的代码编辑器中打开 /config/site_post.php

  2. 加载数据库对象:

    $db = Loader::db();
    
  3. 编写 INSERT 查询:

    $query = 'INSERT INTO CustomTable (name, country) VALUES ("John Doe", "US")';
    
  4. 执行 INSERT 查询:

    $db->execute($query);
    
  5. 输出一条成功消息,以便您知道更新已成功执行:

    echo 'done!';
    exit;
    

它是如何工作的...

execute 函数允许开发者运行用户有权运行的任何查询。在这种情况下,我们只是执行一个语句来向自定义表中添加新行。

还有更多...

execute 函数可以用来在数据库上运行任何任意查询。例如,如果我们想将 CustomTable 的内容清空(TRUNCATE),我们可以编写以下代码片段:

$query = 'TRUNCATE CustomTable';
$db->execute($query);

使用预定义语句防止 SQL 注入

在网络应用程序中,SQL 注入攻击一直是安全问题的主要来源。SQL 注入可能发生在用户提供的输入在插入 SQL 命令之前没有得到适当的转义和净化。恶意用户可能会利用这个机会在数据库上运行任意命令,要么泄露敏感数据,要么执行破坏性操作,如更改或删除数据。

幸运的是,这是一个容易解决的问题。确实,一个人可以在将输入拼接成 SQL 查询之前手动净化所有用户输入,但这很繁琐且容易出错(忘记净化应用程序的一部分仍然可能使其容易受到攻击)。防止 SQL 注入的最佳方式是使用预定义语句。

预定义语句(或参数化语句)与常规 SQL 查询类似。唯一的区别是,不是直接将用户提供的参数插入到查询中,数据库将在不同的时间运行基础查询和参数部分。因此,预定义语句不会受到 SQL 注入的威胁。

当运行包含用户提供的数据的查询时,使用仅预定义语句非常重要。

concrete5 中的数据库对象支持预定义语句,在这个配方中,我们将创建一个预定义语句,允许访客通过用户名搜索 Users 表,并返回该用户的电子邮件地址。

准备就绪

此配方将假设您的 concrete5 系统有一个用户名为 admin 的用户。请随意调整此代码以适应您的环境。

如何实现...

查看以下步骤:

  1. 在您的代码编辑器中打开 /config/site_post.php

  2. 加载数据库对象:

    $db = Loader::db();
    
  3. 创建我们的预定义语句:

    $query = 'SELECT * FROM Users WHERE uName = ?';
    
  4. 将用户在 HTML 表单中提供的值存储起来。我们将假设它等于 admin

    $username = 'admin';
    
  5. 运行预定义查询,将语句作为第一个参数,将过滤器值作为第二个参数:

    $results = $db->getAll($query, $db->getAll($query, $db->getAll($query, $db->getAll($query, $db->getAll($query, 
    
  6. 遍历结果并输出每个用户的电子邮件地址(应该只有一个):

    foreach ($results as $user) {
       echo $user['uEmail'] . '<br />';
    }
    exit;
    

它是如何工作的...

预处理语句是数据库管理系统的一个特性,在本例中是 MySQL。在 concrete5 中,数据库对象利用了这一原生特性,使其在单行函数中使用变得简单。这是因为查询在参数应用之前就已经准备并执行了;不存在 SQL 注入的风险。除了安全优势外,预处理语句也是提高多次运行的查询性能的绝佳方式。

更多内容...

数据库对象支持执行带有多个参数的预处理语句。在这些情况下,只需以查询中指定的相同顺序提供一个包含每个值的数组即可。看看以下代码片段:

$sql = 'INSERT INTO CustomTable (name, country) VALUES (?, ?)';
$values = array('John Doe', 'US');
$db->execute($sql, $values);

参见

创建自定义模型类

在 concrete5 中编写 SQL 命令是快速轻松地与数据库交互的方式,但这并不是最佳方式。由于 concrete5 是一个MVC模型-视图-控制器)应用程序,所有数据操作都应该真正存在于模型中。模型是数据库中存在的对象的表示,它将包含读取和写入该对象的方法,并使其在数据库中持久化。

在这个菜谱中,我们将创建一个名为Books的新表,其中将包含多个书籍记录。然后我们将创建一个Book模型,它将在数据库中表示书籍数据。

准备工作

concrete5 在数据库表命名方面遵循特定的约定。如果你在 SQL 查询浏览器(如 phpMyAdmin 或 OS X 上的 Sequel Pro)中打开 concrete5 数据库,你会看到每个表都以大写字母开头,并且表名中的后续单词也是驼峰式命名。此外,在 concrete5 中,表应该是复数形式,因为它们包含多个项目实例。模型应该是单数形式,因为它们代表数据库中的单个项目(大多数情况下)。因此,我们将创建的新表将被称为Books,模型将被称为Book

如何做...

看看以下步骤:

  1. 首先,创建我们将用于新Book模型的Books表。我们建议使用数据库浏览器工具,如 phpMyAdmin、MySQL Workbench、Sequel Pro(OS X)或 Heidi SQL(Windows)。查询也可以从以下操作执行:

    CREATE TABLE `Books` (
      `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
      `title` varchar(255) NOT NULL DEFAULT '',
      `author` varchar(255) NOT NULL DEFAULT '',
      PRIMARY KEY (`id`)
    );
    
  2. Book模型创建一个新文件。在/models文件夹中,创建一个名为book.php的文件。

  3. 在文件顶部添加defineddie语句。这是在 concrete5 中所有 PHP 文件中必需的,以防止脚本自行执行:

    <?php
    defined('C5_EXECUTE') or die("Access Denied.");
    
  4. Book模型创建类定义,扩展核心Model类。

    class Book extends Model {
    
    }
    
  5. 添加一个创建新书籍的方法,接受标题和作者名称作为参数:

    public function createBook($title, $author) {
      $db = Loader::db();
           $this->title = $title;
       $this->author = $author;
           $query = 'INSERT INTO Books (title, author) VALUES (?, ?)';
       $values = array($title, $author);
           $db->execute($query, $values);
       $this->id = mysql_insert_id();
           return $this->id;
    }
    
  6. 添加另一个方法来通过 ID 加载书籍:

    public function loadById($id) {
       $db = Loader::db();
       $query = 'SELECT * FROM Books WHERE id = ?';
           $books = $db->getAll($query, $id);
         // get the first result (there should be only one)
       $book = $books[0];
           // set each property of the result to the current object
       $this->id = $book['id'];
       $this->title = $book['title'];
       $this->author = $book['author'];
    }
    
  7. 最后,添加一个获取书籍标题的方法:

    public function getTitle() {
       return $this->title;
    }
    
  8. 保存 book.php。现在 Book 模型已经创建并保存,让我们尝试使用它来写入和读取数据库。为了简化,我们将这段代码放在 /config/site_post.php 中。

  9. 使用 Loader 类加载 Book 模型:

    Loader::model('book');
    
  10. 创建 Book 的新实例:

    $book = new Book();
    
  11. 使用我们之前声明的 createBook 函数向数据库中添加一本新书:

    $book->createBook('concrete5 Cookbook', 'David Strack');
    
  12. 使用我们声明的函数获取书籍的标题。

    $title = $book->getTitle();
    

它是如何工作的...

让我们回顾一下我们刚刚编写的代码。首先,我们确保在数据库中创建了一个名为 Books 的表。这个表有三个列,一个 ID 字段(每次创建行时自动递增),一个 title 字段和一个 author 字段。

接下来,我们在 /models/book.php 中创建了一个名为 Book 的类。这个类将代表 Books 表中单个记录的一个实例。该类扩展了核心 Model 类(它是在 /concrete/core/libraries/model.php 中定义的一个基本实现)。然后我们添加了一个方法来向数据库中添加新书。createBook 方法首先加载数据库对象,然后将 titleauthor 赋值给当前的 Book 对象。执行 INSERT 查询后,该方法使用 mysql_insert_id() 函数设置书籍的 ID。最后,函数返回我们刚刚添加的行的新的 ID

接下来添加了 loadById 函数。这个函数将接受一个 ID 作为参数,然后在数据库上执行一个 SELECT 查询以找到对应的行。注意,在这个演示中,我们从未实际验证记录是否存在。在实际应用中,你将想要确保考虑到这一点。一旦我们加载了 Book 对象,我们将三个属性(IDtitleauthor)赋值给类对象。

最后,我们添加了一个简单的获取器函数来返回书籍的标题。请注意,这个函数只有在 Book 类被加载后才会工作,无论是通过调用 loadById,还是通过使用 createBook 函数创建一个新的书籍。

还有更多...

应该很明显,通过创建处理数据对象的模型,开发者可以节省大量工作并保持代码整洁。而不是让 SQL 语句散布在代码中,所有与数据库相关的逻辑都包含在模型中。这允许快速轻松地创建和访问数据库行。

参见

  • 加载数据库对象 的配方

  • 从数据库中检索数据 的配方

  • 将数据写入数据库 的配方

  • 使用预处理语句防止 SQL 注入 的配方

使用活动记录从数据库中读取

现在我们已经创建了一个 Model 类,很容易看出这对想要保持其代码库干净和可维护的开发者来说可以是一个巨大的好处。然而,我们可以通过使用活动记录更进一步。现实是,在先前的食谱中,这些任务可以用不到一半的代码来完成。

如果你熟悉 Ruby on Rails 或 CakePHP 等框架,那么你可能已经对活动记录有一些经验。活动记录 是一种使用包含创建、更新、读取和删除功能以及映射到数据库中记录的属性的类的约定。

在这个食谱中,我们将探讨如何使用活动记录从数据库中加载模型。

准备工作

我们将使用前面食谱中数据库中的相同 Books 表。如果你需要创建此表,请在你的数据库上运行以下 SQL:

CREATE TABLE `Books` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `title` varchar(255) NOT NULL DEFAULT '',
  `author` varchar(255) NOT NULL DEFAULT '',
  PRIMARY KEY (`id`)
);

此外,请确保表中存在 ID 为 1 的记录。如果你已经完成了前面的食谱,它应该已经存在。

如何做到这一点...

看看以下步骤:

  1. 如果 ID 为 1 的记录不存在,请在 /models/book.php 中创建一个 Book 类。

  2. 确保文件 book.php 的内容如下:

    <?php
    defined('C5_EXECUTE') or die("Access Denied.");
    class Book extends Model {
       public $_table = 'Books';
       public function getTitle() {
          return $this->title;
       }
    }
    
  3. 现在,让我们写一点代码来让这个模型变得生动起来。对于这个演示,我们只需在 /config/site_post.php 中编写代码,因为这只是临时的示例代码。

  4. 加载模型:

    Loader::model('book');
    
  5. 创建 Book 类的新实例:

    $book = new Book();
    
  6. 加载 ID 为 1 的书籍:

    $book->load('id = ?', '1');
    
  7. 获取书籍的标题:

    $title = $book->getTitle();
    
  8. 将标题输出到屏幕:

    echo $title;
    exit;
    

它是如何工作的...

如你所见,Book 模型不包含任何 SQL,但它仍然能够对数据库进行查找并加载 ID 为 1 的书籍。Book 类扩展了 Model 类,而 Model 类又扩展了 ADOdb_Active_Record 类。ADOdb_Active_Record 类实现了几个函数,以提供典型的读取、更新、创建和删除功能。

需要注意的一个重要变化是,在类体开始处,我们添加了一个名为 $_table 的成员变量。如果我们省略了它,一切仍然会正常工作。实际上,ADOdb_Active_Record 类进行了一些基本的屈折变化(将单数类名(Book)转换为复数数据库表名(Books))。然而,屈折变化基本上只擅长在类名末尾添加 s,这就是全部。更复杂的复数化可能会失败,所以始终指定表名是一个好主意。

ADOdb_Active_Record 类的 load 函数期望的语法与在 SQL WHERE 语句中找到的语法相同。编写 load('id = ?') 等同于编写以下预编译语句:

SELECT * FROM Books WHERE id = ?

然后 load 函数将所有属性分配给对象。很明显,当在 concrete5 中执行简单的 CRUD 任务时,这可以消除大量的代码。

相关内容

  • 创建自定义模型类 食谱

  • 使用预处理语句防止 SQL 注入 菜谱

使用活动记录写入数据库

活动记录也可以用于写入数据库。在这个菜谱中,我们将使用之前菜谱中创建的 Book 类向数据库添加新的书籍记录。

准备工作

确保已创建 Book 模型和 Books 表。请参阅 使用活动记录从数据库中读取 菜谱,了解该类应该如何创建。

如何做...

看看以下步骤:

  1. 我们将在 /config/site_post.php 中输入代码,所以请打开该文件在您的代码编辑器中。

  2. 加载模型:

    Loader::model('book');
    
  3. 创建 Book 类的新实例:

    $book = new Book();
    
  4. 设置书籍的标题:

    $book->title = 'The Wind in the Willows';
    
  5. 设置书籍的作者:

    $book->author = 'Kenneth Grahame';
    
  6. 保存新的书籍数据:

    $book->save();
    exit;
    

它是如何工作的...

在将 titleauthor 属性设置为 Book 对象后,调用 save 函数将自动将项目保存到数据库中,并创建新行。

相关内容

  • 创建自定义模型类 菜谱

  • 使用活动记录从数据库中读取 菜谱

使用活动记录更新数据库记录

更新数据库项与创建它们非常相似。在这个菜谱中,我们将加载 ID 为 1 的书籍并更改其标题。

准备工作

此菜谱使用与之前的 使用活动记录从数据库中读取 菜谱相同的 Book 模型和 Books 表。在开始此菜谱之前,请确保这些文件已就位。

如何做...

看看以下步骤:

  1. 在您的代码编辑器中打开 /config/site_post.php

  2. 加载模型:

    Loader::model('book');
    
  3. 创建一个书籍类的新实例:

    $book = new Book();
    
  4. 通过其 ID 加载书籍:

    $book->load('id = ?', '1');
    
  5. 更改书籍的标题:

    $book->title = 'New Title';
    
  6. 将更改保存到数据库中:

    $book->update();
    exit;
    

它是如何工作的...

一旦加载了书籍记录,对象的 ID 属性就会被设置。当调用 update 时,Model 类使用这个 ID 来更新正确的记录。如果对象的 ID 在调用 update 时不存在或未设置,将创建一个新的记录。

相关内容

  • 创建自定义模型类 菜谱

  • 使用活动记录从数据库中读取 菜谱

使用活动记录在数据库中搜索

通常,Web 应用程序将需要检索多个记录。在这个菜谱中,我们将继续使用存储在数据库中的 Books 概念,并检索数据库中所有书籍的数组。

准备工作

与之前的其他菜谱一样,我们使用相同的 Book 模型和 Books 表,来自之前的 使用活动记录从数据库中读取 菜谱。在开始此菜谱之前,请确保这些文件已就位。

如何做...

看看以下步骤:

  1. 在您的代码编辑器中打开 /config/site_post.php

  2. 加载模型:

    Loader::model('book');
    
  3. 创建 Book 模型的新实例:

    $book = new Book();
    
  4. 查找所有书籍记录:

    $books = $book->find('1=1');
    
  5. 遍历数组并输出每本书的标题:

    foreach ($books as $b) {
       echo $b->getTitle().'<br />';
    }
    exit;
    

它是如何工作的...

Model 类的 find 函数搜索数据库,并以数组的形式返回结果对象。由于 find 函数已经在查询中包含了 WHERE,因此我们需要通过一个真值条件来过滤,以找到所有记录,所以这里 1=1 就可以完成这个任务。

更多...

find 函数还支持使用预处理语句来搜索表。这里,我们将查找标题中包含 'concrete5' 的书籍:看看以下:

$books = $book->find('title LIKE "%?%"', 'concrete5');

参见

  • 创建自定义模型类 的菜谱

  • 使用活动记录从数据库中读取 的菜谱

使用活动记录和模型类删除对象

使用活动记录进行 CRUD 操作的最后一个方面是删除条目。在这个菜谱中,我们将加载 ID 为 1 的书籍并将其从数据库中删除。

准备工作

我们将使用与之前 使用活动记录从数据库中读取 菜谱中相同的 Book 模型和 Books 表。确保在开始此菜谱之前文件已经就绪。

如何做...

看看以下步骤:

  1. 在你的代码编辑器中打开 /config/site_post.php

  2. 加载模型:

    Loader::model('book');
    
  3. 创建模型的新实例:

    $book = new Book();
    
  4. 加载 ID 为 1 的书籍。

    $book->load('id = ?', '1');
    
  5. 删除那本书:

    $book->delete();
    exit;
    

它是如何工作的...

调用 Model 类的 delete 函数将在数据库上运行 DELETE 查询,永久删除与该条目关联的记录。使用你喜欢的 SQL 浏览工具,你可以看到记录已经被从数据库中删除。

参见

  • 创建自定义模型类 的菜谱

  • 使用活动记录从数据库中读取 的菜谱

使用活动记录定义关系

关系型数据库系统(如 MySQL)的主要特性是能够通过关系将数据链接到其他数据。考虑一个存储美国州和城市的数据库。每个州可以有多个城市,但每个城市只属于一个州。这些关系,“拥有多个”和“属于”,可以使用 concrete5 的活动记录支持来定义。

在这个菜谱中,我们将链接两个表,StatesCities,并使用这些关系来检索相关数据。

准备工作

首先,我们需要为 CitiesStates 两个表创建表。使用以下 SQL 来填充这些表(此 SQL 也可从本书的网站上下载):

CREATE TABLE `Cities` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(255) NOT NULL DEFAULT '',
  `state_id` int(11) NOT NULL,
  PRIMARY KEY (`id`)
);
INSERT INTO `Cities` (`id`, `name`, `state_id`)
VALUES
  (1,'New York',2),
  (2,'Buffalo',2),
  (3,'Green Bay',1),
  (4,'Chicago',3),
  (5,'San Francisco',4),
  (6,'San Diego',4),
  (7,'Oakland',4);
CREATE TABLE `States` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(255) NOT NULL DEFAULT '',
  PRIMARY KEY (`id`)
);
INSERT INTO `States` (`id`, `name`)
VALUES
  (1,'Wisconsin'),
  (2,'New York'),
  (3,'Illinois'),
  (4,'California');

如何做...

看看以下步骤:

  1. /models/state.php 中为州创建一个模型:

    class State extends Model {}
    
  2. /models/city.php 中为 city 创建一个模型:

    class City extends Model {}
    
  3. state 模型文件底部(类体外部),定义与 city 的关系:

    Model::ClassHasMany('State', 'Cities','state_id');
    
  4. 保存这两个类文件。

  5. 现在,我们将获取属于加利福尼亚州(ID 为 4 的州)的城市。

  6. 在你的代码编辑器中打开 /config/site_post.php,这样我们就可以运行一些代码。

  7. 加载 state 模型:

    Loader::model('state');
    
  8. 创建 state 模型的新实例:

    $state = new State();
    
  9. 加载 ID 为 4state(在我们的数据示例中是加利福尼亚州):

    $state->load('id = ?', '4');
    
  10. 使用活动记录关系获取州的城市:

    $cities = $state->Cities;
    
  11. 遍历城市并输出每个城市的名称:

    foreach ($cities as $city) {
       echo $city->name .'<br />';
    }
    exit;
    

它是如何工作的...

Model类上调用静态函数ClassHasMany接受三个参数。第一个参数是我们将此关系分配给类的名称(在这种情况下,State)。第二个参数是包含子内容的数据库表名称。第三个参数是外键的名称,它将用于确定哪些行是父类的子行。

还有更多...

也可以用类似的方式声明属于关系。

Model::ClassBelongsTo('City','State','state_id','id');

参见

  • 创建自定义模型类的配方

  • 使用活动记录从数据库中读取的配方

第六章:创建 CRUD 接口

在本章中,我们将涵盖以下内容:

  • 在仪表板上创建单页的控制器文件

  • 在仪表板上创建单页的视图文件

  • 将单页添加到仪表板

  • 创建创建项的表单

  • 从控制器将数据保存到数据库

  • 创建用于显示数据库项列表的视图

  • 添加编辑功能以创建表单

  • 创建删除操作

简介

concrete5 作为内容管理系统越来越受欢迎的一个特性是它允许开发者快速轻松地自定义它。在自定义内容管理系统时,一个常见的任务是创建自定义界面,以便网站编辑以一致的方式编辑特殊内容。

考虑一个管理数据库中书籍列表的网站。当然,网站编辑可以简单地像典型内容块一样维护这个列表,但这可能很繁琐,而且结果可能无法保证一致。这就是创建 CRUD 接口可以有益的地方。

CRUD(代表创建、读取、更新和删除)接口可以轻松添加到 concrete5 中,使用户能够轻松管理数据库中的自定义数据。在本章中,我们将学习如何在 concrete5 仪表板中创建 CRUD 接口。结合本章中的不同菜谱将产生一个完全功能的 CRUD,用于管理博客文章。

CRUD 接口主要围绕 单页 展开。在 concrete5 中,单页就像常规页面一样,只不过它们可以有一个 PHP 控制器文件和一个单独的视图文件,这允许高级功能。这允许开发者使用 MVC 规范并保持代码整洁。单页也被认为比常规页面更永久,因为它们不会被频繁地添加或删除。

关于本章数据的说明

本章将围绕在数据库中管理简单的博客文章。要处理这些数据,请在您的数据库上执行以下 SQL 代码。代码也将可在本书的网站上下载。

CREATE TABLE BlogPosts (
  id int(11) unsigned NOT NULL AUTO_INCREMENT,
  title varchar(255) NOT NULL DEFAULT '',
  content longtext NOT NULL,
  post_date datetime NOT NULL,
  PRIMARY KEY (id)
);
INSERT INTO BlogPosts (id, title, content, post_date)
VALUES
  (1,'Hello World','This is my first post!','2013-05-01 13:05:00'),
  (2,'Another Sample Post','Some more great content.','2013-05-10 14:42:00');

在仪表板上创建单页的控制器文件

在仪表板上创建用于显示的单页的第一步是为每个页面创建控制器文件。由于我们将创建用于添加、编辑和列出博客文章的页面,我们需要在仪表板上添加两个单页,一个是默认视图(将列出博客文章)和一个添加视图(将是一个用于添加和编辑文章的表单)。

准备工作

文件和目录的名称很重要;concrete5 需要它们与网站 URL 中显示的路径相匹配。例如,如果我们想让我们的博客文章列表出现在 http://example.com/dashboard/posts,我们命名文件和类时必须考虑到这一点。在这个菜谱中,我们将向 /dashboard/posts/dashboard/posts/add 添加单页。

如何做到这一点...

创建仪表板简单页面控制器文件的步骤如下:

  1. 使用您的操作系统文件管理器(或您喜欢的 FTP 工具或文本编辑器),在/controllers目录下创建一个名为dashboard/的目录。

  2. 现在,添加一个名为posts.php的文件。

  3. 接下来,在/controllers/dashboard中添加一个名为posts/的新目录。

  4. /controllers/dashboard/posts/add.php中添加添加/编辑表单的控制器文件。

  5. 您的文件和目录应如下截图所示:如何做...

  6. 在您首选的代码编辑器中打开/controllers/dashboard/posts.php文件。

  7. 声明控制器类,扩展核心控制器类,如下代码片段所示。保存此文件并关闭它。

    class DashboardPostsController extends Controller {
    }
    
  8. /controllers/dashboard/posts/add.php中打开文件。

  9. 声明表单控制器类,确保扩展核心控制器,如下代码片段所示。关闭此文件并保存它。

    class DashboardPostsAddController extends Controller {
    }
    

它是如何工作的...

concrete5 在处理单页时采用了约定优于配置的概念。开发者只需记住 concrete5 期望文件如何呈现,然后 concrete5 将负责加载类和实例化它们的所有工作。因此,文件和目录名称,以及控制器的类名都很重要。我们在这里创建的文件最终将在http://example.com/dashboard/postshttp://example.com/dashboard/posts/add处可用。

参见

  • 为仪表板上的单页创建视图文件配方

  • 将单页添加到仪表板配方

为仪表板上的单页创建视图文件

单页需要控制器和视图文件。遵循 MVC 设计原则规定,表示代码(HTML)应与控制器逻辑分开。添加视图文件与添加控制器非常相似,我们在前面的配方中已经学习过。

准备工作

就像我们添加控制器时一样,文件和目录名称在这里也很重要。

如何做...

创建简单页面视图文件的步骤如下:

  1. /single_pages目录下创建一个名为dashboard/的新目录。

  2. /single_pages/dashboard/posts.php中添加一个名为posts.php的文件。

  3. /single_pages/dashboard中添加一个名为posts/的目录。

  4. 现在,在/single_pages/dashboard/posts/中创建一个名为add.php的文件。

  5. 您的single_pages/目录的内容应如下截图所示:如何做...

它是如何工作的...

文件和目录名称应与页面在网站地图和 URL 中显示的方式一致。本配方中的文件和目录将生成位于http://example.com/dashboard/postshttp://example.com/dashboard/posts/add的单页。我们添加的 PHP 文件目前不需要包含任何内容。

参见

  • 为仪表板上的单页创建控制器文件配方

  • 将单页添加到仪表板 菜谱

将单页添加到仪表板

一旦在 concrete5 文件系统中创建了控制器和视图文件,在我们可以通过浏览器访问这些页面并开始添加自定义 CRUD 逻辑之前,还需要执行一个步骤。页面必须添加到 concrete5 网站地图中,这样 CMS 就知道页面存在,并且可以将请求定向到它们。

准备工作

在你可以将单页添加到网站之前,视图和控制器文件必须在文件系统中存在。请参考之前的两个菜谱了解如何正确执行此操作。

如何操作...

  1. 通过访问 /dashboard/pages/single(你可能需要登录)进入仪表板的单页管理器。页面将看起来像以下截图:如何操作...

  2. 输入文章页面的路径(/dashboard/posts)并点击 添加

  3. 输入添加页面的路径(/dashboard/posts/add)并点击 添加

  4. 页面现在已经被添加,可以通过访问它们的相应 URL 来查看。

它是如何工作的...

concrete5 将验证控制器和视图文件是否存在,然后会将新的单页添加到网站地图中。这使得页面可以通过 URL 访问,如果页面存储在仪表板中,concrete5 将自动对用户执行访问控制检查。

参见

  • 为仪表板上的单页创建控制器文件 菜谱

  • 为仪表板上的单页创建视图文件 菜谱

创建用于创建项目的表单

现在我们已经知道了如何将裸骨单页添加到仪表板中,我们可以创建真正的 CRUD 接口。我们将要编写的第一个接口是用于创建和编辑博客文章的表单。

准备工作

首先,你需要确保你知道如何为单页添加控制器和视图文件。请参考本章前三个菜谱,了解如何进行操作。

我们在本章中的博客文章将包含三个字段:标题内容发布日期标题内容字段将由用户通过本菜谱中的表单设置,而发布日期将由我们的控制器在表单提交后设置。

为了使本章内容集中,我们省略了围绕表单的大部分无关 HTML。如果你在表单的标记方面遇到麻烦,请参考本书的网站以查看完整的 HTML 代码。

如何操作...

创建用于创建项目的表单的步骤如下:

  1. 在你喜欢的代码编辑器中打开 /single_pages/dashboard/posts/add.php

  2. 我们将使用表单助手,所以请将此助手加载到文件顶部。

    <?php $form = Loader::helper('form') ?>
    
  3. 将所有内容包裹在一个带有 ccm-ui 类的 div 标签中,这样我们的表单就能利用 concrete5 中包含的 Bootstrap 样式。

    <div class="ccm-ui">
    
  4. 使用仪表板助手输出表单标题的适当 HTML。

    <?php
       $dashboard = Loader::helper('concrete/dashboard');
       echo $dashboard->getDashboardPaneHeader('Title');
    ?>
    
  5. 将表单的 action 设置为控制器的 save 函数,并确保它以 POST 请求发送数据。

    <form action="<?php echo $this->action('save') ?>" method="POST">
    
  6. 输出 title 字段的输入。

    <?php echo $form->text('title') ?>
    
  7. 输出 content 字段的输入。

    <?php echo $form->textarea('content') ?>
    
  8. 创建提交按钮。

    <input class="btn btn-primary" type="submit" value="Save">
    
  9. 创建一个取消按钮,并在点击时将用户带回到文章列表。

    <a href="<?php echo $this->url('/dashboard/posts') ?>" class="btn">Cancel</a>
    
  10. 保存 add.php 视图文件,因为现在是时候移动到控制器了。

它是如何工作的...

add.php 视图文件是一个 concrete5 View 对象的界面。因此,$this 关键字被设置为 View 类的一个实例。在 $this 关键字上使用 actionurl 等函数将生成了解 concrete5 网站设置的 URL,例如,如果网站启用了漂亮 URL,或者网站位于子目录中。

使用表单辅助工具,我们可以快速输出需要在表单上显示的字段。当我们在本章后面添加编辑数据的能力时,表单辅助工具将更加有用。

更多内容...

如本章开头所述,这里围绕表单的大多数样板 HTML 都被省略了。如果您想查看整个页面的结构,请从本书的网站上下载完整的源代码。

相关内容

  • 为仪表板上的单页创建控制器文件 的菜谱

  • 为仪表板上的单页创建视图文件 的菜谱

  • 将单页添加到仪表板 的菜谱

  • 在 第四章 中加载辅助类 的菜谱,使用核心辅助工具

  • 使用 Form 辅助工具创建自定义表单 的菜谱在 第四章,使用核心辅助工具

  • 从控制器将数据保存到数据库 的菜谱

从控制器将数据保存到数据库

一旦您创建了表单的 HTML(和相关辅助 PHP),就是时候让这个表单做些事情了。在前一个菜谱中,我们将 HTML 表单的动作设置为控制器的 save 动作。在这个菜谱中,我们将编写那个保存动作的代码,这样一旦点击保存按钮,我们的博客文章就会被存储到数据库中。

准备工作

这个菜谱继续本章的主题,为管理简单的博客文章创建一个 CRUD 接口。在开始这一部分之前,请确保本章中之前的菜谱已经完成。同时,请确保在章节介绍中指定的数据库表存在。

如何做到这一点...

从控制器将数据保存到数据库的步骤如下:

  1. /models/blog_post.php 中创建一个新的模型。

  2. 在您的代码编辑器中打开 /models/blog_post.php 并创建 BlogPost 类。

    class BlogPost extends Model {
       var $_table = 'BlogPosts';
    }
    
  3. 在您首选的代码或文本编辑器中打开 /controllers/dashboard/posts/add.php

  4. 定义 save 函数。

    public function save() {
    }
    
  5. save 函数中,加载 BlogPost 模型。

    Loader::model('blog_post');
    
  6. 创建 BlogPost 模型的新实例。

    $post = new BlogPost();
    
  7. title 设置为 HTTP POST 请求中提交的值。

    $post->title = $this->post('title');
    
  8. 内容 设置为表单 POST 请求中提交的值。

    $post->content = $this->post('content');
    
  9. 发布日期 设置为当前日期/时间。

    $post->post_date = date('YYYY-MM-DD H:i:s');
    
  10. 保存模型。

    $post->save();
    
  11. 将用户重定向到帖子列表,这将表明保存成功。

    $this->redirect('/dashboard/posts');
    

它是如何工作的...

当对 /dashboard/posts/add/save 发起 HTTP 请求(GETPOST)时,会运行 save 函数,这正是 HTML 表单提交数据的地方。我们加载 BlogPost 模型并设置其每个属性,最后将新项目保存到数据库中,并将用户重定向到帖子列表。

更多内容...

在实际使用中,您可能希望使用验证助手来确保用户已正确填写表单,并且标题和内容字段均不为空。

参见

  • 在仪表板上为单页创建控制器文件 菜谱

  • 在仪表板上为单页创建视图文件 菜谱

  • 将单页添加到仪表板 菜谱

  • 创建用于创建项目的表单 菜谱

  • 第五章, 使用数据库和模型

创建用于显示数据库项目列表的视图

现在我们可以向数据库中添加项目,确实很希望有一个界面来显示表中已经存在的项目,并从那里添加、编辑和删除这些项目。

在本菜谱中,我们将通过创建一个列出数据库中所有博客文章的 HTML 表格来处理 CRUD 接口的读取方面,并提供编辑和删除这些项目的按钮。

准备工作

与本章中的其他菜谱一样,我们将处理简单的博客文章。确保在处理此菜谱之前已完成前面的菜谱,否则可能会有缺失的步骤!

为了保持本章重点在重要的代码上,本节中省略了此菜谱中的一些样板 HTML。本书的网站包含一个完整的源代码下载,允许您探索此界面中的整个 HTML 代码。

如何操作...

创建用于显示数据库项目列表的视图的步骤如下:

  1. 在您首选的文本编辑器中打开 /controllers/dashboard/posts.php

  2. 定义 view 函数,该函数将在页面加载时自动运行。

    public function view() {
    }
    
  3. view 函数中,加载 BlogPost 模型。

    Loader::model('blog_post');
    
  4. 创建 BlogPost 的新实例。

    $post = new BlogPost();
    
  5. 通过向 find 函数传递一个真值条件(1=1)来查找所有博客文章。

    $posts = $post->find('1=1');
    
  6. 在视图中设置一个名为 $posts 的变量,其值等于模型查询的结果。

    $this->set('posts', $posts);
    
  7. 保存控制器文件。

  8. 打开位于 /single_pages/dashboard/posts.php 的帖子索引视图。

  9. 确保创建一个具有 ccm-ui 类的 div 标签,以便使用内置的 Bootstrap 样式。

    <div class="ccm-ui">
    
  10. 使用仪表板助手生成标题部分的 HTML。

    <?php
      $dashboard = Loader::helper('concrete/dashboard');
      echo $dashboard->getDashboardPaneHeader('Blog Posts');
    ?>
    
  11. 创建一个表格来存放帖子。

    <table class="table table-striped table-bordered">
    
  12. 我们需要为将要显示的四个列添加标题。

    <th>ID</th>
    <th>Title</th>
    <th>Post Date</th>
    <th>Actions</th>
    
  13. 遍历控制器中设置的$posts变量,输出每行的帖子。最后一列将包含编辑或删除每个帖子的按钮。

    <?php foreach ($posts as $post): ?>
      <tr>
        <td><?php echo $post->id ?></td>
        <td><?php echo $post->title ?></td>
        <td><?php echo date('DATE_APP_GENERIC_MDY_FULL,strtotime($post->post_date)) ?></td>
        <td>
          <a href="<?php echo $this->url('/dashboard/posts/add/edit/', $post->id) ?>" class="btn">Edit</a>
          <a href="<?php echo $this->action('/dashboard/posts/delete/', $post->id) ?>" class="btn danger">Delete</a>
        </td>
       </tr>
    <?php endforeach; ?>
    
  14. 保存视图文件。

它是如何工作的...

当对/dashboard/posts/进行 HTTP GETPOST请求时,帖子控制器的view函数会自动执行。在这个函数中,我们从BlogPost模型加载数据,然后将这些数据发送到视图。这允许我们将真实业务逻辑从视图文件中分离出来,创建更多可重用和可维护的代码。

参见

  • 在仪表板上创建单页控制器文件的配方

  • 在仪表板上创建单页视图文件的配方

  • 将单页添加到仪表板的配方

  • 创建创建项的表单的配方

  • 从控制器将数据保存到数据库的配方

为创建表单添加编辑功能

现在我们已经添加了创建和查看项的功能,是时候为 CRUD 界面添加第三个方面:编辑。在这个配方中,我们将实现编辑项所需的逻辑,使用我们在创建创建项的表单配方中创建的表单。

准备工作

与本章中其他配方一样,这个配方围绕管理简单博客文章的概念展开,每篇文章都有一个标题、一段内容文本和一个帖子日期。在开始这段最新的旅程之前,请确保已经完成了之前的配方!本配方的 MySQL 数据也包含在本章的开头以及本书的网站上。

如何操作...

为创建表单添加编辑功能的步骤如下:

  1. 打开添加表单的控制器文件(位于/controllers/dashboard/posts/add.php)。

  2. 声明一个名为edit的函数,该函数有一个参数用于编辑帖子的ID参数。

    public function edit($id) {
    }
    
  3. edit函数中,加载blog post模型。

    Loader::model('blog_post');
    
  4. 创建model类的实例。

    $post = new BlogPost();
    
  5. 使用通过编辑 URL 传递的ID参数加载post对象。

    $post->load('id = ?', $id);
    
  6. post变量设置到视图中,将post对象转换为数组,以防止在没有设置帖子对象时添加表单损坏。

    $this->set($post, (array) $post);
    
  7. 在控制器的save函数中,在$post = new BlogPost()下方添加以下代码;

    if ($this->post('id')) {
      $post->load('id = ?', $this->post('id'));
    }
    
  8. save函数调用更改为使用replace函数。

    $post->replace();
    
  9. 保存控制器文件。

  10. 打开位于/single_pages/dashboard/posts/add.phpview文件

  11. title输入添加第二个参数,如果存在,将填充帖子的标题。

    <?php echo $form->text('title', $post['title']) ?>
    
  12. content输入参数添加第二个参数,当表单处于编辑模式时将预填充内容。

    <?php echo $form->textarea('content', $post['content']) ?>
    
  13. 在关闭表格标签下方,添加以下代码片段以在表单处于编辑模式时添加一个隐藏的输入:

    <?php if ($post['id']): ?>
       <?php echo $form->hidden('id', $post['id']) ?>
    <?php endif; ?>
    
  14. 保存view文件。

它是如何工作的...

当请求 URL /dashboard/posts/add/edit/<id> 时,concrete5 将自动触发控制器的 edit 函数,并将 ID 参数作为第一个参数传递。然后我们可以加载相应的模型并将数据发送到视图。我们需要将帖子数据转换为数组,这样即使在非编辑模式下表单也能正常工作。

我们还在 save 函数中添加了一个小片段,以确保如果 POST 请求中包含 ID,则需要保存现有帖子而不是创建一个新的。通过将 save 函数调用更改为 replace,我们告诉模型如果不存在,则创建一个新的记录,否则将简单地更新现有的模型。

更多...

在实际使用中,检查编辑函数中的 ID 参数以确保它已设置是明智的。同时,处理加载不存在的帖子请求也是一个好主意。

相关内容

  • 为仪表板上的单个页面创建控制器文件 配方

  • 为仪表板上的单个页面创建视图文件 配方

  • 添加单个页面到仪表板 配方

  • 创建创建项的表单 配方

  • 从控制器将数据保存到数据库 配方

创建删除操作

CRUD 界面的最后一个支柱是删除项的能力。在 concrete5 中,这比其他 CRUD 任务要简单一些,因为删除项通常不需要视觉组件。在这个配方中,我们将删除一个博客文章,并将用户简单地重定向回帖子的索引视图。

准备工作

我们将继续使用简单博客文章的概念。这个配方假设你已经完成了本章中的前一个配方,并且创建了适当的数据库表。

如何操作...

  1. 打开位于 /controllers/dashboard/posts.php 的控制器文件。

  2. 声明一个新的名为 delete 的函数,它有一个参数,$id

    public function delete($id) {
    }
    
  3. delete 函数中,加载 博客帖子 模型。

    Loader::model('blog_post');
    
  4. 创建模型的新实例。

    $post = new BlogPost();
    
  5. 通过其 ID 加载帖子。

    $post->load('id = ?', $id);
    
  6. 通过调用 delete 函数删除帖子。

    $post->delete();
    
  7. 将用户重定向回帖子索引。

    $this->redirect('/dashboard/posts');
    

工作原理...

当请求 /dashboard/posts/delete/<id> 时,将执行帖子控制器的 delete 函数。在这个控制器中,我们简单地通过其 ID 加载一个帖子,然后调用模型的内置 delete 函数。然后,我们只需将用户重定向回帖子列表。

更多...

在删除之前验证指定 ID 的帖子是否存在是明智的。此外,大多数用户在执行此类破坏性操作之前都会期望某种类型的确认对话框,所以在现实生活中添加这个功能会很好。

相关内容

  • 为仪表板上的单个页面创建控制器 配方

  • 为仪表板上的单个页面创建视图文件 配方

  • 添加单个页面到仪表板 配方

第七章. 与用户和权限协作

本章我们将涵盖以下内容:

  • 检查当前用户是否登录

  • 获取当前登录用户

  • 通过 ID 加载用户

  • 通过用户名加载用户

  • 获取用户信息

  • 设置用户的属性

  • 获取用户的属性

  • 通过 ID 加载一个组

  • 通过名称加载一个组

  • 将用户添加到组中

  • 从一个组中获取所有用户

  • 检查用户是否是某个组的成员

  • 从组中移除用户

  • 用户登出

  • 删除用户

  • 获取权限对象

  • 检查用户是否可以写入页面

  • 检查用户是否有编辑页面的权限

  • 检查用户的文件权限

简介

concrete5 最伟大的属性之一是围绕用户和权限的功能。concrete5 使得控制哪些用户和用户组可以访问特定页面变得容易。在 concrete5 中,用户可以是网站编辑者、管理员、社区成员或网站所有者可以设定的任何其他角色。

在本章中,我们将探讨几个配方,允许开发者与用户对象、组和它们相关的权限进行交互和操作。本章中的配方将赋予 concrete5 开发者将强大的用户和权限模型纳入他们自己的自定义应用程序和网站的能力。

检查当前用户是否登录

concrete5 开发中最常见的任务之一是找出用户是否登录到网站上。在这个配方中,如果用户已登录,我们将输出一些 HTML 来向登录用户打招呼。如果他们未登录,我们将输出一个指向登录页面的链接。

如何操作...

检查当前用户是否登录的步骤如下:

  1. 检查当前用户是否已登录。

    $isLoggedIn = User::isLoggedIn();
    
  2. 如果他们已登录,显示欢迎信息。

    if ($isLoggedIn) {
      echo '<p>Thanks for logging in!</p>';
    }
    
  3. 否则,显示登录页面的链接。

    else {
      echo '<a href="/login">Login</a>';
    }
    

它是如何工作的...

用户模型包含一个名为isLoggedIn的静态函数,它将简单地返回一个布尔结果。这不会将任何类型的权限检查混合其中,只是检查查看页面的人是否已登录。

获取当前登录用户

concrete5 使得获取当前登录用户的对象变得非常容易。在这个配方中,我们将输出当前登录用户的用户名。

准备工作

在尝试显示用户名之前确保用户已登录是一个好主意。我们将使用前一个配方中的技能来确保用户首先登录。

如何操作...

获取当前登录用户的步骤如下:

  1. 检查用户是否登录。

    $isLoggedIn = User::isLoggedIn();
    
  2. 如果用户已登录,创建User类的新实例。

    $user = new User();
    
  3. 输出user对象的用户名。

    echo $user->getUsername();
    

它是如何工作的...

concrete5 使得获取当前登录用户变得极其容易。本质上,我们只需要实例化User类,它将返回一个代表当前登录用户的对象。

参见

  • 检查当前用户是否已登录 食谱

  • 获取用户信息 食谱

通过 ID 加载用户

开发者也可以通过唯一的 ID 加载用户。在本食谱中,我们将加载 ID 为 1 的用户,并输出其用户名。

如何操作...

通过 ID 加载用户的步骤如下:

  1. 确定要加载的用户的 ID。在本例中,我们将加载 ID 为 1 的用户。

    $userId = 1;
    
  2. 通过 ID 加载用户。

    $user = User::getByUserID($userId);
    
  3. 输出用户的用户名。

    echo $user->getUserName();
    

工作原理...

concrete5 将在数据库的Users表中查找并返回一个包含相应记录数据的用户对象。

相关内容

  • 通过用户名加载用户 食谱

通过用户名加载用户

除了能够通过 ID 加载用户外,开发者还可以通过用户名加载用户。在本食谱中,我们将加载用户名为 admin 的用户,并输出其数值 ID。

如何操作...

通过用户名加载用户的步骤如下:

  1. 确定要加载的用户的用户名。

    $username = 'admin';
    
  2. 通过用户名加载用户。

    $user = UserInfo::getByUserName($username);
    
  3. 输出用户的 ID。

    echo $user->getUserID();
    

工作原理...

嘿,这很简单!UserInfo类包含通过用户名而不是 ID 加载用户的方法。UserInfo类还有一个获取用户数值 ID 的方法。

相关内容

  • 通过 ID 加载用户 食谱

  • 获取当前登录用户 食谱

获取用户信息

用户对象携带大量信息,包括用户的用户名、电子邮件和几个其他属性。在本食谱中,我们将运行几个函数来检索与用户关联的数据。

准备工作

本章的代码不一定属于 concrete5 的任何特定位置。本食谱的步骤是基本的单行函数,用于展示从用户对象获取数据的不同方法。如果您需要一个可以写入任意代码并由 concrete5 评估的地方,config/目录下的site_post.php文件是一个不错的选择。

如何操作...

获取用户信息步骤如下:

  1. 首先,我们将加载当前登录的用户。

    $user = new User();
    
  2. 获取用户的 ID。

    $userId = $user->getUserID();
    
  3. 获取用户的用户名。

    $username = $user->getUserName();
    
  4. 检查用户是否在该网站上注册。

    $isRegistered = $user->isRegistered();
    
  5. 检查用户的账户是否活跃。

    $isActive = $user->isActive();
    
  6. 检查用户是否是超级管理员。

    $isSuper = $user->isSuperUser();
    
  7. 加载包含更多用户信息的UserInfo对象。

    $userInfo = UserInfo::getByID($userId);
    
  8. 获取用户的电子邮件地址。

    $email = $userInfo->getUserEmail();
    
  9. 获取用户的加密密码。

    $password = $userInfo->getUserPassword();
    
  10. 获取用户登录次数。

    $loginCount = $userInfo->getNumLogins();
    
  11. 查询用户是否已验证他们的电子邮件地址。

    $verifiedEmail = $userInfo->isValidated();
    
  12. 获取用户上次登录的 Unix 时间戳。

    $previousLogin = $userInfo->getPreviousLogin();
    
  13. 查询用户是否已上传头像到网站。

    $hasAvatar = $userInfo->hasAvatar();
    
  14. 查询用户何时被添加到网站上。

    $dateAdded = $userInfo->getUserDateAdded();
    

工作原理...

User类包含一些检索基本用户数据的方法,例如用户的 ID 和用户名。当开发者想查看更多关于用户的信息时,他们需要使用UserInfo类。

相关内容

  • 获取当前登录用户 菜谱

设置用户属性

concrete5 的用户可以拥有自定义属性,这些属性通过界面定义。想象一下一个你想知道用户年龄的网站。concrete5 默认不提供用户年龄字段,但可以通过属性轻松添加。

准备工作

首先,在尝试设置属性之前,您需要确保该属性存在于 concrete5 网站中。请访问 http://example.com/dashboard/users/attributes(当然,用您自己的域名替换 example.com),并确保您创建的属性存在。页面看起来类似于以下截图:

准备工作

在这个菜谱中,我们将使用名为年龄的属性,所以请随意创建该属性以跟随操作。

如何操作...

设置用户属性的分步如下:

  1. 加载当前登录用户。

    $user = new User();
    
  2. 加载该用户的 UserInfo 对象。

    $userInfo = UserInfo::getByUserID($user->getUserID());
    
  3. 将年龄属性设置为 35

    $userInfo->setAttribute('age', 35);
    

工作原理...

UserInfo 类包含一个名为 setAttribute 的函数,该函数可以接受一个表示属性键处理的字符串,或者一个实际的 AttributeKey 对象实例。在这个菜谱中,我们选择了更简单的方法,即在字符串中提供属性处理。

相关链接

  • 检索用户属性 菜谱

  • 获取当前登录用户 菜谱

  • 获取用户信息 菜谱

检索用户属性

除了设置属性外,我们还可以检索它们。在这个菜谱中,我们将检索用户年龄的属性,这是我们之前设置的。

准备工作

与之前的菜谱一样,您需要确保您正在检索的任何属性实际上存在于 concrete5 中。在这种情况下,我们将引用一个名为 age 的属性。如果您的 concrete5 系统中没有名为年龄的用户属性,请根据您的需求调整此菜谱。

如何操作...

检索用户属性的分步如下:

  1. 加载当前登录用户。

    $user = new User();
    
  2. 获取用户的 user info 对象。

    $userInfo = UserInfo::getByID($user->getUserID());
    
  3. 获取用户年龄属性的值。

    $age = $userInfo->getAttribute('age');
    

工作原理...

concrete5 提供了一个简单的 API 来从用户中检索属性。在数据库中,属性键和值分布在几个表中,手动查询比较困难。这种方法是检索用户属性的首选方式。

更多内容...

concrete5 还使用“魔法方法”来检索用户属性。本质上,调用一个以属性处理 camelCase 版本为名称的函数,前面加上单词 get。在这个菜谱中,要获取用户的年龄,我们可以简单地编写以下代码:

$age = $userInfo->getAge();

相关链接

  • 设置用户属性 菜谱

  • 获取当前登录用户 菜谱

  • 获取用户信息 菜谱

通过其 ID 加载组

concrete5 中的组是按用户在网站上的角色组织用户的方式。组可以接收权限设置,就像用户可以一样。在这个配方中,我们将加载 ID 为 3 的组(在大多数 concrete5 安装中是管理员组)。

如何操作...

按 ID 加载组的步骤如下:

  1. 确定我们想要加载的组的 ID。

    $groupId = 3;
    
  2. 按 ID 加载组。

    $group = Group::getByID($groupId);
    
  3. 输出组变量的名称以确保它已正确加载。

    echo $group->gName;
    exit;
    

它是如何工作的...

concrete5 将简单地查询数据库中的Groups表以找到与提供的 ID 相对应的组记录。

参见

  • 按名称加载组配方

按名称加载组

组可以通过其名称加载,这在您不知道组的数字 ID 时可能很有用。

如何操作...

按名称加载组的方法如下:

  1. 定义您要加载的组的名称。

    $groupName = 'Administrators';
    
  2. 按名称加载组。

    $group = Group::getByName($groupName);
    
  3. 输出组变量以确保正确加载了组。

    var_dump($group);
    

它是如何工作的...

concrete5 查询数据库以找到与您提供给getByName函数的名称相同的组。组名称可以通过 concrete5 仪表板随时更改,因此在您的应用程序中硬编码组名称时要小心。

参见

  • 按 ID 加载组配方

向组中添加用户

虽然 concrete5 仪表板提供了一个简单的界面来向不同的组添加用户,但有时您可能需要以编程方式执行此操作。在这个配方中,我们将向 ID 为 3 的管理员组(在大多数 concrete5 安装中是管理员组)添加 ID 为 1 的用户。

如何操作...

添加用户到组的步骤如下:

  1. 定义您要加载的用户的 ID。

    $userId = 1;
    
  2. 按 ID 加载用户。

    $user = User::getByID($userId);
    
  3. 定义您想要添加用户到的组的 ID。

    $groupId = 3;
    
  4. 按 ID 加载组。

    $group = Group::getByID($groupId);
    
  5. 将用户添加到组中。

    $user->enterGroup($group);
    

它是如何工作的...

当调用用户模型的enterGroup函数时,用户将被添加到作为第一个参数传递的组中。现在,该用户将继承与该组关联的所有权限。

参见

  • 按 ID 加载用户配方

  • 按 ID 加载组配方

  • 从组中删除用户配方

从组中获取所有用户

一旦加载了组对象,您可以轻松地遍历该组的成员。在这个配方中,我们将加载一个组,然后输出组内每个成员的用户名。

如何操作...

获取组中所有用户的步骤如下:

  1. 定义您要加载的组的 ID。

    $groupId = 3;
    
  2. 按 ID 加载组。

    $group = Group::getByID($groupId);
    
  3. 获取组成员数组。

    $members = $group->getGroupMembers();
    
  4. 遍历成员数组,回显用户名。

    foreach ($members as $member) {
      echo $member->getUserName().'<br />';
    }
    

它是如何工作的...

如同往常,concrete5 在这里负责查询数据库以找到所有已加载的组成员的用户账户。getGroupMembers函数返回一个UserInfo对象的数组,可以用来读取和修改组成员。

参见

  • 通过 ID 加载组 的配方

  • 获取用户信息 的配方

检查用户是否是组成员

concrete5 自带了一个强大的权限模型,但有时开发者可能希望在自己的代码中执行简单的权限和访问控制任务。在这个配方中,我们将检查用户是否在管理员组中。然后,我们将显示一个消息,指示他们是否是管理员。

如何操作...

检查用户是否是组成员的步骤如下:

  1. 加载当前登录用户。

    $user = new User();
    
  2. 确定您要加载的组的 ID(在这个例子中,是 ID 为 3 的管理员组)。

    $groupId = 3; // administrators
    
  3. 通过其 ID 加载组。

    $group = Group::getByID($groupId);
    
  4. 检查用户是否是组成员。

    $isAdmin = $user->inGroup($group);
    
  5. 向用户显示消息,确认或否认他们是否是管理员组的成员。

    if ($isAdmin) {
      echo 'You\'re an administrator!';
    }
    else {
      echo 'You are not an administrator.';
    }
    

它是如何工作的...

concrete5 会检查用户是否是特定组对象的成员,并返回一个布尔值。

参见

  • 通过 ID 加载组 的配方

  • 获取当前登录用户 的配方

从组中删除用户

除了能够将用户添加到组中,concrete5 还允许开发者执行相反的任务:从组中删除用户。在这个配方中,我们将从管理员组中删除一个用户。

如何操作...

从组中删除用户的步骤如下:

  1. 加载当前登录用户。

    $user = new User();
    
  2. 定义您要加载的组的 ID。

    $groupId = 3; // administrators
    
  3. 通过其 ID 加载组。

    $group = Group::getByID($groupId);
    
  4. 检查此用户是否是组成员。

    $inGroup = $user->inGroup($group);
    
  5. 如果用户是成员,则从组中移除他们。

    if ($inGroup) {
      $user->exitGroup($group);
    }
    

它是如何工作的...

在这种情况下,concrete5 将简单地删除用户和组之间的关联。用户将失去从组继承的所有权限。

参见...

  • 将用户添加到组中 的配方

  • 通过 ID 加载组 的配方

  • 获取当前登录用户 的配方

  • 检查用户是否是组成员 的配方

注销用户

concrete5 还包含程序化注销用户的函数。在这个配方中,我们将注销当前登录的用户。

如何操作...

注销用户的步骤如下:

  1. 检查用户是否已登录。

    $loggedIn = User::isLoggedIn();
    
  2. 加载登录用户。

    $user = new User();
    
  3. 注销用户。

    if ($loggedIn) {
      $user->logout();
    }
    

它是如何工作的...

concrete5 删除当前会话,实际上注销了用户。

参见

  • 检查当前用户是否已登录 的配方

  • 获取当前登录用户 的配方

删除用户

在这个配方中,我们将加载 ID 为 3 的用户,并将其从 concrete5 中删除。

如何操作...

删除用户的步骤如下:

  1. 定义您要删除的用户的 ID。

    $userId = 3;
    
  2. 加载该用户的UserInfo对象。

    $user = UserInfo::getByID($userId);
    
  3. 删除用户。

    $user->delete();
    

它是如何工作的...

concrete5 将从数据库中删除用户及其所有属性。此操作是不可逆的,除非恢复数据库备份。

相关内容

  • 获取用户信息的食谱

获取权限对象

验证和修改页面权限,主要围绕权限对象展开。在本食谱中,我们将加载页面的权限对象。

如何操作...

获取权限对象步骤如下:

  1. 指定您要检查权限设置的页面路径。

    $path = '/about';
    
  2. 通过路径加载页面。

    $page = Page::getByPath($path);
    
  3. 加载该页面的permissions对象。

    $permissions = new Permissions($page);
    
  4. permissions对象导出以验证其内容。

    var_dump($permissions);
    

它是如何工作的...

concrete5 将返回一个permissions对象,可以进一步用来确定用户是否有权在该页面上执行各种操作。

更多内容...

您还可以获取内容区域和块的permissions对象,只需将块或区域对象传递给Permissions构造函数,而不是Page对象。

相关内容

  • 在第一章的获取页面对象路径中,页面和页面类型

检查用户是否有阅读页面权限

您可能会发现有时您需要手动确定用户是否有权阅读特定的页面。在本食谱中,我们将通过路径加载页面,获取其permissions对象,然后确定用户是否有权查看该页面。

如何操作...

检查用户是否有阅读页面权限的步骤如下:

  1. 确定要加载的页面的路径。

    $path = '/about';
    
  2. 通过路径加载页面。

    $page = Page::getByPath($path);
    
  3. 加载该页面的permissions对象。

    $permissions = new Permissions($page);
    
  4. 查看用户是否有权阅读该页面。

    $canRead = $permissions->canRead();
    var_dump($canRead);
    exit;
    

它是如何工作的...

concrete5 将检查该Page对象的全部权限,包括组和用户权限,以确定当前用户是否有权查看该页面。canRead函数返回一个布尔值。

更多内容...

可以通过简单地向Permissions构造函数提供一个区域或块对象,而不是Page对象来检查内容区域和块的读取权限。

相关内容

  • 在第一章的获取页面对象路径中,页面和页面类型

  • 获取权限对象的食谱

检查用户是否有编辑页面的权限

除了能够检查用户是否可以查看页面外,开发者还可以手动检查登录用户是否有编辑页面的能力。在本食谱中,我们将通过路径加载页面,获取该页面的permissions对象,然后确定用户是否有权编辑它。

如何操作...

检查用户是否有编辑页面权限的步骤如下:

  1. 指定要加载的页面路径。

    $path = '/about';
    
  2. 加载页面。

    $page = Page::getByPath($path);
    
  3. 加载页面的permissions对象。

    $permissions = new Permissions($page);
    
  4. 查看用户是否有编辑页面的权限。

    $canEdit = $permissions->canWrite();
    var_dump($canEdit);
    exit;
    

它是如何工作的...

concrete5 将查看用户的个人权限设置以及它所属的任何组的设置,并确定用户是否有能力编辑或写入指定的页面。

更多内容...

与读取权限一样,内容区域和块权限也可以使用此方法进行检查。只需提供一个区域或块的实例而不是页面,权限将针对这些项目进行检查。

相关内容

  • 通过路径获取页面对象的配方

  • 获取权限对象的配方

检查用户的文件权限

concrete5 允许网站所有者指定文件管理器的权限。在本配方中,我们将查看用户是否被允许将文件上传到文件管理器。

如何操作...

检查用户文件权限的步骤如下:

  1. 加载 FilePermissions 全局对象。

    $permissions = FilePermissions::getGlobal();
    
  2. 检查用户是否可以查看 文件管理器 界面。

    $canUpload = $permissions->canAddFiles();
    
  3. 检查用户是否可以上传到文件管理器。

    $canViewFileManager = $permissions->canAccessFileManager();
    

它是如何工作的...

FilePermissions 类扩展了 Permissions 类,并允许用户检查文件管理器的全局设置。

更多内容...

concrete5 还允许开发者检查用户是否被允许上传特定类型的文件。

$canUploadMp3 = $permissions->canAddFileType('mp3');

第八章. 使用主题和附加包

在本章中,我们将涵盖以下内容:

  • 创建一个自定义主题

  • 包含 concrete5 所需的脚本和样式

  • 定义可编辑的内容区域

  • 创建页面类型模板

  • 使用元素重复 HTML 的某些部分

  • 自定义系统页面

  • 创建一个自定义的附加包

  • 使用包控制器执行自定义代码

简介

concrete5 与其他内容管理系统略有不同。当然,它拥有世界级的内联编辑功能和强大的开发框架,但它也非常容易创建自定义主题和附加包。开发者和设计师甚至可以在 concrete5 市场中销售他们的作品。在本章中,我们将学习如何创建一个非常基本的主题,以及如何创建一个简单的附加包。尽管每个食谱都有其自己的目的,但对于初学者来说,按照顺序运行这些食谱以确保获得所有必需的知识可能是有用的。

创建一个自定义主题

主题是任何内容管理系统的一个基本组成部分,这是有充分理由的。没有人希望他们的网站看起来和其他所有网站一样。concrete5 附带了一些看起来不错的主题,但很多时候您或您的客户可能希望开发一个自定义主题。实际上,创建主题的主题可以相当长,甚至有整本书专门介绍这个话题(由 Remo Laubacher 所著,Packt Publishing 出版的《Creating concrete5 Themes》一书强烈推荐)。在本食谱中,我们将仅演示在 concrete5 中创建自定义主题的最基本要求。

准备工作

本食谱的完整基本主题代码可在本书的网站上免费获取。

如何操作...

创建自定义主题的步骤如下:

  1. /themes目录下创建一个名为basic_theme的新目录。

  2. basic_theme目录下创建一个名为description.txt的文件。

  3. 在描述文件的第一个位置放置主题的标题。

    Basic Theme
    
  4. 在文本文件的第二行放置对主题的简要描述。

    This theme is extremely basic
    
  5. 保存description.txt文件。

  6. /themes/basic_theme目录下创建一个名为default.php的新文件。

  7. 在文件中输入以下基本的 HTML 代码:

    <!DOCTYPE html>
    <html>
      <head>
        <title>My Super Basic Theme</title>
      </head>
      <body>
        <h1>Hi, this is my super basic theme. It's really boring.</h1>
      </body>
    </html>
    
  8. 保存default.php

  9. 创建一个名为view.php的文件并保持它为空。

  10. 访问您网站仪表板的主题区域,网址为http://example.com/dashboard/pages/themes

  11. 点击您新主题的安装按钮。页面将看起来像以下截图:如何操作...

  12. 点击激活然后点击确定以将主题应用到您网站的所有页面。

  13. 您的网站现在应该看起来像以下截图:

如何操作...

它是如何工作的...

concrete5 只要求主题中存在description.txtdefault.phpview.php这三个文件。description.txt文件包含主题的标题和描述。

更多内容...

显然,这对于实际使用来说将是不可用的。没有地方可以放置内容!concrete5 的编辑栏在哪里?接下来的几个菜谱将在此基础上扩展这个简单主题,使其成为一个真正的 concrete5 主题。

参见

  • 包括 concrete5 所需的脚本和样式 菜谱

  • 使用元素为 HTML 的重复部分 菜谱

  • 定义可编辑的内容区域 菜谱

包括 concrete5 所需的脚本和样式

您可能已经注意到,在上一道菜谱中创建的极其简单的主题之后,通常出现在屏幕顶部的 concrete5 编辑栏已经消失了。这是因为该主题没有包括 concrete5 需要执行其工作的必需的 JavaScript 和 CSS 文件集合。在本菜谱中,我们将添加必要的代码,将这些组件包含到我们的简单主题中。

准备工作

本菜谱将在前一道菜谱中的简单主题代码基础上进行构建。您可以自由地从本书的网站上下载源代码以跟上进度,或者调整这个菜谱以适应您自己的主题。

如何做...

包括 concrete5 所需脚本和样式的步骤如下:

  1. 打开存储我们主题 HTML 的 /themes/basic_theme/default.php 文件。

  2. 删除 <title> 标签,因为我们不再需要它。

  3. 在关闭 </head> 标签之前,将以下代码添加到文件中:

    <?php Loader::element('header_required') ?>
    
  4. 在关闭 </body> 标签之前,将以下代码添加到文件中:

    <?php Loader::element('footer_required') ?>
    
  5. 刷新网站。

它是如何工作的...

通过调用 Loader::element,我们实际上是将 PHP 代码的部分模板注入到我们的主题中。此代码包含 JavaScript 和 CSS 文件,以及额外的标记。

还有更多...

现在我们已经使编辑栏可见,但仍没有方法向我们的简单主题添加内容。下一道菜谱将展示如何向主题添加可编辑区域。

参见

  • 创建自定义主题 菜谱

  • 定义可编辑的内容区域 菜谱

定义可编辑的内容区域

concrete5 的主题约定中的一个伟大功能是能够指定站点编辑员可以编辑内容的精确位置。这防止了用户破坏网站的设计和结构,但仍然使他们能够编辑所有必要的内容。在本菜谱中,我们将向我们在本章早期创建的简单主题中添加一个可编辑区域。

准备工作

我们将在前几道菜谱中创建的主题基础上进行扩展。如果您想赶上进度,本章的源代码可以在本书的网站上免费获取。如果您愿意,也可以根据您自己的主题调整这个菜谱。

如何做...

定义可编辑内容区域的步骤如下:

  1. 在您偏好的代码编辑器中打开 /themes/basic_theme/default.php 文件。

  2. 将当前的 <h1> 标签替换为以下代码:

    <?php $a = new Area('content'); $a->display($c); ?>
    

    屏幕将显示如下两个截图所示:

    如何做...如何做...

它是如何工作的...

在本菜谱中添加的代码片段本质上告诉 concrete5 这是我们添加块的地方。

更多内容...

定义内容区域的代码片段可以放置在您网站 HTML 的<body>标签之间的任何位置。想象一下添加一个用于侧边栏的区域,以及另一个用于页面页眉的区域。需要注意的是,区域名称(在本例中为content)在页面上的每个使用位置都需要不同。

相关内容

  • 创建自定义主题菜谱

  • 包含所需的 concrete5 脚本和样式菜谱

创建页面类型模板

concrete5 允许设计师为网站中的页面创建无限数量的页面模板。这些模板允许不同的布局,例如侧边栏或三列布局。在本菜谱中,我们将向现有的基本主题添加一个新的页面类型模板,该模板显示带有版权声明的页脚。

准备工作

我们将在此基础上构建本章第一道菜谱中创建的基本主题。本章的代码在本书网站上免费提供,因此您可以随时下载作为起点。或者,像往常一样,您可以将菜谱适应到您自己的网站和主题需求中。

如何操作...

创建页面类型模板的步骤如下:

  1. 在您的主题目录中(对于我们当前的示例,是/themes/basic_theme)创建一个名为with_footer.php的新文件。

  2. 打开新文件,粘贴default.php的内容。

    <!DOCTYPE html>
    <html>
    <head>
      <?php Loader::element('header_required') ?>
    </head>
    <body>
      <?php $a = new Area('content'); $a->display($c); ?>
      <?php Loader::element('footer_required') ?>
    </body>
    </html>
    
  3. 在页面上添加页脚,显示版权符号、当前年份和版权所有者。

    <footer>
      &copy; <?php echo date('Y') ?> Somebody
    </footer>
    

工作原理...

concrete5 将使用此模板为所有具有with_footer处理器的页面类型。

小贴士

如果页面类型未通过 concrete5 控制台界面添加,则无法使用此模板(可以通过访问/dashboard/pages/types添加页面类型)。

更多内容...

现在,我们有一个新的模板,但我们违反了编程中最重要的一条规则之一:不要重复自己(DRY)。我们从默认模板中复制了完整的 HTML 并将其粘贴到新模板中。如果模板中有所更改,并且我们希望更改反映在这两个模板上,开发者需要记住更新两个位置。下一个菜谱将介绍解决这个问题的方法。

相关内容

  • 创建自定义主题菜谱

  • 使用元素重复 HTML 的部分菜谱

使用元素重复 HTML 的部分

编写良好代码的基本规则之一可以用缩写 DRY(不要重复自己)来概括。在创建主题时,开发者和设计师会认识到某些代码会在每个页面上重复出现,例如页眉或页脚。在本菜谱中,我们将学习如何使用元素在页面之间安全地重复代码。

准备工作

我们正在继续完善本章第一道菜谱中创建的非常基础的主题。如果您想将其作为起点,本书网站上可以免费获取本章的代码。

如何操作...

使用元素重复 HTML 部分步骤如下:

  1. 在您的themes文件夹中创建一个名为elements的新目录。

  2. elements/目录下创建一个名为header.php的新文件。

  3. 将以下代码插入到header.php中:

    <!DOCTYPE html>
    <html>
    <head>
      <?php Loader::element('header_required') ?>
    </head>
    <body>
    
  4. elements/目录下创建一个新文件,命名为footer.php

  5. 将以下代码插入到footer.php中:

    <?php Loader::element('footer_required') ?>
    </body>
    </html>
    
  6. themes目录中打开default.php

  7. 将页眉和页脚代码替换为以下代码片段,使整个文件看起来如下所示:

    <?php $this->inc('elements/header.php'); ?>
      <?php $a = new Area('content'); $a->display($c); ?>
    <?php $this->inc('elements/footer.php'); ?>
    
  8. 对任何已创建的页面类型模板重复前面的步骤。

工作原理...

通过将页眉和页脚的 HTML 存储在单独的文件中,我们就可以告诉 concrete5 将这些文件包含在所有使用它们的模板中。这使我们能够在仅一个地方对这些元素进行编辑,并保持我们的模板代码整洁。

参见

  • 创建自定义主题 菜谱

定制系统页面

concrete5 使创建主题变得容易,但默认情况下它不会将主题应用于系统页面,如登录页面。对于大多数网站来说,这是可以的,因为只有网站编辑者会看到登录页面。在网站读者可以登录并发表评论,或在论坛中发帖的网站上,登录页面与其它页面保持一致会更好。在这个菜谱中,我们将使登录页面使用与网站其余部分相同的主题。

准备工作

我们将继续使用本章开头构建的自定义主题。像往常一样,这个菜谱的代码可以从本书的网站上免费下载。

如何操作...

定制系统页面的步骤如下:

  1. 在您首选的代码编辑器中打开/config/site_theme_paths.php

  2. site_theme_paths.php文件中输入以下代码:

    $v = View::getInstance();
    $v->setThemeByPath('/login', "basic_theme");
    
  3. 在您的代码编辑器中打开/themes/basic_theme/view.php

  4. view.php中输入以下代码:

    <?php $this->inc('elements/header.php'); ?>
      <?php print $innerContent ?>
    <?php $this->inc('elements/footer.php'); ?>
    

工作原理...

concrete5 附带site_theme_paths.php配置文件,但默认情况下所有配置设置都被注释掉了。此文件允许您设置网站上任何页面的主题,在这个例子中,我们告诉它为登录页面使用我们的基本主题。

您还会注意到,在我们的主题中,直到这一点,view.php页面都是空的。这个文件是 concrete5 用于没有定义自己模板的单页模板。$innerContent变量包含单页的所有 PHP 和 HTML。

参见

  • 创建自定义主题 菜谱

创建自定义附加包

concrete5 允许开发者创建可重用和可安装在任何 concrete5 网站上的模块化组件。这些模块被称为插件,类似于其他内容管理系统中的插件和模块。在本菜谱中,我们将创建一个基本的插件,该插件将安装一个单页到 concrete5 仪表板。

准备工作

此菜谱的完整代码可在书籍网站上免费获取。

如何操作...

创建自定义插件包的步骤如下:

  1. /packages中创建一个名为basic_addon的新目录。

  2. /packages/basic_addon中创建一个名为controller.php的文件。

  3. controller.php中定义包类。

    class BasicAddonPackage extends Package {}
    
  4. 将成员变量添加到类中。

    protected $pkgHandle = 'basic_addon';
    protected $appVersionRequired = '5.5.0';
    protected $pkgVersion = '1.0.0';
    
  5. 定义一个函数以返回包的名称。

    public function getPackageName() {
      return 'Basic Add-On';
    }
    
  6. 定义一个函数以返回包的描述。

    public function getPackageDescription() {
      return 'This is a super-simple package';
    }
    
  7. 覆盖install函数,告诉包控制器还要在仪表板上安装一个新的单页。

    public function install(){
      Loader::model('single_page');
      $pkg = parent::install();
      $page = SinglePage::add('/dashboard/hello', $pkg);
    }
    
  8. basic_addon/中创建一个名为single_pages的目录。

  9. single_pages/中创建一个名为dashboard的目录。

  10. /packages/basic_addon/single_pages/dashboard中创建一个名为hello.php的文件。

  11. hello.php中输入以下代码。

    <h1>Hello World!</h1>
    
  12. 在你的网络浏览器中,访问 concrete5 的插件安装页面,地址为/dashboard/extend/install/。页面将类似于以下截图:如何操作...

  13. 点击你创建的新插件旁边的安装按钮。

  14. 在你的网络浏览器中访问/dashboard/hello以查看由包安装器创建的单页。页面将类似于以下截图:如何操作...

它是如何工作的...

包中唯一的必需文件是controller.php。此文件包含一个类,它为 concrete5 提供获取插件名称和描述的方法。我们还通过让包安装器添加一个新的单页到仪表板来修改包安装器。通过访问http://example.com/dashboard/hello,我们将看到我们创建的单页的 HTML。

更多...

包目录的结构与正常 concrete5 网站的总体目录非常相似。由于我们想要将单页与我们的包捆绑在一起,我们只需创建它并将其存储在一个目录中,就像我们在 concrete5 中通常做的那样。你可以看到如果包必须包含块、控制器、助手或其他任何 concrete5 使用的文件类型,它将如何被结构化。

参见

  • 使用包控制器执行自定义代码菜谱

使用包控制器执行自定义代码

包控制器的一个独特且高级的功能是能够在页面访问时自动运行代码。这可以为插件开发者提供巨大的潜力,以利用系统事件、挂钩到网站 HTTP 请求等。在这个菜谱中,我们将展示如何通过将包含特殊参数的所有请求重定向到主页,轻松地从我们的包中自动运行代码。

准备工作

我们将使用在前一个菜谱中创建的简单插件包来演示这个例子。本菜谱及所有其他菜谱的代码都可以在本书的网站上下载。

如何操作...

使用包控制器执行自定义代码的步骤如下:

  1. 打开位于 /packages/basic_addon/controller.php 的包控制器文件。

  2. 添加一个名为 on_start 的函数,该函数将重定向任何在 URL 中输入参数 redirect_me 的人。

    public function on_start() {
    if (isset($_GET['redirect_me'])) {
        header('Location: /');
      }
    }
    
  3. 通过在 URL 中添加 ?redirect_me 来测试它。

它是如何工作的...

concrete5 在页面加载时自动运行函数 on_start,因此你将包中放置的任何代码都会自动运行。在这个例子中,我们的示例相当无用,但你可以看到开发者几乎有无限的机会(自动解析页面请求、拦截表单提交、向页面添加 CSS 或 JavaScript 等)。

参见

  • 创建自定义插件包 菜谱

第九章。系统事件和高级配置

本章我们将涵盖以下食谱:

  • 声明高级配置变量

  • 启用 concrete5 中的事件

  • 监听系统事件

  • 将参数传递给事件处理器

  • 定义页面类型事件

  • 当用户创建账户时发送电子邮件

  • 当文件被上传时发送电子邮件

  • 创建自定义计划任务

  • 使您的插件翻译准备就绪

  • 将 concrete5 重命名为白标 CMS

  • 更改仪表板背景图片

简介

concrete5 包含许多针对开发者的杂项高级功能。在本书早期,我们已经提到了 concrete5 中的事件概念。在本章中,我们将探讨监听系统事件并对其采取行动的食谱,以及创建自定义配置设置,甚至更改 concrete5 的品牌以实现白标 CMS。

关于本章中的代码

本章有时会在 /config/site_post.php 等位置放置代码,这可能会干扰网站的正常操作。请确保您在开发服务器上执行这些食谱!

声明高级配置变量

concrete5 自带了许多“秘密”的高级配置变量,开发者可以设置这些变量以增强 concrete5 的行为。在本食谱中,我们将设置一个假设的配置设置。

如何操作...

声明高级配置变量的步骤如下:

  1. 打开位于 /config/site.php 的网站配置文件,使用您首选的代码编辑器打开。

  2. 声明一个新的常量变量,名为 FOO,并将其值设置为 BAR,如下所示:

    define('FOO', 'BAR');
    
  3. 保存 site.php 文件。

它是如何工作的...

concrete5 在每次页面请求开始时简单地加载此文件。通过在此处定义配置设置,开发者可以覆盖默认的 concrete5 设置,并创建他们自己的常量变量。如果开发者导出常量 FOO 的内容,他们将看到字符串 BAR

在 concrete5 中启用事件

concrete5 自带了一个发布/订阅事件模型,这使得开发者能够使他们的代码响应系统事件。如果开发者希望在 /config/site_events.php 中声明事件(我们将在本章中这样做),则必须在 site.php 中启用它们。

如何操作...

启用事件的步骤如下:

  1. 定位文件 /config/site.php 并使用您首选的代码编辑器打开它。

  2. 将以下配置设置添加到 config.php 文件中:

    define('ENABLE_APPLICATION_EVENTS', true);
    
  3. 保存文件。

  4. 通过访问 /dashboard/system/optimization/clear_cache/ 并点击 清除缓存 按钮来清除 concrete5 缓存。

它是如何工作的...

在 concrete5 允许开发者在 /config/site_events.php 中注册事件监听器之前,它会检查此配置设置是否存在并设置为 true

更多内容...

在 later concrete5 版本(5.5 及以上版本)中,可以忽略此步骤,尽管作者的个人偏好是无论如何都要放置配置,以便可以轻松启用或禁用事件(通过将值设置为 false)。

参见

  • 声明高级配置变量 菜谱

  • 监听系统事件 菜谱

监听系统事件

一旦在 concrete5 中启用了事件,开发者就可以编写自己的代码来响应不同的事件。在本菜谱中,我们将创建一个基本的 "Hello World!" 事件,当访问页面时立即运行并输出一条消息到屏幕上。

准备工作

site_events.php 中注册一个事件之前,concrete5 必须配置为启用事件系统。请参考前面的菜谱了解如何启用事件。

如何操作...

步骤如下:

  1. /config 目录下创建一个名为 site_events.php 的新文件。

  2. 在你喜欢的代码编辑器中打开 site_events.php

  3. 添加以下代码以监听 on_start 事件。

    Events::extend('on_start', 'MyClass', 'onStartFired', 'libraries/my_class.php');
    
  4. /libraries 目录下创建一个名为 my_class.php 的新文件。

  5. my_class.php 中定义一个名为 MyClass 的新类。

    class MyClass {
    }
    
  6. MyClass 添加一个名为 onStartFired 的方法。

    public function onStartFired() { 
    }
    
  7. onStartFired 中,使用 die 函数输出 hello world!

    die('hello world!');
    
  8. 访问你网站上的任何页面。你将看到一个带有文字 hello world! 的白色屏幕,如下截图所示:如何操作...

  9. 随意取消注释 MyClassonStartFired 函数的 die 语句以恢复你的网站到正常工作状态。

工作原理...

concrete5 将在网站加载时自动检查 /config/site_events.php 文件的存在,并执行其中包含的任何代码(这与 /config/site_post.php 的行为类似)。这是进行事件注册实验的完美地方。当我们调用 Event::extend() 时,我们传入的参数指定了我们想监听的事件、我们的事件处理器所在类的名称(在这个例子中是 MyClass),当事件被触发时将在该类中执行的方法(在这种情况下是 onStartFired),以及包含我们的处理器类的文件路径。

参见

  • 在 concrete5 中启用事件 菜谱

  • 向事件处理器传递参数 菜谱

向事件处理器传递参数

事件处理器是 concrete5 在事件被触发时执行的功能。在先前的菜谱中,我们使用了自定义类 MyClass 和其函数 onStartFired 作为事件处理器。concrete5 允许开发者向这些处理器传递参数。在本菜谱中,我们基于先前的事件处理器构建,并向 onStartFired 处理器传递一条消息,该消息将被输出。

准备工作

我们将使用在先前的菜谱中创建的代码作为本菜谱的基础。同时,确保你已经按照本章第一菜谱中的描述启用了事件。

如何操作...

将参数传递给事件处理函数的步骤如下:

  1. 在代码编辑器中打开位于/configsite_events.php文件。

  2. 在事件注册代码中添加一个新参数,使其看起来像以下代码:

    Events::extend('on_start', 'MyClass', 'onStartFired', 'libraries/my_class.php', array('This is a custom message!'));
    
  3. 打开/libraries/my_class.php,将onStartFired修改为以下代码:

    public function onStartFired($view, $message) {
      die($message);
    }
    
  4. 你现在可以在刷新你的网站时看到新的消息,如下面的截图所示:如何做...

  5. 随意取消注释die语句以允许您的网站正常工作。

它是如何工作的...

通过向Events::extend()函数调用添加第五个参数,我们可以向事件处理函数发送参数。这个新参数需要是一个数组,它包含我们希望发送到处理函数的各种参数。

你可能会注意到,我们的处理函数onStartFired有两个参数($view$message),尽管我们只指定了消息参数。这是因为 concrete5 将当前的View对象作为一点上下文提供给处理函数,这可能很有用。如果你对函数应用了哪些参数不确定,可以将 PHP 的func_get_args()函数的结果输出,以查看所有已发送参数的数组,因为它们可以在事件之间有所不同。

参见

  • 在 concrete5 中启用事件的食谱

  • 监听系统事件的食谱

定义页面类型事件

除了提供各种开发者可以挂钩的事件外,concrete5 还在页面类型级别提供事件系统。我们在本书的第一章详细讨论了页面类型,但现在我们可以向我们的页面类型添加自定义事件。在本食谱中,我们将创建一个名为blog_post的页面类型,并挂钩该页面类型的on_page_add事件。

准备工作

页面类型及其使用方法在第一章页面和页面类型中有更详细的描述。确保在 concrete5 中启用事件,并且你的/config/site_events.php文件存在。

如何做...

定义页面类型事件的步骤如下:

  1. /config/site_events.php中注册事件处理程序:

    Events::extendPageType('blog_post', 'on_page_add');
    
  2. 首先,在/page_types中创建一个名为blog_post.php的新页面类型文件。

  3. 接下来,在/controllers/page_types/blog_post.php中为页面类型创建控制器文件。

  4. 创建控制器类,扩展核心Controller类:

    class BlogPostPageTypeController extends Controller {
    }
    
  5. 在控制器类中添加一个名为on_page_add的方法:

    public function on_page_add() {
    }
    
  6. on_page_add函数中,创建一个简单的die语句,这样我们就能知道这个事件正在工作:

    die('blog post added');
    
  7. 通过访问/dashboard/pages/types安装页面类型。

  8. 点击添加页面类型

  9. 给页面类型起一个名字,并确保处理程序设置为blog_post如何做...

  10. 现在,访问位于/dashboard/sitemap/full/的网站地图。

  11. 向网站添加一个新页面,选择博客文章作为页面类型。如何做...

  12. 添加一个博客文章,如下面的截图所示:如何操作...

  13. 当页面添加时,您将看到事件处理器中创建的消息,如下面的截图所示:如何操作...

  14. 不要忘记从事件处理器中删除die语句,以便您的网站恢复正常功能。

工作原理...

当向页面类型添加事件时,concrete5 消除了开发者手动指定事件处理器类名、函数名和文件位置的需求。因为页面类型遵循特定的约定(控制器名称称为BlogPostPageTypeController)并且通常位于/controllers/page_types目录中,所以 concrete5 可以自动确定应该加载哪个文件和类来处理事件。

更多...

参数可以像在常规事件处理器中一样传递给页面类型事件处理器。只需在事件声明中添加一个第三个参数,一个包含要传递给处理器函数的每个参数的数组,如下所示:

Events::extendPageType('blog_post', 'on_page_add', array('This is a custom parameter'));

然后可以从处理器函数中访问新参数:

public function on_page_add($view, $message) {
  die($message);
}

参见

  • 在 concrete5 中启用事件配方

  • 监听系统事件配方

  • 传递参数到事件处理器配方

当用户创建账户时发送电子邮件

在本章中,我们已经介绍了许多与 concrete5 事件相关的配方。现在我们可以尝试一个常见的现实世界示例,即使用系统事件来执行自定义代码。在这个配方中,每当用户在网站上注册时,我们将向网站管理员发送一封电子邮件。

准备工作

在 PHP 中发送电子邮件可能很棘手,因为很多都取决于服务器配置。我们将使用 concrete5 的邮件助手(在第四章中更详细地讨论),这有助于一点,但配置错误的服务器仍然可能有问题。我们将假设您的服务器(开发或其他)能够发送电子邮件。

此外,确保在 concrete5 中启用事件,如本章中声明高级配置变量配方所述!

如何操作...

当用户创建账户时发送电子邮件的步骤如下:

  1. /config/site_events.php中声明事件监听器:

    Events::extend('on_user_add', 'UserEmailer', 'newAccountCreated', 'libraries/user_emailer.php');
    
  2. 创建在事件注册中提到的user_emailer.php文件,位于/libraries:

  3. user_emailer.php中定义一个新的类,名为UserEmailer

    class UserEmailer {
    }
    
  4. UserEmailer添加一个名为newAccountCreated的方法,该方法接受一个参数,一个名为$userUserInfo对象:

    public function newAccountCreated($user) {
    }
    
  5. newAccountCreated函数中,加载邮件助手:

    $mail = Loader::helper('mail');
    
  6. 设置电子邮件的主题:

    $mail->setSubject('New account created!');
    
  7. 设置电子邮件正文:

    $mail->setBody('Someone with the email address of '.$user->uEmail.' has created an account.');
    
  8. 设置电子邮件的目的地址(将其设置为您的电子邮件,以确保它能够正常工作):

    $mail->to('somebody@example.com');
    
  9. from地址设置为适合您自己网站的地址:

    $mail->from('noreply@example.com');
    
  10. 发送电子邮件:

    $mail->sendMail();
    
  11. 通过向您的网站添加新用户来测试此事件是否正常工作。

  12. 访问您的 concrete5 网站的 /dashboard/users/add/ 以添加新用户。如何操作...

  13. 用户添加后,您应该会收到一封电子邮件。如何操作...

它是如何工作的...

当事件监听器在 site_events.php 中定义时,concrete5 会记住在相关事件触发时执行提供的函数。在这种情况下,每当数据库中添加新用户时,concrete5 会触发 on_user_add 事件,从而运行我们创建的自定义代码。使用邮件助手,我们可以程序化地生成电子邮件并立即发送。

相关内容

  • 第四章 使用核心助手 中的 使用邮件助手发送电子邮件 配方

  • 监听系统事件 的配方

当文件上传时发送电子邮件

我们将再次尝试发送电子邮件;这次,每当文件被添加到文件管理器时,我们将向某人发送电子邮件。电子邮件将包含下载文件的链接。

如何操作...

当文件上传时发送电子邮件的步骤如下:

  1. /config/site_events.php 中设置事件监听器:

    Events::extend('on_file_add', 'FileEmailer', 'fileUploaded', 'libraries/file_emailer.php');
    
  2. /libraries/file_emailer.php 中创建一个新的库:

  3. 声明新的 FileEmailer 类:

    class FileEmailer {
    }
    
  4. 向类中添加一个名为 fileUploaded 的方法:

    public function fileUploaded($file, $fv) {
    }
    
  5. 加载邮件助手:

    $mail = Loader::helper('mail');
    
  6. 设置消息的主题:

    $mail->setSubject('A file has been added to the file manager');
    
  7. 设置消息正文,包括下载文件的链接:

    $mail->setBody('A new file has been uploaded. Download it here: '.
      $fv->getDownloadURL());
    
  8. 添加收件人的电子邮件地址(将其更改为您可访问的电子邮件地址):

    $mail->to('somebody@example.com');
    
  9. 设置回复地址:

    $mail->from('noreply@example.com');
    
  10. 发送电子邮件:

    $mail->sendMail();
    
  11. 访问您的网站文件管理器在 /dashboard/files/search。如何操作...

  12. 上传新文件。

  13. 您将收到一封包含下载新文件链接的电子邮件,如下截图所示:如何操作...

它是如何工作的...

当文件上传时,concrete5 会自动触发 on_file_add 事件,我们在 /config/site_events.php 中注册了监听器。concrete5 将 FileFileVersion 对象作为事件回调的两个参数传递。FileVersion 对象包含获取下载 URL 的方法。

相关内容

  • 当用户创建账户时发送电子邮件 的配方

创建自定义计划任务

concrete5 允许开发者创建特殊的任务,通过服务器上的计划任务自动运行。这些任务可以是您希望定期自动执行的各种操作。在这个配方中,我们将编写一个任务,将早上好电子邮件发送给网站上的每个用户。

准备工作

可能不需要说,但请确保在测试服务器上使用测试用户和电子邮件地址执行此配方。您不希望每天早上用愚蠢的电子邮件打扰整个用户群。

如何操作...

创建自定义计划任务的步骤如下:

  1. /jobs/email_everyone.php创建一个新文件。

  2. 声明一个名为EmailEveryone的新类:

    class EmailEveryone extends Job {
    }
    
  3. 在类中创建一个方法来返回工作的名称:

    public function getJobName() {
      return 'Wakeup Email';
    }
    
  4. 创建另一个方法来返回工作的描述:

    public function getJobDescription() {
      return 'Give all of your site members a morning wakeup email!';
    }
    
  5. 创建一个名为run的函数:

    public function run() {
    }
    
  6. 加载UserList模型:

    Loader::model('user_list');
    
  7. 创建UserList类的新实例:

    $ul = new UserList();
    
  8. 获取网站上所有用户的数组:

    $users = $ul->get();
    
  9. 遍历数组:

    foreach ($users as $user) {
    }
    
  10. 在循环中,加载邮件助手:

    $mail = Loader::helper('mail');
    
  11. 设置电子邮件的主题:

    $mail->setSubject('Good morning!');
    
  12. 设置回复地址:

    $mail->from('noreply@example.com');
    
  13. 在循环中将目标地址设置为当前用户:

    $mail->to($user->getUserEmail());
    
  14. 设置电子邮件正文,包括用户的用户名:

    $mail->setBody('Good morning, '.$user->getUserName());
    
  15. 发送电子邮件:

    $mail->sendMail();
    
  16. 返回要在仪表板上显示的消息:

    return 'Emailed '.count($users).' users.';
    
  17. 访问仪表板的自动化任务页面,位于/dashboard/system/optimization/jobs/

  18. 你将在列表底部看到你的新工作,如下面的截图所示。如何操作...

  19. 点击前面的截图所示的安装按钮。如何操作...

  20. 点击三角形播放图标来运行你的工作。你将看到一个显示已邮寄用户数量的消息。如何操作...

  21. 你将在你的收件箱中收到一封电子邮件(如果你的电子邮件地址分配给了网站成员之一),如下面的截图所示:如何操作...

它是如何工作的...

concrete5 将在点击“播放”按钮后异步运行新任务。该任务简单地加载网站上所有用户的列表,并向他们中的每一个人发送电子邮件。在生产使用中,对于大量成员来说,这可能是低效的,甚至可能导致你的服务器因垃圾邮件而被列入黑名单。

更多...

你可能想知道如何自动运行这样的任务。答案在于服务器自动化任务。在大多数 Linux Web 服务器上,网站管理员将使用cron调度程序来管理自动化任务,并可能使用curl命令向任务运行器发送 HTTP 请求。要自动运行此任务,请创建一个计划任务来 ping 工作页面底部的 URL。此 URL 包含一个令牌,将允许你的系统在不登录的情况下访问 concrete5。请确保保持此 URL 及其令牌的私密性,否则未经授权的用户可能会触发你的网站的自动化任务。

有关在基于 Linux 的 Web 服务器上创建计划任务的更多信息,请参阅en.wikipedia.org/wiki/Cron

使你的附加翻译准备就绪

concrete5 允许开发者采取高级步骤以确保他们的代码与 concrete5 翻译兼容。在本菜谱中,我们将展示如何为翻译准备字符串。

如何操作...

使附加翻译准备就绪的步骤如下:

  1. 在你的代码编辑器中打开/config/site_post.php

  2. 声明一个用于测试的字符串:

    $str = 'Hello world!';
    
  3. 使用翻译函数输出你的字符串:

    echo t($str);
    exit;
    

它是如何工作的...

concrete5 使用 Zend 翻译库。concrete5 定义全局 t() 函数作为字符串可用性的快捷方式,以便于各种翻译。然后翻译人员将使用 Poedit 等工具准备翻译文件以辅助翻译这些字符串。要了解更多关于 Poedit 和创建翻译文件的信息,请参阅 www.poedit.net

将 concrete5 重新品牌化为白色标签 CMS

concrete5 允许开发者将 CMS 的标志、标题和一般品牌信息更改为他们想要的任何内容。通常,像大型组织这样的客户喜欢以这种方式重新品牌化他们的产品,而 concrete5 使这变得很容易。在这个配方中,我们将通过更改编辑栏中的标志来重新品牌化 concrete5。

准备工作

您需要一个 49 x 49 像素的标志图像。我们在这个配方中使用了一个示例标志,它包含在此书的网站上的代码下载中。

如何操作...

步骤如下:

  1. 将您的新标志上传到您的网站。在此示例中,我们的标志位于 /images/new-logo.png(您可能需要创建图像目录)

  2. 在您的代码编辑器中打开 /config/site.php 文件。

  3. 将以下配置添加到文件中:

    define('WHITE_LABEL_LOGO_SRC', '/images/new-logo.png');
    
  4. 保存文件。现在您将在以下截图所示的编辑栏中看到新的标志:如何操作...

它是如何工作的...

concrete5 会检查此配置变量的存在,如果存在,则会更改标志源。如果更改了标志,concrete5 还会在编辑栏中添加 由 concrete5 驱动 的消息。

更多内容...

对于开发者来说,还有一些其他白色标签方面可供使用。在 www.concrete5.org/documentation/how-tos/developers/white-labelling/ 可以找到一份很好的列表。

参见

  • 声明高级配置变量 的配方

更改仪表板背景图片

默认情况下,concrete5 在每个仪表板页面的背景中显示大而明亮的照片。这些图像由在 concrete5 官方服务器上运行的源提供支持,并且图像每天都会更改。

更改仪表板背景图片

这是一个有趣的效果,为仪表板带来了很多色彩,但一些客户和代理可能不喜欢在他们的网站上显示随机的照片,尤其是如果它用于商业目的。幸运的是,concrete5 使更改背景图片变得很容易。

准备工作

您需要一个新图像作为背景,其大小至少为 1024 x 768 像素。在此示例中,我们将使用 Adobe Photoshop 中可以快速创建的微妙深色渐变,但您可以使用任何喜欢的图像。背景图像包含在此书的代码下载中。

如何操作...

更改仪表板背景图片的步骤如下:

  1. 在您的代码编辑器中打开 /config/site.php 文件。

  2. 将以下配置添加到文件中。

    define('WHITE_LABEL_DASHBOARD_BACKGROUND_SRC', '/images/new-background.png');
    
  3. 保存文件。仪表板的背景现在将发生变化。如何操作...

它是如何工作的...

concrete5 会检查WHITE_LABEL_DASHBOARD_BACKGROUND_SRC配置设置,并用您提供的新的背景图片替换每日图片。

更多内容...

开发者可以通过将背景源设置为"none"来完全去除背景图片。

参见

  • 声明高级配置变量的配方。

附录 A. 蓝图 – 创建图像库插件

现在我们已经学习了数十个 concrete5 的食谱,是时候将它们付诸实践了。将本章视为一个巨大的食谱,其唯一目的是创建一个图像库插件,你可以在 concrete5 网站上安装并立即开始使用。如果你访问本书的网站,有一个完整的源代码下载,以帮助你解决问题。

在我们开始之前...

整个章节是在 concrete5 版本 5.6.1.2 的全新安装下开发的,尽管代码在技术上可以在 5.6 版本之后的任何 concrete5 上工作。如果你想完全跟随,在你的开发服务器上运行一个新的 concrete5 版本,并使用它安装示例内容。这将给我们一些页面和图像来工作。

创建包控制器

创建我们的插件的第一步是创建目录和文件。

/packages 中创建一个名为 cookbook_gallery 的新目录。我们需要的第一个文件是 controller.php

controller.php 文件中输入以下代码以定义插件:

<?php
defined('C5_EXECUTE') or die(_("Access Denied."));

class CookbookGalleryPackage extends Package {
  protected $pkgHandle = 'cookbook_gallery';

  protected $appVersionRequired = '5.6.0';
  protected $pkgVersion = '0.9.0';

  public function getPackageName() {
    return t('Cookbook Gallery');
  }

  public function getPackageDescription() {
    return t('An image gallery that ties into the file manager.');
  }

}

你可能还记得来自第八章,与主题和插件一起工作,的内容,即插件只需要一个文件,即 controller 文件。controller 文件包含告诉 concrete5 插件名称的方法,以及插件的文本描述。

在这里我们需要注意几件事情。首先,注意控制器的类名。由于我们的包处理程序是 cookbook_gallery,我们需要将处理程序驼峰化并将其附加到末尾,以创建 concrete5 可以预测和正确加载的类名。

我们接下来需要的是文件顶部的 defineddie 语句。这是 concrete5 的一个特殊安全要求,以确保脚本不能任意执行。所有内容都必须通过 concrete5 分发器运行。如果你打算将包提交到 concrete5 市场的话,这个语句在每个 .php 文件(不包括存在于 libraries/3rd_party 中的第三方库)的顶部都是必需的。

我们还需要注意的另一件事是,所有面向公众的字符串都被包含在 t() 函数中(参见包名称和描述)。正如在第九章系统事件和高级配置中讨论的,t() 函数允许翻译者提供给定字符串的替代翻译。这是插件提交到 concrete5 市场的要求之一。

我们还没有完成控制器;一旦我们的块创建完成,我们还需要回来添加安装功能。

创建块类型

我们的形象画廊将是一个自定义块类型。这种块类型可以被添加到 concrete5 网站的任何页面,并在放置的地方显示图像画廊。我们首先需要做的是创建块的目录。在/packages/cookbook_gallery/blocks中添加一个新的目录。在新的块目录内,添加一个名为cookbook_gallery的目录。这将包含我们的块文件。

块的控制器

我们块类型的首要任务是controller文件。在/packages/cookbook_gallery_blocks/cookbook_gallery中创建controller.php

声明块的controller类并添加以下方法:

<?php defined('C5_EXECUTE') or die(_("Access Denied."));

class CookbookGalleryBlockController extends BlockController {

  protected $btTable = "btCookbookGallery";
  protected $btInterfaceWidth = "350";
  protected $btInterfaceHeight = "300";

  var $defaultCount = 20;

  public function getBlockTypeName() {
    return t('Photo Gallery');
  }

  public function getBlockTypeDescription() {
    return t('Shows photos from a file set.');
  }

}

再次注意文件顶部的defineddie语句以及使用t()函数包装我们的公共字符串。我们还定义了块的数据库表名称,使用成员变量$btTable

保存controller文件,我们稍后会回来添加我们块的函数。

数据库 XML 文件

我们块类型需要的下一个文件是数据库 XML 文件。在/packages/cookbook_gallery/blocks/cookbook_gallery/db.xml中创建它。此文件定义了块类型将需要的所有表和字段。当块类型安装时,concrete5 将自动创建定义的表。

你可能还记得第二章 与块一起工作,这个文件使用了 ADOdb 的 XML 模式(或 AXMLS)。你可以在 ADOdb 网站上了解更多关于 AXMLS 的信息,网址为phplens.com/lens/adodb/docs-datadict.htm#xmlschema

db.xml中输入以下 XML 代码:

<?xml version="1.0"?>
<schema version="0.3">
  <table name="btCookbookGallery">
    <field name="bID" type="I">
      <key />
      <unsigned />
    </field>
    <field name="file_set" type="I"></field>
    <field name="count" type="I"></field>
  </table>
</schema>

我们创建了一个与块类型控制器中指定的同名数据库表。该表有两个字段,一个唯一的整数 ID 称为bID(这是块安装所必需的),以及一个整数文件集 ID 字段。保存此db.xml文件,如果你愿意的话,可以关闭它,因为我们不会再需要它了。

块类型的视图文件

最后,我们需要为块的各个视图创建文件。块有三个视图——添加、编辑和查看。在块的目录中创建add.phpedit.phpview.php。由于添加和编辑共享相同的 HTML,我们将创建一个共享模板,这两个视图都将包含它,称为form.php。哦,为什么不创建view.css呢,因为我们的视图文件将需要使用一些样式。

我们新包的结果内容如下截图所示:

块的类型视图文件

让我们暂时留空这些视图文件,因为我们想将我们的块类型及其包安装到网站上!

使用包安装块类型

现在,如果我们安装这个包,块类型将不会随它一起安装,你的插件用户会感到困惑和失望。不过,我们可以告诉包在包安装期间安装块类型。

在你的代码编辑器中打开包的controller/packages/cookbook_gallery/controller.php)。

controller类中添加一个名为install的新方法,如下所示:

public function install() {
  $pkg = parent::install();

  // install the block type
  BlockType::installBlockTypeFromPackage('cookbook_gallery', $pkg); 
}

这里发生了什么?嗯,Package类有一个名为install的函数,正如你所猜到的,它将包安装到 concrete5 数据库中。由于我们的包控制器扩展了Package类,所以install函数自动对我们可用。

第一步是调用Package类的install函数,并获取它返回的对象。这将使我们能够安装块类型,并将其分配给我们的包。

$pkg对象传递给块类型安装程序很重要,因为如果用户卸载或重新安装你的附加组件,块类型将随之来去。

保存控制器文件。现在是时候安装我们的附加组件了!

在 concrete5 中安装包

访问你的 concrete5 网站的/dashboard/extend/install/(如果你还没有登录,你需要先登录)。你会看到你的附加组件等待安装。

等待安装的画廊附加组件如下截图所示:

在 concrete5 中安装包

点击安装按钮。concrete5 将添加你的包及其块控制器到网站中。如果成功,你将在屏幕顶部看到一个消息。

附加组件安装成功后,我们看到以下截图:

在 concrete5 中安装包

创建画廊页面

访问你的 concrete5 首页,并将鼠标悬停在编辑按钮上,在主页下添加一个子页面。

为画廊创建页面

让我们为这个画廊页面使用布局。

为画廊创建页面

给页面一个标题和路径。比如叫图片画廊

为画廊创建页面

将页面添加到网站中。现在我们已经有一个合适的地方放置我们的块了,让我们实际让我们的块做一些事情吧!

使块活跃起来

在你的代码编辑器中打开你的块的控制器(位于/packages/cookbook_gallery/blocks/cookbook_gallery/controller.php)。我们需要添加一些函数来使这个类工作。首先,让我们让块的添加和编辑表单活跃起来。将以下函数添加到controller类中。

public function add() {
  $this->addEdit();
}

public function edit() {
  $this->addEdit();
}

public function addEdit() {
  $fsList = new FileSetList();
  $sets = $fsList->get();

  $options = array();

  foreach ($sets as $fs) {
    $options[$fs->fsID] = $fs->fsName;
  }

  $this->set('sets', $options);
}

哇,我们在做什么呢?你可能还记得前面的章节,concrete5 控制器使用回调函数,这些函数在类中自动执行,当某些事情发生时。每当一个块首次添加到页面时,concrete5 将在add.php视图显示时调用add函数。对于edit函数和edit.php视图也是同样的道理。

由于我们希望添加和编辑表单都运行相同的代码,为什么不创建一个它们各自都可以使用的函数呢?addEdit函数包含了我们后端工作的实际代码。

首先,我们加载 concrete5 数据库中所有文件集的列表。然后,我们将文件集列表转换为简单的键/值数组,我们可以将其输入到 HTML 表单中的选择框中。最后,我们将<select>选项的数组发送到视图作为变量$sets

太棒了。现在,当画廊块实际上在网站上查看时,也有一个回调函数。

public function view() {
  if ($this->file_set) {
    $list = new FileList();
    $set = FileSet::getByID($this->file_set);

    $list->filterBySet($set);
    $list->filterByType(FileType::T_IMAGE);

    $count = ($this->count) ? $this->count : $this->defaultCount;

    $this->set('images', $list->get($count));
  }
  else {
    $this->set('images', false);
  }
}

当块在网站上显示时,view函数将由 concrete5 自动运行。正是在这里,我们从所选的文件集中加载图片并发送到视图。

首先,我们需要创建FileList类的新实例。这个类允许我们在文件管理器中过滤文件,只显示属于我们图片画廊的文件。

接下来,我们根据在添加/编辑表单中设置的文件集 ID 加载文件集对象。使用文件集对象,我们能够过滤集合,只显示属于该集合的文件。我们不想显示所有类型的文件(想象一下图片画廊中的 PDF 文件——那可不好玩!),所以我们添加另一个过滤器,只显示图片。

接下来,我们编写一个三元表达式,如果添加块到页面时没有选择画廊限制,则回退到默认的画廊限制。

最后,让我们将图片数组发送到视图,这样我们就可以显示我们的画廊了!

填写添加和编辑视图文件

好的,所以我们控制器中有一些很棒的代码,但我们的视图中还没有 HTML。让我们现在就解决这个问题。

在你的代码编辑器中打开form.php。我们将创建一个 HTML 表单,当块在页面上添加或编辑时,网站编辑将看到这个表单。

form.php中输入以下 HTML 和 PHP 代码:

<?php 
defined('C5_EXECUTE') or die(_("Access Denied.")); 
$form = Loader::helper('form');
?>	

<div class="ccm-ui">
  <table class="table table-striped table-bordered">
    <tr>
      <td>
        <?php echo t('File set to show photos from') ?>
      </td>
      <td>
        <?php echo $form->select('file_set', $sets, $file_set) ?>
      </td>
    </tr>
    <tr>
      <td>
        <?php echo t('How many images to show?') ?>
      </td>
      <td>
        <?php echo $form->text('count', $count) ?>
      </td>
    </tr>
  </table>
</div>

嘿,这并不难!这个表单将包含两个字段——一个包含 concrete5 中文件集列表的选择框,以及一个文本输入来限制图片画廊。不用担心将其包裹在表单元素中或添加保存控件,concrete5 会处理所有这些。

现在,让我们将此表单包含在add.phpedit.php中。向这两个文件添加以下代码:

<?php 
defined('C5_EXECUTE') or die(_("Access Denied.")); 
 $this->inc('form.php');

就这样!现在当我们的块添加到网站上时,编辑将看到我们漂亮的新表单。

创建画廊视图文件

当然,我们的画廊还缺少最重要的组件,即画廊本身。让我们在view.php中添加一些 HTML 和 PHP 代码,以显示所选文件集中的各种图片,如下所示:

<?php 
  defined('C5_EXECUTE') or die(_("Access Denied.")); 
  $ih = Loader::helper('image');
?>

<h1><?php echo t('Image Gallery') ?></h1>

<?php if ($images !== false): ?>
  <div class="gallery-wrapper">
    <?php foreach ($images as $image): ?>
      <?php $thumbnail = $ih->getThumbnail($image, 100, 100, true); ?>
      <a class="gallery-image" href="<?php echo $image->getRelativePath() ?>">
        <img src="img/<?php echo $thumbnail->src ?>" />
      </a>
    <?php endforeach; ?>
  </div>
<?php else: ?>
  <p><?php echo t('There are no images!') ?></p>
<?php endif; ?>

太好了。现在让我们看看我们做了什么。当然,在文件的顶部,我们包含了所有 PHP 文件所需的defineddie语句。随后,我们加载 Image 辅助工具,我们将在后面使用它来生成缩略图。

接下来,我们使用t()包装器输出画廊的标题,当然是为了保持翻译友好性。

在那之后不久,我们开始遍历图片数组。这些是 File 对象,因此我们可以访问所有相关属性。让我们使用 Image 辅助工具生成一个 100 x 100 像素的图片裁剪(传递 true 作为第二个参数告诉 Image 辅助工具裁剪图片,而不仅仅是调整大小)。这将使我们的画廊看起来整洁且一致。

接下来,让我们将图片包裹在一个 <a> 标签中,这样我们就可以链接到全尺寸图片。使用缩略图的源输出图片标签。

不要忘记将整个内容包裹在一个 if 语句中,以处理没有图片的文件集。

最后,让我们向 view.css 添加一些基本样式,以便我们的画廊看起来如下:

.gallery-wrapper {
  margin: 50px 0;
}

.gallery-image {
  opacity: .85;
}

.gallery-image:hover {
  opacity: 1;
}

尝试使用块

好的,让我们看看我们做得怎么样!在我们可以使用块之前,让我们在 concrete5 中添加一个文件集。在浏览器中访问 /dashboard/files/sets/ 并点击大蓝色按钮来添加文件集。在使用画廊之前,我们需要至少添加一个文件集。

尝试使用块

创建一个名为 Gallery Images 的新文件集。

尝试使用块

现在我们有一个文件集,但仍然为空。让我们通过访问文件管理器 /dashboard/files/search/ 来添加一些图片到这个文件集中。

选择一些图片添加到集合中。

尝试使用块

点击左上角的下拉菜单。选择 Sets,如以下截图所示:

尝试使用块

选择我们刚刚创建的文件集,将这些图片分配到该集合中。

尝试使用块

太棒了!现在我们准备好尝试我们的块了。访问我们之前创建的图片画廊页面并进入编辑模式。点击主要内容区域以添加新块。

尝试使用块

滚动到块列表的底部,找到我们创建的相册块。

尝试使用块

现在,填写表格以添加块。选择文件集并设置可以出现的图片数量限制(或留空以使用默认的 20 张)。

尝试使用块

将块添加到页面并发布更改。您将看到一个看起来很棒的照片画廊!

尝试使用块

点击其中一张图片,查看其原始大小。

尝试使用块

嗯,看起来我们的代码是有效的!恭喜,您已经创建了一个可以安装在任何 concrete5 网站上并自动工作的插件。

总结

我们在本章中取得了许多成就。我们从无到有,最终完成了一个功能齐全的图片库。尽管如此,仍有很大的扩展和改进空间。如果我们当时添加了一个 jQuery 灯箱插件,比如 fancyBox(可在fancyapps.com/fancybox/找到)会怎样?或者如果画廊有多个页面呢?这种块类型是许多不同可能性的绝佳起点。所有这些任务都可以使用 concrete5 API 实现,所以尽情探索和学习新事物吧。

附录 B. 蓝图 – 创建事件日历插件

许多开发者必须创建的插件最终会结合仪表板界面和自定义块类型,不仅为网站的后端提供强大的编辑能力,还在网站的前端提供独特且强大的界面。网站上的一个常见请求是拥有一个事件日历。此蓝图将结合我们在前几章中获得的大部分知识来创建一个事件日历插件。该插件将在仪表板上具有 CRUD 界面,以及一个自定义块类型来显示事件。

在我们开始之前...

在我们开始之前,我们应该注意,本章中的蓝图是基于一个全新的混凝土 5 安装,并加载了所有示例内容。这将为我们提供一些不错的页面和干净的设计来工作。

此插件的完整工作代码可在书籍网站上免费获取。您可以将其作为起点下载,或用于解决您可能遇到的问题。

创建包

让我们开始行动。首先,我们将创建包的目录。在 /packages 中添加一个名为 cookbook_events 的新目录。在此目录内,创建包的控制器文件。

包控制器

您可能已经熟悉包控制器了;它们告诉混凝土 5 有关包的信息,并为开发者提供执行高级任务的功能。

controller.php 文件中输入以下代码:

<?php
defined('C5_EXECUTE') or die(_("Access Denied."));
class CookbookEventsPackage extends Package {
    protected $pkgHandle = 'cookbook_events';
    protected $appVersionRequired = '5.6.0.0';
    protected $pkgVersion = '0.9.0';
    public function getPackageName() {
        return t('Cookbook Events');
    }
    public function getPackageDescription() {
        return t('A calendar of events for our website.');
    }
}

注意文件顶部使用的 defined or die 语句。这是在包中的每个 PHP 文件顶部必需的,否则如果将您的插件提交到市场,混凝土 5 将拒绝您的插件。

此外,请注意在包名称和描述字符串周围使用 t() 函数。这将允许翻译者以简单和一致的方式提供这些字符串的翻译。

我们将最小混凝土 5 版本设置为 5.6.0,因为我们使用了一些在混凝土 5 旧版本上不完全工作的 CSS 样式。然而,通过一些额外的工作,我们也可以支持旧版本。

包数据库 XML 文件

我们的包需要创建一个数据库表来存储事件数据。而不是执行原始 SQL,首选的方法是创建一个包含所有要创建的表和字段的 db.xml 文件。当包安装时,混凝土 5 将读取此文件并执行必要的数据库操作。

/packages/cookbook_events/db.xml 创建 db.xml 文件。

在文件中输入以下 XML 代码:

<?xml version="1.0"?>
<schema version="0.3">
   <table name="CookbookEvents">
      <field name="id" type="I">
         <key />
         <unsigned />
         <autoincrement />
      </field>
      <field name="title" type="C" size="255"></field>
      <field name="event_date" type="T"></field>
      <field name="location" type="C" size="255"></field>
      <field name="description" type="X2"></field>
      <field name="created_by" type="I"></field>
      <field name="created_at" type="T"></field>
   </table>
</schema>

保存此文件。这告诉混凝土 5 创建一个名为 CookbookEvents 的表,其中包含标题、日期、地点、描述和一些元数据字段。使用 db.xml 也使得在您的插件更新时数据库升级更容易。

你可能记得这个 XML 文件使用了 ADOdb XML 模式格式,或AXMLS。你可以在phplens.com/lens/adodb/docs-datadict.htm#xmlschema了解更多关于 AXMLS 和不同字段类型的信息。

模型

现在我们知道了我们的数据库表的样子,让我们创建我们将用来与表交互的模型。

/packages/cookbook_events/models/cookbook_event.php创建一个新的文件。

创建model类并指定数据库表名:

<?php
defined('C5_EXECUTE') or die(_("Access Denied."));
class CookbookEvent extends Model {
   var $_table = 'CookbookEvents';
    public function getDate() {
        return date(DATE_APP_GENERIC_MDY_FULL, strtotime($this->event_date));
    }
}

注意我们命名类为CookbookEvent而不是仅仅Event。这是为了防止与其他类冲突。由于Event是一个相当常见的类名,可能存在冲突。始终让类名尽可能独特,同时遵循约定并易于理解。

我们还添加了一个函数来返回事件的格式化版本。这将在以后很有用。

单页控制器

为了让我们的附加组件在仪表板上具有接口,我们需要创建几个带有控制器的单页。

/packages/cookbook_events/controllers/dashboard/cookbook_events.php创建一个文件。这是附加组件的根控制器文件。给它一个基本的类文件:

<?php
defined('C5_EXECUTE') or die(_("Access Denied."));
class DashboardCookbookEventsController extends Controller {
    public function on_start() {
        $this->redirect('/dashboard/cookbook_events/list');
    }
}

on_start函数将确保如果有人访问这个页面,他们将被重定向到默认视图,显示事件列表。现在让我们为这个视图创建控制器。

现在在/packages/cookbook_events/controllers/dashboard/cookbook_events/创建一个新的目录。向这个目录添加两个文件:add.phplist.php

list.php中添加以下类:

<?php
defined('C5_EXECUTE') or die(_("Access Denied."));
class DashboardCookbookEventsListController extends Controller {   
}

太棒了!现在在add.php中添加另一个类:

<?php
defined('C5_EXECUTE') or die(_("Access Denied."));
class DashboardCookbookEventsAddController extends Controller {
}

看起来不错!我们的单页现在有了基本的控制器,但它们仍然需要视图文件。

单页视图

/packages/cookbook_events/single_pages/cookbook_events.php创建我们界面的根视图文件。留这个文件为空。在/packages/cookbook_events/single_pages/cookbook_events创建一个目录。将两个文件add.phplist.php添加到这个目录中。我们现在可以留这些文件为空。

事件列表块类型

在我们能够安装我们的包之前,我们需要确保该块类型也存在。这将允许我们在包安装期间自动安装块类型。

我们正在创建的这个块类型将显示已输入数据库的事件列表。它将作为网站事件的简单日程视图。

/packages/cookbook_events/blocks创建一个新的目录。现在,在这个目录中创建另一个名为cookbook_events的目录。

我们将首先添加到我们的块中的第一个文件是控制器。在块的目录中创建controller.php

controller.php中输入以下代码:

<?php defined('C5_EXECUTE') or die(_("Access Denied."));
class CookbookEventsBlockController extends BlockController {
    protected $btTable = "btCookbookEvents";
    protected $btInterfaceWidth = "350";
    protected $btInterfaceHeight = "300";
    public function getBlockTypeName() {
        return t('Events List');
    }
    public function getBlockTypeDescription() {
        return t('A list of events!');
    }
}

注意我们记得在文件顶部包含所需的 defined or die 语句。我们将继续使用 Cookbook 前缀来命名我们的类名,以便我们的类避免与现有类冲突。

我们还定义了此块类型将使用的数据库表名称。现在让我们使用数据库 XML 格式创建该表。

块的数据库 XML 文件

在块目录中创建一个名为 db.xml 的新文件。在 XML 文件中输入以下代码:

<?xml version="1.0"?>
<schema version="0.3">
   <table name="btCookbookEvents">
      <field name="bID" type="I">
         <key />
         <unsigned />
      </field>
      <field name="item_limit" type="I"></field>
   </table>
</schema>

此 XML 代码将告诉 concrete5 创建一个包含两个字段的新表:一个唯一 ID 用于识别块,以及一个字段用于存储我们想要显示的事件数量。

块视图文件

如果您还记得前面的章节,块有三个可激活的视图:添加、编辑和查看。创建 add.phpedit.phpview.php 来表示这些视图。在我们的块中,add.phpedit.php 将显示相同的 HTML,因此我们将为这些视图创建一个第四个文件,命名为 form.php。另外,添加一个 view.css 文件,该文件将用于应用块的前端样式。

目前请留这些文件为空,因为我们准备安装我们的块!

安装包

在您的代码编辑器中打开包控制器(位于 /packages/cookbook_events/controller.php)。向控制器类中添加一个名为 install 的新方法。它应该看起来像以下代码片段:

public function install() {
    $pkg = parent::install();
    // Add the dashboard pages
    $mainPage = SinglePage::add('/dashboard/cookbook_events', $pkg);
    $listPage = SinglePage::add('/dashboard/cookbook_events/list', $pkg);
    $addPage = SinglePage::add('/dashboard/cookbook_events/add', $pkg);
    // install the block type
    BlockType::installBlockTypeFromPackage('cookbook_events', $pkg); 
}

这里发生了什么?好吧,如果您还记得,我们创建了三个带有控制器的单个页面用于仪表板界面。这些页面需要添加到网站地图中,因此我们挂钩到包的安装例程,以确保它们在安装包时被安装。

接下来,我们还安装了块类型。这将确保我们的块可以在网站的前端使用。

当 concrete5 安装该包时,它将运行我们的包的 db.xml 文件,创建其中定义的数据库表。这将使我们的包保持完全可移植,并且可以在任何 concrete5 网站上安装。

让我们现在安装这个包。

将包安装到仪表板

访问您的 concrete5 网站上的包安装页面,位于 /dashboard/extend/install/。您应该看到等待安装的事件包,如下面的截图所示:

将包安装到仪表板

点击包上的 安装 按钮。如果一切顺利,包将被安装!我们应该在仪表板上有一些新页面,所以访问 /dashboard/cookbook_events

您注意到发生了什么吗?当我们访问 /dashboard/cookbook_events 页面时,它将我们重定向到 /dashboard/cookbook_events/list/。这是故意的。仪表板的组织方式要求插件有一个父页面。这将允许我们的 事件列表添加事件 单个页面在仪表板菜单中正确显示。

此列表页面仍然是完全空的。让我们添加一些 HTML 并填充它。

创建列表单页

首先,我们将向列表页面的控制器文件中添加一些逻辑。在您的代码编辑器中打开 /packages/cookbook_events/controllers/dashboard/cookbook_events/list.php

向控制器类中添加一个视图方法:

public function view() {
    Loader::model('cookbook_event', 'cookbook_events');
    $event = new CookbookEvent();
    $events = $event->find('1=1 ORDER BY event_date');
    $this->set('events', $events);
}
public function delete($id = null) {
    if ($id) {
        Loader::model('cookbook_event', 'cookbook_events');
        $event = new CookbookEvent();
        $event->load('id = ?', $id);
        $event->delete();
        $this->redirect('/dashboard/cookbook_events/list?deleted');
    }
}

记住view()是单页查看时自动执行的回调函数之一。在这里,我们正在加载我们创建并使用的model类,并使用它来查找数据库中所有事件的实例。然后我们使用$this->set()将事件对象的数组发送到视图。

我们还添加了一个函数来从系统中删除事件,使用model类和活动记录。

创建列表视图

让我们打开视图并添加一些 HTML 到其中。在您的编辑器中打开 /packages/cookbook_events/single_pages/dashboard/cookbook_events/list.php

将以下 HTML 代码添加到视图文件中:

<?php defined('C5_EXECUTE') or die(_("Access Denied.")); ?>
<div class="ccm-ui">

   <?php if (isset($_GET['success'])): ?>
      <div class="alert-message">
         <?php echo t('The event was saved successfully!') ?>
      </div>
   <?php endif; ?>
   <?php if (isset($_GET['deleted'])): ?>
      <div class="alert-message">
         <?php echo t('The event was deleted successfully!') ?>
      </div>
   <?php endif; ?>
   <div class="ccm-pane">
      <?php
         $dashboard = Loader::helper('concrete/dashboard');
         echo $dashboard->getDashboardPaneHeader(t('Events'));
      ?>
      <div class="ccm-pane-body">
         <?php if (!empty($events)): ?>
            <table class="table table-striped table-bordered">
               <tr>
                  <th><?php echo t('Event ID') ?></th>
                  <th><?php echo t('Date') ?></th>
                  <th><?php echo t('Title') ?></th>
                  <th><?php echo t('Location') ?></th>
                  <th><?php echo t('Actions') ?></th>
               </tr>
               <?php foreach ($events as $event): ?>
                  <tr class="event-row">
                     <td><?php echo $event->id ?></td>
                     <td><?php echo $event->getDate() ?></td>
                     <td><?php echo $event->title ?></td>
                     <td><?php echo $event->location ?></td>
                     <td>
                        <a href="<?php echo $this->url('/dashboard/cookbook_events/add/edit/', $event->id) ?>" class="btn"><?php echo t('Edit') ?></a>
                        <a href="<?php echo $this->action('delete', $event->id) ?>" class="btn danger delete"><?php echo t('Delete') ?></a>
                     </td>
                  </tr>
               <?php endforeach; ?>
            </table>
         <?php else: ?>
            <p>
               <?php echo t('There are no events! Add one now.'); ?>
            </p>
         <?php endif; ?>
      </div>
      <div class="ccm-pane-footer"></div>
   </div>
</div>

这里有很多东西,但实际上并不复杂。首先,我们确保在文件顶部包含defined or die语句。接下来,我们输出仪表板面板的标题。这包括用于在添加组件中导航的控件,以及将页面添加到主仪表板菜单中。

有一点更往下,我们检查$events数组中是否有内容。如果有,我们可以用 HTML 表格显示事件列表。如果没有,我们将向用户显示一条消息,说明系统中没有事件。

接下来,我们创建一个 HTML 表格来存放事件。该表格有五个列:事件 ID、事件日期、标题、地点以及一个用于对事件执行某些操作的列。

一旦我们开始遍历事件数组,我们将为系统中的每个事件输出一行表格。事件行中的每一列将输出事件对应的字段。注意使用了日期获取函数来输出格式良好的日期。

最后一个列包含编辑和删除事件的按钮。我们给删除按钮添加了一个额外的 CSS 类.delete,这将允许我们使用 JavaScript 显示一个确认消息。让我们保存这个文件并刷新页面:

创建列表视图

看起来不错,但我们系统中还没有任何事件。让我们创建一个表单来添加事件。

创建添加表单单页

在您的代码编辑器中打开 /packages/cookbook_events/controllers/dashboard/cookbook_events/add.php。让我们向这个类中添加几个函数:

public function edit($id = null) {
   if ($id) {
      // in edit mode, load the event to be edited
       Loader::model('cookbook_event', 'cookbook_events');
      $event = new CookbookEvent();
      $event->load('id = ?', $id);
      // pass the event object to the view as an array
      $this->set('data', (array) $event);
   }
}

public function save() {
   $data = $_POST;
   // verify that all required fields have been filled out
   $val = Loader::helper('validation/form');
   $val->setData($data);
   $val->addRequired('title', t('Please enter a title.'));
   $passed = $val->test();
   if (!$passed) {
      $this->set('errors', $val->getError()->getList());
   }
   else {
      $dth = Loader::helper('form/date_time');
      Loader::model('cookbook_event', 'cookbook_events');
      $event = new CookbookEvent();
      if ($data['id']) {
         $event->load('id = ?', $data['id']);
      }
      $event->title = $data['title'];
      $event->event_date = $dth->translate('event_date');
      if ($data['location']) {
         $event->location = $data['location'];
      }
      if ($data['description']) {
         $event->description = $data['description'];
      }
      if (!$data['id']) {
         $user = new User();
         $event->created_by = $user->getUserID();
         $event->created_at = date('Y-m-d H:i:s');
      }
      $event->save();

      $this->redirect('/dashboard/cookbook_events/list?success');
   }
}

首先,我们添加了一个函数来为这个表单提供编辑功能。本质上,如果 URL 中提供了 ID,我们将使用事件模型加载相应的事件并将其作为数组发送到视图。我们使用数组是因为如果数组为空,视图不会像对象那样产生错误。

接下来,我们定义一个实际保存新事件的函数。我们使用验证助手来验证所需字段是否已填写。之后,我们开始填充要保存到数据库的事件对象。这里需要注意的一个重要事项是我们检查POST数据中是否存在事件 ID。这是为了允许我们编辑现有事件,而不是创建一个重复的事件。我们还使用这个区域来设置事件的元数据,例如添加该事件的用户 ID 和创建时的时间戳。

最后,我们将事件对象保存到数据库中,并将用户重定向回事件列表,显示成功消息。

表单视图文件

当然,我们仍然需要编写这个单页面的另一半,即视图。让我们打开/packages/cookbook_events/single_pages/dashboard/cookbook_events/add.php,并向其中添加以下 HTML 和 PHP 代码:

<?php 
   defined('C5_EXECUTE') or die(_("Access Denied."));
   $form = Loader::helper('form');
   $dth = Loader::helper('form/date_time');

   Loader::element('editor_init');
   Loader::element('editor_config');
?>
<div class="ccm-ui">
   <?php if (!empty($errors)): ?>
      <div class="alert-message block-message error">
         <strong><?php echo t('There were some problems saving the event.') ?></strong>
         <ul style="margin-top: 5px;">
            <?php foreach ($errors as $e): ?>
               <li><?php echo $e ?></li>
            <?php endforeach ?>
         </ul>
      </div>
   <?php endif; ?>
   <div class="ccm-pane">
      <?php
         $dashboard = Loader::helper('concrete/dashboard');
         echo $dashboard->getDashboardPaneHeader(t('Add Event'));
      ?>
      <form action=<?php echo $this->action('save') ?> method="POST">
         <div class="ccm-pane-body">
            <table class="table table-striped table-bordered">
               <tr>
                  <td class="form-label">
                     <?php echo t('Event Title') ?>
                     <span class="req">*</span>
                  </td>
                  <td>
                     <?php echo $form->text('title', $data['title']) ?>
                  </td>
               </tr>
               <tr>
                  <td class="form-label">
                     <?php echo t('Event Date') ?>
                     <span class="req">*</span>
                  </td>
                  <td>
                     <?php echo $dth->datetime('event_date', $data['event_date']) ?>
                  </td>
               </tr>
               <tr>
                  <td class="form-label">
                     <?php echo t('Location') ?>
                  </td>
                  <td>
                     <?php echo $form->text('location', $data['location']) ?>
                  </td>
               </tr>
               <tr>
                  <td class="form-label">
                     <?php echo t('Description') ?>
                  </td>
                  <td>
                     <?php
                        Loader::element('editor_controls');
                        echo $form->textarea('description', $data['description'], array('style' => 'width:100%;', 'class' => 'ccm-advanced-editor'));
                     ?>
                  </td>
               </tr>
            </table>
         </div>
         <div class="ccm-pane-footer">
            <div class="pull-right">
               <input type="submit" class="btn primary" value="<?php echo t('Save Event') ?>">
               <a href="<?php echo $this->url('/dashboard/cookbook_events/list') ?>" class="btn"><?php echo t('Cancel') ?></a>
            </div>
         </div>
         <?php if (!empty($data)): ?>
            <input type="hidden" name="id" value="<?php echo $data['id'] ?>">
         <?php endif; ?>
      </form>
   </div>
</div>

哇,这代码好多!别担心,它并没有看起来那么复杂。在文件顶部,我们当然添加了我们的defined or die语句,然后加载两个助手,即表单助手和日期字段助手。

由于我们的事件描述字段可以包含 HTML 格式,我们需要使用一个所见即所得(WYSIWYG)编辑器。这个编辑器在加载之前需要在页面上添加一些特殊的 JavaScript,所以我们立即使用editor_initeditor_config元素输出它。

接下来,我们首先显示在保存过程中发生的任何错误(例如,如果标题字段被留空)。之后,我们使用 concrete5 的仪表板助手输出页面的标题,包括原生页面控件。

之后,我们将定义表单,设置表单的动作使用本页面控制器中的save函数,并设置 HTTP 方法为POST

在表单内部,我们使用表格来为我们的表单提供一个简单的布局。我们输出标题、位置、日期和描述的字段。在页面底部,我们显示一些按钮来保存数据或取消并返回到事件列表。现在让我们在我们的浏览器中查看这个表单!

表单视图文件

看起来很棒!现在让我们使用这个表单添加一些事件到网站上。

将事件添加到数据库

填写出现的添加事件表单,添加一些要添加到数据库的事件:

将事件添加到数据库

一旦你输入了几个事件,你的列表视图应该看起来像以下这样:

将事件添加到数据库

看起来很棒!让我们点击这些事件中的一个的删除按钮。它有效,但如果用户改变主意,他们没有任何机会取消这个操作。我们应该使用 JavaScript 询问用户他们是否确定要删除该事件。

添加删除确认

让我们在/packages/cookbook_events/js/list.js中添加一个新的 JavaScript 文件。添加一些 JavaScript(使用 jQuery 库)以监听删除按钮的点击:

$(document).ready(function() {
   $('.delete').on('click', function(e) {
      return confirm('Are you sure you want to delete this item?');
   });
});

接下来,我们需要确保这个脚本包含在我们的列表页面上。打开位于/packages/cookbook_events/controllers/dashboard/cookbook_events/list.php的列表页面的控制器。

向页面添加一个新函数以包含 JavaScript 文件:

public function on_before_render() {
    $html = Loader::helper('html');
    $this->addHeaderItem($html->javascript('list.js', 'cookbook_events'));
}

这个函数将使用 HTML 助手自动将<script>标签添加到页面的<head>区域。

现在,如果你尝试删除一个事件,你应该会看到一个确认对话框,如下面的截图所示:

添加删除确认

完美!我们可以认为插件的后端已经完成!剩下要做的就是在前端显示事件。

创建自定义块类型

如果你记得,我们为我们的块类型创建了一些样板文件,但实际上并没有做任何事情。我们希望创建一个显示数据库中输入的事件列表的块。

首先,让我们向form.php添加 HTML 表单,该表单将在网站编辑器添加或编辑块时显示:

<?php
defined('C5_EXECUTE') or die(_("Access Denied.")); 
$form = Loader::helper('form');
?>
<div class="ccm-ui">
   <table class="table table-striped table-bordered">
      <tr>
         <td>
            <?php echo t('Maximum events to show') ?>
         </td>
         <td>
            <?php echo $form->text('item_limit', $item_limit) ?>
         </td>
      </tr>
   </table>
</div>

太好了!让我们将此文件包含在add.phpedit.php中。向每个文件添加以下内容:

<?php 
defined('C5_EXECUTE') or die(_("Access Denied.")); 
include('form.php');

好吧!我们现在要做的就是创建块的客户端视图。在你的代码编辑器中打开view.php,并输入以下 HTML 和 PHP 代码:

<?php defined('C5_EXECUTE') or die(_("Access Denied.")); ?>
<h1 class="events-title"><?php echo t('Events Calendar') ?></h1>
<div class="events-list">
   <?php if (!empty($events)): ?>
      <?php foreach ($events as $event): ?>
         <div class="event-item">
            <h2><?php echo $event->title ?></h2>
            <div class="event-date">
               <?php echo $event->getDate() ?>
               <?php if ($event->location): ?>
                  @ <?php echo $event->location ?>
               <?php endif; ?>
            </div>
            <?php if ($event->description): ?>
               <div class="event-description">
                  <?php echo $event->description ?>
               </div>
            <?php endif; ?>
         </div>
      <?php endforeach; ?>
   <?php else: ?>
      <p><?php echo t('There are no events!') ?></p>
   <?php endif; ?>
</div>

看起来很棒!在这里,我们实际上是在遍历$events数组并为每个事件显示一行。我们再次利用事件模型上的getDate()函数来输出干净友好的日期。

最后,让我们向view.css添加一些简单的 CSS 样式:

h1.events-title {
    margin-bottom: 30px !important;
}
.event-item {
    padding: 20px 0;
    border-bottom: 1px solid #ddd;
}
.event-item:last-child {
    border-bottom: 0;
}
.event-item p {
    margin: 0 !important;
}
.event-date {
    font-size: 12px;
    color: #888;
}

很好!现在我们准备好看到它的实际效果了!

将块添加到页面

在网站上创建一个新页面来保存事件:

将块添加到页面

在此页面上添加一个新块。滚动到块列表的底部,查看我们创建的块:

将块添加到页面

填写表格以将块添加到页面。设置要显示的事件数量限制。

将块添加到页面

现在将页面上的更改发布。你应该会看到一个令人印象深刻的事件列表!

将块添加到页面

总结

哇,我们取得了很大的成就!我们从一无所有开始,构建了一个完全功能的事件日历插件。这个插件可以扩展以显示事件的不同模板,或者包括高级功能,例如隐藏已发生的事件,或者在网站地图中为每个事件提供自己的页面。

希望这次练习能帮助你获得如何为任何需求或情况创建包的想法。

附录 C. 提交 concrete5 市场附加组件包

大多数内容管理系统都有某种插件或模块。concrete5 相对独特,因为它附带了一个完整的附加组件和主题生态系统。这允许附加组件开发者通过为 concrete5 创建的包赚取一些收入,同时也支持 concrete5 团队,因为 concrete5 从每个销售的附加组件中获得一定比例的收益。

提交 concrete5 市场附加组件包

规则

你的附加组件必须遵守一些规则。首先,你的附加组件必须能够工作。在安装或使用附加组件时不应出现任何错误。此外,请确保你拥有附加组件中包含的所有代码和资产的权利,或者你已经从代码作者那里获得了包含其代码在附加组件中的适当许可。

一些其他规则包括在每个 PHP 文件顶部使用 defined or die 语句,包括一个图标,并确保将所有字符串包装在全局 t() 函数中。附加组件开发者还预期将支持他们的附加组件并发布更新以修复错误和解决客户投诉。

concrete5 网站上发布了更多提示和规则,请参阅 www.concrete5.org/developers/marketplace-submission-rules/

流程

当向 concrete5 市场提交包时,首先你需要在 www.concrete5.org 上有一个账户。一旦你创建了账户,你必须填写一个表格(位于 www.concrete5.org/marketplace/manage_item/),其中包含有关你的包的信息:

流程

你将填写所有将在市场列表中出现的营销副本,以及一些关于你的附加组件的内部元数据。

一旦你提交了附加组件,将对其进行一些自动化测试,以查看它是否符合资格要求。一旦附加组件通过这些测试,同行评审委员会PRB)的成员将审查你的附加组件。

同行评审委员会

PRB 是来自 concrete5 社区的一组志愿者。这些志愿者负责测试提交给市场的每个附加组件和主题。他们将在自己的 concrete5 版本上安装你的包并进行全面测试,以确保它不会遇到困难,并确保你的附加组件遵守规则。

销售你的附加组件

concrete5 允许开发者销售他们的附加组件。你可以为附加组件设定的最低价格(除了免费)是 15 美元。concrete5 将保留你附加组件收入的 25%,但他们在市场中将你的附加组件作为特色推荐所提供的曝光通常值得一小笔佣金。

如果你在大理石 5 市场中销售插件,你将需要支持它。如果你的插件无法正常工作,而你又没有提供支持,大理石 5 将退还客户并对你收取 15%的罚款。确保你已经准备好投入时间来支持你的插件。

一旦插件获得批准...

如果你的插件通过了审查委员会并获得批准,它将在大理石 5 市场中列出为可用。务必注意客户咨询或支持请求。此外,如果你正在销售你的插件,请记住定期请求下载付款。

官方资源

以下链接推荐给有兴趣销售其主题和插件的开发者:

posted @ 2025-09-05 09:26  绝不原创的飞龙  阅读(6)  评论(0)    收藏  举报