Module OG Color

Events happening in the community are now at Drupal community events on www.drupal.org.
thehong's picture
  • Hỏi:
    i. Người điều hành của mỗi group (module organic group) có thể thiết lập giao diện riêng cho group của họ.
    ii. Theme Garland hỗ trợ chọn các tông màu khác nhau, người điều hành hệ thống có thể chọn lựa màu phù hợp để sử dụng cho hệ thống chung.
    iii. Có thể viết một module hỗ trợ mỗi group có một tông màu riêng hay không?

  • Trả lời: Module viết theo cách bình thường không thể thực hiện yêu cầu đó. Tuy nhiên, nếu chỉnh sửa mã nguồn nhân thì việc giải quyết yêu cầu trên là khả thi.

I. Khai báo module với hệ thống

  • Tên module: og_color
  • Module chắc chắn phải chạy dựa trên 2 module khác: color và og
  • Khi đó, tập tin og_color.info của module có dạng:
name = Organic Group color
version = 5.x-dev
description = Support every group has its own color schema
dependencies = og color
packe = @toila.net

II. Lưu trữ group color schema.

Trước khi tổ chức cấu trúc lưu trữ color schema của từng group, chúng ta cần quan sát cách lưu của module color. Module color sử dụng *** biến hệ thống để lưu trữ:
1. color_{theme_name}files: xác định thư mục chứa các file css và các hình ảnh tùy chỉnh.
2. color
{theme_name}logo: xác định đường dẫn đến file logo tùy chỉnh
3.. color
{theme_name}palette: xác định tông màu hiện thời của giao diện tuỳ chỉnh
4. color
{theme_name}screenshot: xác định đường dẫn đến file screenshot tùy chỉnh
5. color
{theme_name}_stylesheet: xác định đường dẫn đến file stylesheet tùy chỉnh

Khi áp dụng color schema vào groups, nếu sử dụng cách lưu trữ trên, số lượng biến sẽ tăng lên theo cấp số nhân, bộ nhớ PHP chắc chắn sẽ sớm quá tải. Chúng ta có hai cách giải quyết:
(1) Lưu trữ trong bảng của CSDL; (2) Lưu trữ trong hệ thống tập tin. Ở đây, tôi chọn (2), do đó, trong kịch bản cài đặt, tôi sẽ phải tạo một thư mục cho việc lưu trữ:

<?php
/<strong>
* @
file og_color.install
*/

/</
strong>
*
Implementation of hook_install
*
*
Tạo các thư mục cho việc lưu trữ
*/
function
og_color_install () {
 
$dirs[] = file_directory_path() . '/og';
 
$dirs[] = file_directory_path() . '/og/color';
 
  foreach (
$dirs as $dir) {
   
file_check_directory($dir, FILE_CREATE_DIRECTORY);
  }
}
?>

III. Biểu mẫu cấu hình

Mỗi một group cần có một biểu mẫu cấu hình để người điều hành có thể tuỳ chỉnh tông màu cho group của họ. Chúng ta sử dụng hook_menu để thực hiện điều này. Một vài chú ý:
- Hàm định nghĩa biểu mẫu cấu hình group's color schema: og_color_select
- Kịch bản thực thi khi biểu mẫu được đệ trình: og_color_select_submit
- Quyền truy cập biểu mẫu: người có quyền điều hành group.

<?php
/<strong>
*
file og_color.module
*/

/</
strong>
*
Implementation of hook_menu
*
*/
function
og_color_menu($may_cache) {
  if (!
$may_cache) {
    if (
arg (0) == 'node' && is_numeric (arg (1))) {
      if (
$group_context = og_get_group_context ()) {
       
$items[] = array (
         
'path' => 'node/' . arg (1) . '/color',
         
'title' => t('Color schema'),
         
'access' => node_access ('update', $group_context),
         
'callback' => 'og_color_select'
       
);
      }
    }
  }
 
  return
$items;
}
?>

Callback đã định nghĩa, giờ đây chúng ta định nghĩa biểu mẫu cấu hình:

<?php
/<strong>
*
file og_color.module
*/

/</
strong>
* ...
*/

/**
* Group's color schema selection form
*/
function og_color_select () {
 
$group_context = og_get_group_context ();
 
$group_context->og_color = og_color_get_schema();
 
$theme = $group_context->og_theme;
 
 
// Kiểm tra giao diện group hiện tại có hỗ trợ
  //   1. color module
  //   2. Hệ thống có cài đặt GD library
  //   3. Phương thức tải file phải là public
 
if (
   
color_get_info($theme)
    &&
function_exists('gd_info')
    &&
variable_get('file_downloads', FILE_DOWNLOADS_PUBLIC) == FILE_DOWNLOADS_PUBLIC
 
) {
   
$form = array ();
   
   
$form['color'] = array(
     
'#type' => 'fieldset',
     
'#title' => t('Color scheme'),
     
'#weight' => -1,
     
'#attributes' => array('id' => 'color_scheme_form'),
     
'#theme' => 'color_scheme_form'
   
);
   
   
$form['color'] += color_scheme_form ($theme);
   
    if (
is_array ($group_context->og_color['palette'])) {
     
$form['color']['scheme']['#default_value'] = implode (',', $group_context->og_color['palette']);
     
      foreach (
$form['color']['palette'] as $k => $v) {
        if (isset (
$form['color']['palette'][$k]['#default_value'])) {
         
$form['color']['palette'][$k]['#default_value'] = $group_context->og_color['palette'][$k];
        }
      }
    }
   
   
$form['color']['theme']['#value'] = $theme;
   
   
$form['submit'] = array (
     
'#type' => 'submit',
     
'#value' => t('Submit')
    );
  }
 
// Thông báo với người dùng: Giao diện họ đang sử dụng không có hỗ trợ module color
 
else {
   
drupal_set_message (t('Your current theme doest support color selecting.'), 'error');
   
   
// Biểu mẫu trả về chỉ là một phần tử markup không có gì
   
$form['markup'] = array (
     
'#type' => 'markup',
     
'#value' => ''
   
);
  }
 
  return
$form;
}
?>

Biểu mẫu khi được đệ trình, cần có kịch bản xử lý:

<?php
/<strong>
*
file og_color.module
*/

/</
strong>
* ...
*/

/**
* Submit handler for group's color schema selection form
*/
function og_color_select_submit ($form_id, $form_values) {
 
// Get theme coloring info
 
if (!isset($form_values['info'])) {
    return;
  }
 
 
$theme = $form_values['theme'];
 
$info = $form_values['info'];
 
 
// Resolve palette
 
$palette = $form_values['palette'];
  if (
$form_values['scheme'] != '') {
   
$scheme = explode(',', $form_values['scheme']);
   
    foreach (
$palette as $k => $color) {
     
$palette[$k] = array_shift($scheme);
    }
  }
 
 
// Make sure enough memory is available, if PHP's memory limit is compiled in.
 
if (function_exists('memory_get_usage')) {
   
// Fetch source image dimensions.
   
$source = drupal_get_path('theme', $theme) .'/'. $info['base_image'];
    list(
$width, $height) = getimagesize($source);
 
   
// We need at least a copy of the source and a target buffer of the same
    // size (both at 32bpp).
   
$required = $width * $height * 8;
   
$usage = memory_get_usage();
   
$limit = parse_size(ini_get('memory_limit'));
    if (
$usage + $required > $limit) {
     
drupal_set_message(t('There is not enough memory available to PHP to change this theme\'s color scheme. You need at least %size more. Check the <a href="@url">PHP documentation</a> for more information.', array('%size' => format_size($usage + $required - $limit), '@url' => 'http://www.php.net/manual/en/ini.core.php#ini.sect.resource-limits')), 'error');
      return;
    }
  }
 
 
// Delete old files
 
if (is_array ($group_context->og_color['files'])) {
    foreach (
$group_context->og_color['files'] as $file) {
      @
unlink($file);
    }
   
    if (
$file = dirname($file)) {
      @
rmdir($file);
    }
  }

 
// delete current settings
 
unset ($group_context->og_color['palette']);
  unset (
$group_context->og_color['stylesheet']);
  unset (
$group_context->og_color['files']);
  unset (
$group_context->og_color['logo']);
 
 
// Don't render the default colorscheme, use the standard theme instead.
 
if (implode(',', color_get_palette($theme, true)) != implode(',', $palette)) {
   
// Prepare target locations for generated files
   
$id = $group_context->nid . $theme . '-' . substr(md5(serialize($palette) . microtime()), 0, 8);
   
$paths['color'] = file_directory_path() . '/og/color';
   
$paths['target'] = $paths['color'] .'/'. $id;
   
    foreach (
$paths as $path) {
     
file_check_directory($path, FILE_CREATE_DIRECTORY);
    }
   
   
$paths['target'] = $paths['target'] . '/';
   
$paths['id'] = $id;
   
$paths['source'] = drupal_get_path ('theme', $theme) . '/';
   
$paths['stylesheet'] = $paths['target'] . 'style.css';
   
$paths['files'] = $paths['map'] = array();
   
   
// Save palette and stylesheet location
   
$group_context->og_color['palette'] = $palette;
   
$group_context->og_color['stylesheet'] = $paths['stylesheet'];
   
$group_context->og_color['logo'] = $paths['target'] . 'logo.png';
   
   
// Copy over neutral images
   
foreach ($info['copy'] as $file) {
     
$base = basename($file);
     
$source = $paths['source'] . $file;
     
file_copy($source, $paths['target'] . $base);
     
$paths['map'][$file] = $base;
     
$paths['files'][] = $paths['target'] . $base;
    }
   
   
// Render new images
   
_color_render_images ($theme, $info, $paths, $palette);
   
   
// Rewrite stylesheet
   
_color_rewrite_stylesheet ($theme, $info, $paths, $palette);
   
   
// Maintain list of files
   
$group_context->og_color['files'] = $paths['files'];
  }
 
 
// lưu thông tin cấu hình vào tập tin files/og/color/{nid}.color
 
$result = file_save_data (
   
serialize ($group_context->og_color),
   
file_create_path ($paths['target'] . '/' . $group_context->nid . '.color'),
   
FILE_EXISTS_REPLACE
 
);
?>

Các hàm trên thiếu hàm hỗ trợ og_color_get_schema ():

<?php
/<strong>
*
file og_color.module
*/

/</
strong>
* ...
*/

/**
* Get group's color schema informations
*/
function og_color_get_schema ($gid) {
  static
$schemas;
 
$group_context = og_get_group_context ();
 
  if (!
$gid) {
   
$gid = $group_context->nid;
  }
 
  if (!isset (
$schemas[$gid])) {
    if (
$group_context->nid == $gid) {
     
$color_path = file_directory_path() . '/og/color/' . $node->nid . '.color';
     
      if (
is_file ($color_path)) {
       
$schemas[$gid] = unserialize ($color_path);
      }
      else {
       
$schemas[$gid] = false;
      }
    }
  }
 
  return
$schemas[$gid];
}
?>

IV. Hack theme (template.php :: _phptemplate_variables)

Công việc vẫn chưa ngã ngủ. Chúngta cần tạo hàm _phptemplate_variables trong tập tin template.php của giao diện đang sử dụng. Trường hợp tập tin/hàm đã tồn tại, cần chỉnh sửa thành ra dạng sau:

<?php
/<strong>
* @
file template.php
*/

/</
strong>
*
Override or insert PHPTemplate variables into the templates.
*/
function
_phptemplate_variables($hook, $vars) {
  if (
$hook == 'page') {
   
// ...

    // Hook into color.module
   
if (module_exists('color')) {
     
_og_color_page_alter($vars);
    }

   
// ...
 
}
}
?>

Chắc chắn lúc này chúng ta phải thêm hàm _og_color_page_alter () vào tập tin og_color.module. Mục đích: Thay đổi tập tin stylesheet và logo mặc định của giao diện hiện tại:

<?php
/<strong>
*
file og_color.module
*/

/</
strong>
* ...
*/

/**
* Modified version of _color_page_alter ()
*/
function _og_color_page_alter (&$vars) {
  global
$theme_key;
 
$schema = og_color_get_schema();

 
// Override stylesheet
 
$path = $schema['stylesheet'];
 
  if (
$path) {
   
$vars['css']['all']['theme'][$path] = TRUE;
   
$vars['styles'] = drupal_get_css($vars['css']);
  }

 
// Override logo
 
$logo = variable_get('color_' . $theme_key . '_logo', NULL);
  if (
$logo && $vars['logo'] && preg_match('!' . $theme_key . '/logo.png$!', $vars['logo'])) {
   
$vars['logo'] = base_path() . $logo;
  }
}
?>

Thế Hồng