月度归档:2016年10月

编写 October CMS Form Widget

 

概述

近期接触 Laravel 这一框架之后,对使用便捷性和功能的丰富感到十分满意,同时开发者与相关的社区都相当活跃,这样的框架算是相当之理想的了。

了解了框架的使用之后,自然是希望能够找到这一框架构建的应用进行进一步的学习。CMS作为常见的系统,模式上个人理解起来比较容易,同时涉及面也比较多,同时还有一定的实用性,学习起来有价值。

使用 Laravel 的 CMS 不少,有本文的主角October CMSAsgard CMSLavalite,但是后续的这些,无论从 GitHub star数目上,还是更新频率上,以及社区活跃度上,完全无法与 October CMS 相提并论。

于是决定简单了解一下October CMS(以下将会用October表示,二者不做区分)。希望通过开发一个表单部件的方式,开始二次开发的学习。

本文写作的前提是:

  • 使用过基本的OctoberCMS的Ajax框架
  • 基本了解后端管理界面的组织方式
  • 了解基本的jQuery/CSS知识
  • 了解基本的Laravel使用

需求

October宣传自身是一个简单、现代、以人为本、通用的、可拓展的、有趣的、可靠地、易学、节省时间的CMS。

对于OctoberCMS,对于一对多的关系,可以在model层进行处理。

然而,处于对体验优化的考虑,简单的关联记录的效果并不能满足。譬如需要完成一个相关文章的编辑表单,如果能够以card的形式展现相关文章的头图标题摘要等内容,那么会更加便于后台人员的操作,提供更好的体验。

同时,可以通过这一个简单的表单插件,熟悉October CMS表单插件的二次开发。

总而言之,需求如下:

  • 开发一个相关记录的表单插件
  • 表单插件可以显示相关记录的头图标题摘要
  • 相关记录可以调整顺序

OctoberCMS 表单部件

OctoberCMS的有一类组件,被称为Form组件,为后台操作数据提供了极大的方便,通过配置各种Form插件的组合,可以对数据进行操作。

常规的管理界面的开发,一种模式是通过编写接口,提供修改对应数据的功能,并且前端开发需要构建对应的操作界面。对于CMS系统,这样无疑是一个低效的行为,使得管理平台开发也成为了开发工作的一大负担,提供更为简便的管理平台开发方式,对于减少开发工作量有很大意义。

OctoberCMS的表单部件通过yaml配置文件的形式,将数据库字段与前端编辑表单部件关联起来,为快速构建针对于数据的管理界面提供了可能。

针对于基本的字符串,时间选择器,富文本编辑器,单选/复选框,OctoberCMS也都默认提供了。

组件设计

对于表单部件,功能上可以一言概之,即通过图形方式构建JSON格式的字符串,并写入数据库。

设计细化

细化需求来说,关键点在于表单,数据格式,图形界面。

对于表单,最简单的情况即通过一个input标签,在进行form提交时,带上需要提交的数据。

对于数据格式,我们需要记录的是相关记录的数据库中的自增ID,存储格式会整编为JSON格式。

对于图形界面,考虑到操作的便捷性,同时考虑到显示足够的有效信息,通过显示blog的头图、标题、摘要等信息的card的形式,表现关联记录。

进一步细化[表单]

对于表单来说,只需要确定表单中的name属性即可。

新增的情况,无需填充记录的默认值,而在更新的情况,则需要进行填充,相关PHP代码的说明会在后续提及。

进一步细化[数据格式]

选用JSON作为数据格式,记录各个关联记录的自增ID。

进一步细化[图形界面]

同时显示头图,标题,摘要,通过card形式展现。

操作上,需要有增加删除调整顺序三种。

  • 增加操作可以通过弹出记录列表的形式,选取后展现。
  • 删除则直接通过点击card上的删除按钮/文字即可。
  • 调整顺序通过前移/后移按钮完成。

组件目录结构

OctoberCMS的表单插件需要符合一定的目录结构规则。

可以通过直接创建对应的目录以及文件,也可以通过内置的工具进行初始化:

rainlab.blog 是将要创建这一组件的插件的名称,这里可以换成自己插件的名字。关于插件,参见OctoberCMS的手册

自动建立的目录结构如下:

文件不多,简而言之,RelatedRecords.php用来描述表单部件以及编写处理逻辑,relatedrecords.css自然是控制表单后台操作样式,relatedrecords.js则是实现表单项目在后台的前端操作逻辑,最后partials中的_relatedrecords.htm则定义了表单部件在后台的html展示部分。

