Flexを使ったApexアプリケーション開発(3)

by Shinichi Tomita on 6月 29, 2007 at 06:29 午後

ドラッグ&ドロップ機能の追加

前回、Salesforceのデータベース内にあるレコードを検索して一覧表示するアプリケーションを作成しました。今回はFlexによるApexアプリケーション構築の最終回として、前回のアプリケーションをもう少し高度なアプリケーションに発展させてみましょう。

Ws000007

このアプリケーションは、取引先の一覧から任意の取引先を選んで、訪問予定を自分のカレンダーの行動リストに追加することができるアプリケーションです。画面を左右2つに分けて、左側にユーザの行動予定(スケジュール)情報、右側に取引先の検索画面を表示しています。

左側にはカレンダーを表示するDateChooserコンポーネントと、垂直にリスト表示を行うためのListコンポーネントを新たに配置しています。

右側の取引先データの検索および一覧表示には前回に作成したものをほぼそのまま用いていますが、前回とは異なりグリッドに表示されている取引先レコード(行)をマウスで掴んでドラッグできるようになっています。

Flexでのドラッグ&ドロップ操作の追加は非常に簡単です。アイテムのドラッグを有効にしたいコンポーネントのdragEnabled属性をtrueに設定して、アイテムのドロップを受け付けるコンポーネントにはdropEnabled属性をtrueに設定しておけばOKです。後はドロップしたときのイベントを処理する関数を独自に定義しておくことで、カスタムのロジックを動かすことが可能です。

DataGridコンポーネントのドラッグを有効化
<mx:DataGrid id="accountTable" width="100%" height="100%" 
             dataProvider="{accounts}" dragEnabled="true">
...
Listコンポーネントへのドロップを有効化
<mx:List id="eventList" width="100%" height="100%" dataProvider="{events}" 
         dropEnabled="true" dragDrop="handleDropOnEventList(event)"
         labelFunction="formatEventLabel" />
....

ドロップイベントの処理関数では、ドロップされた取引先レコードに関連付けて、新たに行動予定(Event)レコードをSalesforceデータベース内に作成します。ここでは処理の記述を簡単にするため、終日の行動のみに固定しています。レコード作成が成功すると、行動予定の情報を格納しているevents変数に作成したレコードを追加します。

ドロップイベントを処理する関数
/**
* 行動予定リストへのドロップイベントを処理する
* ドロップした取引先情報に関連付けて、新規の行動予定を作成する
*/
private function handleDropOnEventList(e:DragEvent):void {
  // デフォルトのイベント処理を上書き
  e.preventDefault();
 
  var account:SObject = accountTable.selectedItem as SObject;
  var event:SObject = new SObject('Event');
  event.WhatId = account.Id;
  event.Subject = account.Name+"様訪問";
  event.IsAllDayEvent = true;
  event.ActivityDate = Util.dateToString(calendar.selectedDate);
  conn.create([event], new AsyncResponder(function(results:Array):void {
    if (results[0].success) {
      // 行動予定リストに追加
      event.Id = results[0].id;
      events.addItem(event);
    }
  }));
}

すでに登録済みの行動予定の情報も参照できるようにするために、アプリケーションロード時に自動的にデータベースに登録されている行動情報を検索して取得するようにしています。取得した行動情報は一括でevents変数に格納されますが、行動予定リストにカレンダーで選択された日付の予定のみが表示されるようにフィルタ関数を追加指定しています。

行動情報をSalesforceから検索する関数
/**
* ユーザの行動予定情報を取得
*/
private function queryEvents():void {
  // ログインユーザの情報を取得
  conn.getUserInfo(new AsyncResponder(function(userInfo:Object):void {

    // 前後30日間の行動予定情報を一括で取得
    var soql:String =
      "SELECT Id, Subject, IsAllDayEvent, ActivityDate, ActivityDateTime, DurationInMinutes FROM Event"+
      " WHERE OwnerId = '"+userInfo.userId+"'"+
      " AND (ActivityDate = LAST_N_DAYS:30 OR ActivityDate = NEXT_N_DAYS:30 "+
      "      OR ActivityDateTime = LAST_N_DAYS:30 OR ActivityDateTime = NEXT_N_DAYS:30)";
    conn.query(soql, new AsyncResponder(function(result:QueryResult):void {
      if (result.size>0) {
        events = result.records;
        // カレンダーで選択した日のみをリスト表示するようにフィルタリング
        events.filterFunction = function(event:Object):Boolean {
          var dateStr:String = Util.dateToString(calendar.selectedDate);
          return String(event.ActivityDate || event.ActivityDateTime || "").indexOf(dateStr)==0;
        }
        events.refresh();
      } else {
        events = new ArrayCollection();
      }
    })); // end of conn.query()
   
  })); // end of conn.getUserInfo()

}

