Drupal开发

作者:老葛 亚艾元软件

初级阶段:

1,会覆写模板的预处理函数

2,会自定义模块,定义菜单+回调 controller

3, 能够通过代码定义区块

4,定义表单区块,或者表单页面

5,能够操作数据库,


另外就是:加强主题模板复写的学习:

1,能够复写node 的模板

2,复写views的模板文件



Drupal版本:

Drupal8 Entity::save()的返回值

  作者:老葛 亚艾元软件

  我在Drupal8的项目中,写了这样一段代码:

function mycustom_load_term_helper($name, $vocabulary){

       $terms = taxonomy_term_load_multiple_by_name($name, $vocabulary);

       $term = reset($terms);

       if(!empty($term)){

         //return $term;

       }else{

         $term = Term::create([

                'name' => $name,

                'vid' => $vocabulary,

              ]) ->save();    

      

        

       }              

       return $term;

}

在其他地方,调用了这里的代码:

       //根据赛事文本,自动设置 赛事分类字段

    if(!empty($entity->event->value) && empty($entity->field_event->target_id)){

              $term = mycustom_load_term_helper($entity->event->value, 'event');

              //drupal_set_message($entity->event->value);

              if(!empty($term) ){

                //\Drupal::logger('my_module')->notice(var_export($term, true));

                $entity->field_event->target_id = $term->id();

              }

       }

 

大部分情况下,代码都是正确的,但是偶尔会报错。大致的错误信息,就是对于整数类型的数据调用了->id()函数。

这个错误信息偶尔能会出现,一直没有解决,因为很快下面的就正常了,我只需要再运行一下。

我今天仔细分析了这段代码。发现了这样的问题:

Term的save方法是继承自Entity的,在对应的说明里面。

  Return value

int Either SAVED_NEW or SAVED_UPDATED, depending on the operation performed.

 

Entity::save返回的是整数。SAVED_NEW 和SAVED_UPDATED都是定义好的常量整数。

 

这下问题解决了,这是我改进的代码:

function mycustom_load_term_helper($name, $vocabulary){

       $terms = taxonomy_term_load_multiple_by_name($name, $vocabulary);

       $term = reset($terms);

       if(!empty($term)){

         //return $term;

       }else{

         $term = Term::create([

                'name' => $name,

                'vid' => $vocabulary,

              ]);   

              $term->save();

        

       }              

       return $term;

}

   使用Term::create创建一个$term,对它调用save方法,这时返回的term就是一个对象了。

为了让代码更多健壮一点,其实在调用的时候,可以这么改进:

    if(!empty($entity->event->value) && empty($entity->field_event->target_id)){

              $term = mycustom_load_term_helper($entity->event->value, 'event');

              //if(!empty($term) ){

        if ($term instanceof \Drupal\Core\Entity\ContentEntityInterface) {

               $entity->field_event->target_id = $term->id();

              }

       }

 

这里使用instanceof判断一下,成立的时候调用->id()就不会出错了。


Drupal版本:

Drupal连接Oracle

当我们使用Drupal构建一个大型项目的时候,我们常常会和各种业务系统打交道,而有的业务系统数据库用的是oracle,我们需要建立与oracle的连接,从里面查询我们需要的数据。

我们假定你已经配置好了,oracle的相关库。

windows下面参考:

Drupal 与Oracle集成时,oracle相关配置文档, http://www.thinkindrupal.com/node/6009 

linux下面也需要安装oracle的客户端,然后安装PHP的oracle扩展,这个过程有点费事,网上有很多教程。


我们假定你已经完成了这些配置。我们封装的连接oracle的函数我们封装的连接oracle的函数,


/**
 * 从 Oracle 获取数据.
 *
 * @param string $sql
 *   SQL 链接字符串.
 * @param array $column_names
 *   返回的数据列名. 依据列名返回数据.
 * @return array
 *   数据.
 */
