组件开发
介绍
组件文件和目录位于插件目录的 /components 子目录中。 每个组件都有一个定义组件类的PHP文件和一个可选的组件partials目录。 组件partials目录名称与以小写字母书写的组件类名称匹配。 组件目录结构的示例:
plugins/acme/myplugin/components/componentname/ <=== 组件partials目录default.htm <=== 组件默认标记(可选)ComponentName.php <=== 组件类文件Plugin.php
组件必须使用registerComponents方法在Plugin注册类中注册。
组件类定义
组件类文件定义组件功能和组件属性。 组件类文件名应与组件类名匹配。 组件类应该继承\Cms\Classes\ComponentBase类。 下一个示例的组件应该在plugins/acme/blog/components/BlogPosts.php文件中定义。
namespace Acme\Blog\Components;class BlogPosts extends \Cms\Classes\ComponentBase{public function componentDetails(){return ['name' => 'Blog Posts','description' => 'Displays a collection of blog posts.'];}// This array becomes available on the page as {{ component.posts }}public function posts(){return ['First Post', 'Second Post', 'Third Post'];}}
componentDetails方法是必需的。该方法应该返回一个带有两个键的数组:name和description。 名称和说明显示在CMS后端用户界面中。
当此组件附加到页面或布局时,类属性和方法在页面上通过组件变量可用,该组件变量的名称与组件短名称或别名匹配。 例如,如果上一个示例中的BlogPost组件是在具有短名称的页面上定义的:
url = "/blog"[blogPosts]==
您可以通过blogPosts变量访问其posts方法。 请注意,Twig支持方法的属性表示法,因此您不需要使用括号。
{% for post in blogPosts.posts %}{{ post }}{% endfor %}
组件注册
必须通过覆盖Plugin注册类中的registerComponents方法来注册组件。 这告诉CMS有关组件并提供短名称以便使用它。 注册组件的示例:
public function registerComponents(){return ['October\Demo\Components\Todo' => 'demoTodo'];}
这将使用默认别名demoTodo注册Todo组件类。 有关使用组件的更多信息,请参见CMS组件文章。
组件属性
将组件添加到页面或布局时,可以使用属性对其进行配置。 使用组件类的defineProperties方法定义属性。 下一个示例显示了如何定义组件属性:
public function defineProperties(){return ['maxItems' => ['title' => 'Max items','description' => 'The most amount of todo items allowed','default' => 10,'type' => 'string','validationPattern' => '^[0-9]+$','validationMessage' => 'The Max Items property can contain only numeric symbols']];}
该方法应该返回一个数组,其中属性键作为索引,属性参数作为值。 属性键用于访问组件类中的组件属性值。 使用具有以下键的数组定义属性参数:
| 键 | 描述 |
|---|---|
| title | 标题,必需的属性,它由CMS后端的组件Inspector使用。 |
| description | 必需的属性描述,它由CMS后端的组件Inspector使用。 |
| default | 选填,将组件添加到CMS后端中的页面或布局时使用的默认属性值。 |
| type | 选填,指定属性类型。 该类型定义了在Inspector中显示属性的方式。 目前支持的类型是string,checkbox和dropdown。 默认值:string。 |
| validationPattern | 用户在检查器中输入属性值时使用的可选正则表达式。 验证只能用于string属性。 |
| validationMessage | 验证失败时显示的可选错误消息。 |
| required | 可选,该字段必填,不填是提示validationMessage中的内容 |
| placeholder | 字符串和下拉属性的可选占位符。 |
| options | 下拉属性的可选选项数组。 |
| depends | 下拉属性所依赖的属性名称数组。 请参阅下面的下拉属性。 |
| group | 一个可选的组名。 组在Inspector中创建部分,简化用户体验。 在多个属性中使用相同的组名来组合它们。 |
| showExternalParam | 指定Inspector中属性的外部参数编辑器的可见性。 默认值:true。 |
在组件内部,您可以使用property方法读取属性值:
$this->property('maxItems');
如果未定义属性值,则可以提供默认值作为property方法的第二个参数:
$this->property('maxItems', 6);
您还可以将所有属性加载为数组:
$properties = $this->getProperties();
要从组件的Twig partials访问该属性,请使用引用Component对象的__SELF__变量:
{{ __SELF__.property('maxItems') }}
下拉属性
下拉属性的选项列表可以是静态的或动态的。 静态选项使用属性定义的options元素定义。示例:
public function defineProperties(){return ['units' => ['title' => 'Units','type' => 'dropdown','default' => 'imperial','placeholder' => 'Select units','options' => ['metric'=>'Metric', 'imperial'=>'Imperial']]];}
显示Inspector时,可以从服务器动态获取选项列表。 如果在下拉属性定义中省略options参数,则选项列表被视为动态。 组件类必须定义返回选项列表的方法。 该方法应具有以下格式的名称:get*Property*Options,其中Property是属性名称,例如:getCountryOptions。 该方法返回一个选项数组,其中选项值为键,选项标签为值。 动态下拉列表定义的示例:
public function defineProperties(){return ['country' => ['title' => 'Country','type' => 'dropdown','default' => 'us']];}public function getCountryOptions(){return ['us'=>'United states', 'ca'=>'Canada'];}
动态下拉列表可以依赖于其他属性。 例如,州名单可能取决于所选国家。 依赖项在属性定义中使用depends参数声明。 下一个示例定义了两个动态下拉属性,状态列表取决于国家/地区:
public function defineProperties(){return ['country' => ['title' => 'Country','type' => 'dropdown','default' => 'us'],'state' => ['title' => 'State','type' => 'dropdown','default' => 'dc','depends' => ['country'],'placeholder' => 'Select a state']];}
要加载状态列表,您应该知道Inspector中当前选择的国家/地区。 Inspector将所有属性值POST到getPropertyOptions处理程序,因此您可以执行以下操作:
public function getStateOptions(){$countryCode = Request::input('country'); // Load the country property value from POST$states = ['ca' => ['ab'=>'Alberta', 'bc'=>'British columbia'],'us' => ['al'=>'Alabama', 'ak'=>'Alaska']];return $states[$countryCode];}
页面列表属性
有时组件需要创建指向网站页面的链接。 例如,博客帖子列表包含指向博客帖子详细信息页面的链接。 在这种情况下,组件应该知道帖子详细信息页面文件名(然后它可以使用页面Twig过滤器)。 October包含一个用于创建动态下拉页面列表的帮助程序。 下一个示例定义了postPage属性,该属性显示了一个页面列表:
public function defineProperties(){return ['postPage' => ['title' => 'Post page','type' => 'dropdown','default' => 'blog/post']];}public function getPostPageOptions(){return Page::sortBy('baseFileName')->lists('baseFileName', 'baseFileName');}
路由参数
组件可以直接访问页面URL中定义的路由参数值。
// 返回URL段值,例如: /page/:post_id$postId = $this->param('post_id');
在某些情况下,组件属性可以充当硬编码值或引用URL中的值。
这个硬编码示例显示了使用标识符“2”的博客文章:
url = "/blog/hard-coded-page"[blogPost]id = "2"
或者,可以使用external property value从页面URL动态引用该值:
url = "/blog/:my_custom_parameter"[blogPost]id = "{{ :my_custom_parameter }}"
在这两种情况下,都可以使用property方法检索值:
$this->property('id');
如果需要访问路由参数名称:
$this->paramName('id'); // 返回 "my_custom_parameter"
处理页面执行周期
通过覆盖组件类中的onRun方法,组件可以参与页面执行循环事件。 每次加载页面或布局时,CMS控制器都会执行此方法。 在方法内部,您可以通过page属性将变量注入到Twig环境中:
public function onRun(){// 加载页面或布局并将组件附加到该代码时,将执行此代码。$this->page['var'] = 'value'; // 将一些变量注入页面}
页面执行生命周期处理程序
当页面加载时,October执行可以在布局和页面PHP部分和组件类中定义的处理函数。 执行处理程序的顺序如下:
- 布局Layout
onInit()function. - 页面Page
onInit()function. - 布局Layout
onStart()function. - 布局中的组件Layout components
onRun()method. - 布局Layout
onBeforePageStart()function. - 页面Page
onStart()function. - 页面组件Page components
onRun()method. - 页面Page
onEnd()function. - 组件Layout
onEnd()function.
组建初始化
有时您可能希望在首次实例化组件类时执行代码。 您可以覆盖组件类中的init方法来处理任何初始化逻辑,这将在AJAX处理程序之前和页面执行生命周期之前执行。 例如,此方法可用于动态地将另一个组件附加到页面。
public function init(){$this->addComponent('Acme\Blog\Components\BlogPosts', 'blogPosts');}
页面周期响应
与页面执行生命周期中的所有方法一样,如果组件中的onRun方法返回一个值,这将在此时停止循环并返回 响应浏览器。 这里我们使用Responsefacade返回一个拒绝访问的消息:
public function onRun(){if (true) {return Response::make('Access denied!', 403);}}
AJAX处理
组件可以托管AJAX事件处理程序。 它们在组件类中定义,就像它们可以在页面或布局代码中定义一样。 在组件类中定义的示例AJAX处理程序方法:
public function onAddItem(){$value1 = post('value1');$value2 = post('value2');$this->page['result'] = $value1 + $value2;}
如果此组件的别名是demoTodo,则可以通过demoTodo::onAddItem访问此处理程序。 有关将AJAX与组件一起使用的详细信息,请参阅[调用组件中定义的AJAX处理程序(ajax-handlers.md#calling-handlers))文章。
默认标签
所有组件都可以带有默认标记,当将其包含在带有{%component%}标记的页面上时使用该标记,尽管这是可选的。 默认标记保存在组件partials部分目录中,该目录与小写的组件类具有相同的名称。
默认组件标记应放在名为default.htm的文件中。 例如,Demo ToDo组件的默认标记在文件 /plugins/october/demo/components/todo/default.htm 中定义。 然后可以使用{%component%}标记将其插入页面的任何位置:
url = "/todo"[demoTodo]=={% component 'demoTodo' %}
默认标记还可以采用在渲染时覆盖组件属性 的参数。
{% component 'demoTodo' maxItems="7" %}
这些属性在onRun方法中不可用,因为它们是在页面循环完成后建立的。 相反,可以通过覆盖组件类中的onRender方法来处理它们。 CMS控制器在呈现默认标记之前执行此方法。
public function onRender(){// 此代码将在页面或布局上呈现默认组件标记之前执行。$this->page['var'] = 'Maximum items allowed: ' . $this->property('maxItems');}
组件部分(cms-partials.md)
除了默认标记之外,组件还可以提供可以在前端或默认标记本身内使用的其他部分。 如果Demo ToDo组件具有分页部分,它将位于 /plugins/october/demo/components/todo/pagination.htm 中并使用以下内容显示在页面上:
{% partial 'demoTodo::pagination' %}
可以使用比较容易的方法,即上下文。 如果在组件partial内部调用,它将直接引用自身。 如果在主题partial内部调用,它将扫描页面/布局上使用的所有组件以获得匹配的部分名称并使用它。
{% partial '@pagination' %}
通过将部分文件放在名为 components/partials 的目录中,多个组件可以共享部分。 当找不到通常的组件部分时,此目录中找到的部分用作后备。 例如,位于 /plugins/acme/blog/components/partials/shared.htm 中的共享部分可以由任何组件在页面上显示,使用:
{% partial '@shared' %}
引用自身 “self”
组件可以使用__SELF__变量在其partials中引用它们自己。 默认情况下,它将返回组件的短名称或别名。
<form data-request="{{__SELF__}}::onEventHandler">[...]</form>
组件也可以引用自己的属性。
{% for item in __SELF__.items() %}{{ item }}{% endfor %}
如果在组件partial中你需要渲染另一个组件,则部分地将__SELF__变量与部分名称连接起来:
{% partial __SELF__~"::screenshot-list" %}
唯一标识符
如果在同一页面上调用两次相同的组件,则可以使用id属性来引用每个实例。
{{__SELF__.id}}
每次显示组件时,ID都是唯一的。
<!-- ID: demoTodo527c532e9161b -->{% component 'demoTodo' %}<!-- ID: demoTodo527c532ec4c33 -->{% component 'demoTodo' %}
在代码里引用partials
您可以使用renderPartial方法以编程方式在PHP代码中呈现组件部分。 这将检查组件的名为component-partial.htm的部分,并将结果作为字符串返回。 第二个参数用于传递视图变量。
$content = $this->renderPartial('component-partial.htm');$content = $this->renderPartial('component-partial.htm', ['name' => 'John Smith']);
例如,要将partial作为对AJAX 处理的响应呈现:
function onGetTemplate(){return ['#someDiv' => $this->renderPartial('component-partial.htm')];}
另一个例子可能是通过从onRun 页面循环方法返回一个值来覆盖整个页面视图响应。 此代码将使用“Response”facade专门返回XML响应:
public function onRun(){$content = $this->renderPartial('default.htm');return Response::make($content)->header('Content-Type', 'text/xml');}
使用组件注入页面资源
组件可以将静态文件(CSS和JavaScript文件)注入它们所附加的页面或布局。 使用控制器的addCss和addJs方法将静态文件添加到CMS控制器。 它可以在组件的onRun方法中完成。 请阅读有关在页面文章中注入静态文件.的更多详细信息。 例:
public function onRun(){$this->addJs('/plugins/acme/blog/assets/javascript/blog-controls.js');}
如果addCss和addJs方法参数中指定的路径以斜杠(/)开头,那么它将相对于网站根目录。 如果资源路径不以斜杠开头,则它相对于组件目录。