以下は完成したFlexアプリケーションのソースコード(SalesScheduler.mxml)です。

SalesScheduler.mxml
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
                xmlns:salesforce="com.salesforce.*"
                layout="vertical"
                applicationComplete="login()" >
  <mx:Script>
    <![CDATA[
import mx.collections.ArrayCollection;
import mx.events.DateChooserEvent;
import mx.events.DragEvent;
import mx.formatters.DateFormatter;
import com.salesforce.*;
import com.salesforce.events.*;
import com.salesforce.objects.*;
import com.salesforce.results.*;

/**
* 取引先情報レコードを保管する変数
* Bindable メタデータを記述して、コンポーネントにデータを関連付けられるように設定
*/
[Bindable]
private var accounts:ArrayCollection = new ArrayCollection();

/**
* 行動予定(Event)レコードを保管する変数
*/
[Bindable]
private var events:ArrayCollection = new ArrayCollection();


/**
* 「種別」フィールド値の選択リストデータを保管する変数
*/
[Bindable]
private var typeDefs:ArrayCollection = new ArrayCollection([
  { label : '--------', data : 0 }
]);

/**
* 「評価」フィールド値の選択リストデータを保管する変数
*/
[Bindable]
private var ratingDefs:ArrayCollection = new ArrayCollection([
  { label : '--------', data : 0 }
]);


/**
* Salesforceにログインして、セッションを構築する
* アプリケーションのロード完了時に呼び出される
*/
private function login():void {
  var lr:LoginRequest = new LoginRequest({
    server_url : Application.application.parameters.server_url,
    session_id : Application.application.parameters.session_id,
    // username : '', // <-- put your username here!
    // password : '', // <-- put your password here!
    callback : new AsyncResponder(function(result:Object):void {
      setupForm();
      calendar.selectedDate = new Date();
      queryEvents();
    })
  });
  conn.login(lr);
}


/**
* 検索絞込みフォームのセットアップ
* 選択リストの定義をdescribeSObjectメソッドで取得
*/
private function setupForm():void {
  conn.describeSObject("Account", new AsyncResponder(function(result:DescribeSObjectResult):void{
    // 「種別(Type)」項目の選択リスト値を取得
    for each (var p:PickListEntry in result.fields['Type'].picklistValues) {
      // アクティブな選択リストのラベルと値のペアを保存
      if (p.active) typeDefs.addItem({ label : p.label, data : p.value });
    }
    // 「評価(Rating)」項目の選択リスト値を取得
    for each (var q:PickListEntry in result.fields['Rating'].picklistValues) {
      // アクティブな選択リストのラベルと値のペアを保存
      if (q.active) ratingDefs.addItem({ label : q.label, data : q.value });
    }
    // 検索ボタンを有効化する
    queryButton.enabled = true;
  }));
}

/**
* 取引先レコード情報の取得
* 検索条件に合致するレコードを上限まで取得する
*/
private function queryAccounts():void {
  var soql:String = "SELECT Id, Name, Type, Rating, BillingState, Phone FROM Account";
  var conditions:Array = [];
  if (ratingPicklist.value) {
    conditions.push(" Rating = '"+ratingPicklist.value+"' ");
  }
  if (typePicklist.value) {
    conditions.push(" Type = '"+typePicklist.value+"' ");
  }
  if (conditions.length>0) { // 条件指定があればWHERE句としてSOQLに追加
    soql += ' WHERE '+conditions.join(' AND ');
  }
  conn.query(soql, new AsyncResponder(function(result:QueryResult):void {
    accounts = result.records;
  }));
}


/**
* ユーザの行動予定情報を取得
*/
private function queryEvents():void {
  // ログインユーザの情報を取得
  conn.getUserInfo(new AsyncResponder(function(userInfo:Object):void {

    // 前後30日間の行動予定情報を一括で取得
    var soql:String =
      "SELECT Id, Subject, IsAllDayEvent, ActivityDate, ActivityDateTime, DurationInMinutes FROM Event"+
      " WHERE OwnerId = '"+userInfo.userId+"'"+
      " AND (ActivityDate = LAST_N_DAYS:30 OR ActivityDate = NEXT_N_DAYS:30 "+
      "      OR ActivityDateTime = LAST_N_DAYS:30 OR ActivityDateTime = NEXT_N_DAYS:30)";
    conn.query(soql, new AsyncResponder(function(result:QueryResult):void {
      if (result.size>0) {
        events = result.records;
        // カレンダーで選択した日のみをリスト表示するようにフィルタリング
        events.filterFunction = function(event:Object):Boolean {
            var dateStr:String = Util.dateToString(calendar.selectedDate);
            return String(event.ActivityDate || event.ActivityDateTime || "").indexOf(dateStr)==0;
        }
        events.refresh();
      } else {
        events = new ArrayCollection();
      }
    })); // end of conn.query()
   
  })); // end of conn.getUserInfo()

}

/**
* 行動予定リストへのドロップイベントを処理する
* ドロップした取引先情報に関連付けて、新規の行動予定を作成する
*/
private function handleDropOnEventList(e:DragEvent):void {
  // デフォルトのイベント処理を上書き
  e.preventDefault();
 
  var account:SObject = accountTable.selectedItem as SObject;
  var event:SObject = new SObject('Event');
  event.WhatId = account.Id;
  event.Subject = account.Name+"様訪問";
  event.IsAllDayEvent = true;
  event.ActivityDate = Util.dateToString(calendar.selectedDate);
  conn.create([event], new AsyncResponder(function(results:Array):void {
    if (results[0].success) {
      // 行動予定リストに追加
      event.Id = results[0].id;
      events.addItem(event);
    }
  }));
}


/**
* 行動予定リストのラベルの表示を定義するメソッド
*/
private function formatEventLabel(event:SObject):String {
  var time:String;
  if (event.IsAllDayEvent) {
    time = "終日";
  } else {
    var df:DateFormatter = new DateFormatter();
    df.formatString = "H:NN";
    var startTime:Date = Util.stringToDateTime(event.ActivityDateTime);
    var endTime:Date = new Date(startTime.getTime()+event.DurationInMinutes*1000*60);
    time = df.format(startTime)+" - "+df.format(endTime);
  }
  return time + " " + event.Subject;
}
    ]]>
  </mx:Script>

  <!-- Salesforce Connection オブジェクト -->
  <salesforce:Connection id="conn" />

 
  <!-- 左右に分割 -->
  <mx:HDividedBox width="100%" height="100%">

    <!-- 左ペイン -->
    <mx:Panel width="200" height="100%" layout="vertical" title="行動予定">

      <!-- カレンダー -->
      <mx:DateChooser id="calendar" width="100%" change="events.refresh()"/>
      <!-- 行動予定のリスト -->
      <mx:List id="eventList" width="100%" height="100%" dataProvider="{events}"
               dropEnabled="true" dragDrop="handleDropOnEventList(event)"
               labelFunction="formatEventLabel"
               dropShadowEnabled="true" />
    </mx:Panel>


    <!-- 右ペイン -->
    <mx:Panel width="100%" height="100%" layout="vertical" title="取引先" horizontalAlign="center">

      <!-- 取引先検索フォーム -->
      <mx:HBox>
        <mx:FormHeading label="種別" />
        <mx:ComboBox id="typePicklist" dataProvider="{typeDefs}" />
        <mx:FormHeading label="評価" />
        <mx:ComboBox id="ratingPicklist" dataProvider="{ratingDefs}" />
        <mx:Button id="queryButton" click="queryAccounts()" label="検索" enabled="false" />
      </mx:HBox>

      <!-- 取引先検索結果表示 -->
      <mx:DataGrid id="accountTable" width="100%" height="100%" dataProvider="{accounts}" dragEnabled="true">
        <mx:columns>
          <mx:DataGridColumn headerText="ID" dataField="Id" editable="false"/>
          <mx:DataGridColumn headerText="取引先名" dataField="Name" />
          <mx:DataGridColumn headerText="種別" dataField="Type" />
          <mx:DataGridColumn headerText="評価" dataField="Rating" />
          <mx:DataGridColumn headerText="都道府県(請求先)" dataField="BillingState" />
          <mx:DataGridColumn headerText="電話番号" dataField="Phone"/>
        </mx:columns>
      </mx:DataGrid>

    </mx:Panel>

  </mx:HDividedBox>

