Visualforceでカレンダーっぽいものを作る方法

   

SOQLではjoinが出来ないので適切にリレーションをはりつつSOQLで取得したデータをpageBlockTableで表示しましょう。みたいなのばかりで、どうにかして出来ないものかと試行錯誤していたのですが、その結果です。もっと簡単な方法があったら教えて欲しい…

前提

SOQLのガバナ制限に引っかからない範囲であればという条件です。

方法概要

カレンダーですので、日付のリストを作って、その日付を元にMapからデータを引っ張ってくるみたいな実装になっています

結果

やってること

VisualforcePageにアクセスした人の、アクセスした日の月の一覧を作り、EventのSubjectに休暇という文字が含まれているものを抜き出しています。

Class

public class EventCal {
    public String userID{get;set;}
    Date today;
    static Date firstDay;
    static Date lastDay;
    Integer daysInMonth;

    public EventCal(ApexPages.StandardController controller) {
        //ユーザ情報を取得
        userID = UserInfo.getUserId();
        userName = UserInfo.getName();
        //今日の日付を取得
        today = Date.today();

        /**
         * 月初日付取得
         */
        firstDay =  Date.newInstance(today.year(), today.month(), 1) ;
        /**
         * 月末日付取得
         */
        lastDay = Date.newInstance(today.year(), today.month() + 1 ,0) ;
        
        //月の日数を取得
        daysInMonth = Date.daysInMonth(today.year(), today.month());

        //当月の日にちリストを作成する
        for(Integer i = 0; i < daysInMonth ; i++){
            thisMonthDate.add(firstDay.addDays(i));         
        }

        //休暇という文字が入っているEventを取得。ここは日付さえ入っていれば何でも良い
        myHolidays = [
            SELECT ActivityDate,Owner.Name,Subject
            FROM Event
            WHERE Subject LIKE '%休暇%'
            AND OwnerId = :userID
            AND (ActivityDate >= :firstDay AND ActivityDate <= :lastDay )
        ];
        //取得したEventの日付とSubjectをMapに投入
        for(Event uH : myHolidays){
            HolidaysSubject.put(uH.ActivityDate , uH.Subject);
        } 

    }

    //当月の日にちリスト
    public LIST<DATE> thisMonthDate = new LIST<DATE>();
    //休暇という文字が入ったEventを入れるリスト
    public LIST<Event> myHolidays = new LIST<Event>();
    //上記で抽出されているEventから日付とSubjectのセットを入れる為のMap
    public static Map<Date , String> HolidaysSubject = new Map<Date , String>();

    //
    public LIST<calClass> getThisMonthDate(){
        LIST<calClass> lstResultThisMonthDates = new list<calClass>();
        for (DATE ar : thisMonthDate){
            calClass objcalClass = new calClass(ar);
            lstResultThisMonthDates.add(objcalClass);
        }
        return lstResultThisMonthDates;
    }
  
    //カレンダー用のクラスを定義する
    class calClass{
        //日付を表示するためのStringを定義
        public String whatIsThisDay{ get;set; }
        //Subjectを表示するためのStringを定義
        public String dateSubject{get;set;}
       
        public calClass(DATE ar){
            //arにはDATE形式のデータが入ってくるのでformatで変換してある。必要であればdatetime型に変換してから好みの表示方式に変える
            whatIsThisDay = ar.format();
            //Mapに入ったデータをar(つまり日付)で取得する
            dateSubject = HolidaysSubject.get(ar);
        } 
    }

}

VisualforcePage

<apex:page standardController="Event" extensions="EventCal" standardStylesheets="false" showHeader="true" sidebar="false" applyHtmlTag="true" applyBodyTag="false" docType="html-5.0">
	<apex:pageBlock title="今月"> 
		<apex:pageBlockTable value="{!thisMonthDate}" var="br">
		<apex:column headerValue="日付" value="{!br.whatIsThisDay}"/>
		<apex:column headerValue="Subject" value="{!br.dateSubject}"/>
		</apex:pageBlockTable>
	</apex:pageBlock> 
</apex:page>

Test

あとで書くと思う…

参考にしたのはこちら:http://salesforcetrekbin.blogspot.jp/2010/04/group-by-clause-in-salesforce-soql.html

注意点

Mapに同じキーで2つ以上のものは入れられないので同じ日付で複数入る事がある場合はこの方法ではダメです。
それらは別々にSELECTしてこないと上書きされてしまいます。同じオブジェクトで同じ日付に色々入ってくるという場合は多分Eventを突っ込んだ部分をLISTにして受け取らないとダメな気がする。
VF表示前に予めfor文で文字列を格納しておいて表示みたいな感じになっちゃうのでは。(未検証)

所感

どうにかしてpageBlockTableで処理できないかなと思っていたのだが、良い方法が見つけられず。皆さんどうやってるんだろうという感じでした。
Classの定義を行ってそこにデータを投入していくという形であればなんとかなるということを発見してその応用。
そんなことしなくてもこんな方法があるよという人は是非アドバイスを下さい。

おすすめ記事一覧

 - Salesforce