如果不想通过内置工具生成表单部件,同样也可以直接在对应plugin的目录中中的widgets子目录中直接新增插件的方式完成,仿照October默认的modules/backend中表单插件的结构即可:

本文的demo即是通过这种方式生成的,结构如下:

可以看到,二者并无太大差别,都需要有css/js/partial以及主要的逻辑所在的.php文件,后续以demo中的文件组织结构进行描述。

组件实现细节简述

主要逻辑文件RelatedRecords.php

这一文件要直接放置于widgets的目录之下。

需要继承Backend\Classes\FormWidgetBase这一基类,同时我们需要实现一些关键的方法,以便完成逻辑以及正确显示组件。

下面,将会说明几个关键的方法。

init()

init()方法顾名思义,即初始化表单部件,一些组件自身需要进行的变量定义,参数定义等操作可以在这里编写。

在使用过程中,每个表单部件都或多或少有一些自定义的参数,譬如富文本编辑器的大小等,这些参数通过yaml文件配置,但是如何才能在表单部件中的读取到呢?

可以在init()中调用fillFromConfig()这一成员方法,通过数组的形式,将参数名传入,之后将会出现同名的成员变量,其值就是传入的参数名称。如果没有设定,那么也可以指定默认值。

为了完成需求,我们需要允许配置:

  • titleField card的标题域数据库字段名
  • imageField card的图片域数据库字段名
  • contentField card的正文域数据库字段名
  • modelClass 需要操作的Model名称
  • whereClause 查询数据时的WHERE子句内容
  • recordsPerPage 弹出列表页每页显示个数

在实际使用中,在models/yourmodel/下的fields.yaml文件中指定使用这一表单部件时,可以通过指定这些参数的形式,影响展现以及效果,形如:

render()

render()方法,即完成组件的渲染,如果已经设定好了模板中需要的值,那么只需要通过makePartial这一个成员方法即可对当前组件渲染完成。

实现以上两个方法之后,几乎这一组件就能基本上完成数据获取并展现的功能了。其他方法,也可以按照默认生成的文件的模式进行组织。

模板文件_relatedrecords.htm

模板文件作为一个partial,文件名需要以下划线开头,放置在组件的partials目录下。

由于实际要修改的数值是一个JSON格式的数组,提交时,实际上是作为表单的一对键值。为了完成表单提交,需要设定input标签的name属性。

那么问题来了,如何才能设定正确的name属性呢?

OctoberCMS框架在实现表单部件时,会根据表单部件所对应的Model和列的名称,生成key的名字,即input标签的name属性,可以通过成员变量formField的方法getName()获取。

在主逻辑文件RelatedRecords.phprender()(或者其他被这一方法调用的方法之中),为name属性赋值:

在partial中进行相应变量赋值代码编写即可。

而展现上,使用了部分materialize的样式,实现了图文card的显示效果。

弹出列表模板文件_list_related_records_sample.htm

图文card的底部,有添加记录的按钮,但是如何才能最便捷的展现出可以加入的记录呢?

这里可以借用OctoberCMS内置的一个特性:Remote popups

实现简要说明

想要通过列表展示数据对于OctoberCMS来说简直是轻而易举。从操作步骤上来看,可以描述如下:

  • 点击添加
  • 触发Ajax请求,请求对应Controller上的方法
  • 对应方法获取指定数据,渲染partial返回

Ajax请求如何能够返回并显示html呢?作为OctoberCMS的一个重要特性,简要来说即通过特定的请求方法发出请求,指定操作的handler。这里可以通过js完成。

参见下的assets/js/relatedrecords.js文件:

通过popup方法,指定了handler为onLoadRelatedRecords方法。

handler方法归属的Controller,即当前编辑对象所对应的

Controller,所以,需要在Controller中实现对应的同名方法。demo中编辑的是Sample这一个对象,那么方法实现起来将会类似:

考虑到不能重复加入关联记录,所以每次请求要通过excludeIds传入已加入的id,进行排除。

通过popup方式弹出列表之后,选择加入这些操作就相当容易实现了。

其他如前端的操作、样式的编写等等不在赘述。

注册表单部件

完成上述工作之后,还需要关键的一步,即在Plugin.php中的registerFormWidgets()方法注册编写完成的组件。

组件效果

通过弹出的Modal窗口添加关联:

select related records

选择后可供调整顺序或移除:

selected

《从自我苛求中解放出来》

 

概述

《从自我苛求中解放出来》是弗雷德里克•方热 (Frédéric Fanget)的一本出版书籍。这位任教于法国里昂第一大学的精神科医生、心理治疗师也是一位畅销书作家。