</mx:Application>

Flexを使ったApexアプリケーション開発(2)

by Shinichi Tomita on 6月 28, 2007 at 03:38 午後

Salesforceのレコードを一覧表示する

Flexでは多数の再利用可能なユーザーインターフェース部品がコンポーネントとして提供されています。特にDataGridコンポーネントは、複数レコードの情報を表形式で一覧表示することができるため、データベースのレコード検索結果を表示するのによく使われます。

ここではSalesforceのデータベースから検索したレコードを、DataGridコンポーネントに一覧表示するアプリケーションを作成します。

AccountGrid1.mxml
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
                xmlns:salesforce="com.salesforce.*"
                layout="vertical"
                applicationComplete="login()" >
  <mx:Script>
    <![CDATA[
import mx.collections.ArrayCollection;
import com.salesforce.*;
import com.salesforce.events.*;
import com.salesforce.objects.*;
import com.salesforce.results.*;

/**
* 取引先情報レコードを保管する変数
* Bindable メタデータを記述して、コンポーネントにデータを関連付けられるように設定
*/
[Bindable]
private var accounts:ArrayCollection = new ArrayCollection();


/**
* Salesforceにログインして、セッションを構築する
* アプリケーションのロード完了時に呼び出される
*/
private function login():void {
  var lr:LoginRequest = new LoginRequest({
    server_url : Application.application.parameters.server_url,
    session_id : Application.application.parameters.session_id,
    // username : '', // <-- put your username here!
    // password : '', // <-- put your password here!
    callback : new AsyncResponder(function(result:Object):void {
      // ログイン後、取引先データを取得
      queryAccounts();
    })
  });
  conn.login(lr);
}

/**
* 取引先レコード情報の取得
* テーブル内の全レコードを上限まで取得
*/
private function queryAccounts():void {
  var soql:String = "SELECT Id, Name, Type, Rating, BillingState, Phone FROM Account";
  // SOQLクエリを送信
  conn.query(soql, new AsyncResponder(function(result:QueryResult):void {
    // 取得したレコードをそのままaccounts変数に格納
    accounts = result.records;
  }));
}
    ]]>
  </mx:Script>

  <!-- Salesforce Connection オブジェクト -->
  <salesforce:Connection id="conn" />

  <!-- 検索結果表示 -->
  <mx:DataGrid width="100%" height="100%" dataProvider="{accounts}">
    <mx:columns>
      <mx:DataGridColumn headerText="ID" dataField="Id" />
      <mx:DataGridColumn headerText="取引先名" dataField="Name" />
      <mx:DataGridColumn headerText="種別" dataField="Type" />
      <mx:DataGridColumn headerText="評価" dataField="Rating" />
      <mx:DataGridColumn headerText="都道府県(請求先)" dataField="BillingState" />
      <mx:DataGridColumn headerText="電話番号" dataField="Phone"/>
    </mx:columns>
  </mx:DataGrid>

</mx:Application>
実行結果(AccountGrid1.mxml)

Ws000005

上記のソースコード(AccountGrid1.mxml)では、ログイン完了後にコールバック関数からqueryAccounts メソッドが呼び出され、その中でSOQLクエリをSalesforceに対して送信しています。クエリの結果は非同期で取得するため、レスポンスを受け取るためのコールバック関数を指定してクエリを送信します。コールバック関数が結果レスポンスを受け取ると、そのままレコード情報がaccounts変数に設定されます。

DataGrid中のデータ表示には、Flexのデータバインディングの仕組みを用いているので、開発者はレンダリングについて特に気にする必要はありません。あらかじめMXML中のDataGrid要素のdataProvider属性にバインディングするデータを指定しておくだけです。バインディングされた変数にデータ変更があった場合は自動的にグリッド表示にも反映されます。

DataGridには、ソートや列の入れ替えといった機能もあらかじめ備わっています。そのため、上記コードは最小のコード量ではありますが、実際に実行してみると、結果として単なるレコード一覧表示のみにはとどまっていないのが確認できるかと思います。

検索の条件を指定する

次のステップとして、上記のアプリケーションを拡張して、検索するレコードの絞込みができるようにします。ここでは検索条件として、項目値の選択リストを用いることで、合致するレコードのみを抽出するように設定します。

AccountGrid2.mxml
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
                xmlns:salesforce="com.salesforce.*"
                layout="vertical"
                applicationComplete="login()" >
  <mx:Script>
    <![CDATA[
import mx.collections.ArrayCollection;
import com.salesforce.*;
import com.salesforce.events.*;
import com.salesforce.objects.*;
import com.salesforce.results.*;

/**
* 取引先情報レコードを保管する変数
* Bindable メタデータを記述して、コンポーネントにデータを関連付けられるように設定
*/
[Bindable]
private var accounts:ArrayCollection = new ArrayCollection();

/**
* 「種別」フィールド値の選択リストデータを保管する変数
*/
[Bindable]
private var typeDefs:ArrayCollection = new ArrayCollection([
  { label : '--------', data : 0 }
]);

/**
* 「評価」フィールド値の選択リストデータを保管する変数
*/
[Bindable]
private var ratingDefs:ArrayCollection = new ArrayCollection([
  { label : '--------', data : 0 }
]);


/**
* Salesforceにログインして、セッションを構築する
* アプリケーションのロード完了時に呼び出される
*/
private function login():void {
  var lr:LoginRequest = new LoginRequest({
    server_url : Application.application.parameters.server_url,
    session_id : Application.application.parameters.session_id,
    // username : '', // <-- put your username here!
    // password : '', // <-- put your password here!
    callback : new AsyncResponder(function(result:Object):void {
      setupForm();
    })
  });
  conn.login(lr);
}


/**
* 検索絞込みフォームのセットアップ
* 選択リストの定義をdescribeSObjectメソッドで取得
*/
private function setupForm():void {
  conn.describeSObject("Account", new AsyncResponder(function(result:DescribeSObjectResult):void{
    // 「種別(Type)」項目の選択リスト値を取得
    for each (var p:PickListEntry in result.fields['Type'].picklistValues) {
      // アクティブな選択リストのラベルと値のペアを保存
      if (p.active) typeDefs.addItem({ label : p.label, data : p.value });
    }
    // 「評価(Rating)」項目の選択リスト値を取得
    for each (var p:PickListEntry in result.fields['Rating'].picklistValues) {
      // アクティブな選択リストのラベルと値のペアを保存
      if (p.active) ratingDefs.addItem({ label : p.label, data : p.value });
    }
    // 検索ボタンを有効化する
    queryButton.enabled = true;
  }));
}

/**
* 取引先レコード情報の取得
* 検索条件に合致するレコードを上限まで取得する
*/
private function queryAccounts():void {
  var soql:String = "SELECT Id, Name, Type, Rating, BillingState, Phone FROM Account";
  var conditions:Array = [];
  if (ratingPicklist.value) {
    conditions.push(" Rating = '"+ratingPicklist.value+"' ");
  }
  if (typePicklist.value) {
    conditions.push(" Type = '"+typePicklist.value+"' ");
  }
  if (conditions.length>0) { // 条件指定があればWHERE句としてSOQLに追加
    soql += ' WHERE '+conditions.join(' AND ');
  }
  conn.query(soql, new AsyncResponder(function(result:QueryResult):void {
    accounts = result.records;
  }));
}
    ]]>
  </mx:Script>

  <!-- Salesforce Connection オブジェクト -->
  <salesforce:Connection id="conn" />
 
  <!-- 検索フォーム -->
  <mx:HBox>
    <mx:FormHeading label="種別" />
    <mx:ComboBox id="typePicklist" dataProvider="{typeDefs}" />
    <mx:FormHeading label="評価" />
    <mx:ComboBox id="ratingPicklist" dataProvider="{ratingDefs}" />
    <mx:Button id="queryButton" click="queryAccounts()" label="検索" enabled="false" />
  </mx:HBox>

  <!-- 検索結果表示 -->
  <mx:DataGrid width="100%" height="100%" dataProvider="{accounts}">
    <mx:columns>
      <mx:DataGridColumn headerText="ID" dataField="Id" editable="false"/>
      <mx:DataGridColumn headerText="取引先名" dataField="Name" />
      <mx:DataGridColumn headerText="種別" dataField="Type" />
      <mx:DataGridColumn headerText="評価" dataField="Rating" />
      <mx:DataGridColumn headerText="都道府県(請求先)" dataField="BillingState" />
      <mx:DataGridColumn headerText="電話番号" dataField="Phone"/>
    </mx:columns>
  </mx:DataGrid>