function myoracle_retrieve_data($sql, array $column_names = array()) {

  $data = array();

  $conn = oci_connect('username', 'password', 'dbname');
  if (!$conn) {
    $e = oci_error();
	\Drupal::logger('myoracle')->error("数据库连接时出错: " .var_export($e,true));
    return $data;
  }
  \Drupal::logger('myoracle')->notice("查询SQL: " .var_export($sql,true));

  // 编译sql语句.
  $ora = oci_parse($conn, $sql);
  oci_execute($ora, OCI_DEFAULT);

  while ($row = oci_fetch_array($ora)) {

    $tmp = array();
    foreach ($column_names as $name) {
      $tmp[$name] = $row[$name];
    }
    $data[] = $tmp;
  }
  return $data;
}


    在这个函数里面,设置用oracle的用户名,密码,数据库名,就可以连接oracle,给出一个oracle的sql语句,就能够查找到一个结果数组,剩下的就交给你自己处理了。


我们是直接连的,Drupal官方有oracle的数据库驱动,https://www.drupal.org/project/oracle  ,它允许你将整个Drupal跑在oracle上,这个用的人很少,至少理论上是可行的。


Drupal版本:

Linux下面的Drupal连接oracle配置文档

1, 先用一段代码测试一下:

       $conn = oci_connect('username', 'password', 'dbname');

if($conn) {

  //echo"连接oracle成功!";

  drupal_set_message('连接oracle成功!');

}else{

 // echo"连接oracle失败!";exit;

  drupal_set_message('连接oracle失败!');

}

 

报错:

The website encountered an unexpected error. Please try again later.
Error: Call to undefined function Drupal\mycustom\Controller\oci_connect() in Drupal\mycustom\Controller\MycustomController->testPage() (line 30 of modules/custom/mycustom/src/Controller/MycustomController.php).


参考文档:

https://www.cnblogs.com/xuzhengzong/p/9104700.html

 

第一步:

分别下载 oracle-instantclient11.2-basic-11.2.0.4.0-1.x86_64.rpm     oracle-instantclient11.2-devel-11.2.0.4.0-1.x86_64.rpm

放在/usr/packages/目录下,执行:

#  cd /usr/packages/

# rpm -ivh oracle-instantclient*

此时会生成/usr/lib/oracle/11.2/client64/lib/目录

  

2步:


二、修改/etc/ld.so.conf配置文件

追加以下内容 -- 上面生成文件的路径,没有64的写client/lib/

/usr/lib/oracle/11.2/client64/lib/

保存、退出,执行命令 # ldconfig

  

第3步:

三、安装oci8

 

下载地址:http://pecl.php.net/package/oci8

下载 oci-2.0.8.tgz

放在/usr/packages/目录下,依次执行:

 

tar -xvzf oci-2.0.8.tgz


 

 

Can't find PHP headers in /usr/include/php

The php-devel package is required for use of this command.

 

 

安装php-dev以及依赖Perl(tap::parser)

 

对应于:

rpm -ivh perl-Test-Harness-3.28-3.el7.noarch.rpm

 


 编辑php.ini

 

extension=oci8.so

 



Drupal版本:

亚艾元模块精选

这部分内容,以亚艾元CMS发行版为基础,讲述亚艾元团队在Drupal开发过程中,使用了哪些常用模板。主要讲述:


1,核心自带模块。

2,亚艾元CMS自带模块。

3,开发过程中常见的备用模块。

4,优秀发行包里面包含的模块。


亚艾元CMS发行版,是一个基于Drupal8/9版本基础上,亚艾元自主开发的一个Drupal发行包,主要根据中国用户实际情况,满足常见中国用户需求。

特色:

1,基于频道、栏目的内容管理、权限设置,更符合中国国情。

2,更丰富的多媒体支持,图片,附件、PDF、视频、音频,满足日常需要。

3,内置10多种列表模板,普通用户只需要选择哪种模板即可改变展现形式。

4,内置ludwig贝多芬模块,支持非composer模式,复合国内内网要求。

5,精选多个常用模块,对于编辑器、图片处理,等常用功能做了加强。

6,内置专题管理,快速搭建专题站。

7,默认符合中国习惯的默认配置。

8,基于bootstrap的响应式实现,兼容手机、平板、PC。

9,除了网站,默认携带微信小程序版本,基于React, material UI的H5版本。


亚艾元模板站,基于亚艾元CMS发行包打造,是亚艾元软件,针对中国用户,面向特定行业的解决方案。亚艾元CMS发行版目前不提供免费下载。



Drupal版本:

亚艾元模块精选--Drupal下内容访问保护模块

作者:亚艾元技术部

Protected Pages

