Spring '11: テストのバックグラウンドでの実行

by Kaz Kawamura on 1月 18, 2011 at 06:35 午後

Spring '11の新機能に関して、米国のDeveloperForceのブログでいろいろな記事が投稿されています。今回の新機能の一つにテストのエンハンスもあります。テストに関して、こちらの記事「Spring '11: Run Apex Tests In The Background」が投稿されましたので、翻訳しました。多少直訳っぽい文章になってしまいましたが。。。以下、訳です。

このSpring '11の新機能は、モニターの前に座り、もしかするとコーヒー片手に、EclipseのApex Test RunnderかブラウザのRun All Testsページを見つめながら、プロセスがスローダウンしていないかひそかに心配しているすべての開発者向けです。

その新機能のイメージは以下のような感じです:

6a00d8341cded353ef0147e1958c75970_2

この二つの矢印がループになった小さなアイコンは何ですかって?これがみそです。これが、テストがまだ実行中でのちほど制御が戻ってくることを知らせてくれます。リフレッシュボタンを押すこともできます。ページがリロードされることを願いながら画面の前で待機する必要もありません。テストカバレッジは、エンタープライズアプリケーションの成功にとても有益です。apexテストを簡単に実行でき、コーヒーをもう一杯取りに行く理由を与えることなく結果のレポートを見れることは、いいことでしょう。

実際にこの機能が動いている様子をみたいですか? 今夜のSpring '11 webinarにご参加ください。

訳注:この機能はパイロットです。正式リリースの際には仕様の変更がある可能性もあります。

Spring '11でのコンテキストの一本化とガバナの新しい制限

by Kaz Kawamura on 1月 17, 2011 at 03:39 午後

今回の記事は、USのdeveloper forceで先週公開された記事ですが、日本の開発者の方にも有用だと思いますので、翻訳しました。元記事は、こちらの「One Context and New Limits For Governors in Spring ‘11」を参照してください。以下、翻訳です。

このタイトルは一言で言えることではないですが、このSpring '11での変更は、どのトリガが貴重な20のDML文のうちの7つを消費しアプリケーションを落としているかをデバッグログから見つけ出すため、夜遅く他の10人の開発者と電話会議を行っているような開発者の皆さまには喜ばれる変更ではないでしょうか?

Spring '11では、トリガ独自のコンテキストはなくなり、他のコードと同じDMLリミットになります。加えて、制限そのものも150まで上がり、コントローラなどでもいままでの息苦しさが多少緩和されるでしょう。

それだけではありません。SOQLで扱える検索結果の最大行数も10,000から50、000に変更になります。Force.comで開発をしていてうれしいことの一つに、去年制限を回避するためにしていたトリックが毎年過去のものになることです。今年の春はとりわけ大きな一歩でしょう。

詳しくは、リリースWebサイトをチェックして、Spring '11 webinarにてどこが新しくなったかを確認して私たちに直接チャットでご質問ください。

訳者追記

Spring'11でのガバナ制限は、こちらで公開されています。かなりすっきりしたことと、各制限の説明がより詳しくなりました。

Google Maps JavaScript API V3 を用いたマーカー表示

by Madoka Fukahori on 1月 13, 2011 at 04:37 午後

V3からAPIキーが不要になったGoogle Maps JavaScript API V3を利用して、
Salesforce内のデータを地図上にマーカー表示するサンプルをご紹介します。

Gmapsample1_2

今回ご紹介するのは,Salesforceの取引先データに格納されている住所データを用いてGoogleMapへプロットするVisualforceコンポーネントです。取引先の詳細画面から現在表示している取引先の場所とその周辺にある取引先の位置情報が確認できます。

下記のサンプルコードのようなVisualforceと拡張コントローラを作成後に、取引先の詳細ページのページレイアウトにコンポーネントを追加します。

Gmapsample2

今回は周囲の取引先データを表示していますが、Force.com上に任意のデータベースを作り、 それらのデータを下記の方法でJSONデータとして取得し、表示することで施設情報の地図などを簡単に作ることができます。

是非色々とお試しください。

サンプルコード( Visualforce)


<apex:page showHeader="false" sidebar="false" standardController="Account" extensions="CntNearByAccount">
<head>
<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false">
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js">
<script type="text/javascript">
google.maps.event.addDomListener(window, 'load', function() {
var mapOptions = {
zoom: 14,
mapTypeId: google.maps.MapTypeId.ROADMAP,
scaleControl: true
};
var mapObj = new google.maps.Map(document.getElementById('gmap'), mapOptions);
var request = {
address: '{!Account.BillingPostalCode} + {!Account.BillingState} + {!Account.BillingCity} + {!Account.BillingStreet}'
};
// 表示取引先をジオコーディング
var ACgeocoder = new google.maps.Geocoder();
ACgeocoder.geocode(request, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
mapObj.setCenter(results[0].geometry.location);
// マーカーを表示
var marker = new google.maps.Marker({
position: results[0].geometry.location, // 表示取引先を中心に表示
title: request.address,
map: mapObj
});
// ポップアップ内の情報
var ACinfoWindow = new google.maps.InfoWindow();
var ACHTMLinfo = '<a target=\"_top\" href=\"/{!Account.Id}\">{!Account.Name}</a><br/>{!Account.BillingState}{!Account.BillingCity}{!Account.BillingStreet}';
ACinfoWindow.setContent(ACHTMLinfo);
ACinfoWindow.setPosition(results[0].geometry.location);
// マップクリックイベントを追加
google.maps.event.addListener(marker, 'click', function(){
ACinfoWindow.open(mapObj,marker);
});
}
});
// 周囲の取引先情報を取得
var ACdata ={
list: {!accountsData},
// Getter
getAll: function(){
return this.list;
}
};
// マーカー画像を作成
var markerImg = new google.maps.MarkerImage(
// マーカーの画像URL
"{!URLFOR($Resource.AC_icon)}",
// マーカーのサイズ
new google.maps.Size(30, 30),
// 画像の基準位置
new google.maps.Point(0, 0),
// Anchorポイント
new google.maps.Point(0, 0)
);
// マーカー影画像
var shadow = new google.maps.MarkerImage(
//影画像URL
"{!URLFOR($Resource.AC_shadow)}",
// マーカーのサイズ
new google.maps.Size(43, 38),
// 画像の基準位置
new google.maps.Point(0, 0),
// Anchorポイント
new google.maps.Point(0, 5)
);
var shape = {
coord: [1, 1, 1, 20, 18, 20, 18 , 1],
type: 'poly'
};
// マーカーを作成
jQuery.each(ACdata.getAll(), function(i, ACdata) {
// ジオコーディング
var address = ACdata.address;
var geocoder = new google.maps.Geocoder();
geocoder.geocode( { 'address': address}, function(results, status) {
// ステータスがOKならマーカーを表示する。
if (status == google.maps.GeocoderStatus.OK) {
var marker = new google.maps.Marker({
position: results[0].geometry.location,
map: mapObj,
shadow: shadow,
icon: markerImg,
shape: shape,
title: ACdata.name,
zIndex : 0
});
// ポップアップ内の情報
var infoWindow = new google.maps.InfoWindow();
var HTMLinfo = '<a target=\"_top\" href=\"/' + ACdata.id + '\">' + ACdata.name + '</a><br/>' + ACdata.info;
infoWindow.setContent(HTMLinfo);
infoWindow.setPosition(results[0].geometry.location);
// マップクリックイベントを追加
google.maps.event.addListener(marker, 'click', function(){
infoWindow.open(mapObj,marker);
});
}
});
});
});
</script>
</head>
<body>
<div id="gmap" style="height:300px;width: 500px;"></div>
</body>
</apex:page>

サンプルコード( Apex)

public with sharing class CntNearByAccount {
    public Account a{get;set;}
    public CntNearByAccount(ApexPages.StandardController stdController) {
        a = (Account)stdController.getRecord();
    }
    public Object[] getAccountsData(){
        Object[] jsonData = new Object[]{};
        // 表示取引先以外を取得
        for(Account AccountsData : [SELECT Id, Name, BillingStreet, BillingCity, BillingState, BillingPostalCode 
            FROM Account where Id != :a.Id]){ 
            jsonData.add(
                '{name:\'' + AccountsData.Name + 
                    '\', address:\'' + AccountsData.BillingPostalCode + AccountsData.BillingState + AccountsData.BillingCity + AccountsData.BillingStreet + 
                    '\', id:\'' + AccountsData.Id + 
                    '\', info:\'' + AccountsData.BillingState + AccountsData.BillingCity + AccountsData.BillingStreet + 
                '\'}'
            );
        }
        return jsonData;
    } 
}