</mx:Application>
実行結果(AccountGrid2.mxml)

Ws000006

今回のソースコード(AccountGrid2.mxml)では、コンポーネントとして新しく、2つの選択リスト(ComboBoxコンポーネント)と検索実行のためのボタン(Buttonコンポーネント)が追加されました。

また、ログイン後に自動的に取引先レコードの検索を行うのではなく、検索ボタンをクリックした場合にクエリが呼び出されるように変更しています。

アプリケーションの初期化作業としてログイン処理後にsetupFormメソッドが呼び出されます。その中では、取引先オブジェクトの定義情報をdescribeSObjectメソッドで呼び出して、あらかじめ定義されている「種別(Type)」および「評価(Rating)」選択リスト項目の選択リストの値を取り出しています。

取り出された選択リストの情報は、typeDefsおよびratingDefs変数に格納され、データバインディングによって検索フォームのComboBoxコンポーネントに値が反映されます。

検索ボタンがクリックされるとqueryAccountsメソッドが呼び出されます。queryAccountsメソッドでは、検索実行前に検索フォームの値をチェックし、検索条件が設定されている場合には動的にSOQLクエリに条件句(WHERE)を追加しています。検索後、グリッドに表示されるレコードがあらかじめ選択リストに設定した条件に絞り込まれたものになっていることを確認してください。

Flexを使ったApexアプリケーション開発(1)

by Shinichi Tomita on 6月 26, 2007 at 10:46 午前

インターネットのアプリケーション開発環境について興味のある方の中には、Adobe社が提供しているFlashベースのRIA(Rich Internet Application)フレームワークである「Flex」についてお聞きになったことがあるかもしれません。

現在Salesforceでは、「Flex Toolkit for Force.com」として、Flexアプリケーションの中からSalesforceのデータにアクセスするためのライブラリを提供しています。このActionScriptでできたライブラリは、HTMLページからAJAX Toolkitを使用する場合と同様に、簡単にApex APIにアクセスすることができます。

必要条件

Flex BuilderはAdobe社が提供しているFlexアプリケーション作成のためのIDEです。ソースコードの記述からドラッグドロップによるコンポーネント配置などの機能が利用できます。Flex Builderの替わりにコマンドラインでのFlex 2 SDKを使用することもできます。

セットアップ

ここでは無料のFlex 2 SDKを利用して、Salesforceに埋め込んだFlexアプリケーションを作成する方法について説明します。

  1. ダウンロードしたFlex2 SDKを解凍し、適当なフォルダにコピーしておきます。
    例)
    C:\Program Files\Adobe\flex_sdk_2
  2. 環境変数のパスにFlex SDKの実行ファイルが含まれるように設定します。
    Windowsの場合は「コントロールパネル>システム>詳細設定>環境変数」からシステム環境変数 "Path" に
    c:\Program Files\Adobe\flex_sdk_2\bin
    を追加します。既存のパスの後ろにセミコロン(;)で区切って追加してください。

    パスを設定したら、コマンドプロンプトから以下のコマンドを実行して、実際にパスが通っているか確かめます

    c:\> mxmlc --version
    Version 2.0.1 build 155542
  3. ダウンロードした Apex Flex ライブラリを解凍し、適切なフォルダにインストールします
    例)
    C:\Program Files\salesforce.com\FlexSalesforce_R3_6

    解凍したフォルダの中のbinフォルダに、ビルド済みのas3Salesforce.swcというライブラリがあります。これがFlexアプリケーションからSalesforceに接続するためのライブラリの本体です。

Salesforce連携FlexのHello Worldのサンプル

エディタを使用して、以下のXMLファイルを記述して保存します(SalesforceHello.mxml)。これはFlexアプリでSalesforceのログインユーザ名を表示するだけの単純なサンプルアプリケーションを定義しています。

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
              xmlns:salesforce="com.salesforce.*"
              layout="absolute"
              applicationComplete="login()" >
  <mx:Script>
    <![CDATA[
import com.salesforce.*;
import com.salesforce.events.*;
import com.salesforce.objects.*;
import com.salesforce.results.*;

private function login():void {
  var lr:LoginRequest = new LoginRequest({
    server_url : Application.application.parameters.server_url,
    session_id : Application.application.parameters.session_id,
    // username : 'admin@demo.com', // <-- put your username here when connecting from local app
    // password : 'mypassword1234', // <-- put your password here when connection from local app
    callback : new AsyncResponder(sayHello)
  });
  conn.login(lr);
}

private function sayHello(result:Object):void {
  conn.getUserInfo(new AsyncResponder(function(userInfo:Object):void {
    message.text = "こんにちは、" + userInfo.userFullName;
  }));
}
    ]]>
  </mx:Script>

  <salesforce:Connection id="conn" />

  <mx:Label id="message" x="10" y="10" fontSize="32" color="#FFFFFF" text=""/>
</mx:Application>

記述したXMLファイルは、以下のコマンドでSWFファイル形式にコンパイルできます。

> mxmlc -use-network=true -library-path+="C:\Program Files\salesforce.com\FlexSalesforce_R3_6\bin" 
SalesforceHello.mxml (一行で続けて入力します)

library-pathオプションには、as3Salesforce.swcファイルが保存されているディレクトリ名を指定してください。

SalesforceにFlexアプリケーションをアップロード

作成したFlexアプリケーションをアップロードするには、まずSalesforceに管理者としてログインし、「設定>アプリケーションの設定>開発>カスタムSコントロール」から新規にSコントロールを作成します。

Flex Toolkit for Force.com を解凍したフォルダの中に、flexScontrolContent.htmというHTMLファイルがありますので、この中身のHTMLをそのままSコントロールの作成画面の内容として登録します。ファイルの参照ボックスで、コンパイルして作成されたSWFファイルを指定します。

Sコントロールを保存したら、Sコントロールを表示するためのタブを作成します。「設定>アプリケーションの設定>開発>カスタムタブ」からWebタブを新規作成し、Sコントロールとして先ほど作成したSコントロールを選択します。タブの作成が完了すると、右端に作成したタブが表示されますので、クリックするとログインしているユーザの名前がFlexの画面上が表示されます。

ここまででFlex Toolkit for Force.comを利用したFlexのアプリケーションを作成し、Salesforce上で動作させる方法について学びました。次回はFlexのコンポーネントを使ってSalesforceから取得したデータを表示するアプリケーションを作成してみます。

翔泳社DBマガジンでSalesforceプラットフォームが紹介されます

by Shinichi Tomita on 6月 20, 2007 at 06:42 午後

データベースの技術情報誌として有名なDBマガジン2007/08月号(翔泳社)で、Salesforceプラットフォームが紹介されます(6月23日発売予定)。本記事では、Salesforceを単なるSFAやCRMアプリケーションサービスとしてだけではなく、基盤サービスの面から切り込んで紹介しており、技術的な濃度の濃い内容になっています。

具体的にはSalesforceのプラットフォームアーキテクチャについて紹介した後、AJAX Toolkitを使ったAPIの利用方法から、簡単なアプリケーションのチュートリアルまで記載しています。

同号ではAjaxとデータベースのアプリケーション開発についての特集が別途組まれていますが、SalesforceのようにWeb経由でデータベースサービスを提供できるプラットフォームが、既存のインストールベースのデータベース開発に対してどれだけインパクトを与えることができるかについて考えてみるのもよいかもしれません。

DBマガジン2007/08月号

