スタッフブログ Staff Blog

社員旅行へ行ってきました。

先月、社員旅行でディズニーシーへ行ってきました。

私はディズニーランドもシーも行ったことがなかったので、4月にガイドブックを買って、情報収集するところからのスタートでした。

社員旅行で行くのはおそらく最初で最後になるだろうと思い、思い切ってアンバサダーホテルに宿泊。

ディズニーのホテルに宿泊すると15分前に入園できるんですよね。
おかげでトイストーリーの11時台のファストパスを取ることができました。

ただ、梅雨の平日ということもあり、人は少ない方だったと思います。

前日の夕食はホテル内のエンパイア・グリルで七夕仕様のコース。

当日の朝食も同じホテル内のシェフ・ミッキーでビュッフェ。

シェフ・ミッキーはキャラクターが各テーブルに会いにきてくれ、サインや写真撮影をしてくれます。
パーク内でキャラクターと撮影するには長蛇の列だったので、これも予約して正解でした。

Daisy.JPG

Minnie.JPG

当日の昼食はパーク内のホテルミラコスタのレストラン ベッラヴィスタ・ラウンジで七夕のコース。

会社設立当初は「社員旅行は沖縄へ行こう!」と考えていたのに、前回の北海道に続いてなぜか違う場所を選んでしまいます。

会社負担(経費で認められる範囲内)での実施なので行ける場所は限られますが、次回はまたどこか行ったことのない場所へ行きたいな、と思っています。

参考)社員旅行費用が経費と認められる目安
・4泊5日以内の旅行であること
・従業員の過半数が参加していること
・一人あたりの旅費が10万円程度であること

設立4周年を迎えました。

本日、株式会社LAB(ラボ)は設立4周年を迎えました。

この4年間、多くの方からご支援ご協力を賜りましたことを、心より感謝申し上げます。

これからも感謝の気持ちを忘れず、お客様のお役に立てるよう
スタッフ一同取り組んでまいります。

今後とも末永くご指導お引き立てを賜りますようお願いいたします。

株式会社LAB
スタッフ一同

PowerCMS Xで検索フォームの条件指定に応じてリアルタイムに検索マッチ数を表示する

PowerCMS Xの案件において、「検索フォームで検索条件を指定していくと条件に合致する件数がいくつあるかをリアルタイムに表示する」という要件がありました。これはPowerCMS Xのダイナミック出力機能と複数の条件を指定可能なウェブサイト内検索を利用することで容易に実装が可能です。
画面キャプチャ:検索フォームと検索マッチ数の表示

テンプレート

PowerCMS XにはPowerCMS 5のようなData API機能は現在の所ありませんが、出力パスをobject_count.jsonのように拡張子をJSONにするとContent-Typeがapplication/jsonで送信されるような仕組みになっており、DataAPIのような感覚で扱うことができます。

よって、object_count.jsonのテンプレートにJSONのような文字列を出力するコードを書くことで、リクエスト内容に応じたオブジェクトの件数を返すことができるようになります。この時、mt:entriesmt:schools(私が独自に定義したモデル)等のタグを使用しても良いのですが、mt:objectloopを使用することでどのモデルにも対応したテンプレートにすることができ、object_count.jsonを汎用的に利用することが可能となります。検索条件のパラメータは自動で処理されるため、テンプレートへの記述は不要です。

<mt:var name="request._filter" setvar="model" /><mt:var name="request.workspace_id" setvar="workspace_id" />
<mt:objectloop model="$model" workspace_id="$workspace_id">
  <mt:If name="__first__"><mt:var name="object_count" setvar="result_count" /></mt:If>
</mt:objectloop>
{ "totalResult": <mt:If name="result_count"><mt:var name="result_count"><mt:Else>0</mt:If> }

※見やすいように改行・スペースを入れていますが、実際は1行で書いています。

JavaScript

フォームのselect要素やinput要素の状態が変化した時に、条件にマッチする件数を取得するgetCount関数を用意しました。

フォームの内容を$('#school_search').serialize().split('&')で取得して処理を行っているのは、PowerCMS Xの検索仕様に合わせたデータを送信するためです。select要素やinput要素には_filter_value_カラム名[]が指定してあり、これらに値が設定されている時に検索条件を指定する_filter_cond_カラム名[]_filter_and_or_[カラム名]を追加して送信する仕組みです。

const formElem = document.getElementById('school_search');
const formSlectedItems = formElem.querySelectorAll('.Search__formItem.-select');

function getCount() {
    const dataArray = $('#school_search').serialize().split('&');
    const dataArrayForPost = [];
    const existKeys = [];

    dataArray.forEach(function (data) {
        if (/^_filter_value.*\=$/.test(data)) {
            // 送信しない
        } else if (/^_filter_value.*\=.*/.test(data)) {
            const condKey = data.replace(/^_filter_value(.*)\=.*$/, '$1');
            dataArrayForPost.push(
              data,
              '_filter_cond' + condKey + '=eq'
            );
            if (existKeys.indexOf(condKey) === -1) {
              dataArrayForPost.push(
                '_filter_and_or' + condKey.replace('%5B%5D', '') + '=OR'
              );
              existKeys.push(condKey);
            }
        } else {
            dataArrayForPost.push(data);
        }
    });

    fetch('/search/object_count.json?' + dataArrayForPost.join('&'))
      .then(function (response) {
        return response.json();
      })
      .then(function (json) {
        const targetElem = document.getElementById('school_search_result_count');
        targetElem.textContent = json.totalResult;
      })
}

formSlectedItems.forEach(function (formItem) {
  formItem.addEventListener('change', getCount);
});
formElem.addEventListener('reset', function () {
  window.setTimeout(getCount, 200);
});

getCount();

余談ですが、ほぼバニラJSで書いているのですが、フォームのデータを取得する部分のみjQueryに依存しています。ここを上手く書き換えたいですが、ほとんどの構築案件でjQueryが利用されており書き換えてもあまり利がないのが現状でしょうか。

表示速度

データは学校モデルに広島県の公立学校805件を登録しています。学校種別(小・中・高)のカラムは数値(小=1・中=2・高= 3)で格納しています。また、市町村カラムは市町村コードを数値で格納していますが、この市町村コードはデータ登録時に市町村モデルの内容をダイアログ表示し該当する市町村を選択するようになっています。よって検索時は市町村名で市町村モデル検索して該当するIDを取得し、さらに学校モデルの市町村カラムを検索するようになります。サーバーはさくらのVPSにnginx + php-fpmで構築しています。

上記のような条件で検索条件を変化させてリクエストに要した時間を確認したところTTFB(接続が確立した後最初の1バイトが到着するまでの時間)は200ms〜300msとなっており、ストレスを感じることなく検索マッチ数の更新ができています。

PowerCMS Xのモデルのテンプレートタグを一覧にする

目下PowerCMS Xの案件を進めていて、モデルにカラムが多くカラム名も少々長いため、テンプレートタグを書くことに疲れてきました...。「なんとか楽ができないか」と考えたのですが、モデルの情報はmt_tableテーブルに、カラムの情報はmt_columnテーブルに入っていたので「PADO : PHP Alternative Database Object」を利用してテンプレートタグを一覧にして出力しました!

単純にモデル名とカラム名を繋げたものを出力するだけでなく、テンプレートタグでは省略されるアンダースコアを除去したり、編集表示がリッチテキストの場合はconvert_breaks="auto"を付けたり、リレーションだとブロックタグにしたりと色々工夫しました。またリレーションしているモデルへのリンクを表示して、リレーション先のテンプレートタグも書きやすくしています。
テンプレートタグを一覧した画面

動作サンプルを下記に置きました。(私の研究開発用サーバーで、PowerCMS Xをインストールしたホストとは別のホストに設置しています。データは学習用に作成したものです。)  

以下のコードをサイトルートに設置して$pcmsx_dir_path = '[PowerCMS X設置ディレクトリのパス]';にすると動作します。お試し下さい。なお、使い終わった際は必ず削除するようにしてください。

ちなみに後から気付いたのですが、mt:objectcolsタグでもカラムの情報が取得できるようです。

Googleマップとスライダーを連携させる

とある案件でGoogleマップにマーカー(ピン)を立て、マーカーに関する情報をスライダーに表示させる実装を行いました。
実装した画面のキャプチャ

当初ES6でコードを書いていたのですが、ゴールデンウィークで時間があることもあり以前から関心を寄せていたTypeScriptで書くとどうなるか試してみるなどしました。TypeScriptは型定義について覚えればわりとスムーズに始められるのではないかと感じました。

本題の「Googleマップとスライダーを連携させる」ですが、APIが充実したスライダーのプログラム「Swiper」を使用することで意外と楽に実装が行えました。ただ、普段jQueryやjQueryプラグインのみ使われている方には難しいかもしれませんね。やはり「継承とプロトタイプチェーン」あたりを理解する必要があるでしょう。ただ、ES6で導入された 「クラス」を使用することで以前よりは書きやすいのではないかとも思います。(しかし、ターゲットブラウザにIEが入るとBabelでトランスパイルする必要があり、またややこしくなるのかと...。)

クラス構文を理解したら、後は必要な処理を整理してメソッドを書いていきます。今回は以下のようなメソッドを書きました。スライドが動いた場合の処理・マーカーをクリックした場合の処理を書くために「イベント」も理解する必要があるでしょう。ただ、jQueryでもよく書く処理ですね。

  • Googleマップのインスタンス化
  • Swiperのインスタンス化
    • スライドが動いた場合の処理
  • マッピングデータの取得
  • マーカーの配置
    • マーカーをクリックした場合の処理
  • マーカー画像の変更
  • Swiperスライドの作成

メソッドを書き終えたらGoogleMapのインスタンスを作成し、initメソッドを実行して表示させます。selectorjsonPathを変更することで、同じような機能を持つマップを複数配置することができます。

const schoolMap = new GoogleMap({
    selector: '#schoolmap',
    jsonPath: 'json/schools.json',
    center: {
        lat: 34.51044761493913,
        lng: 133.37627491015624
    }
});
schoolMap.init();

書店でいくつかの書籍を見ましたが、jQueryの世界からステップアップしようにもなかなか良いものが見つからないように感じました。私は今回記事に書いたような実装の仕方を以前在籍していた会社の先輩が書いたコードから学びました。(その他、オライリーの「JavaScript 第5版」を読みました。)TypeScriptで書いたために変数の型が書いてありSwiftやJava等の言語に触れた経験がない方には少し難しいかもしれませんが、JavaScriptの技術を磨いていきたいというエンジニアの方はぜひソースを眺めてみて下さい。

なお、サンプルコードに記載しているGoogleのAPIキーはリファラ制限を設定していますので、ご自身のAPIキーを作成してお試し下さい。

お問い合わせ Contact

制作のご依頼、ご相談などは下記のフォームからご連絡ください。