微博上看到@郝景芳推荐,决定购入阅读。

想要让所有人都能够满意,希望能做好每一件事,似乎是很多人所期望的。但是事与愿违的情况会远比想象中的做,太过于在意他人的感受,陷入对自己的不完美的懊悔之中,给自己带来了痛苦。

各个地方不乏对于悦纳自我,接受缺陷的,拜托焦虑这类的说辞,但是具体的实现方式却语焉不详,这本小书的优势就在于此。没有说教的成分,语言上的通俗让人易于接受,而篇幅也比较适中。

个人的内心的正确认识是个很困难的事情,另外没有学习过类似的课程,自己尝试一下分析消化读到的内容。

笔记

认同书中最后提到的一个等式:

尤其是身处的环境,多次证明了在当前的情况下,选择给生活带来的影响相当巨大,职业上来说更是如此。看到了选择带来的巨大差距之后,焦虑的放大系数会变得更大,很多时候会更加的畏首畏尾。

然而做出选择并不一定是让自己最愉快的,往往都会被内心自我苛求的声音给勒索,原本能保护自己的焦虑成了伤害的来源。

这个时候使用工具一定程度上可以帮助分解问题,找到办法打破或者改变恶性循环。

认知概念化

作者提出的认知概念化方法,一个实现的方式,就是通过循环图的形式将其模型化,在可视化问题的各个阶段和状态流转之后,辅助认识问题。

做出选择一般都事出有因,大多数是来源于一个人生准则,比如完美主义,书中举例一位以“做事求赞”为生活准则的女性的例子(人生准则细则的原文是必须做出超乎寻常的事),例子的主角为了避免被人否定,而季度的追求完美主义,希望万事都是做的完美。

通过认知概念化的方法,会发现造成例子中的主角内心不自由的根源在于扭曲了信心和价值感的获取和渴望出色的完成事情的关系,在周而复始的过程中,这个扭曲会不断的加强,从而绑架了个人。

实现认知概念化的方法,简单概括为:

  • 确定具体情境
  • 找到这一情境下行为准则
  • 找到对行为的影响
  • 找到对情绪的影响
  • 推导出认知扭曲的结果
  • 最后总结出对个人的影响

生活中的一些场景,个人按照这一方法分析,如内向的人被拉去聚会结识新朋友,可以是:

  1. 具体情境:结识新朋友
  2. 行为准则:必须外向,否则不会受欢迎
  3. 对行为的影响:尝试与他人热烈的沟通,获取认同
  4. 对情绪的影响:满足
  5. 认知扭曲:因为变得外向,所以能够结识新朋友
  6. 对个人的影响:要改变自己内向的状态,迎合大家

事实上,人际关系的建立,个人也一定程度上决定于个人的内在特质,内向外向的性格固然影响巨大,但是因为这一人生准则而痛苦不堪,是没有必要的。

带来问题的人生准则

什么样的准则可能会带来问题?

简答来说,如下句式的可能会带来问题:

  • 必须
  • 应该
  • 如果……才会……

更容易的一个概括方式,大概就是书中提及的,美国认知疗法先驱Alber Ellis提出的musturbation了,第一个音节的must概括了这类认知的特性,即一个人给自己的定下的不可改变的人生准则。

在与准则的共处过程中,如果当事人被压制到毫无回旋余地,那么这些准则就变得有害。痛苦也就随之而来。

概念化模板

在说明这一个工具之前,先说两个概念的个人理解:条件认知模式无条件认知模式

条件认知模式是受到外界因素的影响而产生的对事物的看法,而无条件认知模式则是自发的产生的对事物的看法。条件认知模式的更易于接受和理解。

给个人带来困惑的问题实际上可以总结出一个循环,即处理A问题时,如果选择行为B则带来不良后果C,会影响我的正面情绪D,增强负面情绪E,最后在类似A问题再次到来时,心理上会推广这一个循环的适用范围,迫使自身选择不利于自身的行为B。对于让自己产生焦虑的问题,可以尝试总结出这一个循环,看看是否存在口是心非的情况,解决的方法是直面现实,从保护自己的利益的方面做出考虑。

童年生活中往往会影响无条件认知模式,这类焦虑产生时,对自身提问是能解决问题的好办法,多问为什么可以帮助分清现实和内心虚构出来的影响。

总结

选择和焦虑共处,遭遇焦虑时寻找出焦虑产生的循环,针对当中的准则多问为什么。

肯定自己,勇敢说不,是两件最艰难的事情之一。

最后,最重要的,不要过度关注焦虑本身,思绪被焦虑占据,就没有了生活的空间。