项目地址:https://www.drupal.org/project/protected_pages

Drupal8模块安装量:6168

通过这个模块,管理员可以对网站的特定页面进行保护,只有提供了正确密码才能访问内容。支持设置全局密码,支持特定页面单独设置密码。

 

Shield

项目地址:https://www.drupal.org/project/shield

Drupal8模块安装量:8531

使用apache的Shield功能,保护开发站点,只有输入正确的用户名密码后才能访问站点。需要修改apache的配置。

 

Protected node

项目地址: https://www.drupal.org/project/protected_node

Drupal8模块安装量:暂无D8版本,Drupal8版本正在计划开发中。

与Protected Pages模块类似,但是只支持对节点的密码保护,在节点的编辑页面增加了一个tab配置选项,配置起来比较简单。

 


Drupal版本:

亚艾元模块精选--Drupal编辑器增强

 作者:亚艾元技术部

我们当前使用的版本是Drupal8.8,从D8开始,自身携带了Ckeditor编辑器。默认就提供了所见即所得编辑功能。默认启用的编辑器里面按钮不够丰富,我们为其做了加强。

1, 开启media、media library模块,启用多媒体上传按钮。

2, 增加对font,color的设置,安装模块colorbutton、ckeditor_font、panelbutton,下载对应的js存放到libraries目录.如果没有下载的话,会报警告信息:

Warning: file_get_contents(/libraries/font/plugin.js): failed to open stream: No such file or directory in _locale_parse_js_file() (line 1133 of core\modules\locale\locale.module).

_locale_parse_js_file('/libraries/font/plugin.js')

调整使用的按钮。

  

3, 字体,支持中文:

添加以下代码到libraries\font的plugin.js文件中:

CKEDITOR.config.font_names = '宋体/SimSun;新宋体/NSimSun;仿宋_GB2312/FangSong_GB2312;楷体_GB2312/KaiTi_GB2312;黑体/SimHei;微软雅黑/Microsoft YaHei;'+
'Arial/Arial, Helvetica, sans-serif;' +

这样增强以后,Ckeditor的功能就比较丰富了。

 

上述的两个常见查找js库的时候,路径写死了,默认不支持子目录的形式,我在本地修改了一下。

public function getLibraryPath() {
    $path = '/zhanhui/libraries/colorbutton';
    if (\Drupal::moduleHandler()->moduleExists('libraries')) {
      $path = libraries_get_path('colorbutton');
    }
 
    return $path;
  }


Drupal版本:

通过模块为管理主题的views列表提供模板文件

 作者:亚艾元技术部

  我们在为客户实现一个很复杂的统计功能时,用到了views field view模块,通过多层的嵌套,使用views实现了按照分类统计节点数量、浏览量,还能基于日期筛选查找。

   我们在解决问题的时候,遇到了一个问题,由于views创建的页面位于admin的管理界面,我们想给views指定一个主题模板,这个时候,由于使用的是核心主题,所以不能直接将模板文件放到主题的templates目录下面。

经过检查,我们可以这样实现。

 

Module文件中增加了以下代码:

function mycustom_theme() {
  $theme['views_view__statistic_helper'] = [
    'base hook' => 'views_view',
  ];
 
  return $theme;
}

  创建一个temlates目录,里面放上我们的模板文件:

views-view--statistic-helper.html.twig

 

注意下划线和连字符之间的转换。

<div{{ attributes.addClass(classes) }}>
  {{ title_prefix }}
  {{ title }}
  {{ title_suffix }}
 
  {% if header %}
    <header>
      {{ header }}
    </header>
  {% endif %}
 
 
  {{ attachment_before }}
 
  {% if rows -%}
    {{ rows }}
  {% elseif empty -%}
    {{ empty }}
  {% endif %}
  {{ pager }}
 
  {{ attachment_after }}
  {{ more }}
 
  {% if footer %}
    <footer>
      {{ footer }}
    </footer>
  {% endif %}
 
  {{ feed_icons }}
</div>

 

模板文件中,我删除了exposed对应代码:

  {{ exposed }}

这样通过views field view嵌套进去的数据就干净了很多,同时,多个views之间的同名exposed filter,是可以同时起作用的。上面的日期筛选,就作用于了分类列表的节点统计上面。


Drupal版本: