年齢フィールド

出典: SugarForum.jp

2009年9月15日 (火) 16:14; Cognitom (会話 | 投稿記録) による版
(差分) ←前の版 | 最新版を表示 (差分) | 次の版→ (差分)

生年月日(birthdate)フィールドを作成するケースで、同時にその人の年齢(age)を表示したい場合があります。しかし、日々年齢は変化するため別フィールドとしてデータベース上に持つべきではありません。birthdateを元に表示の際に年齢を計算して表示する方法を紹介します。

目次

ヘルパー関数の作成

<?php
function calculateAge($focus, $field="", $value="", $view="") {
   global $timedate;
   
    if (empty($focus->birthdate)) return "";
    
    list($y0,$m0,$d0) = explode('-', date('Y-m-d'));
    list($y1,$m1,$d1) = explode('-', $timedate->to_db_date($focus->birthdate));
    
    return ($y0-$y1) - ($m0.$d0 < $m1.$d1 ? 1 : 0);
}
?>

このコードを、モジュールディレクトリ内に「helper.php」というファイル名で保存します。(ファイル名は任意です)

フィールド定義

モジュールのvardefsに、以下のフィールド定義を加えます。

'birthdate' => array (
   'name' => 'birthdate',
   'vname' => 'LBL_BIRTHDATE',
   'type' => 'date',
   'massupdate' => false,
   'comment' => '生年月日',
),
'age' => array (
   'name' => 'age',
   'vname' => 'LBL_AGE',
   'type' => 'int',
   'function' => array(
      'name' => 'calculateAge',
      'returns' => 'html',
      'include' => 'modules/@モジュール名/helper.php'
   ),
   'source' => 'nondb',
   'sort_on' => 'birthdate',
   'len' => '3',
   'comment' => '誕生日を元に計算した、今日時点の年齢'
),

詳細ビュー

detailviewdefs.phpのレイアウト定義で、通常通り

array (
   'name' => 'birthdate',
   'label' => 'LBL_BIRTHDATE',
),
array (
   'name' => 'age',
   'label' => 'LBL_AGE',
),

とするか、下記のようにまとめてしまうのも手です。

array (
   'name' => 'birthdate',
   'label' => 'LBL_BIRTHDATE',
   'customCode' => '{$fields.birthdate.value}{if $fields.age.value} (満{$fields.age.value}歳){/if}',
),

リストピュー

listviewdefs.phpに、下記を追加しておきます。

'AGE' => array(
   'width' => '10', 
   'label' => 'LBL_LIST_AGE', 
   'default' => true,
   'related_fields' => array('birthdate'),
),

これだけでは、一覧表示に値が表示されないので、Beanクラスの fill_in_additional_list_fields関数を次のようにオーバーライドします。

function fill_in_additional_list_fields(){
   parent::fill_in_additional_list_fields();
   
   require_once('modules/@モジュール名/helper.php');
   $this->age = calculateAge($this);
}

検索

年齢の検索については、現状のSugarではあまりスマートな解決はありませんが、ひとつのやり方を示します。(もし、もっと良い方法があれば、コメントください!)

検索フィールド定義

SearchFields.php に以下を追加。

'age'=>array( 
   'query_type'=>'default',
   'operator'=>'subquery',
   'db_field'=>array('birthdate'),
   'subquery'=>"'dummy')
      OR YEAR(NOW()) -YEAR(birthdate)
         - IF(DATE_FORMAT(birthdate,'%m%d')<DATE_FORMAT(NOW(),'%m%d'),0,1) =(",
),

「subquery」の箇所が非常にトリッキーなことになっています。実際にはサブクエリーではなく、下記のようなSQL(の一部)が発行されます。(検索フォームに「30」と入力した場合)

WHERE birthdate IN ('dummy')
   OR YEAR(NOW()) -YEAR(birthdate)
      - IF(DATE_FORMAT(birthdate,'%m%d')<DATE_FORMAT(NOW(),'%m%d'),0,1) =( "30%")

一応、解説すると、

  • 「IN ('dummy') OR」のところは無視、
  • YEAR(NOW()) -YEAR(birthdate) で年の差分
  • DATE_FORMAT関数で日付の月日の部分だけ比較し、誕生日前の場合は1を引く
  • ( "30%") は、30として評価される

という感じです。※MySQL以外だと多分動きません。

Sugarの今後のバージョンで、検索フォームについて自由度の高いカスタマイズが可能になることを切に願います :-)

検索のレイアウト定義

searchdefs.php に、以下を追加しておきましょう。

array('name'=>'age', 'label'=>'LBL_AGE', 'type'=>'name', 'displayParams' => array('size'=>5)),