特集:JavaScriptのデバッグやJava連携も簡単になった Ajaxによる最新型DBアプリ開発
商品番号:810708
添付:CD-ROM 1点
サイズ:A4変
ページ:228
販売価格:\1,380(本体\1,314 消費税5%)
出版社:株式会社翔泳社


(追記)

なお以下は誌面のチュートリアルで利用した掲示板アプリケーションの完成版のURLです。開発用アカウントでアプリケーションをインストールして、Sコントロールのソースコードを参照してみてください。

https://www.salesforce.com/jp/appexchange/detail_overview.jsp?id=a03300000035ra1AAA

アプリケーションの紹介:開発用サンプルデータセット

by Shinichi Tomita on 6月 7, 2007 at 08:19 午後

SalesforceではDeveloper Editionに申し込むことによって、無料で開発用のSalesforce環境を手に入れることができます。ADNへの登録からDeveloper Editionアカウントの取得まではすべてオンラインで簡単かつ迅速にできますが、残念ながら現在 Developer Edition にあらかじめ含まれているサンプルデータは英語圏のデータのみで、しかもあまり充実しているとはいえません。そのため、ちょっとしたデモや開発のテストを行う際にも自分でデータを用意する必要が出てきてしまいます。

今回紹介するAppExchangeアプリケーションは、そういった簡単なデモやテストの際に必要になるダミーのデータをSalesforceにロードするためのアプリケーションです。元になるレコードの情報はCSVドキュメントとしてアプリケーションにパッケージされており、アプリケーションインストール後に画面のボタンをクリックするだけで自動的にレコード情報がデータベースにロードされるようになっています。

開発用サンプルデータセット

01530000000gecnaag

https://www.salesforce.com/jp/appexchange/detail_overview.jsp?id=a03300000034ht2AAA

なお、CSVドキュメントのデータを置き換えたり、新規にCSVをフォルダ内に追加しておくことによって、任意のデータをSalesforceにロードするためのツールとして使うことも可能です。もちろんData Loaderなどの純正クライアントツールもありますが、Webアプリケーション画面上でデータのローディングを行いたい場合などには重宝するでしょう。特にアプリケーションパッケージに初期データも含めてAppExchange上で配布したい時などにこの方法は有効です。

アプリケーションの紹介:SWOT分析ツール

by Shinichi Tomita on 6月 1, 2007 at 09:20 午後

今回は現在AppExchangeサイトに掲載されているアプリケーションを紹介すると同時に、おもに技術的な面の解説をしていきたいと思います。

SWOT分析ツール

Swot http://www.salesforce.com/jp/appexchange/detail_overview.jsp?id=a03300000032QXDAA2

SWOT分析という分析手法を用いた戦略立案の仕組みをSalesforce上で実行できるアプリケーションです。SalesforceのSコントロールを用いて実装しています。表示方法として、Salesforceの詳細レコード画面の中にインラインSコントロールという形(IFRAME)でSWOT表を埋め込んでおり、そのデータについての分析結果を組織内のユーザで共有できるようになっています。

一度トライアルしていただければ分かると思いますが、表示されているデータをクリックすることでインラインでデータ編集を行うことができます。このUIの実現には Dojo Toolkit InlineEditBox ウィジットを利用しています。Dojo Toolkit は、Salesforceが標準でホスティングしているAJAXライブラリになりますが、機能は非常に多岐にわたりますので、詳しい解説は今後に譲りたいと思います。

AppExchangeパートナー&デベロッパーセミナー資料

by Shinichi Tomita on 6月 1, 2007 at 08:57 午後

セールスフォース・ドットコムではAppExchangeアプリケーションの開発に興味のあるパートナーおよびデベロッパーの方を対象に、定期的に概要説明のセミナーを行っています。

以下はパートナー&デベロッパーセミナーで使用しているプレゼンテーションの資料です。実際に参加していただいたほうが理解しやすいかとは思いますが、セミナーに参加する時間のない方はぜひ下記資料をご覧ください。なお同セミナーは前半部はビジネス寄り、後半部は技術寄りの内容になります。

第1部:

第2部:

次回のパートナー&デベロッパーセミナーのスケジュールについてはコーポレートのサイトのイベントページからご確認いただけます