メインコンテンツに移動

メインナビゲーション

  • ホーム
  • サイトマップ
  • ビデオ
  • ご連絡

パンくず

  • ホーム
  • Drupalでajaxのフレームワークが簡単に作成できる

Drupalでajaxのフレームワークが簡単に作成できる

drupal
development
ajax

やりたいこと:Drupalのプログラムレベルで簡単にajaxを利用してクライアント側でデータ交信をしたいです

  • 環境:Drupal7.54
  • DrupalのFormAPIで簡単にajaxの実装ができます(Drupalのフォーム(FromAPI)でのajaxの実装 )
  • FormAPIだけではなく、Drupalをカスタマイズ時にいろいろなところでajaxを実装したいことがあります

ポイント1:Drupalでajaxに必要なライブラリをロードし、クライアント側にjquery.form.jsファイルをセット

  • サーバー側でdrupal.ajaxのライブラリをロードする必要があります
  • クライアント側にjquery.form.jsファイルを設置する必要があります
  • この処理はajax処理するページをロード時に行えれば良いです。
    • 例:hook_init()内で処理する
      /**
       * Implements hook_init().
       */
      function YOUR_MODULE_NAME_init()
      {
        drupal_add_js('misc/jquery.form.js');
        drupal_add_library('system','drupal.ajax');
      }
  • クライアント側のブラウザのプロパティでjquery.form.jsがセットされたことの確認ができます

ポイント2:クライアント側のajax起動リンク内にajax対応可否のパラメーター「nojs」とクラス属性「use-ajax」のセット

  • ajaxの起動リンクの作成基本パターン: 
    <a href="text/ajax/nojs/1234" class="use-ajax">ajaxリンク</a>
    • hrefにある「nojs」が決まりの文字
    • hrefにある「1234」はサーバー側に転送したい必要なパラメーター
    • class="use-ajax"はこのリンクがajax用に決める
  • クライアント側のjsで使用しているブラウザがajax対応可能かを判断して、ajax起動リンクに「nojs」のパラメーターを書き換え(利用可能:nojs⇒ajax)てサーバー側に転送
  • サーバー側がajax利用可否よりクライアント側にajax対応有無の結果を返します
    Drupalのajaxフレームワークの利用
  • 上記例のプログラムは以下のようで
    /**
     * Implements hook_init().
     */
    function test_module_init()
    {
      drupal_add_js('misc/jquery.form.js');
      drupal_add_library('system','drupal.ajax');
    }
    
    /**
     *  Implementation of hook_menu()
     */
    function test_module_menu() {
      $items['test/ajax/%/%']=array(     // URLの2,3番目がクライアント側で生成
          'page callback' => 'ajax_node_response',
          'page arguments' => array(2,3),   // URLの2,3番目の引数をコールバック関数に渡す
          'access callback' => 'user_access',
          'access arguments' => array('access content'),
          'type' => MENU_CALLBACK,
      );
      return $items;
    }
    
    function ajax_node_response($type="ajax", $nid=0){
      $node = node_load( $nid, NULL, false );
      $vnode = node_view($node);
      $output = theme('node', $vnode);
      if( $type="ajax" ){
        $commands=array();
        $commands[]=ajax_command_replace( '#block-system-main','<section id="block-system-main">'.$output.'</section>' ) ;
        $page = array(
          '#type' => 'ajax',
          '#commands' => $commands,
        );
        ajax_deliver( $page ) ;   // ajax対応ブラウザの結果
      } else {
        $output = '<div id="content">'.$output.'</div>';  // ajax非対応ブラウザの結果
        return $output;
      }
    }
    

ポイント3:クライアント側で実行させたい部分はajax_commandを使用します

  • クライアント側で処理結果をどこに入り替えはajax_command_replaceで指定します
  • 結果の挿入、入れ替え、削除、css処理などがいろいろあります。詳細は本家のajax_command一覧を参考してください

 

drupal
development
form

やりたいこと:Drupalのフォーム(FormAPI)でajaxを実装して各フォーム要素を動的に制御したいです

  • 環境:Drupal7.54
  • フォーム(FormAPI)で各要素の表示/非表示などの制御が簡単にできます(Drupalのフォーム(Form API)の「#states」で各フォーム要素の動作制御が可能)。
    • フォームを作成時にJavascriptを意識しなくてよい
    • 事前にフォームの要素を用意して表示/非表示のようなお動作制御
    • データ取得するなどの動作制御はできません
  • ajaxで高等な動作(データ取得など)制御ができるので、FormAPIもこれ基盤を用意して、簡単に実装できます。

FormAPIで「#ajax」の記述(ポイント:callback、wrapper)だけで良いのでJavascriptの意識必要はありません

  • FormAPIがajaxのインターフェースを用意しています。Form記述で「#ajax」要素を追加すれば、Javascriptなどのコーティングはいらないです
    • callbak:ajaxのリクエストが来た時に呼び出される関数
    • wrapper:ajaxのサーバー処理完了後に結果を画面に表示させる場所の指定
  • 簡単の例:テキスト入力フォームを生成して、入力したメッセージを画面のどこかに再表示させるajax処理
    FormAPIのajaxの実装方法
  • ajaxの記述はFormAPIの実装時に追加します。
    /**
     *  Implementation of hook_menu()
     *  新規フォームを表示するページのメニュー設定
     */
    function my_module_name_menu() {
      $items['test/form'] = array(
          'title' => 'Ajaxテスト',
          'page callback' => 'drupal_get_form',
          'page arguments' => array('my_sample_form'),
          'access arguments' => array('access content'),
      );
    }
    
    /**
     * フォームの各要素の記述
     */
    function my_sample_form($form, &$form_state){
      // メッセージ入力フィールド
      $form['message'] = array(
          '#type' => 'textfield',
          '#title' => t('メッセージを入力'),
      );
    
      // 入力されたメッセージをajaxで表示する場所
      $form['msg_wrapper'] = array(
          '#type' => 'markup',
          '#markup' => "",
          '#prefix' => '<div id="msg-wrapper">',
          '#suffix' => '</div>',
      );
    
      // サブミットボタン
      $form['submit'] = array(
          '#type' => 'submit',
          '#value' => '送信',
          '#ajax' => array(
              'callback' => 'test_sample_form_ajax_callback',
              'wrapper' => 'msg-wrapper',
              'effect' => 'fade',
          ),
      );
    
      return $form;
    }
    
    /**
     * ajaxに呼び出される関数
     */
    function test_sample_form_ajax_callback($form, $form_state) {
      // 入力されたメッセージを指定した場所にセット
      $form['msg_wrapper']['#markup'] = '入力されたメッセージ:' .
                  check_plain($form_state['values']['message']) ;
      // 置換する部品を返す
      return $form['msg_wrapper'] ;
    }

     
drupal
customization
development
ctools
menu
modal

今回、画面でポップアップでデータ入力、ajaxでデータを更新することを試みたいですが、jQuery、Bootstrapなどのmodalライブラリで実現ができます。但しDrupalサイトでポップアップを作るとしたら、やはりctoolsのModal機能を利用してみたいです(ctools(Chaos tool suite)はDrualの開発によく利用されているAPI)。

やりたいこと:ポップアップを立ち上げて入力したデータをajaxでサーバーと交信

  • ポップアップ(modal)の作成
  • データ入力フォームの表示
  • 入力されたデータをajaxでサーバーに送信、データ更新

ポップアップ作成の流れの基本:ctoolsのmodal.jsを利用します

  • ポップアップを開くリンク/ボタンの作成
    • ctoolsのmodal.js、modal.cssをこのページに入れる(ajaxで操作するため)
  • ポップアップのリンク/ボタンがクリックされた、ポップアップが開く
  • ポップアップのフォームにデータ入力、送信ボタンクリック
    • 入力されたデータをサーバーにajaxで送信、データ更新される

ctoolsのmodal利用の問題点

  • ctoolsのmodal利用に関する紹介はウェブ上にたくさんあります。また、インストールされたctools(modules\ctools\ctools_ajax_sample\ctools_ajax_sample.module)にサンプルプログラムもあります
  • 問題点1:ポップアップに表示されるフォームはjavascriptでhtmlコードとして吐き出されています(modules\ctools\ctools_ajax_sample\js\ctools-ajax-sample.js)
    • 簡単なフォームに問題はないが、複雑なフォームに煩雑になります
  • 問題点2:ポップアップウィンドウに関する設定はphpソースコード内で定義
    • ロジックとUI設定を分離しべき、ポップアップに関する設定はcss、jsに任せるべき

ctoolsのmodal利用の改善

  • 上記問題1は、DrupalのForm APIを利用して、フォーム作成を行います
  • 上記問題2は、ポップアップの外観はサイト全体のテーマ(bootstrap)に統一し、背景、フォントサイズなどはcssファイルで個別に設定します

ポップアップの作成

  • ポップアップを起動するリンク/ボタンの作成は省略します
  • ポップアップとの通信URLをhook_menuで作成
    $items['my-module/%ctools_js/add'] = array(
    	'page callback' => 'my_module_callback',
    	'page arguments' => array(1),
    	'access callback' => TRUE,
    	'type' => MENU_CALLBACK,
    );
  • URLの設定に「%ctools_js」部分があります。ここで、'nojs'の定数を入力する必要はあります。例:http://your-site/my-module/nojs/add
  • ポップアップの起動リンク/ボタンのクラス属性: class="ctools-use-modal"をセットします(これがないと、Modalポップアップの起動はできないです)
  • ページのコールバック関数(my_module_callback)の作成
    function my_module_callback($ajax) {
        if ($ajax) {
    		// ctoolsのajax、modalに関するjsファイルをクライアントへ
            ctools_include('ajax');
            ctools_include('modal');
    		
    		//フォーム作成に関する上方
            $form_state = array(
                'ajax' => TRUE,
                'title' => t('New Group Creation'),
            );
    
    		//ポップアップフォームの作成
    		//フォームからの更新データを$form_stateにセットする
            $output = ctools_modal_form_wrapper('my_module_form', $form_state);
    
    		//新規ポップアップにajaxが有効にする
            if (!empty($form_state['ajax_commands'])) {
                $output = $form_state['ajax_commands'];
            }
    
    		//ポップアップの出力
            print ajax_render($output);
            drupal_exit();
        }
        else {
            return drupal_get_form('mymodule_form');
        }
    }
    // ポップアップにある入力フォームの定義
    function my_module_form($form, $form_state) {
        $form = array();
    
        $form['new_link_text'] = array(
            '#type' => 'textfield',
            '#title' => t('Group Name'),
        );
    
        $form['submit'] = array(
            '#type' => 'submit',
            '#value' => t('Submit'),
        );
    
        return $form;
    }
    // データ更新
    function my_module_form_submit(&$form, &$form_state) {
        // データの更新
        // ロジックは省略
    
        // ポップアップを閉じるコマンド
        $form_state['ajax_commands'][] = ctools_modal_command_dismiss();
    }
  • 注目すべき関数の役割: ctools_modal_form_wrapper
    • 定義されたフォーム(my_module_form)をレンダリング可能にする
    • ajaxからのデータ送信情報を$form_stateに設定
    • hook_form_submitなどの起動

 

 

drupal
development
ajax

やりたいこと:Drupalのプログラムレベルで簡単にajaxを利用してクライアント側でデータ交信をしたいです

  • 環境:Drupal7.54
  • DrupalのFormAPIで簡単にajaxの実装ができます(Drupalのフォーム(FromAPI)でのajaxの実装 )
  • FormAPIだけではなく、Drupalをカスタマイズ時にいろいろなところでajaxを実装したいことがあります

ポイント1:Drupalでajaxに必要なライブラリをロードし、クライアント側にjquery.form.jsファイルをセット

  • サーバー側でdrupal.ajaxのライブラリをロードする必要があります
  • クライアント側にjquery.form.jsファイルを設置する必要があります
  • この処理はajax処理するページをロード時に行えれば良いです。
    • 例:hook_init()内で処理する
      /**
       * Implements hook_init().
       */
      function YOUR_MODULE_NAME_init()
      {
        drupal_add_js('misc/jquery.form.js');
        drupal_add_library('system','drupal.ajax');
      }
  • クライアント側のブラウザのプロパティでjquery.form.jsがセットされたことの確認ができます

ポイント2:クライアント側のajax起動リンク内にajax対応可否のパラメーター「nojs」とクラス属性「use-ajax」のセット

  • ajaxの起動リンクの作成基本パターン: 
    <a href="text/ajax/nojs/1234" class="use-ajax">ajaxリンク</a>
    • hrefにある「nojs」が決まりの文字
    • hrefにある「1234」はサーバー側に転送したい必要なパラメーター
    • class="use-ajax"はこのリンクがajax用に決める
  • クライアント側のjsで使用しているブラウザがajax対応可能かを判断して、ajax起動リンクに「nojs」のパラメーターを書き換え(利用可能:nojs⇒ajax)てサーバー側に転送
  • サーバー側がajax利用可否よりクライアント側にajax対応有無の結果を返します
    Drupalのajaxフレームワークの利用
  • 上記例のプログラムは以下のようで
    /**
     * Implements hook_init().
     */
    function test_module_init()
    {
      drupal_add_js('misc/jquery.form.js');
      drupal_add_library('system','drupal.ajax');
    }
    
    /**
     *  Implementation of hook_menu()
     */
    function test_module_menu() {
      $items['test/ajax/%/%']=array(     // URLの2,3番目がクライアント側で生成
          'page callback' => 'ajax_node_response',
          'page arguments' => array(2,3),   // URLの2,3番目の引数をコールバック関数に渡す
          'access callback' => 'user_access',
          'access arguments' => array('access content'),
          'type' => MENU_CALLBACK,
      );
      return $items;
    }
    
    function ajax_node_response($type="ajax", $nid=0){
      $node = node_load( $nid, NULL, false );
      $vnode = node_view($node);
      $output = theme('node', $vnode);
      if( $type="ajax" ){
        $commands=array();
        $commands[]=ajax_command_replace( '#block-system-main','<section id="block-system-main">'.$output.'</section>' ) ;
        $page = array(
          '#type' => 'ajax',
          '#commands' => $commands,
        );
        ajax_deliver( $page ) ;   // ajax対応ブラウザの結果
      } else {
        $output = '<div id="content">'.$output.'</div>';  // ajax非対応ブラウザの結果
        return $output;
      }
    }
    

ポイント3:クライアント側で実行させたい部分はajax_commandを使用します

  • クライアント側で処理結果をどこに入り替えはajax_command_replaceで指定します
  • 結果の挿入、入れ替え、削除、css処理などがいろいろあります。詳細は本家のajax_command一覧を参考してください

 

javascript
development
ctools
ajax

やりたいこと:AJAXで動的に別のJSファイルをクライアント側に追加します

  • 環境:Drupal7.54、ctools7.x-1.12
  • Drupalのajax(ctoolsモジュールに含まれている)のコマンド(ajax_command_append)で動的にクライアント側にJSファイルをHTMLのheadに追加します
    ・・・・・・ // ここで、ajax_commandの使用方法を省略
    $commands[] = ajax_command_append("head", "<script type='text/javascript' src='/your/module/path/test.js"></script>" );
    return array('#type' => 'ajax', '#commands' => $commands);

    DrupalのAJAXで動的にJSファイルをクライアント側に追加します

  • Drupalのajaxの利用は「Drupalのフォーム(FromAPI)でのajaxの実装」、「Drupalでajaxのフレームワークが簡単に作成できる」をご参考ください
  • 上記追加されたJSファイルが正常に動作しています

問題点:動的に追加したJSファイルがブラウザの開発ツールのソースから見つからないです(デバッグはできない)

  • なぜか、追加されたJSファイルが正常に動作しているにも関わらず、ブラウザの開発ツールのソースから見つからにです
  • デバッグのブレイクポイントを入れて、動作を確認したいが、ソースファイルが見つからなくて、デバッグはできないです。

解決:動的に追加されたJSファイルに「debugger」命令を入れて強制的にブレイクポイントを入れます

  • いろいろ調べてみたが、なぜJSファイルがソースから見つからない原因は分からないです
  • javascriptデバッグのために「debugger」命令がありまして、それは強制的にブレイクポイントを入れたこと同じです
  • 実際にdebugger命令を入れて、追加されたJSファイルが現れて、JSファイル名が変わりました
    debugger命令でJSファイルの実行を強制的に止める
  • 結果として、JSファイルのデバッグができるようになりました
drupal
development
form

やりたいこと:Drupalのフォーム(FormAPI)でajaxを実装して各フォーム要素を動的に制御したいです

  • 環境:Drupal7.54
  • フォーム(FormAPI)で各要素の表示/非表示などの制御が簡単にできます(Drupalのフォーム(Form API)の「#states」で各フォーム要素の動作制御が可能)。
    • フォームを作成時にJavascriptを意識しなくてよい
    • 事前にフォームの要素を用意して表示/非表示のようなお動作制御
    • データ取得するなどの動作制御はできません
  • ajaxで高等な動作(データ取得など)制御ができるので、FormAPIもこれ基盤を用意して、簡単に実装できます。

FormAPIで「#ajax」の記述(ポイント:callback、wrapper)だけで良いのでJavascriptの意識必要はありません

  • FormAPIがajaxのインターフェースを用意しています。Form記述で「#ajax」要素を追加すれば、Javascriptなどのコーティングはいらないです
    • callbak:ajaxのリクエストが来た時に呼び出される関数
    • wrapper:ajaxのサーバー処理完了後に結果を画面に表示させる場所の指定
  • 簡単の例:テキスト入力フォームを生成して、入力したメッセージを画面のどこかに再表示させるajax処理
    FormAPIのajaxの実装方法
  • ajaxの記述はFormAPIの実装時に追加します。
    /**
     *  Implementation of hook_menu()
     *  新規フォームを表示するページのメニュー設定
     */
    function my_module_name_menu() {
      $items['test/form'] = array(
          'title' => 'Ajaxテスト',
          'page callback' => 'drupal_get_form',
          'page arguments' => array('my_sample_form'),
          'access arguments' => array('access content'),
      );
    }
    
    /**
     * フォームの各要素の記述
     */
    function my_sample_form($form, &$form_state){
      // メッセージ入力フィールド
      $form['message'] = array(
          '#type' => 'textfield',
          '#title' => t('メッセージを入力'),
      );
    
      // 入力されたメッセージをajaxで表示する場所
      $form['msg_wrapper'] = array(
          '#type' => 'markup',
          '#markup' => "",
          '#prefix' => '<div id="msg-wrapper">',
          '#suffix' => '</div>',
      );
    
      // サブミットボタン
      $form['submit'] = array(
          '#type' => 'submit',
          '#value' => '送信',
          '#ajax' => array(
              'callback' => 'test_sample_form_ajax_callback',
              'wrapper' => 'msg-wrapper',
              'effect' => 'fade',
          ),
      );
    
      return $form;
    }
    
    /**
     * ajaxに呼び出される関数
     */
    function test_sample_form_ajax_callback($form, $form_state) {
      // 入力されたメッセージを指定した場所にセット
      $form['msg_wrapper']['#markup'] = '入力されたメッセージ:' .
                  check_plain($form_state['values']['message']) ;
      // 置換する部品を返す
      return $form['msg_wrapper'] ;
    }

     
drupal
development
ajax

やりたいこと:Drupalのプログラムレベルで簡単にajaxを利用してクライアント側でデータ交信をしたいです

  • 環境:Drupal7.54
  • DrupalのFormAPIで簡単にajaxの実装ができます(Drupalのフォーム(FromAPI)でのajaxの実装 )
  • FormAPIだけではなく、Drupalをカスタマイズ時にいろいろなところでajaxを実装したいことがあります

ポイント1:Drupalでajaxに必要なライブラリをロードし、クライアント側にjquery.form.jsファイルをセット

  • サーバー側でdrupal.ajaxのライブラリをロードする必要があります
  • クライアント側にjquery.form.jsファイルを設置する必要があります
  • この処理はajax処理するページをロード時に行えれば良いです。
    • 例:hook_init()内で処理する
      /**
       * Implements hook_init().
       */
      function YOUR_MODULE_NAME_init()
      {
        drupal_add_js('misc/jquery.form.js');
        drupal_add_library('system','drupal.ajax');
      }
  • クライアント側のブラウザのプロパティでjquery.form.jsがセットされたことの確認ができます

ポイント2:クライアント側のajax起動リンク内にajax対応可否のパラメーター「nojs」とクラス属性「use-ajax」のセット

  • ajaxの起動リンクの作成基本パターン: 
    <a href="text/ajax/nojs/1234" class="use-ajax">ajaxリンク</a>
    • hrefにある「nojs」が決まりの文字
    • hrefにある「1234」はサーバー側に転送したい必要なパラメーター
    • class="use-ajax"はこのリンクがajax用に決める
  • クライアント側のjsで使用しているブラウザがajax対応可能かを判断して、ajax起動リンクに「nojs」のパラメーターを書き換え(利用可能:nojs⇒ajax)てサーバー側に転送
  • サーバー側がajax利用可否よりクライアント側にajax対応有無の結果を返します
    Drupalのajaxフレームワークの利用
  • 上記例のプログラムは以下のようで
    /**
     * Implements hook_init().
     */
    function test_module_init()
    {
      drupal_add_js('misc/jquery.form.js');
      drupal_add_library('system','drupal.ajax');
    }
    
    /**
     *  Implementation of hook_menu()
     */
    function test_module_menu() {
      $items['test/ajax/%/%']=array(     // URLの2,3番目がクライアント側で生成
          'page callback' => 'ajax_node_response',
          'page arguments' => array(2,3),   // URLの2,3番目の引数をコールバック関数に渡す
          'access callback' => 'user_access',
          'access arguments' => array('access content'),
          'type' => MENU_CALLBACK,
      );
      return $items;
    }
    
    function ajax_node_response($type="ajax", $nid=0){
      $node = node_load( $nid, NULL, false );
      $vnode = node_view($node);
      $output = theme('node', $vnode);
      if( $type="ajax" ){
        $commands=array();
        $commands[]=ajax_command_replace( '#block-system-main','<section id="block-system-main">'.$output.'</section>' ) ;
        $page = array(
          '#type' => 'ajax',
          '#commands' => $commands,
        );
        ajax_deliver( $page ) ;   // ajax対応ブラウザの結果
      } else {
        $output = '<div id="content">'.$output.'</div>';  // ajax非対応ブラウザの結果
        return $output;
      }
    }
    

ポイント3:クライアント側で実行させたい部分はajax_commandを使用します

  • クライアント側で処理結果をどこに入り替えはajax_command_replaceで指定します
  • 結果の挿入、入れ替え、削除、css処理などがいろいろあります。詳細は本家のajax_command一覧を参考してください

 

drupal
development
system_management
ajax

DrupalのFormAPIでフォーム内でAJAXを扱うのは基本です

  • DrupalのFormAPIがAJAXを実装しています
  • FormAPIでのAJAXの扱う:「Drupalのフォーム(FromAPI)でのajaxの実装」を参考してください
  • FormAPIでのAJAXでの扱う利点:
    • フォームを作成しているときに簡単にAJAXの実装が可能
    • AJAXの仕組みを知らなくても、手順通りに実装すればよいです
  • 大半のケースでFormAPIで解決できるので、AJAXをFormAPIで実装するのは一般的となります

FormAPI以外にAJAXの実装はDrupal.ajaxオブジェクトで行います

  • DrupalのAJAXのフレームワークは「misc/ajax.js」にあります
  • AJAXを実装する場合、このjsファイルを必ずインポートする必要があります
    drupal_add_js("/misc/ajax.js") ;  // ajaxのjsファイルをインポート
  • ここで、あるフォーム(text_form)のボタンを押してajaxを通じてサーバーとの交信を行う例とします
    Drupalのajaxの仕組みと扱い方法
  • フォームはDrupalのFormAPIで生成、または別の方法で生成します
    // 例: DrupalのAPIでフォームを作成
    //     送信ボタンを押して、"test message"の文字列でフォームを置換します
      $form['card_last']=array(
          "#type" => "markup",
          "#markup" => "",
          "#prefix" => "<div id='card-last-result-div'>",  // ajaxで置換したいエリア
          "#suffix" => "</div>",
      );
    
      $form['card_last']['submit'] = array(
          '#type' => 'submit',
          '#value' => '送信',
          '#attributes' => array( 'id'=>'test-form-submit' ),  // ajaxのIDを指定します
          "#ajax" => array(
            "callback" => "_ajax_callback_form",  // ajaxのコールバック
            'wrapper' => 'card-last-result-div',
            'method' => 'replace',
            'effect' => 'fade',
          ),
      );
    
    // カスタムJSファイルをフォームと一緒に添付
      $form['#attached']['js'] = array( "file_path/custom_ajax.js" );

DrupalのAJAXオブジェクトを生成してサーバーとの交信を用意します

  • 一つカスタムjsファイルを用意して(例:custom_ajax.js)、フォーム生成と同時にクライアント側に渡します
  • Drupal.ajaxオブジェクトを生成します
    (function($){
      Drupal.behaviors.custom_module_name={
        attach:function(cotext,settings){
          $("#test-form-submit").once("test-form-submit",function(){ //指定したフォームのみ
            var base = $(this).attr('id');  //フォームIDの使用
            var element_settings = {
              url: window.location.protocol + "//"+ window.location.hostname + settings.basePath + settings.pathPrefix + "system/ajax",
              event: 'click',
              progress: { type: 'throbber', },
            };
        // Drupalのajaxオブジェクトを生成します
            Drupal.ajax[base] = new Drupal.ajax(base, this, element_settings);
    
        // 送信ボタンにListenerを追加
            $("#test-form-submit").on( 'click',function(){
              $(this).click();  // ajaxを作動させます
            });
          });
        }
      };
    })(jQuery)
    
    • base(必須): ajaxの識別、ここでフォームID(test-form-submit)で指定
    • url(必須): サイトのパス/system/ajax
    • event: ajaxを作動させるイベントの指定
    • progress: ajaxでデータ交信中にロードの動画アイコンの表示
  • サーバーサイトでajaxに呼び出されるファンクションを用意します、"test message"をajaxに返還します
    function _ajax_callback_card_last_form($form, &$form_state){
      $commands[] = ajax_command_replace('#card-last-result-div', "test message"); 
      return array('#type' => 'ajax', '#commands' => $commands);
    }
  • ここで、ajax_commandを利用しなくても、ajax_deliverでメッセージの返還もできます
drupal
form
ajax

Drupalのajax_commandの基本:登録されているコマンド(例:ajax_command_invokeなど)でクライアント側に実行コマンドを送ります

  • 背景:Drupal7.54、コアーモジュールajaxの利用
  • Drupalのajax利用は別の記事を参考してください
    • Drupalでajaxのフレームワークが簡単に作成できる
    • Drupalのajaxの仕組みおよびプログラム上での扱う
  • サーバーサイトの処理結果をクライアント側に送る方法:
    • FormAPIに"#ajax"セットにある"wrapper"に指定されたエレメントに処理結果の置換 <-  'replaceWith', 'append', 'prepend', 'before', 'after', or 'html'
    • ajax_commadよりクライアント側の要素挿入、置換、削除などの操作ができます
  • ajax_commandがサーバー側での処理結果をクライアント側により柔軟に操作することができます
    • ajax_commandに登録されている関数が本家のページを参考してください
    • クライアント側の要素挿入、置換、削除、javascript実行などができます

処理結果をクライアント側に実行させるためカスタムajaxコマンドの作成

  • クライアント側でjQueryのセレクターで選択できる要素の操作にはajax_commandに登録された関数で行うことができます
  • 複雑なjascript実行、複数のセレクターなどの場合、カスタムajax_commandの作成が必要となります
    • クライアント側のjavascript関数を呼び出します
    • サーバーサイトの処理ロジックをクライアント側で行います

jQueryで登録さた関数をajax_command_invokeで呼び出します

  • クライアント側で事前にjQueryのjavascript関数を定義します
  • ajax_command_invokeで定義された関数を呼び出します
    ajax_command_invokeでカスタムajax関数の呼び出し

Drupal.ajaxネームスペースのプロトタイプに登録されたjavascript関数をajax_commandで呼び出します

  • Drupal.ajaネームスペースのプロトタイプを利用して、javascript関数を事前に登録します
  • ajax_command(登録済みの関数ではない)でjavascript関数を呼び出します
    ajax_commandに登録されていないjs関数の呼び出し
drupal
development
ajax

やりたいこと:Drupalのプログラムレベルで簡単にajaxを利用してクライアント側でデータ交信をしたいです

  • 環境:Drupal7.54
  • DrupalのFormAPIで簡単にajaxの実装ができます(Drupalのフォーム(FromAPI)でのajaxの実装 )
  • FormAPIだけではなく、Drupalをカスタマイズ時にいろいろなところでajaxを実装したいことがあります

ポイント1:Drupalでajaxに必要なライブラリをロードし、クライアント側にjquery.form.jsファイルをセット

  • サーバー側でdrupal.ajaxのライブラリをロードする必要があります
  • クライアント側にjquery.form.jsファイルを設置する必要があります
  • この処理はajax処理するページをロード時に行えれば良いです。
    • 例:hook_init()内で処理する
      /**
       * Implements hook_init().
       */
      function YOUR_MODULE_NAME_init()
      {
        drupal_add_js('misc/jquery.form.js');
        drupal_add_library('system','drupal.ajax');
      }
  • クライアント側のブラウザのプロパティでjquery.form.jsがセットされたことの確認ができます

ポイント2:クライアント側のajax起動リンク内にajax対応可否のパラメーター「nojs」とクラス属性「use-ajax」のセット

  • ajaxの起動リンクの作成基本パターン: 
    <a href="text/ajax/nojs/1234" class="use-ajax">ajaxリンク</a>
    • hrefにある「nojs」が決まりの文字
    • hrefにある「1234」はサーバー側に転送したい必要なパラメーター
    • class="use-ajax"はこのリンクがajax用に決める
  • クライアント側のjsで使用しているブラウザがajax対応可能かを判断して、ajax起動リンクに「nojs」のパラメーターを書き換え(利用可能:nojs⇒ajax)てサーバー側に転送
  • サーバー側がajax利用可否よりクライアント側にajax対応有無の結果を返します
    Drupalのajaxフレームワークの利用
  • 上記例のプログラムは以下のようで
    /**
     * Implements hook_init().
     */
    function test_module_init()
    {
      drupal_add_js('misc/jquery.form.js');
      drupal_add_library('system','drupal.ajax');
    }
    
    /**
     *  Implementation of hook_menu()
     */
    function test_module_menu() {
      $items['test/ajax/%/%']=array(     // URLの2,3番目がクライアント側で生成
          'page callback' => 'ajax_node_response',
          'page arguments' => array(2,3),   // URLの2,3番目の引数をコールバック関数に渡す
          'access callback' => 'user_access',
          'access arguments' => array('access content'),
          'type' => MENU_CALLBACK,
      );
      return $items;
    }
    
    function ajax_node_response($type="ajax", $nid=0){
      $node = node_load( $nid, NULL, false );
      $vnode = node_view($node);
      $output = theme('node', $vnode);
      if( $type="ajax" ){
        $commands=array();
        $commands[]=ajax_command_replace( '#block-system-main','<section id="block-system-main">'.$output.'</section>' ) ;
        $page = array(
          '#type' => 'ajax',
          '#commands' => $commands,
        );
        ajax_deliver( $page ) ;   // ajax対応ブラウザの結果
      } else {
        $output = '<div id="content">'.$output.'</div>';  // ajax非対応ブラウザの結果
        return $output;
      }
    }
    

ポイント3:クライアント側で実行させたい部分はajax_commandを使用します

  • クライアント側で処理結果をどこに入り替えはajax_command_replaceで指定します
  • 結果の挿入、入れ替え、削除、css処理などがいろいろあります。詳細は本家のajax_command一覧を参考してください

 

drupal
development
system_management
ajax

DrupalのFormAPIでフォーム内でAJAXを扱うのは基本です

  • DrupalのFormAPIがAJAXを実装しています
  • FormAPIでのAJAXの扱う:「Drupalのフォーム(FromAPI)でのajaxの実装」を参考してください
  • FormAPIでのAJAXでの扱う利点:
    • フォームを作成しているときに簡単にAJAXの実装が可能
    • AJAXの仕組みを知らなくても、手順通りに実装すればよいです
  • 大半のケースでFormAPIで解決できるので、AJAXをFormAPIで実装するのは一般的となります

FormAPI以外にAJAXの実装はDrupal.ajaxオブジェクトで行います

  • DrupalのAJAXのフレームワークは「misc/ajax.js」にあります
  • AJAXを実装する場合、このjsファイルを必ずインポートする必要があります
    drupal_add_js("/misc/ajax.js") ;  // ajaxのjsファイルをインポート
  • ここで、あるフォーム(text_form)のボタンを押してajaxを通じてサーバーとの交信を行う例とします
    Drupalのajaxの仕組みと扱い方法
  • フォームはDrupalのFormAPIで生成、または別の方法で生成します
    // 例: DrupalのAPIでフォームを作成
    //     送信ボタンを押して、"test message"の文字列でフォームを置換します
      $form['card_last']=array(
          "#type" => "markup",
          "#markup" => "",
          "#prefix" => "<div id='card-last-result-div'>",  // ajaxで置換したいエリア
          "#suffix" => "</div>",
      );
    
      $form['card_last']['submit'] = array(
          '#type' => 'submit',
          '#value' => '送信',
          '#attributes' => array( 'id'=>'test-form-submit' ),  // ajaxのIDを指定します
          "#ajax" => array(
            "callback" => "_ajax_callback_form",  // ajaxのコールバック
            'wrapper' => 'card-last-result-div',
            'method' => 'replace',
            'effect' => 'fade',
          ),
      );
    
    // カスタムJSファイルをフォームと一緒に添付
      $form['#attached']['js'] = array( "file_path/custom_ajax.js" );

DrupalのAJAXオブジェクトを生成してサーバーとの交信を用意します

  • 一つカスタムjsファイルを用意して(例:custom_ajax.js)、フォーム生成と同時にクライアント側に渡します
  • Drupal.ajaxオブジェクトを生成します
    (function($){
      Drupal.behaviors.custom_module_name={
        attach:function(cotext,settings){
          $("#test-form-submit").once("test-form-submit",function(){ //指定したフォームのみ
            var base = $(this).attr('id');  //フォームIDの使用
            var element_settings = {
              url: window.location.protocol + "//"+ window.location.hostname + settings.basePath + settings.pathPrefix + "system/ajax",
              event: 'click',
              progress: { type: 'throbber', },
            };
        // Drupalのajaxオブジェクトを生成します
            Drupal.ajax[base] = new Drupal.ajax(base, this, element_settings);
    
        // 送信ボタンにListenerを追加
            $("#test-form-submit").on( 'click',function(){
              $(this).click();  // ajaxを作動させます
            });
          });
        }
      };
    })(jQuery)
    
    • base(必須): ajaxの識別、ここでフォームID(test-form-submit)で指定
    • url(必須): サイトのパス/system/ajax
    • event: ajaxを作動させるイベントの指定
    • progress: ajaxでデータ交信中にロードの動画アイコンの表示
  • サーバーサイトでajaxに呼び出されるファンクションを用意します、"test message"をajaxに返還します
    function _ajax_callback_card_last_form($form, &$form_state){
      $commands[] = ajax_command_replace('#card-last-result-div', "test message"); 
      return array('#type' => 'ajax', '#commands' => $commands);
    }
  • ここで、ajax_commandを利用しなくても、ajax_deliverでメッセージの返還もできます
drupal
form
ajax

やりたいこと:Drupalのajaxフレームワークを利用して表示している要素を削除

  • Drupalのモジュール(Views)で作成した一覧の要素を選択して削除します
    • 要素を選択して削除するモジュール:Views Bulk Operations
    • 例:Drupalのモジュール(VBO)の各種処理(Operation)に独自(カスタムオ)のプションの追加方法
  • 前提条件:要素削除する確認の必要はありません
  • ajaxで動的に削除するのはやさしいUIとも言えるでしょう(以下のイメージのように削除)
    Drupalのajaxフレームワークより要素を動的に削除

Step1:削除リンクにDrupalのajax使用するクラス:use-ajax を追加

  • Drupalのajaxフレームワークに関する説明は以下の記事をご参考ください
    • Drupalでajaxのフレームワークが簡単に作成できる
  • 削除アイコン付きのリンクは以下のようです
    // 削除エレメントID:123 (例)
    <a href="/delete/element/id/123/nojs" class="use-ajax del-link" id="del-link-123">
           <i class="fa fa-trash-o" aria-hidden="true"></i>
    </a>
    • アンカー(a)に削除するエレメントID(または別の識別パラメーター)を入れる必要はあります
    • アンカーリンクの後ろに「nojs」を追加します(クライアント側のajax作動時に、nojs->ajaxに変換され)
    • アンカーがクリックされると、Drupalのajaxフレームワークが起動され、削除パラメーターをサイト側に渡します

Step2:hook_menuで要素削除のリクエストをキャッチします

  • hook_menuで要素削除のリクエストを受け取り、削除処理を行います
    // 要素削除URLの設定
    $items['delete/element/%/nojs'] = array(
    	'page callback' => 'delete_element',
    	'page arguments' => array( 2, 3 ) ,
    	'access callback' => 'delete_access',
    	'type' => MENU_CALLBACK,
    );
    // ajaxが以下のURLでリクエストをします(クライアント側でnojs->ajaxに変換)
    $items['delete/element/%/ajax'] = array(
    	'delivery callback' => 'ajax_deliver',
    )+$items['delete/element/%/nojs'] ;    // 要素削除定義に遷移
    
  • 要素削除処理ファンクション:delete_element で削除処理、処理結果をクライアント側に返します
    function delete_element ($id, $ajax){
        $is_ajax = $ajax === "ajax" ;  // ajaxと通用のリクエスト両方対応のため
    
        // 要素をDBから削除
        db_delete("element_table")->condition("entity_id", $id)->execute() ;
    
        // 画面要素も削除コマンドを返す
        if( $is_ajax ){
            // ajaxで要素削除後の処理
            $commands = array();
            $commands[] = ajax_command_remove( '#element-123');
            return array(
              '#type'=>"ajax",
              '#commands' => $commands,
            );
        } else {
            // 通常での要素削除後の処理
            drupal_set_message(t('Deleted 1 vocabulary'));
            drupal_goto();
        }
    }

     

Drupalのajaxフレームワークで要素削除

纏め:Drupalのajaxフレームワークを利用すればajax処理が自動的に行います

  • 上記例では、削除リンクにクラス:use-ajax を追加するだけで、ajax関連処理を記述する必要はあります
    • 削除リンクではなく、削除ボタン(button)要素を使用する場合クラス: use-ajax-submit
  • サーバー側では、hook_menuで削除リンクの定義、削除リクエストをキャッチして、削除処理関数を作成します
    • DB上のデータ削除完了後に、クライアント側の要素削除命令(ajax_command_remove)を返せば良いです
  • この一連のajax処理の記述はほどんとありません。簡単、便利です
drupal
development
ajax

やりたいこと:Drupalのプログラムレベルで簡単にajaxを利用してクライアント側でデータ交信をしたいです

  • 環境:Drupal7.54
  • DrupalのFormAPIで簡単にajaxの実装ができます(Drupalのフォーム(FromAPI)でのajaxの実装 )
  • FormAPIだけではなく、Drupalをカスタマイズ時にいろいろなところでajaxを実装したいことがあります

ポイント1:Drupalでajaxに必要なライブラリをロードし、クライアント側にjquery.form.jsファイルをセット

  • サーバー側でdrupal.ajaxのライブラリをロードする必要があります
  • クライアント側にjquery.form.jsファイルを設置する必要があります
  • この処理はajax処理するページをロード時に行えれば良いです。
    • 例:hook_init()内で処理する
      /**
       * Implements hook_init().
       */
      function YOUR_MODULE_NAME_init()
      {
        drupal_add_js('misc/jquery.form.js');
        drupal_add_library('system','drupal.ajax');
      }
  • クライアント側のブラウザのプロパティでjquery.form.jsがセットされたことの確認ができます

ポイント2:クライアント側のajax起動リンク内にajax対応可否のパラメーター「nojs」とクラス属性「use-ajax」のセット

  • ajaxの起動リンクの作成基本パターン: 
    <a href="text/ajax/nojs/1234" class="use-ajax">ajaxリンク</a>
    • hrefにある「nojs」が決まりの文字
    • hrefにある「1234」はサーバー側に転送したい必要なパラメーター
    • class="use-ajax"はこのリンクがajax用に決める
  • クライアント側のjsで使用しているブラウザがajax対応可能かを判断して、ajax起動リンクに「nojs」のパラメーターを書き換え(利用可能:nojs⇒ajax)てサーバー側に転送
  • サーバー側がajax利用可否よりクライアント側にajax対応有無の結果を返します
    Drupalのajaxフレームワークの利用
  • 上記例のプログラムは以下のようで
    /**
     * Implements hook_init().
     */
    function test_module_init()
    {
      drupal_add_js('misc/jquery.form.js');
      drupal_add_library('system','drupal.ajax');
    }
    
    /**
     *  Implementation of hook_menu()
     */
    function test_module_menu() {
      $items['test/ajax/%/%']=array(     // URLの2,3番目がクライアント側で生成
          'page callback' => 'ajax_node_response',
          'page arguments' => array(2,3),   // URLの2,3番目の引数をコールバック関数に渡す
          'access callback' => 'user_access',
          'access arguments' => array('access content'),
          'type' => MENU_CALLBACK,
      );
      return $items;
    }
    
    function ajax_node_response($type="ajax", $nid=0){
      $node = node_load( $nid, NULL, false );
      $vnode = node_view($node);
      $output = theme('node', $vnode);
      if( $type="ajax" ){
        $commands=array();
        $commands[]=ajax_command_replace( '#block-system-main','<section id="block-system-main">'.$output.'</section>' ) ;
        $page = array(
          '#type' => 'ajax',
          '#commands' => $commands,
        );
        ajax_deliver( $page ) ;   // ajax対応ブラウザの結果
      } else {
        $output = '<div id="content">'.$output.'</div>';  // ajax非対応ブラウザの結果
        return $output;
      }
    }
    

ポイント3:クライアント側で実行させたい部分はajax_commandを使用します

  • クライアント側で処理結果をどこに入り替えはajax_command_replaceで指定します
  • 結果の挿入、入れ替え、削除、css処理などがいろいろあります。詳細は本家のajax_command一覧を参考してください

 

drupal
Views

やりたいこと:モジュール(VBO)の各処理(Operation)に独自(カスタム)オプションを追加したい

  • 前回モジュール(VBO)にたいして処理(Operation)オプション追加を紹介しました
    •  Drupalのモジュール(VBO)の一括処理後にページ遷移させる方法
    • このオプションは全VBOに対して作成したものですが、すべての処理に影響を与えています
  • 各種処理(Operation)に対してどのようにオプションを追加するか前回の課題として残っています
  • 今回はこの課題を解決に新しいカスタムモジュール(vbo_redirect_option)を作成して、紹介します
    モジュールVBOの各種処理に独自のオプション追加

hook_formとCtoolsのdepent systemより各オペレーションに独自のオプションを追加

  • VBOのオペレーション設定フォームがカスタマイズとして開放していないです(前回も説明した)
  • ここで、Drupalのhook_formでVBOのオペレーション設定画面を特定して、カスタムオプション追加することになりました
    function vbo_redirect_option_form_alter(&$form, &$form_state, $form_id)
    {
        if( isset($form_state['id']) && $form_state['id'] === "views_bulk_operations"){
    
            foreach( $form_state['input']['options']['vbo_operations'] as $key => $operation) {
                if( $operation['redirect_check'] && strlen( trim($operation['redirect_url']))>0 ) {
                    variable_set( $key, $operation['redirect_url'] );
                } else {
                    if( !empty( variable_get($key) ) ) variable_del( $key ) ;
                }
            }
    
    
            foreach( $form['options']['vbo_operations'] as $key => &$operation ){
                if( !is_array($operation) ) continue ;
    
                $redirect_url = variable_get($key);
                $dep_key = "edit-options-vbo-operations-" . str_replace("_", "-", str_replace("::","",$key) ) ;
    
                $operation['redirect_check'] = array(
                    '#type' => 'checkbox',
                    '#title' => t('Redirect page to after operation'),
                    '#default_value' =>  $redirect_url ? 1 : 0 ,
                    '#dependency' => array(    // Ctoolsのdependent systemに依存
                        $dep_key."-selected" => array(1),
                    ),
                );
                $operation['redirect_url'] = array(
                    '#type' => 'textfield',
                    '#title' => t('Provide label'),
                    '#title_display' => 'invisible',
                    '#default_value' => empty($redirect_url) ? "" : $redirect_url,
                    '#dependency' => array(    // Ctoolsのdependent systemに依存
                        $dep_key."-selected" => array(1),
                        $dep_key . '-redirect-check' => array(1),
                    ),
                    '#dependency_count' => 2,
                );
            }
        }
    }
    • 設定フォームにチェックボックスをチェックしたら、画面遷移URL入力フィールドが現れるダイナミックフォームはモジュール(Ctools)のdependent systemを利用しています

処理(Operation)確認ステップをスキップがあるかないかを確認してhook_views_bulk_operations_form_alter()実装でオプションの設定を行う

  • VBOの処理(Operation)が確認ステップがあるかないかは2種類あります(この二種類をの処理プロセスが違うのでしっかりテストする必要がある)
  • hook_views_bulk_operations_form_alter()を実装して、各処理ステップにカスタマイズを行います
    function vbo_redirect_option_views_bulk_operations_form_alter(&$form, &$form_state, $vbo)
    {
        // collect all operations that has contained redirect_rul
        $redirect_arr = array();
        foreach( $vbo->options['vbo_operations'] as $key => $operation ) {
            if( !empty( variable_get($key) ) ){
                $redirect_arr[$key] = $key ;
            }
        }
    
        // add redirect step to #submit element
        if(isset($form['select'])) {
    
            // this is the form start step
            foreach( $form['select'] as $key => &$element ){
                if( isset($redirect_arr[$key]) ){
                    // we check if there is any operation has redirect_url
                    $element['#submit'][] = 'vbo_redirect_after_operation';
                    // only one is enough, we will detect witch one in the callback function
                    break;
                }
            }
    
            // do operation with confirmation step
            // this is the confirmation step
        } else if( !$form_state['operation']->getAdminOption('skip_confirmation') ) {
            $form['actions']['submit']['#submit'][] = "vbo_redirect_after_operation_with_confirmation";
            $form_state['redirect_to_after_operation'] = $form_state['operation']->getAdminOption('redirect_url');
        }
    
    }
    
    
    /**
     * callback function that has called by operation
     * this is the form start step, we don't know if it has confirmation step or not
     * @param $form
     * @param $form_state
     */
    function vbo_redirect_after_operation(&$form, &$form_state){
        // the are multiple element can be operated
        // the right one that has be sent to this step
        // we need get redirect_url if the it has
        if( isset($form_state['operation']) ){
            // get redirect_url by operation_id
            $redirec=variable_get($form_state['operation']->operationId) ;
            if( !empty($redirec) ){
                if( $form_state['operation']->getAdminOption('skip_confirmation') ) {
                    $form_state['redirect'] = $redirec;
                }
            }
        }
    }
    
    /**
     * callback function that has be called by operation with confirmation step
     * @param $form
     * @param $form_state
     */
    function vbo_redirect_after_operation_with_confirmation( $form, &$form_state ){
        // there is only operation that has be sent here with the confirmation step
        if( isset($form_state['redirect_to_after_operation']) ){
            // set redirect_url that should be stored in $form_state
            $form_state['redirect'] = $form_state['redir ect_to_after_operation'];
        }
    }

感想と結論:VBOの処理オプション設定はカスタマイズに開放していないため、各種処理(Operation)のオプションの取得、設定に苦労します

  • VBOの処理オプション設定はユーザーにカスタマイズに開放していないです
  • オペレーションの各ステップに$form、$form_state、$vbo変数から必要な情報を取得したり、セットしたりしました
  • 必要な情報がどこにあるかは不明だし(その時dsm($vbo)などで確認)、特定するまでに、時間がかかりました。
添付 サイズ
vbo_redirect_option.zip (1.77 KB) 1.77 KB
Embedded thumbnail for Drupalのモジュール(VBO)の各種処理(Operation)に独自(カスタムオ)のプションの追加方法
drupal
development
Views

Drupalのモジュール(Rules)で作成した各種アクションセットコンポーネントをモジュールVBOで一括処理

  • 背景:Drupal7.x.56、Views Bulk Operation(VBO)7.x-3.4、Rules7.x-2.10
  • モジュール(Rules)がいろいろなアクションセットの作成ができます
    • データの作成/更新/削除
    • メール送信、フラグを立てる
    • などなど
  • モジュール(VBO)がRulesで作成したアクションコンポーネントの利用ができます
    • Drupalのモジュール(Rules)のアクションコンポーネントでVBOより新規ノード作成とフィールドのコピー
  • 今回の例として、Rulesでメッセージ表示する単純なアクションコンポーネント(show message)を作成して、VBOで一括処理を行います
    Rulesでメッセージ表示コンポーネントをVBOで一括処理

問題点:VBO一括処理後に画面遷移(redirect)はできません

  • VBOで一括処理後に、画面を遷移して処理結果を確認することがあります
  • VBOの設定オプションに、処理後の画面遷移設定がありません
  • ネットで調べてみたが、VBO一括処理後の画面遷移オプション追加パッチがります
    • これは、モジュールVBOに対するパッチです
    • このパッチ適応したら、次回VBOアップグレード時に、ソースのマージ作業が面だと思います
    • できれば、VBOのパッチを使用したくないです

解決:カスタムモジュール(vbo_redirect_option.zip)でVBO処理後の画面遷移オプションの追加

  • モジュール(VBO)の主要部分がクラス(class)構造なので、簡単に画面遷移ロジックを追加することはできません
  • 「Bulk Operation Settings」に処理後の画面遷移オプションを追加します
    • 「Bulk Operation Settings」のオーバーライドができないので、hook_form_alter()でオプションを追加することになりました
      /**
       * Implements hook_form_alter().
       */
      function vbo_redirect_option_form_alter(&$form, &$form_state, $form_id)
      {
        // VBOの処理かのチェック
          if( isset($form_state['id']) && $form_state['id'] === "views_bulk_operations"){
      
         // ここで、画面遷移先の保存処理は少し反則
         //  vbo_settingsに画面遷移先の追加は難しい(クラス構造体内にあるため)
         //  環境変数に画面遷移先(uri)を保存
              if( isset($form_state['input']['options']['vbo_settings'][vbo_redirect_url]) ){
                  variable_set( 'vbo_redirect_url', $form_state['input']['options']['vbo_settings'][vbo_redirect_url] ) ;
              }
      
         // 画面遷移先のテキストフィールドを追加
              $form['options']['vbo_settings']['vbo_redirect_url'] = array(
                  '#type' => 'textfield',
                  '#title' => t('Page to direct to after completion of  batch'),
                  '#description' => t('Redirects to the view when finished the operation'),
                  '#default_value' => variable_get('vbo_redirect_url'),
              );
          }
      }
    • 画面遷移先を入力するテキストフィールドを設定画面に追加
    • 画面遷移先(uri)をvbo_settingsに入れたいですが、クラスの構造体にあるため追加できません。環境変数に保存することにしました。
    • 設定画面を保存("#submit")後に、画面遷移先を保存する処理を行いたいですが、"#submit"にコールバック関数を入れても、呼び出されない現象があって、仕方がなく、hook_form_alter()内で画面遷移先(uri)の保存処理を行いました
      VBOに一括処理後に画面遷移オプションの追加
  • hook_views_bulk_operations_form_alter()を実装して、実際のVBO一括処理後に、画面遷移設定を行います
    /**
     * Implements hook_views_bulk_operations_form_alter().
     */
    function vbo_redirect_option_views_bulk_operations_form_alter(&$form, &$form_state, $vbo)
    {
        $vbo_redirect_url = trim( variable_get('vbo_redirect_url') ) ;
    
        if( isset($vbo_redirect_url) && strlen($vbo_redirect_url) >0 ){
    
            // check if vbo operation skip confirmation
            $skip_confirmation = false ;
            foreach( $vbo->options['vbo_operations'] as $key => $operation ){
                if( $operation['selected'] && $operation['skip_confirmation'] ){
                    if( isset($form['select'][$key]) ) {
                        $form['select'][$key]['#submit'][] = 'vbo_redirect_after_operation';
                        $skip_confirmation = true ;
                    }
                }
            }
    
            // set redirect method when vbo has confirmation step
            if( !$skip_confirmation ){
                $form['actions']['submit']['#submit'][] = 'vbo_redirect_after_operation' ;
            }
        }
    }
    
    // callback function to set redirect url
    function vbo_redirect_after_operation($form, &$form_state){
        $vbo_redirect_url = trim( variable_get('vbo_redirect_url') ) ;
        $form_state['redirect'] = $vbo_redirect_url;
    }
    • VBO一括処理の「確認のステップをスキップ」があるか、ないかを分けて処理します(画面遷移設定場所が違うため)
    • "#submit"に画面遷移処理を追加します
    • 画面遷移処理は$form_state['redirect'] で行います

結論と感想:簡単のカスタモジュールでVBOへの影響はありません。各オペレーション設定に画面遷移オプションを追加したほうよいかもしれない

  • このカスタムモジュールのインストールより、モジュール(VBO)への影響はありません
  • この画面遷移オプションを「Bulk Operation Settings」に追加したので、すべてのオペレーションに適応されます
    • VBOの一括処理内容がいろいろあります(例:オーナー変更、エンティティ内容変更など)
    • これらの処理後に一つの画面遷移先の設定はやや強引的だと思います
  • できれば、「Selected Bulk Operations」にある、選択したオペレーションの設定に画面遷移先の設定をしたほうが柔軟的な対応だと思います(次回の課題)
    画面遷移オプションを各オペレーションに追加すべき
添付 サイズ
vbo_redirect_option.zip (1.19 KB) 1.19 KB
Embedded thumbnail for Drupalのモジュール(VBO)の一括処理後にページ遷移させる方法
drupal
form
ajax

やりたいこと:Drupalのajaxフレームワークを利用して表示している要素を削除

  • Drupalのモジュール(Views)で作成した一覧の要素を選択して削除します
    • 要素を選択して削除するモジュール:Views Bulk Operations
    • 例:Drupalのモジュール(VBO)の各種処理(Operation)に独自(カスタムオ)のプションの追加方法
  • 前提条件:要素削除する確認の必要はありません
  • ajaxで動的に削除するのはやさしいUIとも言えるでしょう(以下のイメージのように削除)
    Drupalのajaxフレームワークより要素を動的に削除

Step1:削除リンクにDrupalのajax使用するクラス:use-ajax を追加

  • Drupalのajaxフレームワークに関する説明は以下の記事をご参考ください
    • Drupalでajaxのフレームワークが簡単に作成できる
  • 削除アイコン付きのリンクは以下のようです
    // 削除エレメントID:123 (例)
    <a href="/delete/element/id/123/nojs" class="use-ajax del-link" id="del-link-123">
           <i class="fa fa-trash-o" aria-hidden="true"></i>
    </a>
    • アンカー(a)に削除するエレメントID(または別の識別パラメーター)を入れる必要はあります
    • アンカーリンクの後ろに「nojs」を追加します(クライアント側のajax作動時に、nojs->ajaxに変換され)
    • アンカーがクリックされると、Drupalのajaxフレームワークが起動され、削除パラメーターをサイト側に渡します

Step2:hook_menuで要素削除のリクエストをキャッチします

  • hook_menuで要素削除のリクエストを受け取り、削除処理を行います
    // 要素削除URLの設定
    $items['delete/element/%/nojs'] = array(
    	'page callback' => 'delete_element',
    	'page arguments' => array( 2, 3 ) ,
    	'access callback' => 'delete_access',
    	'type' => MENU_CALLBACK,
    );
    // ajaxが以下のURLでリクエストをします(クライアント側でnojs->ajaxに変換)
    $items['delete/element/%/ajax'] = array(
    	'delivery callback' => 'ajax_deliver',
    )+$items['delete/element/%/nojs'] ;    // 要素削除定義に遷移
    
  • 要素削除処理ファンクション:delete_element で削除処理、処理結果をクライアント側に返します
    function delete_element ($id, $ajax){
        $is_ajax = $ajax === "ajax" ;  // ajaxと通用のリクエスト両方対応のため
    
        // 要素をDBから削除
        db_delete("element_table")->condition("entity_id", $id)->execute() ;
    
        // 画面要素も削除コマンドを返す
        if( $is_ajax ){
            // ajaxで要素削除後の処理
            $commands = array();
            $commands[] = ajax_command_remove( '#element-123');
            return array(
              '#type'=>"ajax",
              '#commands' => $commands,
            );
        } else {
            // 通常での要素削除後の処理
            drupal_set_message(t('Deleted 1 vocabulary'));
            drupal_goto();
        }
    }

     

Drupalのajaxフレームワークで要素削除

纏め:Drupalのajaxフレームワークを利用すればajax処理が自動的に行います

  • 上記例では、削除リンクにクラス:use-ajax を追加するだけで、ajax関連処理を記述する必要はあります
    • 削除リンクではなく、削除ボタン(button)要素を使用する場合クラス: use-ajax-submit
  • サーバー側では、hook_menuで削除リンクの定義、削除リクエストをキャッチして、削除処理関数を作成します
    • DB上のデータ削除完了後に、クライアント側の要素削除命令(ajax_command_remove)を返せば良いです
  • この一連のajax処理の記述はほどんとありません。簡単、便利です
drupal
development
ajax

やりたいこと:Drupalのプログラムレベルで簡単にajaxを利用してクライアント側でデータ交信をしたいです

  • 環境:Drupal7.54
  • DrupalのFormAPIで簡単にajaxの実装ができます(Drupalのフォーム(FromAPI)でのajaxの実装 )
  • FormAPIだけではなく、Drupalをカスタマイズ時にいろいろなところでajaxを実装したいことがあります

ポイント1:Drupalでajaxに必要なライブラリをロードし、クライアント側にjquery.form.jsファイルをセット

  • サーバー側でdrupal.ajaxのライブラリをロードする必要があります
  • クライアント側にjquery.form.jsファイルを設置する必要があります
  • この処理はajax処理するページをロード時に行えれば良いです。
    • 例:hook_init()内で処理する
      /**
       * Implements hook_init().
       */
      function YOUR_MODULE_NAME_init()
      {
        drupal_add_js('misc/jquery.form.js');
        drupal_add_library('system','drupal.ajax');
      }
  • クライアント側のブラウザのプロパティでjquery.form.jsがセットされたことの確認ができます

ポイント2:クライアント側のajax起動リンク内にajax対応可否のパラメーター「nojs」とクラス属性「use-ajax」のセット

  • ajaxの起動リンクの作成基本パターン: 
    <a href="text/ajax/nojs/1234" class="use-ajax">ajaxリンク</a>
    • hrefにある「nojs」が決まりの文字
    • hrefにある「1234」はサーバー側に転送したい必要なパラメーター
    • class="use-ajax"はこのリンクがajax用に決める
  • クライアント側のjsで使用しているブラウザがajax対応可能かを判断して、ajax起動リンクに「nojs」のパラメーターを書き換え(利用可能:nojs⇒ajax)てサーバー側に転送
  • サーバー側がajax利用可否よりクライアント側にajax対応有無の結果を返します
    Drupalのajaxフレームワークの利用
  • 上記例のプログラムは以下のようで
    /**
     * Implements hook_init().
     */
    function test_module_init()
    {
      drupal_add_js('misc/jquery.form.js');
      drupal_add_library('system','drupal.ajax');
    }
    
    /**
     *  Implementation of hook_menu()
     */
    function test_module_menu() {
      $items['test/ajax/%/%']=array(     // URLの2,3番目がクライアント側で生成
          'page callback' => 'ajax_node_response',
          'page arguments' => array(2,3),   // URLの2,3番目の引数をコールバック関数に渡す
          'access callback' => 'user_access',
          'access arguments' => array('access content'),
          'type' => MENU_CALLBACK,
      );
      return $items;
    }
    
    function ajax_node_response($type="ajax", $nid=0){
      $node = node_load( $nid, NULL, false );
      $vnode = node_view($node);
      $output = theme('node', $vnode);
      if( $type="ajax" ){
        $commands=array();
        $commands[]=ajax_command_replace( '#block-system-main','<section id="block-system-main">'.$output.'</section>' ) ;
        $page = array(
          '#type' => 'ajax',
          '#commands' => $commands,
        );
        ajax_deliver( $page ) ;   // ajax対応ブラウザの結果
      } else {
        $output = '<div id="content">'.$output.'</div>';  // ajax非対応ブラウザの結果
        return $output;
      }
    }
    

ポイント3:クライアント側で実行させたい部分はajax_commandを使用します

  • クライアント側で処理結果をどこに入り替えはajax_command_replaceで指定します
  • 結果の挿入、入れ替え、削除、css処理などがいろいろあります。詳細は本家のajax_command一覧を参考してください

 

drupal
Views

やりたいこと:モジュール(VBO)の各処理(Operation)に独自(カスタム)オプションを追加したい

  • 前回モジュール(VBO)にたいして処理(Operation)オプション追加を紹介しました
    •  Drupalのモジュール(VBO)の一括処理後にページ遷移させる方法
    • このオプションは全VBOに対して作成したものですが、すべての処理に影響を与えています
  • 各種処理(Operation)に対してどのようにオプションを追加するか前回の課題として残っています
  • 今回はこの課題を解決に新しいカスタムモジュール(vbo_redirect_option)を作成して、紹介します
    モジュールVBOの各種処理に独自のオプション追加

hook_formとCtoolsのdepent systemより各オペレーションに独自のオプションを追加

  • VBOのオペレーション設定フォームがカスタマイズとして開放していないです(前回も説明した)
  • ここで、Drupalのhook_formでVBOのオペレーション設定画面を特定して、カスタムオプション追加することになりました
    function vbo_redirect_option_form_alter(&$form, &$form_state, $form_id)
    {
        if( isset($form_state['id']) && $form_state['id'] === "views_bulk_operations"){
    
            foreach( $form_state['input']['options']['vbo_operations'] as $key => $operation) {
                if( $operation['redirect_check'] && strlen( trim($operation['redirect_url']))>0 ) {
                    variable_set( $key, $operation['redirect_url'] );
                } else {
                    if( !empty( variable_get($key) ) ) variable_del( $key ) ;
                }
            }
    
    
            foreach( $form['options']['vbo_operations'] as $key => &$operation ){
                if( !is_array($operation) ) continue ;
    
                $redirect_url = variable_get($key);
                $dep_key = "edit-options-vbo-operations-" . str_replace("_", "-", str_replace("::","",$key) ) ;
    
                $operation['redirect_check'] = array(
                    '#type' => 'checkbox',
                    '#title' => t('Redirect page to after operation'),
                    '#default_value' =>  $redirect_url ? 1 : 0 ,
                    '#dependency' => array(    // Ctoolsのdependent systemに依存
                        $dep_key."-selected" => array(1),
                    ),
                );
                $operation['redirect_url'] = array(
                    '#type' => 'textfield',
                    '#title' => t('Provide label'),
                    '#title_display' => 'invisible',
                    '#default_value' => empty($redirect_url) ? "" : $redirect_url,
                    '#dependency' => array(    // Ctoolsのdependent systemに依存
                        $dep_key."-selected" => array(1),
                        $dep_key . '-redirect-check' => array(1),
                    ),
                    '#dependency_count' => 2,
                );
            }
        }
    }
    • 設定フォームにチェックボックスをチェックしたら、画面遷移URL入力フィールドが現れるダイナミックフォームはモジュール(Ctools)のdependent systemを利用しています

処理(Operation)確認ステップをスキップがあるかないかを確認してhook_views_bulk_operations_form_alter()実装でオプションの設定を行う

  • VBOの処理(Operation)が確認ステップがあるかないかは2種類あります(この二種類をの処理プロセスが違うのでしっかりテストする必要がある)
  • hook_views_bulk_operations_form_alter()を実装して、各処理ステップにカスタマイズを行います
    function vbo_redirect_option_views_bulk_operations_form_alter(&$form, &$form_state, $vbo)
    {
        // collect all operations that has contained redirect_rul
        $redirect_arr = array();
        foreach( $vbo->options['vbo_operations'] as $key => $operation ) {
            if( !empty( variable_get($key) ) ){
                $redirect_arr[$key] = $key ;
            }
        }
    
        // add redirect step to #submit element
        if(isset($form['select'])) {
    
            // this is the form start step
            foreach( $form['select'] as $key => &$element ){
                if( isset($redirect_arr[$key]) ){
                    // we check if there is any operation has redirect_url
                    $element['#submit'][] = 'vbo_redirect_after_operation';
                    // only one is enough, we will detect witch one in the callback function
                    break;
                }
            }
    
            // do operation with confirmation step
            // this is the confirmation step
        } else if( !$form_state['operation']->getAdminOption('skip_confirmation') ) {
            $form['actions']['submit']['#submit'][] = "vbo_redirect_after_operation_with_confirmation";
            $form_state['redirect_to_after_operation'] = $form_state['operation']->getAdminOption('redirect_url');
        }
    
    }
    
    
    /**
     * callback function that has called by operation
     * this is the form start step, we don't know if it has confirmation step or not
     * @param $form
     * @param $form_state
     */
    function vbo_redirect_after_operation(&$form, &$form_state){
        // the are multiple element can be operated
        // the right one that has be sent to this step
        // we need get redirect_url if the it has
        if( isset($form_state['operation']) ){
            // get redirect_url by operation_id
            $redirec=variable_get($form_state['operation']->operationId) ;
            if( !empty($redirec) ){
                if( $form_state['operation']->getAdminOption('skip_confirmation') ) {
                    $form_state['redirect'] = $redirec;
                }
            }
        }
    }
    
    /**
     * callback function that has be called by operation with confirmation step
     * @param $form
     * @param $form_state
     */
    function vbo_redirect_after_operation_with_confirmation( $form, &$form_state ){
        // there is only operation that has be sent here with the confirmation step
        if( isset($form_state['redirect_to_after_operation']) ){
            // set redirect_url that should be stored in $form_state
            $form_state['redirect'] = $form_state['redir ect_to_after_operation'];
        }
    }

感想と結論:VBOの処理オプション設定はカスタマイズに開放していないため、各種処理(Operation)のオプションの取得、設定に苦労します

  • VBOの処理オプション設定はユーザーにカスタマイズに開放していないです
  • オペレーションの各ステップに$form、$form_state、$vbo変数から必要な情報を取得したり、セットしたりしました
  • 必要な情報がどこにあるかは不明だし(その時dsm($vbo)などで確認)、特定するまでに、時間がかかりました。
添付 サイズ
vbo_redirect_option.zip (1.77 KB) 1.77 KB
Embedded thumbnail for Drupalのモジュール(VBO)の各種処理(Operation)に独自(カスタムオ)のプションの追加方法
drupal
development
Views

Drupalのモジュール(Rules)で作成した各種アクションセットコンポーネントをモジュールVBOで一括処理

  • 背景:Drupal7.x.56、Views Bulk Operation(VBO)7.x-3.4、Rules7.x-2.10
  • モジュール(Rules)がいろいろなアクションセットの作成ができます
    • データの作成/更新/削除
    • メール送信、フラグを立てる
    • などなど
  • モジュール(VBO)がRulesで作成したアクションコンポーネントの利用ができます
    • Drupalのモジュール(Rules)のアクションコンポーネントでVBOより新規ノード作成とフィールドのコピー
  • 今回の例として、Rulesでメッセージ表示する単純なアクションコンポーネント(show message)を作成して、VBOで一括処理を行います
    Rulesでメッセージ表示コンポーネントをVBOで一括処理

問題点:VBO一括処理後に画面遷移(redirect)はできません

  • VBOで一括処理後に、画面を遷移して処理結果を確認することがあります
  • VBOの設定オプションに、処理後の画面遷移設定がありません
  • ネットで調べてみたが、VBO一括処理後の画面遷移オプション追加パッチがります
    • これは、モジュールVBOに対するパッチです
    • このパッチ適応したら、次回VBOアップグレード時に、ソースのマージ作業が面だと思います
    • できれば、VBOのパッチを使用したくないです

解決:カスタムモジュール(vbo_redirect_option.zip)でVBO処理後の画面遷移オプションの追加

  • モジュール(VBO)の主要部分がクラス(class)構造なので、簡単に画面遷移ロジックを追加することはできません
  • 「Bulk Operation Settings」に処理後の画面遷移オプションを追加します
    • 「Bulk Operation Settings」のオーバーライドができないので、hook_form_alter()でオプションを追加することになりました
      /**
       * Implements hook_form_alter().
       */
      function vbo_redirect_option_form_alter(&$form, &$form_state, $form_id)
      {
        // VBOの処理かのチェック
          if( isset($form_state['id']) && $form_state['id'] === "views_bulk_operations"){
      
         // ここで、画面遷移先の保存処理は少し反則
         //  vbo_settingsに画面遷移先の追加は難しい(クラス構造体内にあるため)
         //  環境変数に画面遷移先(uri)を保存
              if( isset($form_state['input']['options']['vbo_settings'][vbo_redirect_url]) ){
                  variable_set( 'vbo_redirect_url', $form_state['input']['options']['vbo_settings'][vbo_redirect_url] ) ;
              }
      
         // 画面遷移先のテキストフィールドを追加
              $form['options']['vbo_settings']['vbo_redirect_url'] = array(
                  '#type' => 'textfield',
                  '#title' => t('Page to direct to after completion of  batch'),
                  '#description' => t('Redirects to the view when finished the operation'),
                  '#default_value' => variable_get('vbo_redirect_url'),
              );
          }
      }
    • 画面遷移先を入力するテキストフィールドを設定画面に追加
    • 画面遷移先(uri)をvbo_settingsに入れたいですが、クラスの構造体にあるため追加できません。環境変数に保存することにしました。
    • 設定画面を保存("#submit")後に、画面遷移先を保存する処理を行いたいですが、"#submit"にコールバック関数を入れても、呼び出されない現象があって、仕方がなく、hook_form_alter()内で画面遷移先(uri)の保存処理を行いました
      VBOに一括処理後に画面遷移オプションの追加
  • hook_views_bulk_operations_form_alter()を実装して、実際のVBO一括処理後に、画面遷移設定を行います
    /**
     * Implements hook_views_bulk_operations_form_alter().
     */
    function vbo_redirect_option_views_bulk_operations_form_alter(&$form, &$form_state, $vbo)
    {
        $vbo_redirect_url = trim( variable_get('vbo_redirect_url') ) ;
    
        if( isset($vbo_redirect_url) && strlen($vbo_redirect_url) >0 ){
    
            // check if vbo operation skip confirmation
            $skip_confirmation = false ;
            foreach( $vbo->options['vbo_operations'] as $key => $operation ){
                if( $operation['selected'] && $operation['skip_confirmation'] ){
                    if( isset($form['select'][$key]) ) {
                        $form['select'][$key]['#submit'][] = 'vbo_redirect_after_operation';
                        $skip_confirmation = true ;
                    }
                }
            }
    
            // set redirect method when vbo has confirmation step
            if( !$skip_confirmation ){
                $form['actions']['submit']['#submit'][] = 'vbo_redirect_after_operation' ;
            }
        }
    }
    
    // callback function to set redirect url
    function vbo_redirect_after_operation($form, &$form_state){
        $vbo_redirect_url = trim( variable_get('vbo_redirect_url') ) ;
        $form_state['redirect'] = $vbo_redirect_url;
    }
    • VBO一括処理の「確認のステップをスキップ」があるか、ないかを分けて処理します(画面遷移設定場所が違うため)
    • "#submit"に画面遷移処理を追加します
    • 画面遷移処理は$form_state['redirect'] で行います

結論と感想:簡単のカスタモジュールでVBOへの影響はありません。各オペレーション設定に画面遷移オプションを追加したほうよいかもしれない

  • このカスタムモジュールのインストールより、モジュール(VBO)への影響はありません
  • この画面遷移オプションを「Bulk Operation Settings」に追加したので、すべてのオペレーションに適応されます
    • VBOの一括処理内容がいろいろあります(例:オーナー変更、エンティティ内容変更など)
    • これらの処理後に一つの画面遷移先の設定はやや強引的だと思います
  • できれば、「Selected Bulk Operations」にある、選択したオペレーションの設定に画面遷移先の設定をしたほうが柔軟的な対応だと思います(次回の課題)
    画面遷移オプションを各オペレーションに追加すべき
添付 サイズ
vbo_redirect_option.zip (1.19 KB) 1.19 KB
Embedded thumbnail for Drupalのモジュール(VBO)の一括処理後にページ遷移させる方法
drupal
form
ajax

やりたいこと:Drupalのajaxフレームワークを利用して表示している要素を削除

  • Drupalのモジュール(Views)で作成した一覧の要素を選択して削除します
    • 要素を選択して削除するモジュール:Views Bulk Operations
    • 例:Drupalのモジュール(VBO)の各種処理(Operation)に独自(カスタムオ)のプションの追加方法
  • 前提条件:要素削除する確認の必要はありません
  • ajaxで動的に削除するのはやさしいUIとも言えるでしょう(以下のイメージのように削除)
    Drupalのajaxフレームワークより要素を動的に削除

Step1:削除リンクにDrupalのajax使用するクラス:use-ajax を追加

  • Drupalのajaxフレームワークに関する説明は以下の記事をご参考ください
    • Drupalでajaxのフレームワークが簡単に作成できる
  • 削除アイコン付きのリンクは以下のようです
    // 削除エレメントID:123 (例)
    <a href="/delete/element/id/123/nojs" class="use-ajax del-link" id="del-link-123">
           <i class="fa fa-trash-o" aria-hidden="true"></i>
    </a>
    • アンカー(a)に削除するエレメントID(または別の識別パラメーター)を入れる必要はあります
    • アンカーリンクの後ろに「nojs」を追加します(クライアント側のajax作動時に、nojs->ajaxに変換され)
    • アンカーがクリックされると、Drupalのajaxフレームワークが起動され、削除パラメーターをサイト側に渡します

Step2:hook_menuで要素削除のリクエストをキャッチします

  • hook_menuで要素削除のリクエストを受け取り、削除処理を行います
    // 要素削除URLの設定
    $items['delete/element/%/nojs'] = array(
    	'page callback' => 'delete_element',
    	'page arguments' => array( 2, 3 ) ,
    	'access callback' => 'delete_access',
    	'type' => MENU_CALLBACK,
    );
    // ajaxが以下のURLでリクエストをします(クライアント側でnojs->ajaxに変換)
    $items['delete/element/%/ajax'] = array(
    	'delivery callback' => 'ajax_deliver',
    )+$items['delete/element/%/nojs'] ;    // 要素削除定義に遷移
    
  • 要素削除処理ファンクション:delete_element で削除処理、処理結果をクライアント側に返します
    function delete_element ($id, $ajax){
        $is_ajax = $ajax === "ajax" ;  // ajaxと通用のリクエスト両方対応のため
    
        // 要素をDBから削除
        db_delete("element_table")->condition("entity_id", $id)->execute() ;
    
        // 画面要素も削除コマンドを返す
        if( $is_ajax ){
            // ajaxで要素削除後の処理
            $commands = array();
            $commands[] = ajax_command_remove( '#element-123');
            return array(
              '#type'=>"ajax",
              '#commands' => $commands,
            );
        } else {
            // 通常での要素削除後の処理
            drupal_set_message(t('Deleted 1 vocabulary'));
            drupal_goto();
        }
    }

     

Drupalのajaxフレームワークで要素削除

纏め:Drupalのajaxフレームワークを利用すればajax処理が自動的に行います

  • 上記例では、削除リンクにクラス:use-ajax を追加するだけで、ajax関連処理を記述する必要はあります
    • 削除リンクではなく、削除ボタン(button)要素を使用する場合クラス: use-ajax-submit
  • サーバー側では、hook_menuで削除リンクの定義、削除リクエストをキャッチして、削除処理関数を作成します
    • DB上のデータ削除完了後に、クライアント側の要素削除命令(ajax_command_remove)を返せば良いです
  • この一連のajax処理の記述はほどんとありません。簡単、便利です
drupal
development
ajax

やりたいこと:Drupalのプログラムレベルで簡単にajaxを利用してクライアント側でデータ交信をしたいです

  • 環境:Drupal7.54
  • DrupalのFormAPIで簡単にajaxの実装ができます(Drupalのフォーム(FromAPI)でのajaxの実装 )
  • FormAPIだけではなく、Drupalをカスタマイズ時にいろいろなところでajaxを実装したいことがあります

ポイント1:Drupalでajaxに必要なライブラリをロードし、クライアント側にjquery.form.jsファイルをセット

  • サーバー側でdrupal.ajaxのライブラリをロードする必要があります
  • クライアント側にjquery.form.jsファイルを設置する必要があります
  • この処理はajax処理するページをロード時に行えれば良いです。
    • 例:hook_init()内で処理する
      /**
       * Implements hook_init().
       */
      function YOUR_MODULE_NAME_init()
      {
        drupal_add_js('misc/jquery.form.js');
        drupal_add_library('system','drupal.ajax');
      }
  • クライアント側のブラウザのプロパティでjquery.form.jsがセットされたことの確認ができます

ポイント2:クライアント側のajax起動リンク内にajax対応可否のパラメーター「nojs」とクラス属性「use-ajax」のセット

  • ajaxの起動リンクの作成基本パターン: 
    <a href="text/ajax/nojs/1234" class="use-ajax">ajaxリンク</a>
    • hrefにある「nojs」が決まりの文字
    • hrefにある「1234」はサーバー側に転送したい必要なパラメーター
    • class="use-ajax"はこのリンクがajax用に決める
  • クライアント側のjsで使用しているブラウザがajax対応可能かを判断して、ajax起動リンクに「nojs」のパラメーターを書き換え(利用可能:nojs⇒ajax)てサーバー側に転送
  • サーバー側がajax利用可否よりクライアント側にajax対応有無の結果を返します
    Drupalのajaxフレームワークの利用
  • 上記例のプログラムは以下のようで
    /**
     * Implements hook_init().
     */
    function test_module_init()
    {
      drupal_add_js('misc/jquery.form.js');
      drupal_add_library('system','drupal.ajax');
    }
    
    /**
     *  Implementation of hook_menu()
     */
    function test_module_menu() {
      $items['test/ajax/%/%']=array(     // URLの2,3番目がクライアント側で生成
          'page callback' => 'ajax_node_response',
          'page arguments' => array(2,3),   // URLの2,3番目の引数をコールバック関数に渡す
          'access callback' => 'user_access',
          'access arguments' => array('access content'),
          'type' => MENU_CALLBACK,
      );
      return $items;
    }
    
    function ajax_node_response($type="ajax", $nid=0){
      $node = node_load( $nid, NULL, false );
      $vnode = node_view($node);
      $output = theme('node', $vnode);
      if( $type="ajax" ){
        $commands=array();
        $commands[]=ajax_command_replace( '#block-system-main','<section id="block-system-main">'.$output.'</section>' ) ;
        $page = array(
          '#type' => 'ajax',
          '#commands' => $commands,
        );
        ajax_deliver( $page ) ;   // ajax対応ブラウザの結果
      } else {
        $output = '<div id="content">'.$output.'</div>';  // ajax非対応ブラウザの結果
        return $output;
      }
    }
    

ポイント3:クライアント側で実行させたい部分はajax_commandを使用します

  • クライアント側で処理結果をどこに入り替えはajax_command_replaceで指定します
  • 結果の挿入、入れ替え、削除、css処理などがいろいろあります。詳細は本家のajax_command一覧を参考してください

 

drupal
Views

やりたいこと:モジュール(VBO)の各処理(Operation)に独自(カスタム)オプションを追加したい

  • 前回モジュール(VBO)にたいして処理(Operation)オプション追加を紹介しました
    •  Drupalのモジュール(VBO)の一括処理後にページ遷移させる方法
    • このオプションは全VBOに対して作成したものですが、すべての処理に影響を与えています
  • 各種処理(Operation)に対してどのようにオプションを追加するか前回の課題として残っています
  • 今回はこの課題を解決に新しいカスタムモジュール(vbo_redirect_option)を作成して、紹介します
    モジュールVBOの各種処理に独自のオプション追加

hook_formとCtoolsのdepent systemより各オペレーションに独自のオプションを追加

  • VBOのオペレーション設定フォームがカスタマイズとして開放していないです(前回も説明した)
  • ここで、Drupalのhook_formでVBOのオペレーション設定画面を特定して、カスタムオプション追加することになりました
    function vbo_redirect_option_form_alter(&$form, &$form_state, $form_id)
    {
        if( isset($form_state['id']) && $form_state['id'] === "views_bulk_operations"){
    
            foreach( $form_state['input']['options']['vbo_operations'] as $key => $operation) {
                if( $operation['redirect_check'] && strlen( trim($operation['redirect_url']))>0 ) {
                    variable_set( $key, $operation['redirect_url'] );
                } else {
                    if( !empty( variable_get($key) ) ) variable_del( $key ) ;
                }
            }
    
    
            foreach( $form['options']['vbo_operations'] as $key => &$operation ){
                if( !is_array($operation) ) continue ;
    
                $redirect_url = variable_get($key);
                $dep_key = "edit-options-vbo-operations-" . str_replace("_", "-", str_replace("::","",$key) ) ;
    
                $operation['redirect_check'] = array(
                    '#type' => 'checkbox',
                    '#title' => t('Redirect page to after operation'),
                    '#default_value' =>  $redirect_url ? 1 : 0 ,
                    '#dependency' => array(    // Ctoolsのdependent systemに依存
                        $dep_key."-selected" => array(1),
                    ),
                );
                $operation['redirect_url'] = array(
                    '#type' => 'textfield',
                    '#title' => t('Provide label'),
                    '#title_display' => 'invisible',
                    '#default_value' => empty($redirect_url) ? "" : $redirect_url,
                    '#dependency' => array(    // Ctoolsのdependent systemに依存
                        $dep_key."-selected" => array(1),
                        $dep_key . '-redirect-check' => array(1),
                    ),
                    '#dependency_count' => 2,
                );
            }
        }
    }
    • 設定フォームにチェックボックスをチェックしたら、画面遷移URL入力フィールドが現れるダイナミックフォームはモジュール(Ctools)のdependent systemを利用しています

処理(Operation)確認ステップをスキップがあるかないかを確認してhook_views_bulk_operations_form_alter()実装でオプションの設定を行う

  • VBOの処理(Operation)が確認ステップがあるかないかは2種類あります(この二種類をの処理プロセスが違うのでしっかりテストする必要がある)
  • hook_views_bulk_operations_form_alter()を実装して、各処理ステップにカスタマイズを行います
    function vbo_redirect_option_views_bulk_operations_form_alter(&$form, &$form_state, $vbo)
    {
        // collect all operations that has contained redirect_rul
        $redirect_arr = array();
        foreach( $vbo->options['vbo_operations'] as $key => $operation ) {
            if( !empty( variable_get($key) ) ){
                $redirect_arr[$key] = $key ;
            }
        }
    
        // add redirect step to #submit element
        if(isset($form['select'])) {
    
            // this is the form start step
            foreach( $form['select'] as $key => &$element ){
                if( isset($redirect_arr[$key]) ){
                    // we check if there is any operation has redirect_url
                    $element['#submit'][] = 'vbo_redirect_after_operation';
                    // only one is enough, we will detect witch one in the callback function
                    break;
                }
            }
    
            // do operation with confirmation step
            // this is the confirmation step
        } else if( !$form_state['operation']->getAdminOption('skip_confirmation') ) {
            $form['actions']['submit']['#submit'][] = "vbo_redirect_after_operation_with_confirmation";
            $form_state['redirect_to_after_operation'] = $form_state['operation']->getAdminOption('redirect_url');
        }
    
    }
    
    
    /**
     * callback function that has called by operation
     * this is the form start step, we don't know if it has confirmation step or not
     * @param $form
     * @param $form_state
     */
    function vbo_redirect_after_operation(&$form, &$form_state){
        // the are multiple element can be operated
        // the right one that has be sent to this step
        // we need get redirect_url if the it has
        if( isset($form_state['operation']) ){
            // get redirect_url by operation_id
            $redirec=variable_get($form_state['operation']->operationId) ;
            if( !empty($redirec) ){
                if( $form_state['operation']->getAdminOption('skip_confirmation') ) {
                    $form_state['redirect'] = $redirec;
                }
            }
        }
    }
    
    /**
     * callback function that has be called by operation with confirmation step
     * @param $form
     * @param $form_state
     */
    function vbo_redirect_after_operation_with_confirmation( $form, &$form_state ){
        // there is only operation that has be sent here with the confirmation step
        if( isset($form_state['redirect_to_after_operation']) ){
            // set redirect_url that should be stored in $form_state
            $form_state['redirect'] = $form_state['redir ect_to_after_operation'];
        }
    }

感想と結論:VBOの処理オプション設定はカスタマイズに開放していないため、各種処理(Operation)のオプションの取得、設定に苦労します

  • VBOの処理オプション設定はユーザーにカスタマイズに開放していないです
  • オペレーションの各ステップに$form、$form_state、$vbo変数から必要な情報を取得したり、セットしたりしました
  • 必要な情報がどこにあるかは不明だし(その時dsm($vbo)などで確認)、特定するまでに、時間がかかりました。
添付 サイズ
vbo_redirect_option.zip (1.77 KB) 1.77 KB
Embedded thumbnail for Drupalのモジュール(VBO)の各種処理(Operation)に独自(カスタムオ)のプションの追加方法
drupal
development
Views

Drupalのモジュール(Rules)で作成した各種アクションセットコンポーネントをモジュールVBOで一括処理

  • 背景:Drupal7.x.56、Views Bulk Operation(VBO)7.x-3.4、Rules7.x-2.10
  • モジュール(Rules)がいろいろなアクションセットの作成ができます
    • データの作成/更新/削除
    • メール送信、フラグを立てる
    • などなど
  • モジュール(VBO)がRulesで作成したアクションコンポーネントの利用ができます
    • Drupalのモジュール(Rules)のアクションコンポーネントでVBOより新規ノード作成とフィールドのコピー
  • 今回の例として、Rulesでメッセージ表示する単純なアクションコンポーネント(show message)を作成して、VBOで一括処理を行います
    Rulesでメッセージ表示コンポーネントをVBOで一括処理

問題点:VBO一括処理後に画面遷移(redirect)はできません

  • VBOで一括処理後に、画面を遷移して処理結果を確認することがあります
  • VBOの設定オプションに、処理後の画面遷移設定がありません
  • ネットで調べてみたが、VBO一括処理後の画面遷移オプション追加パッチがります
    • これは、モジュールVBOに対するパッチです
    • このパッチ適応したら、次回VBOアップグレード時に、ソースのマージ作業が面だと思います
    • できれば、VBOのパッチを使用したくないです

解決:カスタムモジュール(vbo_redirect_option.zip)でVBO処理後の画面遷移オプションの追加

  • モジュール(VBO)の主要部分がクラス(class)構造なので、簡単に画面遷移ロジックを追加することはできません
  • 「Bulk Operation Settings」に処理後の画面遷移オプションを追加します
    • 「Bulk Operation Settings」のオーバーライドができないので、hook_form_alter()でオプションを追加することになりました
      /**
       * Implements hook_form_alter().
       */
      function vbo_redirect_option_form_alter(&$form, &$form_state, $form_id)
      {
        // VBOの処理かのチェック
          if( isset($form_state['id']) && $form_state['id'] === "views_bulk_operations"){
      
         // ここで、画面遷移先の保存処理は少し反則
         //  vbo_settingsに画面遷移先の追加は難しい(クラス構造体内にあるため)
         //  環境変数に画面遷移先(uri)を保存
              if( isset($form_state['input']['options']['vbo_settings'][vbo_redirect_url]) ){
                  variable_set( 'vbo_redirect_url', $form_state['input']['options']['vbo_settings'][vbo_redirect_url] ) ;
              }
      
         // 画面遷移先のテキストフィールドを追加
              $form['options']['vbo_settings']['vbo_redirect_url'] = array(
                  '#type' => 'textfield',
                  '#title' => t('Page to direct to after completion of  batch'),
                  '#description' => t('Redirects to the view when finished the operation'),
                  '#default_value' => variable_get('vbo_redirect_url'),
              );
          }
      }
    • 画面遷移先を入力するテキストフィールドを設定画面に追加
    • 画面遷移先(uri)をvbo_settingsに入れたいですが、クラスの構造体にあるため追加できません。環境変数に保存することにしました。
    • 設定画面を保存("#submit")後に、画面遷移先を保存する処理を行いたいですが、"#submit"にコールバック関数を入れても、呼び出されない現象があって、仕方がなく、hook_form_alter()内で画面遷移先(uri)の保存処理を行いました
      VBOに一括処理後に画面遷移オプションの追加
  • hook_views_bulk_operations_form_alter()を実装して、実際のVBO一括処理後に、画面遷移設定を行います
    /**
     * Implements hook_views_bulk_operations_form_alter().
     */
    function vbo_redirect_option_views_bulk_operations_form_alter(&$form, &$form_state, $vbo)
    {
        $vbo_redirect_url = trim( variable_get('vbo_redirect_url') ) ;
    
        if( isset($vbo_redirect_url) && strlen($vbo_redirect_url) >0 ){
    
            // check if vbo operation skip confirmation
            $skip_confirmation = false ;
            foreach( $vbo->options['vbo_operations'] as $key => $operation ){
                if( $operation['selected'] && $operation['skip_confirmation'] ){
                    if( isset($form['select'][$key]) ) {
                        $form['select'][$key]['#submit'][] = 'vbo_redirect_after_operation';
                        $skip_confirmation = true ;
                    }
                }
            }
    
            // set redirect method when vbo has confirmation step
            if( !$skip_confirmation ){
                $form['actions']['submit']['#submit'][] = 'vbo_redirect_after_operation' ;
            }
        }
    }
    
    // callback function to set redirect url
    function vbo_redirect_after_operation($form, &$form_state){
        $vbo_redirect_url = trim( variable_get('vbo_redirect_url') ) ;
        $form_state['redirect'] = $vbo_redirect_url;
    }
    • VBO一括処理の「確認のステップをスキップ」があるか、ないかを分けて処理します(画面遷移設定場所が違うため)
    • "#submit"に画面遷移処理を追加します
    • 画面遷移処理は$form_state['redirect'] で行います

結論と感想:簡単のカスタモジュールでVBOへの影響はありません。各オペレーション設定に画面遷移オプションを追加したほうよいかもしれない

  • このカスタムモジュールのインストールより、モジュール(VBO)への影響はありません
  • この画面遷移オプションを「Bulk Operation Settings」に追加したので、すべてのオペレーションに適応されます
    • VBOの一括処理内容がいろいろあります(例:オーナー変更、エンティティ内容変更など)
    • これらの処理後に一つの画面遷移先の設定はやや強引的だと思います
  • できれば、「Selected Bulk Operations」にある、選択したオペレーションの設定に画面遷移先の設定をしたほうが柔軟的な対応だと思います(次回の課題)
    画面遷移オプションを各オペレーションに追加すべき
添付 サイズ
vbo_redirect_option.zip (1.19 KB) 1.19 KB
Embedded thumbnail for Drupalのモジュール(VBO)の一括処理後にページ遷移させる方法
drupal
form
ajax

やりたいこと:Drupalのajaxフレームワークを利用して表示している要素を削除

  • Drupalのモジュール(Views)で作成した一覧の要素を選択して削除します
    • 要素を選択して削除するモジュール:Views Bulk Operations
    • 例:Drupalのモジュール(VBO)の各種処理(Operation)に独自(カスタムオ)のプションの追加方法
  • 前提条件:要素削除する確認の必要はありません
  • ajaxで動的に削除するのはやさしいUIとも言えるでしょう(以下のイメージのように削除)
    Drupalのajaxフレームワークより要素を動的に削除

Step1:削除リンクにDrupalのajax使用するクラス:use-ajax を追加

  • Drupalのajaxフレームワークに関する説明は以下の記事をご参考ください
    • Drupalでajaxのフレームワークが簡単に作成できる
  • 削除アイコン付きのリンクは以下のようです
    // 削除エレメントID:123 (例)
    <a href="/delete/element/id/123/nojs" class="use-ajax del-link" id="del-link-123">
           <i class="fa fa-trash-o" aria-hidden="true"></i>
    </a>
    • アンカー(a)に削除するエレメントID(または別の識別パラメーター)を入れる必要はあります
    • アンカーリンクの後ろに「nojs」を追加します(クライアント側のajax作動時に、nojs->ajaxに変換され)
    • アンカーがクリックされると、Drupalのajaxフレームワークが起動され、削除パラメーターをサイト側に渡します

Step2:hook_menuで要素削除のリクエストをキャッチします

  • hook_menuで要素削除のリクエストを受け取り、削除処理を行います
    // 要素削除URLの設定
    $items['delete/element/%/nojs'] = array(
    	'page callback' => 'delete_element',
    	'page arguments' => array( 2, 3 ) ,
    	'access callback' => 'delete_access',
    	'type' => MENU_CALLBACK,
    );
    // ajaxが以下のURLでリクエストをします(クライアント側でnojs->ajaxに変換)
    $items['delete/element/%/ajax'] = array(
    	'delivery callback' => 'ajax_deliver',
    )+$items['delete/element/%/nojs'] ;    // 要素削除定義に遷移
    
  • 要素削除処理ファンクション:delete_element で削除処理、処理結果をクライアント側に返します
    function delete_element ($id, $ajax){
        $is_ajax = $ajax === "ajax" ;  // ajaxと通用のリクエスト両方対応のため
    
        // 要素をDBから削除
        db_delete("element_table")->condition("entity_id", $id)->execute() ;
    
        // 画面要素も削除コマンドを返す
        if( $is_ajax ){
            // ajaxで要素削除後の処理
            $commands = array();
            $commands[] = ajax_command_remove( '#element-123');
            return array(
              '#type'=>"ajax",
              '#commands' => $commands,
            );
        } else {
            // 通常での要素削除後の処理
            drupal_set_message(t('Deleted 1 vocabulary'));
            drupal_goto();
        }
    }

     

Drupalのajaxフレームワークで要素削除

纏め:Drupalのajaxフレームワークを利用すればajax処理が自動的に行います

  • 上記例では、削除リンクにクラス:use-ajax を追加するだけで、ajax関連処理を記述する必要はあります
    • 削除リンクではなく、削除ボタン(button)要素を使用する場合クラス: use-ajax-submit
  • サーバー側では、hook_menuで削除リンクの定義、削除リクエストをキャッチして、削除処理関数を作成します
    • DB上のデータ削除完了後に、クライアント側の要素削除命令(ajax_command_remove)を返せば良いです
  • この一連のajax処理の記述はほどんとありません。簡単、便利です
drupal
development
ajax

やりたいこと:Drupalのプログラムレベルで簡単にajaxを利用してクライアント側でデータ交信をしたいです

  • 環境:Drupal7.54
  • DrupalのFormAPIで簡単にajaxの実装ができます(Drupalのフォーム(FromAPI)でのajaxの実装 )
  • FormAPIだけではなく、Drupalをカスタマイズ時にいろいろなところでajaxを実装したいことがあります

ポイント1:Drupalでajaxに必要なライブラリをロードし、クライアント側にjquery.form.jsファイルをセット

  • サーバー側でdrupal.ajaxのライブラリをロードする必要があります
  • クライアント側にjquery.form.jsファイルを設置する必要があります
  • この処理はajax処理するページをロード時に行えれば良いです。
    • 例:hook_init()内で処理する
      /**
       * Implements hook_init().
       */
      function YOUR_MODULE_NAME_init()
      {
        drupal_add_js('misc/jquery.form.js');
        drupal_add_library('system','drupal.ajax');
      }
  • クライアント側のブラウザのプロパティでjquery.form.jsがセットされたことの確認ができます

ポイント2:クライアント側のajax起動リンク内にajax対応可否のパラメーター「nojs」とクラス属性「use-ajax」のセット

  • ajaxの起動リンクの作成基本パターン: 
    <a href="text/ajax/nojs/1234" class="use-ajax">ajaxリンク</a>
    • hrefにある「nojs」が決まりの文字
    • hrefにある「1234」はサーバー側に転送したい必要なパラメーター
    • class="use-ajax"はこのリンクがajax用に決める
  • クライアント側のjsで使用しているブラウザがajax対応可能かを判断して、ajax起動リンクに「nojs」のパラメーターを書き換え(利用可能:nojs⇒ajax)てサーバー側に転送
  • サーバー側がajax利用可否よりクライアント側にajax対応有無の結果を返します
    Drupalのajaxフレームワークの利用
  • 上記例のプログラムは以下のようで
    /**
     * Implements hook_init().
     */
    function test_module_init()
    {
      drupal_add_js('misc/jquery.form.js');
      drupal_add_library('system','drupal.ajax');
    }
    
    /**
     *  Implementation of hook_menu()
     */
    function test_module_menu() {
      $items['test/ajax/%/%']=array(     // URLの2,3番目がクライアント側で生成
          'page callback' => 'ajax_node_response',
          'page arguments' => array(2,3),   // URLの2,3番目の引数をコールバック関数に渡す
          'access callback' => 'user_access',
          'access arguments' => array('access content'),
          'type' => MENU_CALLBACK,
      );
      return $items;
    }
    
    function ajax_node_response($type="ajax", $nid=0){
      $node = node_load( $nid, NULL, false );
      $vnode = node_view($node);
      $output = theme('node', $vnode);
      if( $type="ajax" ){
        $commands=array();
        $commands[]=ajax_command_replace( '#block-system-main','<section id="block-system-main">'.$output.'</section>' ) ;
        $page = array(
          '#type' => 'ajax',
          '#commands' => $commands,
        );
        ajax_deliver( $page ) ;   // ajax対応ブラウザの結果
      } else {
        $output = '<div id="content">'.$output.'</div>';  // ajax非対応ブラウザの結果
        return $output;
      }
    }
    

ポイント3:クライアント側で実行させたい部分はajax_commandを使用します

  • クライアント側で処理結果をどこに入り替えはajax_command_replaceで指定します
  • 結果の挿入、入れ替え、削除、css処理などがいろいろあります。詳細は本家のajax_command一覧を参考してください

 

drupal
Views

やりたいこと:モジュール(VBO)の各処理(Operation)に独自(カスタム)オプションを追加したい

  • 前回モジュール(VBO)にたいして処理(Operation)オプション追加を紹介しました
    •  Drupalのモジュール(VBO)の一括処理後にページ遷移させる方法
    • このオプションは全VBOに対して作成したものですが、すべての処理に影響を与えています
  • 各種処理(Operation)に対してどのようにオプションを追加するか前回の課題として残っています
  • 今回はこの課題を解決に新しいカスタムモジュール(vbo_redirect_option)を作成して、紹介します
    モジュールVBOの各種処理に独自のオプション追加

hook_formとCtoolsのdepent systemより各オペレーションに独自のオプションを追加

  • VBOのオペレーション設定フォームがカスタマイズとして開放していないです(前回も説明した)
  • ここで、Drupalのhook_formでVBOのオペレーション設定画面を特定して、カスタムオプション追加することになりました
    function vbo_redirect_option_form_alter(&$form, &$form_state, $form_id)
    {
        if( isset($form_state['id']) && $form_state['id'] === "views_bulk_operations"){
    
            foreach( $form_state['input']['options']['vbo_operations'] as $key => $operation) {
                if( $operation['redirect_check'] && strlen( trim($operation['redirect_url']))>0 ) {
                    variable_set( $key, $operation['redirect_url'] );
                } else {
                    if( !empty( variable_get($key) ) ) variable_del( $key ) ;
                }
            }
    
    
            foreach( $form['options']['vbo_operations'] as $key => &$operation ){
                if( !is_array($operation) ) continue ;
    
                $redirect_url = variable_get($key);
                $dep_key = "edit-options-vbo-operations-" . str_replace("_", "-", str_replace("::","",$key) ) ;
    
                $operation['redirect_check'] = array(
                    '#type' => 'checkbox',
                    '#title' => t('Redirect page to after operation'),
                    '#default_value' =>  $redirect_url ? 1 : 0 ,
                    '#dependency' => array(    // Ctoolsのdependent systemに依存
                        $dep_key."-selected" => array(1),
                    ),
                );
                $operation['redirect_url'] = array(
                    '#type' => 'textfield',
                    '#title' => t('Provide label'),
                    '#title_display' => 'invisible',
                    '#default_value' => empty($redirect_url) ? "" : $redirect_url,
                    '#dependency' => array(    // Ctoolsのdependent systemに依存
                        $dep_key."-selected" => array(1),
                        $dep_key . '-redirect-check' => array(1),
                    ),
                    '#dependency_count' => 2,
                );
            }
        }
    }
    • 設定フォームにチェックボックスをチェックしたら、画面遷移URL入力フィールドが現れるダイナミックフォームはモジュール(Ctools)のdependent systemを利用しています

処理(Operation)確認ステップをスキップがあるかないかを確認してhook_views_bulk_operations_form_alter()実装でオプションの設定を行う

  • VBOの処理(Operation)が確認ステップがあるかないかは2種類あります(この二種類をの処理プロセスが違うのでしっかりテストする必要がある)
  • hook_views_bulk_operations_form_alter()を実装して、各処理ステップにカスタマイズを行います
    function vbo_redirect_option_views_bulk_operations_form_alter(&$form, &$form_state, $vbo)
    {
        // collect all operations that has contained redirect_rul
        $redirect_arr = array();
        foreach( $vbo->options['vbo_operations'] as $key => $operation ) {
            if( !empty( variable_get($key) ) ){
                $redirect_arr[$key] = $key ;
            }
        }
    
        // add redirect step to #submit element
        if(isset($form['select'])) {
    
            // this is the form start step
            foreach( $form['select'] as $key => &$element ){
                if( isset($redirect_arr[$key]) ){
                    // we check if there is any operation has redirect_url
                    $element['#submit'][] = 'vbo_redirect_after_operation';
                    // only one is enough, we will detect witch one in the callback function
                    break;
                }
            }
    
            // do operation with confirmation step
            // this is the confirmation step
        } else if( !$form_state['operation']->getAdminOption('skip_confirmation') ) {
            $form['actions']['submit']['#submit'][] = "vbo_redirect_after_operation_with_confirmation";
            $form_state['redirect_to_after_operation'] = $form_state['operation']->getAdminOption('redirect_url');
        }
    
    }
    
    
    /**
     * callback function that has called by operation
     * this is the form start step, we don't know if it has confirmation step or not
     * @param $form
     * @param $form_state
     */
    function vbo_redirect_after_operation(&$form, &$form_state){
        // the are multiple element can be operated
        // the right one that has be sent to this step
        // we need get redirect_url if the it has
        if( isset($form_state['operation']) ){
            // get redirect_url by operation_id
            $redirec=variable_get($form_state['operation']->operationId) ;
            if( !empty($redirec) ){
                if( $form_state['operation']->getAdminOption('skip_confirmation') ) {
                    $form_state['redirect'] = $redirec;
                }
            }
        }
    }
    
    /**
     * callback function that has be called by operation with confirmation step
     * @param $form
     * @param $form_state
     */
    function vbo_redirect_after_operation_with_confirmation( $form, &$form_state ){
        // there is only operation that has be sent here with the confirmation step
        if( isset($form_state['redirect_to_after_operation']) ){
            // set redirect_url that should be stored in $form_state
            $form_state['redirect'] = $form_state['redir ect_to_after_operation'];
        }
    }

感想と結論:VBOの処理オプション設定はカスタマイズに開放していないため、各種処理(Operation)のオプションの取得、設定に苦労します

  • VBOの処理オプション設定はユーザーにカスタマイズに開放していないです
  • オペレーションの各ステップに$form、$form_state、$vbo変数から必要な情報を取得したり、セットしたりしました
  • 必要な情報がどこにあるかは不明だし(その時dsm($vbo)などで確認)、特定するまでに、時間がかかりました。
添付 サイズ
vbo_redirect_option.zip (1.77 KB) 1.77 KB
Embedded thumbnail for Drupalのモジュール(VBO)の各種処理(Operation)に独自(カスタムオ)のプションの追加方法
drupal
development
Views

Drupalのモジュール(Rules)で作成した各種アクションセットコンポーネントをモジュールVBOで一括処理

  • 背景:Drupal7.x.56、Views Bulk Operation(VBO)7.x-3.4、Rules7.x-2.10
  • モジュール(Rules)がいろいろなアクションセットの作成ができます
    • データの作成/更新/削除
    • メール送信、フラグを立てる
    • などなど
  • モジュール(VBO)がRulesで作成したアクションコンポーネントの利用ができます
    • Drupalのモジュール(Rules)のアクションコンポーネントでVBOより新規ノード作成とフィールドのコピー
  • 今回の例として、Rulesでメッセージ表示する単純なアクションコンポーネント(show message)を作成して、VBOで一括処理を行います
    Rulesでメッセージ表示コンポーネントをVBOで一括処理

問題点:VBO一括処理後に画面遷移(redirect)はできません

  • VBOで一括処理後に、画面を遷移して処理結果を確認することがあります
  • VBOの設定オプションに、処理後の画面遷移設定がありません
  • ネットで調べてみたが、VBO一括処理後の画面遷移オプション追加パッチがります
    • これは、モジュールVBOに対するパッチです
    • このパッチ適応したら、次回VBOアップグレード時に、ソースのマージ作業が面だと思います
    • できれば、VBOのパッチを使用したくないです

解決:カスタムモジュール(vbo_redirect_option.zip)でVBO処理後の画面遷移オプションの追加

  • モジュール(VBO)の主要部分がクラス(class)構造なので、簡単に画面遷移ロジックを追加することはできません
  • 「Bulk Operation Settings」に処理後の画面遷移オプションを追加します
    • 「Bulk Operation Settings」のオーバーライドができないので、hook_form_alter()でオプションを追加することになりました
      /**
       * Implements hook_form_alter().
       */
      function vbo_redirect_option_form_alter(&$form, &$form_state, $form_id)
      {
        // VBOの処理かのチェック
          if( isset($form_state['id']) && $form_state['id'] === "views_bulk_operations"){
      
         // ここで、画面遷移先の保存処理は少し反則
         //  vbo_settingsに画面遷移先の追加は難しい(クラス構造体内にあるため)
         //  環境変数に画面遷移先(uri)を保存
              if( isset($form_state['input']['options']['vbo_settings'][vbo_redirect_url]) ){
                  variable_set( 'vbo_redirect_url', $form_state['input']['options']['vbo_settings'][vbo_redirect_url] ) ;
              }
      
         // 画面遷移先のテキストフィールドを追加
              $form['options']['vbo_settings']['vbo_redirect_url'] = array(
                  '#type' => 'textfield',
                  '#title' => t('Page to direct to after completion of  batch'),
                  '#description' => t('Redirects to the view when finished the operation'),
                  '#default_value' => variable_get('vbo_redirect_url'),
              );
          }
      }
    • 画面遷移先を入力するテキストフィールドを設定画面に追加
    • 画面遷移先(uri)をvbo_settingsに入れたいですが、クラスの構造体にあるため追加できません。環境変数に保存することにしました。
    • 設定画面を保存("#submit")後に、画面遷移先を保存する処理を行いたいですが、"#submit"にコールバック関数を入れても、呼び出されない現象があって、仕方がなく、hook_form_alter()内で画面遷移先(uri)の保存処理を行いました
      VBOに一括処理後に画面遷移オプションの追加
  • hook_views_bulk_operations_form_alter()を実装して、実際のVBO一括処理後に、画面遷移設定を行います
    /**
     * Implements hook_views_bulk_operations_form_alter().
     */
    function vbo_redirect_option_views_bulk_operations_form_alter(&$form, &$form_state, $vbo)
    {
        $vbo_redirect_url = trim( variable_get('vbo_redirect_url') ) ;
    
        if( isset($vbo_redirect_url) && strlen($vbo_redirect_url) >0 ){
    
            // check if vbo operation skip confirmation
            $skip_confirmation = false ;
            foreach( $vbo->options['vbo_operations'] as $key => $operation ){
                if( $operation['selected'] && $operation['skip_confirmation'] ){
                    if( isset($form['select'][$key]) ) {
                        $form['select'][$key]['#submit'][] = 'vbo_redirect_after_operation';
                        $skip_confirmation = true ;
                    }
                }
            }
    
            // set redirect method when vbo has confirmation step
            if( !$skip_confirmation ){
                $form['actions']['submit']['#submit'][] = 'vbo_redirect_after_operation' ;
            }
        }
    }
    
    // callback function to set redirect url
    function vbo_redirect_after_operation($form, &$form_state){
        $vbo_redirect_url = trim( variable_get('vbo_redirect_url') ) ;
        $form_state['redirect'] = $vbo_redirect_url;
    }
    • VBO一括処理の「確認のステップをスキップ」があるか、ないかを分けて処理します(画面遷移設定場所が違うため)
    • "#submit"に画面遷移処理を追加します
    • 画面遷移処理は$form_state['redirect'] で行います

結論と感想:簡単のカスタモジュールでVBOへの影響はありません。各オペレーション設定に画面遷移オプションを追加したほうよいかもしれない

  • このカスタムモジュールのインストールより、モジュール(VBO)への影響はありません
  • この画面遷移オプションを「Bulk Operation Settings」に追加したので、すべてのオペレーションに適応されます
    • VBOの一括処理内容がいろいろあります(例:オーナー変更、エンティティ内容変更など)
    • これらの処理後に一つの画面遷移先の設定はやや強引的だと思います
  • できれば、「Selected Bulk Operations」にある、選択したオペレーションの設定に画面遷移先の設定をしたほうが柔軟的な対応だと思います(次回の課題)
    画面遷移オプションを各オペレーションに追加すべき
添付 サイズ
vbo_redirect_option.zip (1.19 KB) 1.19 KB
Embedded thumbnail for Drupalのモジュール(VBO)の一括処理後にページ遷移させる方法
drupal
form
ajax

やりたいこと:Drupalのajaxフレームワークを利用して表示している要素を削除

  • Drupalのモジュール(Views)で作成した一覧の要素を選択して削除します
    • 要素を選択して削除するモジュール:Views Bulk Operations
    • 例:Drupalのモジュール(VBO)の各種処理(Operation)に独自(カスタムオ)のプションの追加方法
  • 前提条件:要素削除する確認の必要はありません
  • ajaxで動的に削除するのはやさしいUIとも言えるでしょう(以下のイメージのように削除)
    Drupalのajaxフレームワークより要素を動的に削除

Step1:削除リンクにDrupalのajax使用するクラス:use-ajax を追加

  • Drupalのajaxフレームワークに関する説明は以下の記事をご参考ください
    • Drupalでajaxのフレームワークが簡単に作成できる
  • 削除アイコン付きのリンクは以下のようです
    // 削除エレメントID:123 (例)
    <a href="/delete/element/id/123/nojs" class="use-ajax del-link" id="del-link-123">
           <i class="fa fa-trash-o" aria-hidden="true"></i>
    </a>
    • アンカー(a)に削除するエレメントID(または別の識別パラメーター)を入れる必要はあります
    • アンカーリンクの後ろに「nojs」を追加します(クライアント側のajax作動時に、nojs->ajaxに変換され)
    • アンカーがクリックされると、Drupalのajaxフレームワークが起動され、削除パラメーターをサイト側に渡します

Step2:hook_menuで要素削除のリクエストをキャッチします

  • hook_menuで要素削除のリクエストを受け取り、削除処理を行います
    // 要素削除URLの設定
    $items['delete/element/%/nojs'] = array(
    	'page callback' => 'delete_element',
    	'page arguments' => array( 2, 3 ) ,
    	'access callback' => 'delete_access',
    	'type' => MENU_CALLBACK,
    );
    // ajaxが以下のURLでリクエストをします(クライアント側でnojs->ajaxに変換)
    $items['delete/element/%/ajax'] = array(
    	'delivery callback' => 'ajax_deliver',
    )+$items['delete/element/%/nojs'] ;    // 要素削除定義に遷移
    
  • 要素削除処理ファンクション:delete_element で削除処理、処理結果をクライアント側に返します
    function delete_element ($id, $ajax){
        $is_ajax = $ajax === "ajax" ;  // ajaxと通用のリクエスト両方対応のため
    
        // 要素をDBから削除
        db_delete("element_table")->condition("entity_id", $id)->execute() ;
    
        // 画面要素も削除コマンドを返す
        if( $is_ajax ){
            // ajaxで要素削除後の処理
            $commands = array();
            $commands[] = ajax_command_remove( '#element-123');
            return array(
              '#type'=>"ajax",
              '#commands' => $commands,
            );
        } else {
            // 通常での要素削除後の処理
            drupal_set_message(t('Deleted 1 vocabulary'));
            drupal_goto();
        }
    }

     

Drupalのajaxフレームワークで要素削除

纏め:Drupalのajaxフレームワークを利用すればajax処理が自動的に行います

  • 上記例では、削除リンクにクラス:use-ajax を追加するだけで、ajax関連処理を記述する必要はあります
    • 削除リンクではなく、削除ボタン(button)要素を使用する場合クラス: use-ajax-submit
  • サーバー側では、hook_menuで削除リンクの定義、削除リクエストをキャッチして、削除処理関数を作成します
    • DB上のデータ削除完了後に、クライアント側の要素削除命令(ajax_command_remove)を返せば良いです
  • この一連のajax処理の記述はほどんとありません。簡単、便利です
drupal
development
ajax

やりたいこと:Drupalのプログラムレベルで簡単にajaxを利用してクライアント側でデータ交信をしたいです

  • 環境:Drupal7.54
  • DrupalのFormAPIで簡単にajaxの実装ができます(Drupalのフォーム(FromAPI)でのajaxの実装 )
  • FormAPIだけではなく、Drupalをカスタマイズ時にいろいろなところでajaxを実装したいことがあります

ポイント1:Drupalでajaxに必要なライブラリをロードし、クライアント側にjquery.form.jsファイルをセット

  • サーバー側でdrupal.ajaxのライブラリをロードする必要があります
  • クライアント側にjquery.form.jsファイルを設置する必要があります
  • この処理はajax処理するページをロード時に行えれば良いです。
    • 例:hook_init()内で処理する
      /**
       * Implements hook_init().
       */
      function YOUR_MODULE_NAME_init()
      {
        drupal_add_js('misc/jquery.form.js');
        drupal_add_library('system','drupal.ajax');
      }
  • クライアント側のブラウザのプロパティでjquery.form.jsがセットされたことの確認ができます

ポイント2:クライアント側のajax起動リンク内にajax対応可否のパラメーター「nojs」とクラス属性「use-ajax」のセット

  • ajaxの起動リンクの作成基本パターン: 
    <a href="text/ajax/nojs/1234" class="use-ajax">ajaxリンク</a>
    • hrefにある「nojs」が決まりの文字
    • hrefにある「1234」はサーバー側に転送したい必要なパラメーター
    • class="use-ajax"はこのリンクがajax用に決める
  • クライアント側のjsで使用しているブラウザがajax対応可能かを判断して、ajax起動リンクに「nojs」のパラメーターを書き換え(利用可能:nojs⇒ajax)てサーバー側に転送
  • サーバー側がajax利用可否よりクライアント側にajax対応有無の結果を返します
    Drupalのajaxフレームワークの利用
  • 上記例のプログラムは以下のようで
    /**
     * Implements hook_init().
     */
    function test_module_init()
    {
      drupal_add_js('misc/jquery.form.js');
      drupal_add_library('system','drupal.ajax');
    }
    
    /**
     *  Implementation of hook_menu()
     */
    function test_module_menu() {
      $items['test/ajax/%/%']=array(     // URLの2,3番目がクライアント側で生成
          'page callback' => 'ajax_node_response',
          'page arguments' => array(2,3),   // URLの2,3番目の引数をコールバック関数に渡す
          'access callback' => 'user_access',
          'access arguments' => array('access content'),
          'type' => MENU_CALLBACK,
      );
      return $items;
    }
    
    function ajax_node_response($type="ajax", $nid=0){
      $node = node_load( $nid, NULL, false );
      $vnode = node_view($node);
      $output = theme('node', $vnode);
      if( $type="ajax" ){
        $commands=array();
        $commands[]=ajax_command_replace( '#block-system-main','<section id="block-system-main">'.$output.'</section>' ) ;
        $page = array(
          '#type' => 'ajax',
          '#commands' => $commands,
        );
        ajax_deliver( $page ) ;   // ajax対応ブラウザの結果
      } else {
        $output = '<div id="content">'.$output.'</div>';  // ajax非対応ブラウザの結果
        return $output;
      }
    }
    

ポイント3:クライアント側で実行させたい部分はajax_commandを使用します

  • クライアント側で処理結果をどこに入り替えはajax_command_replaceで指定します
  • 結果の挿入、入れ替え、削除、css処理などがいろいろあります。詳細は本家のajax_command一覧を参考してください

 

drupal
Views

やりたいこと:モジュール(VBO)の各処理(Operation)に独自(カスタム)オプションを追加したい

  • 前回モジュール(VBO)にたいして処理(Operation)オプション追加を紹介しました
    •  Drupalのモジュール(VBO)の一括処理後にページ遷移させる方法
    • このオプションは全VBOに対して作成したものですが、すべての処理に影響を与えています
  • 各種処理(Operation)に対してどのようにオプションを追加するか前回の課題として残っています
  • 今回はこの課題を解決に新しいカスタムモジュール(vbo_redirect_option)を作成して、紹介します
    モジュールVBOの各種処理に独自のオプション追加

hook_formとCtoolsのdepent systemより各オペレーションに独自のオプションを追加

  • VBOのオペレーション設定フォームがカスタマイズとして開放していないです(前回も説明した)
  • ここで、Drupalのhook_formでVBOのオペレーション設定画面を特定して、カスタムオプション追加することになりました
    function vbo_redirect_option_form_alter(&$form, &$form_state, $form_id)
    {
        if( isset($form_state['id']) && $form_state['id'] === "views_bulk_operations"){
    
            foreach( $form_state['input']['options']['vbo_operations'] as $key => $operation) {
                if( $operation['redirect_check'] && strlen( trim($operation['redirect_url']))>0 ) {
                    variable_set( $key, $operation['redirect_url'] );
                } else {
                    if( !empty( variable_get($key) ) ) variable_del( $key ) ;
                }
            }
    
    
            foreach( $form['options']['vbo_operations'] as $key => &$operation ){
                if( !is_array($operation) ) continue ;
    
                $redirect_url = variable_get($key);
                $dep_key = "edit-options-vbo-operations-" . str_replace("_", "-", str_replace("::","",$key) ) ;
    
                $operation['redirect_check'] = array(
                    '#type' => 'checkbox',
                    '#title' => t('Redirect page to after operation'),
                    '#default_value' =>  $redirect_url ? 1 : 0 ,
                    '#dependency' => array(    // Ctoolsのdependent systemに依存
                        $dep_key."-selected" => array(1),
                    ),
                );
                $operation['redirect_url'] = array(
                    '#type' => 'textfield',
                    '#title' => t('Provide label'),
                    '#title_display' => 'invisible',
                    '#default_value' => empty($redirect_url) ? "" : $redirect_url,
                    '#dependency' => array(    // Ctoolsのdependent systemに依存
                        $dep_key."-selected" => array(1),
                        $dep_key . '-redirect-check' => array(1),
                    ),
                    '#dependency_count' => 2,
                );
            }
        }
    }
    • 設定フォームにチェックボックスをチェックしたら、画面遷移URL入力フィールドが現れるダイナミックフォームはモジュール(Ctools)のdependent systemを利用しています

処理(Operation)確認ステップをスキップがあるかないかを確認してhook_views_bulk_operations_form_alter()実装でオプションの設定を行う

  • VBOの処理(Operation)が確認ステップがあるかないかは2種類あります(この二種類をの処理プロセスが違うのでしっかりテストする必要がある)
  • hook_views_bulk_operations_form_alter()を実装して、各処理ステップにカスタマイズを行います
    function vbo_redirect_option_views_bulk_operations_form_alter(&$form, &$form_state, $vbo)
    {
        // collect all operations that has contained redirect_rul
        $redirect_arr = array();
        foreach( $vbo->options['vbo_operations'] as $key => $operation ) {
            if( !empty( variable_get($key) ) ){
                $redirect_arr[$key] = $key ;
            }
        }
    
        // add redirect step to #submit element
        if(isset($form['select'])) {
    
            // this is the form start step
            foreach( $form['select'] as $key => &$element ){
                if( isset($redirect_arr[$key]) ){
                    // we check if there is any operation has redirect_url
                    $element['#submit'][] = 'vbo_redirect_after_operation';
                    // only one is enough, we will detect witch one in the callback function
                    break;
                }
            }
    
            // do operation with confirmation step
            // this is the confirmation step
        } else if( !$form_state['operation']->getAdminOption('skip_confirmation') ) {
            $form['actions']['submit']['#submit'][] = "vbo_redirect_after_operation_with_confirmation";
            $form_state['redirect_to_after_operation'] = $form_state['operation']->getAdminOption('redirect_url');
        }
    
    }
    
    
    /**
     * callback function that has called by operation
     * this is the form start step, we don't know if it has confirmation step or not
     * @param $form
     * @param $form_state
     */
    function vbo_redirect_after_operation(&$form, &$form_state){
        // the are multiple element can be operated
        // the right one that has be sent to this step
        // we need get redirect_url if the it has
        if( isset($form_state['operation']) ){
            // get redirect_url by operation_id
            $redirec=variable_get($form_state['operation']->operationId) ;
            if( !empty($redirec) ){
                if( $form_state['operation']->getAdminOption('skip_confirmation') ) {
                    $form_state['redirect'] = $redirec;
                }
            }
        }
    }
    
    /**
     * callback function that has be called by operation with confirmation step
     * @param $form
     * @param $form_state
     */
    function vbo_redirect_after_operation_with_confirmation( $form, &$form_state ){
        // there is only operation that has be sent here with the confirmation step
        if( isset($form_state['redirect_to_after_operation']) ){
            // set redirect_url that should be stored in $form_state
            $form_state['redirect'] = $form_state['redir ect_to_after_operation'];
        }
    }

感想と結論:VBOの処理オプション設定はカスタマイズに開放していないため、各種処理(Operation)のオプションの取得、設定に苦労します

  • VBOの処理オプション設定はユーザーにカスタマイズに開放していないです
  • オペレーションの各ステップに$form、$form_state、$vbo変数から必要な情報を取得したり、セットしたりしました
  • 必要な情報がどこにあるかは不明だし(その時dsm($vbo)などで確認)、特定するまでに、時間がかかりました。
添付 サイズ
vbo_redirect_option.zip (1.77 KB) 1.77 KB
Embedded thumbnail for Drupalのモジュール(VBO)の各種処理(Operation)に独自(カスタムオ)のプションの追加方法
drupal
development
Views

Drupalのモジュール(Rules)で作成した各種アクションセットコンポーネントをモジュールVBOで一括処理

  • 背景:Drupal7.x.56、Views Bulk Operation(VBO)7.x-3.4、Rules7.x-2.10
  • モジュール(Rules)がいろいろなアクションセットの作成ができます
    • データの作成/更新/削除
    • メール送信、フラグを立てる
    • などなど
  • モジュール(VBO)がRulesで作成したアクションコンポーネントの利用ができます
    • Drupalのモジュール(Rules)のアクションコンポーネントでVBOより新規ノード作成とフィールドのコピー
  • 今回の例として、Rulesでメッセージ表示する単純なアクションコンポーネント(show message)を作成して、VBOで一括処理を行います
    Rulesでメッセージ表示コンポーネントをVBOで一括処理

問題点:VBO一括処理後に画面遷移(redirect)はできません

  • VBOで一括処理後に、画面を遷移して処理結果を確認することがあります
  • VBOの設定オプションに、処理後の画面遷移設定がありません
  • ネットで調べてみたが、VBO一括処理後の画面遷移オプション追加パッチがります
    • これは、モジュールVBOに対するパッチです
    • このパッチ適応したら、次回VBOアップグレード時に、ソースのマージ作業が面だと思います
    • できれば、VBOのパッチを使用したくないです

解決:カスタムモジュール(vbo_redirect_option.zip)でVBO処理後の画面遷移オプションの追加

  • モジュール(VBO)の主要部分がクラス(class)構造なので、簡単に画面遷移ロジックを追加することはできません
  • 「Bulk Operation Settings」に処理後の画面遷移オプションを追加します
    • 「Bulk Operation Settings」のオーバーライドができないので、hook_form_alter()でオプションを追加することになりました
      /**
       * Implements hook_form_alter().
       */
      function vbo_redirect_option_form_alter(&$form, &$form_state, $form_id)
      {
        // VBOの処理かのチェック
          if( isset($form_state['id']) && $form_state['id'] === "views_bulk_operations"){
      
         // ここで、画面遷移先の保存処理は少し反則
         //  vbo_settingsに画面遷移先の追加は難しい(クラス構造体内にあるため)
         //  環境変数に画面遷移先(uri)を保存
              if( isset($form_state['input']['options']['vbo_settings'][vbo_redirect_url]) ){
                  variable_set( 'vbo_redirect_url', $form_state['input']['options']['vbo_settings'][vbo_redirect_url] ) ;
              }
      
         // 画面遷移先のテキストフィールドを追加
              $form['options']['vbo_settings']['vbo_redirect_url'] = array(
                  '#type' => 'textfield',
                  '#title' => t('Page to direct to after completion of  batch'),
                  '#description' => t('Redirects to the view when finished the operation'),
                  '#default_value' => variable_get('vbo_redirect_url'),
              );
          }
      }
    • 画面遷移先を入力するテキストフィールドを設定画面に追加
    • 画面遷移先(uri)をvbo_settingsに入れたいですが、クラスの構造体にあるため追加できません。環境変数に保存することにしました。
    • 設定画面を保存("#submit")後に、画面遷移先を保存する処理を行いたいですが、"#submit"にコールバック関数を入れても、呼び出されない現象があって、仕方がなく、hook_form_alter()内で画面遷移先(uri)の保存処理を行いました
      VBOに一括処理後に画面遷移オプションの追加
  • hook_views_bulk_operations_form_alter()を実装して、実際のVBO一括処理後に、画面遷移設定を行います
    /**
     * Implements hook_views_bulk_operations_form_alter().
     */
    function vbo_redirect_option_views_bulk_operations_form_alter(&$form, &$form_state, $vbo)
    {
        $vbo_redirect_url = trim( variable_get('vbo_redirect_url') ) ;
    
        if( isset($vbo_redirect_url) && strlen($vbo_redirect_url) >0 ){
    
            // check if vbo operation skip confirmation
            $skip_confirmation = false ;
            foreach( $vbo->options['vbo_operations'] as $key => $operation ){
                if( $operation['selected'] && $operation['skip_confirmation'] ){
                    if( isset($form['select'][$key]) ) {
                        $form['select'][$key]['#submit'][] = 'vbo_redirect_after_operation';
                        $skip_confirmation = true ;
                    }
                }
            }
    
            // set redirect method when vbo has confirmation step
            if( !$skip_confirmation ){
                $form['actions']['submit']['#submit'][] = 'vbo_redirect_after_operation' ;
            }
        }
    }
    
    // callback function to set redirect url
    function vbo_redirect_after_operation($form, &$form_state){
        $vbo_redirect_url = trim( variable_get('vbo_redirect_url') ) ;
        $form_state['redirect'] = $vbo_redirect_url;
    }
    • VBO一括処理の「確認のステップをスキップ」があるか、ないかを分けて処理します(画面遷移設定場所が違うため)
    • "#submit"に画面遷移処理を追加します
    • 画面遷移処理は$form_state['redirect'] で行います

結論と感想:簡単のカスタモジュールでVBOへの影響はありません。各オペレーション設定に画面遷移オプションを追加したほうよいかもしれない

  • このカスタムモジュールのインストールより、モジュール(VBO)への影響はありません
  • この画面遷移オプションを「Bulk Operation Settings」に追加したので、すべてのオペレーションに適応されます
    • VBOの一括処理内容がいろいろあります(例:オーナー変更、エンティティ内容変更など)
    • これらの処理後に一つの画面遷移先の設定はやや強引的だと思います
  • できれば、「Selected Bulk Operations」にある、選択したオペレーションの設定に画面遷移先の設定をしたほうが柔軟的な対応だと思います(次回の課題)
    画面遷移オプションを各オペレーションに追加すべき
添付 サイズ
vbo_redirect_option.zip (1.19 KB) 1.19 KB
Embedded thumbnail for Drupalのモジュール(VBO)の一括処理後にページ遷移させる方法
drupal
form
ajax

やりたいこと:Drupalのajaxフレームワークを利用して表示している要素を削除

  • Drupalのモジュール(Views)で作成した一覧の要素を選択して削除します
    • 要素を選択して削除するモジュール:Views Bulk Operations
    • 例:Drupalのモジュール(VBO)の各種処理(Operation)に独自(カスタムオ)のプションの追加方法
  • 前提条件:要素削除する確認の必要はありません
  • ajaxで動的に削除するのはやさしいUIとも言えるでしょう(以下のイメージのように削除)
    Drupalのajaxフレームワークより要素を動的に削除

Step1:削除リンクにDrupalのajax使用するクラス:use-ajax を追加

  • Drupalのajaxフレームワークに関する説明は以下の記事をご参考ください
    • Drupalでajaxのフレームワークが簡単に作成できる
  • 削除アイコン付きのリンクは以下のようです
    // 削除エレメントID:123 (例)
    <a href="/delete/element/id/123/nojs" class="use-ajax del-link" id="del-link-123">
           <i class="fa fa-trash-o" aria-hidden="true"></i>
    </a>
    • アンカー(a)に削除するエレメントID(または別の識別パラメーター)を入れる必要はあります
    • アンカーリンクの後ろに「nojs」を追加します(クライアント側のajax作動時に、nojs->ajaxに変換され)
    • アンカーがクリックされると、Drupalのajaxフレームワークが起動され、削除パラメーターをサイト側に渡します

Step2:hook_menuで要素削除のリクエストをキャッチします

  • hook_menuで要素削除のリクエストを受け取り、削除処理を行います
    // 要素削除URLの設定
    $items['delete/element/%/nojs'] = array(
    	'page callback' => 'delete_element',
    	'page arguments' => array( 2, 3 ) ,
    	'access callback' => 'delete_access',
    	'type' => MENU_CALLBACK,
    );
    // ajaxが以下のURLでリクエストをします(クライアント側でnojs->ajaxに変換)
    $items['delete/element/%/ajax'] = array(
    	'delivery callback' => 'ajax_deliver',
    )+$items['delete/element/%/nojs'] ;    // 要素削除定義に遷移
    
  • 要素削除処理ファンクション:delete_element で削除処理、処理結果をクライアント側に返します
    function delete_element ($id, $ajax){
        $is_ajax = $ajax === "ajax" ;  // ajaxと通用のリクエスト両方対応のため
    
        // 要素をDBから削除
        db_delete("element_table")->condition("entity_id", $id)->execute() ;
    
        // 画面要素も削除コマンドを返す
        if( $is_ajax ){
            // ajaxで要素削除後の処理
            $commands = array();
            $commands[] = ajax_command_remove( '#element-123');
            return array(
              '#type'=>"ajax",
              '#commands' => $commands,
            );
        } else {
            // 通常での要素削除後の処理
            drupal_set_message(t('Deleted 1 vocabulary'));
            drupal_goto();
        }
    }

     

Drupalのajaxフレームワークで要素削除

纏め:Drupalのajaxフレームワークを利用すればajax処理が自動的に行います

  • 上記例では、削除リンクにクラス:use-ajax を追加するだけで、ajax関連処理を記述する必要はあります
    • 削除リンクではなく、削除ボタン(button)要素を使用する場合クラス: use-ajax-submit
  • サーバー側では、hook_menuで削除リンクの定義、削除リクエストをキャッチして、削除処理関数を作成します
    • DB上のデータ削除完了後に、クライアント側の要素削除命令(ajax_command_remove)を返せば良いです
  • この一連のajax処理の記述はほどんとありません。簡単、便利です
drupal
development
ajax

やりたいこと:Drupalのプログラムレベルで簡単にajaxを利用してクライアント側でデータ交信をしたいです

  • 環境:Drupal7.54
  • DrupalのFormAPIで簡単にajaxの実装ができます(Drupalのフォーム(FromAPI)でのajaxの実装 )
  • FormAPIだけではなく、Drupalをカスタマイズ時にいろいろなところでajaxを実装したいことがあります

ポイント1:Drupalでajaxに必要なライブラリをロードし、クライアント側にjquery.form.jsファイルをセット

  • サーバー側でdrupal.ajaxのライブラリをロードする必要があります
  • クライアント側にjquery.form.jsファイルを設置する必要があります
  • この処理はajax処理するページをロード時に行えれば良いです。
    • 例:hook_init()内で処理する
      /**
       * Implements hook_init().
       */
      function YOUR_MODULE_NAME_init()
      {
        drupal_add_js('misc/jquery.form.js');
        drupal_add_library('system','drupal.ajax');
      }
  • クライアント側のブラウザのプロパティでjquery.form.jsがセットされたことの確認ができます

ポイント2:クライアント側のajax起動リンク内にajax対応可否のパラメーター「nojs」とクラス属性「use-ajax」のセット

  • ajaxの起動リンクの作成基本パターン: 
    <a href="text/ajax/nojs/1234" class="use-ajax">ajaxリンク</a>
    • hrefにある「nojs」が決まりの文字
    • hrefにある「1234」はサーバー側に転送したい必要なパラメーター
    • class="use-ajax"はこのリンクがajax用に決める
  • クライアント側のjsで使用しているブラウザがajax対応可能かを判断して、ajax起動リンクに「nojs」のパラメーターを書き換え(利用可能:nojs⇒ajax)てサーバー側に転送
  • サーバー側がajax利用可否よりクライアント側にajax対応有無の結果を返します
    Drupalのajaxフレームワークの利用
  • 上記例のプログラムは以下のようで
    /**
     * Implements hook_init().
     */
    function test_module_init()
    {
      drupal_add_js('misc/jquery.form.js');
      drupal_add_library('system','drupal.ajax');
    }
    
    /**
     *  Implementation of hook_menu()
     */
    function test_module_menu() {
      $items['test/ajax/%/%']=array(     // URLの2,3番目がクライアント側で生成
          'page callback' => 'ajax_node_response',
          'page arguments' => array(2,3),   // URLの2,3番目の引数をコールバック関数に渡す
          'access callback' => 'user_access',
          'access arguments' => array('access content'),
          'type' => MENU_CALLBACK,
      );
      return $items;
    }
    
    function ajax_node_response($type="ajax", $nid=0){
      $node = node_load( $nid, NULL, false );
      $vnode = node_view($node);
      $output = theme('node', $vnode);
      if( $type="ajax" ){
        $commands=array();
        $commands[]=ajax_command_replace( '#block-system-main','<section id="block-system-main">'.$output.'</section>' ) ;
        $page = array(
          '#type' => 'ajax',
          '#commands' => $commands,
        );
        ajax_deliver( $page ) ;   // ajax対応ブラウザの結果
      } else {
        $output = '<div id="content">'.$output.'</div>';  // ajax非対応ブラウザの結果
        return $output;
      }
    }
    

ポイント3:クライアント側で実行させたい部分はajax_commandを使用します

  • クライアント側で処理結果をどこに入り替えはajax_command_replaceで指定します
  • 結果の挿入、入れ替え、削除、css処理などがいろいろあります。詳細は本家のajax_command一覧を参考してください

 

drupal
Views

やりたいこと:モジュール(VBO)の各処理(Operation)に独自(カスタム)オプションを追加したい

  • 前回モジュール(VBO)にたいして処理(Operation)オプション追加を紹介しました
    •  Drupalのモジュール(VBO)の一括処理後にページ遷移させる方法
    • このオプションは全VBOに対して作成したものですが、すべての処理に影響を与えています
  • 各種処理(Operation)に対してどのようにオプションを追加するか前回の課題として残っています
  • 今回はこの課題を解決に新しいカスタムモジュール(vbo_redirect_option)を作成して、紹介します
    モジュールVBOの各種処理に独自のオプション追加

hook_formとCtoolsのdepent systemより各オペレーションに独自のオプションを追加

  • VBOのオペレーション設定フォームがカスタマイズとして開放していないです(前回も説明した)
  • ここで、Drupalのhook_formでVBOのオペレーション設定画面を特定して、カスタムオプション追加することになりました
    function vbo_redirect_option_form_alter(&$form, &$form_state, $form_id)
    {
        if( isset($form_state['id']) && $form_state['id'] === "views_bulk_operations"){
    
            foreach( $form_state['input']['options']['vbo_operations'] as $key => $operation) {
                if( $operation['redirect_check'] && strlen( trim($operation['redirect_url']))>0 ) {
                    variable_set( $key, $operation['redirect_url'] );
                } else {
                    if( !empty( variable_get($key) ) ) variable_del( $key ) ;
                }
            }
    
    
            foreach( $form['options']['vbo_operations'] as $key => &$operation ){
                if( !is_array($operation) ) continue ;
    
                $redirect_url = variable_get($key);
                $dep_key = "edit-options-vbo-operations-" . str_replace("_", "-", str_replace("::","",$key) ) ;
    
                $operation['redirect_check'] = array(
                    '#type' => 'checkbox',
                    '#title' => t('Redirect page to after operation'),
                    '#default_value' =>  $redirect_url ? 1 : 0 ,
                    '#dependency' => array(    // Ctoolsのdependent systemに依存
                        $dep_key."-selected" => array(1),
                    ),
                );
                $operation['redirect_url'] = array(
                    '#type' => 'textfield',
                    '#title' => t('Provide label'),
                    '#title_display' => 'invisible',
                    '#default_value' => empty($redirect_url) ? "" : $redirect_url,
                    '#dependency' => array(    // Ctoolsのdependent systemに依存
                        $dep_key."-selected" => array(1),
                        $dep_key . '-redirect-check' => array(1),
                    ),
                    '#dependency_count' => 2,
                );
            }
        }
    }
    • 設定フォームにチェックボックスをチェックしたら、画面遷移URL入力フィールドが現れるダイナミックフォームはモジュール(Ctools)のdependent systemを利用しています

処理(Operation)確認ステップをスキップがあるかないかを確認してhook_views_bulk_operations_form_alter()実装でオプションの設定を行う

  • VBOの処理(Operation)が確認ステップがあるかないかは2種類あります(この二種類をの処理プロセスが違うのでしっかりテストする必要がある)
  • hook_views_bulk_operations_form_alter()を実装して、各処理ステップにカスタマイズを行います
    function vbo_redirect_option_views_bulk_operations_form_alter(&$form, &$form_state, $vbo)
    {
        // collect all operations that has contained redirect_rul
        $redirect_arr = array();
        foreach( $vbo->options['vbo_operations'] as $key => $operation ) {
            if( !empty( variable_get($key) ) ){
                $redirect_arr[$key] = $key ;
            }
        }
    
        // add redirect step to #submit element
        if(isset($form['select'])) {
    
            // this is the form start step
            foreach( $form['select'] as $key => &$element ){
                if( isset($redirect_arr[$key]) ){
                    // we check if there is any operation has redirect_url
                    $element['#submit'][] = 'vbo_redirect_after_operation';
                    // only one is enough, we will detect witch one in the callback function
                    break;
                }
            }
    
            // do operation with confirmation step
            // this is the confirmation step
        } else if( !$form_state['operation']->getAdminOption('skip_confirmation') ) {
            $form['actions']['submit']['#submit'][] = "vbo_redirect_after_operation_with_confirmation";
            $form_state['redirect_to_after_operation'] = $form_state['operation']->getAdminOption('redirect_url');
        }
    
    }
    
    
    /**
     * callback function that has called by operation
     * this is the form start step, we don't know if it has confirmation step or not
     * @param $form
     * @param $form_state
     */
    function vbo_redirect_after_operation(&$form, &$form_state){
        // the are multiple element can be operated
        // the right one that has be sent to this step
        // we need get redirect_url if the it has
        if( isset($form_state['operation']) ){
            // get redirect_url by operation_id
            $redirec=variable_get($form_state['operation']->operationId) ;
            if( !empty($redirec) ){
                if( $form_state['operation']->getAdminOption('skip_confirmation') ) {
                    $form_state['redirect'] = $redirec;
                }
            }
        }
    }
    
    /**
     * callback function that has be called by operation with confirmation step
     * @param $form
     * @param $form_state
     */
    function vbo_redirect_after_operation_with_confirmation( $form, &$form_state ){
        // there is only operation that has be sent here with the confirmation step
        if( isset($form_state['redirect_to_after_operation']) ){
            // set redirect_url that should be stored in $form_state
            $form_state['redirect'] = $form_state['redir ect_to_after_operation'];
        }
    }

感想と結論:VBOの処理オプション設定はカスタマイズに開放していないため、各種処理(Operation)のオプションの取得、設定に苦労します

  • VBOの処理オプション設定はユーザーにカスタマイズに開放していないです
  • オペレーションの各ステップに$form、$form_state、$vbo変数から必要な情報を取得したり、セットしたりしました
  • 必要な情報がどこにあるかは不明だし(その時dsm($vbo)などで確認)、特定するまでに、時間がかかりました。
添付 サイズ
vbo_redirect_option.zip (1.77 KB) 1.77 KB
Embedded thumbnail for Drupalのモジュール(VBO)の各種処理(Operation)に独自(カスタムオ)のプションの追加方法
drupal
development
Views

Drupalのモジュール(Rules)で作成した各種アクションセットコンポーネントをモジュールVBOで一括処理

  • 背景:Drupal7.x.56、Views Bulk Operation(VBO)7.x-3.4、Rules7.x-2.10
  • モジュール(Rules)がいろいろなアクションセットの作成ができます
    • データの作成/更新/削除
    • メール送信、フラグを立てる
    • などなど
  • モジュール(VBO)がRulesで作成したアクションコンポーネントの利用ができます
    • Drupalのモジュール(Rules)のアクションコンポーネントでVBOより新規ノード作成とフィールドのコピー
  • 今回の例として、Rulesでメッセージ表示する単純なアクションコンポーネント(show message)を作成して、VBOで一括処理を行います
    Rulesでメッセージ表示コンポーネントをVBOで一括処理

問題点:VBO一括処理後に画面遷移(redirect)はできません

  • VBOで一括処理後に、画面を遷移して処理結果を確認することがあります
  • VBOの設定オプションに、処理後の画面遷移設定がありません
  • ネットで調べてみたが、VBO一括処理後の画面遷移オプション追加パッチがります
    • これは、モジュールVBOに対するパッチです
    • このパッチ適応したら、次回VBOアップグレード時に、ソースのマージ作業が面だと思います
    • できれば、VBOのパッチを使用したくないです

解決:カスタムモジュール(vbo_redirect_option.zip)でVBO処理後の画面遷移オプションの追加

  • モジュール(VBO)の主要部分がクラス(class)構造なので、簡単に画面遷移ロジックを追加することはできません
  • 「Bulk Operation Settings」に処理後の画面遷移オプションを追加します
    • 「Bulk Operation Settings」のオーバーライドができないので、hook_form_alter()でオプションを追加することになりました
      /**
       * Implements hook_form_alter().
       */
      function vbo_redirect_option_form_alter(&$form, &$form_state, $form_id)
      {
        // VBOの処理かのチェック
          if( isset($form_state['id']) && $form_state['id'] === "views_bulk_operations"){
      
         // ここで、画面遷移先の保存処理は少し反則
         //  vbo_settingsに画面遷移先の追加は難しい(クラス構造体内にあるため)
         //  環境変数に画面遷移先(uri)を保存
              if( isset($form_state['input']['options']['vbo_settings'][vbo_redirect_url]) ){
                  variable_set( 'vbo_redirect_url', $form_state['input']['options']['vbo_settings'][vbo_redirect_url] ) ;
              }
      
         // 画面遷移先のテキストフィールドを追加
              $form['options']['vbo_settings']['vbo_redirect_url'] = array(
                  '#type' => 'textfield',
                  '#title' => t('Page to direct to after completion of  batch'),
                  '#description' => t('Redirects to the view when finished the operation'),
                  '#default_value' => variable_get('vbo_redirect_url'),
              );
          }
      }
    • 画面遷移先を入力するテキストフィールドを設定画面に追加
    • 画面遷移先(uri)をvbo_settingsに入れたいですが、クラスの構造体にあるため追加できません。環境変数に保存することにしました。
    • 設定画面を保存("#submit")後に、画面遷移先を保存する処理を行いたいですが、"#submit"にコールバック関数を入れても、呼び出されない現象があって、仕方がなく、hook_form_alter()内で画面遷移先(uri)の保存処理を行いました
      VBOに一括処理後に画面遷移オプションの追加
  • hook_views_bulk_operations_form_alter()を実装して、実際のVBO一括処理後に、画面遷移設定を行います
    /**
     * Implements hook_views_bulk_operations_form_alter().
     */
    function vbo_redirect_option_views_bulk_operations_form_alter(&$form, &$form_state, $vbo)
    {
        $vbo_redirect_url = trim( variable_get('vbo_redirect_url') ) ;
    
        if( isset($vbo_redirect_url) && strlen($vbo_redirect_url) >0 ){
    
            // check if vbo operation skip confirmation
            $skip_confirmation = false ;
            foreach( $vbo->options['vbo_operations'] as $key => $operation ){
                if( $operation['selected'] && $operation['skip_confirmation'] ){
                    if( isset($form['select'][$key]) ) {
                        $form['select'][$key]['#submit'][] = 'vbo_redirect_after_operation';
                        $skip_confirmation = true ;
                    }
                }
            }
    
            // set redirect method when vbo has confirmation step
            if( !$skip_confirmation ){
                $form['actions']['submit']['#submit'][] = 'vbo_redirect_after_operation' ;
            }
        }
    }
    
    // callback function to set redirect url
    function vbo_redirect_after_operation($form, &$form_state){
        $vbo_redirect_url = trim( variable_get('vbo_redirect_url') ) ;
        $form_state['redirect'] = $vbo_redirect_url;
    }
    • VBO一括処理の「確認のステップをスキップ」があるか、ないかを分けて処理します(画面遷移設定場所が違うため)
    • "#submit"に画面遷移処理を追加します
    • 画面遷移処理は$form_state['redirect'] で行います

結論と感想:簡単のカスタモジュールでVBOへの影響はありません。各オペレーション設定に画面遷移オプションを追加したほうよいかもしれない

  • このカスタムモジュールのインストールより、モジュール(VBO)への影響はありません
  • この画面遷移オプションを「Bulk Operation Settings」に追加したので、すべてのオペレーションに適応されます
    • VBOの一括処理内容がいろいろあります(例:オーナー変更、エンティティ内容変更など)
    • これらの処理後に一つの画面遷移先の設定はやや強引的だと思います
  • できれば、「Selected Bulk Operations」にある、選択したオペレーションの設定に画面遷移先の設定をしたほうが柔軟的な対応だと思います(次回の課題)
    画面遷移オプションを各オペレーションに追加すべき
添付 サイズ
vbo_redirect_option.zip (1.19 KB) 1.19 KB
Embedded thumbnail for Drupalのモジュール(VBO)の一括処理後にページ遷移させる方法
drupal
form
ajax

やりたいこと:Drupalのajaxフレームワークを利用して表示している要素を削除

  • Drupalのモジュール(Views)で作成した一覧の要素を選択して削除します
    • 要素を選択して削除するモジュール:Views Bulk Operations
    • 例:Drupalのモジュール(VBO)の各種処理(Operation)に独自(カスタムオ)のプションの追加方法
  • 前提条件:要素削除する確認の必要はありません
  • ajaxで動的に削除するのはやさしいUIとも言えるでしょう(以下のイメージのように削除)
    Drupalのajaxフレームワークより要素を動的に削除

Step1:削除リンクにDrupalのajax使用するクラス:use-ajax を追加

  • Drupalのajaxフレームワークに関する説明は以下の記事をご参考ください
    • Drupalでajaxのフレームワークが簡単に作成できる
  • 削除アイコン付きのリンクは以下のようです
    // 削除エレメントID:123 (例)
    <a href="/delete/element/id/123/nojs" class="use-ajax del-link" id="del-link-123">
           <i class="fa fa-trash-o" aria-hidden="true"></i>
    </a>
    • アンカー(a)に削除するエレメントID(または別の識別パラメーター)を入れる必要はあります
    • アンカーリンクの後ろに「nojs」を追加します(クライアント側のajax作動時に、nojs->ajaxに変換され)
    • アンカーがクリックされると、Drupalのajaxフレームワークが起動され、削除パラメーターをサイト側に渡します

Step2:hook_menuで要素削除のリクエストをキャッチします

  • hook_menuで要素削除のリクエストを受け取り、削除処理を行います
    // 要素削除URLの設定
    $items['delete/element/%/nojs'] = array(
    	'page callback' => 'delete_element',
    	'page arguments' => array( 2, 3 ) ,
    	'access callback' => 'delete_access',
    	'type' => MENU_CALLBACK,
    );
    // ajaxが以下のURLでリクエストをします(クライアント側でnojs->ajaxに変換)
    $items['delete/element/%/ajax'] = array(
    	'delivery callback' => 'ajax_deliver',
    )+$items['delete/element/%/nojs'] ;    // 要素削除定義に遷移
    
  • 要素削除処理ファンクション:delete_element で削除処理、処理結果をクライアント側に返します
    function delete_element ($id, $ajax){
        $is_ajax = $ajax === "ajax" ;  // ajaxと通用のリクエスト両方対応のため
    
        // 要素をDBから削除
        db_delete("element_table")->condition("entity_id", $id)->execute() ;
    
        // 画面要素も削除コマンドを返す
        if( $is_ajax ){
            // ajaxで要素削除後の処理
            $commands = array();
            $commands[] = ajax_command_remove( '#element-123');
            return array(
              '#type'=>"ajax",
              '#commands' => $commands,
            );
        } else {
            // 通常での要素削除後の処理
            drupal_set_message(t('Deleted 1 vocabulary'));
            drupal_goto();
        }
    }

     

Drupalのajaxフレームワークで要素削除

纏め:Drupalのajaxフレームワークを利用すればajax処理が自動的に行います

  • 上記例では、削除リンクにクラス:use-ajax を追加するだけで、ajax関連処理を記述する必要はあります
    • 削除リンクではなく、削除ボタン(button)要素を使用する場合クラス: use-ajax-submit
  • サーバー側では、hook_menuで削除リンクの定義、削除リクエストをキャッチして、削除処理関数を作成します
    • DB上のデータ削除完了後に、クライアント側の要素削除命令(ajax_command_remove)を返せば良いです
  • この一連のajax処理の記述はほどんとありません。簡単、便利です
drupal
development
ajax

やりたいこと:Drupalのプログラムレベルで簡単にajaxを利用してクライアント側でデータ交信をしたいです

  • 環境:Drupal7.54
  • DrupalのFormAPIで簡単にajaxの実装ができます(Drupalのフォーム(FromAPI)でのajaxの実装 )
  • FormAPIだけではなく、Drupalをカスタマイズ時にいろいろなところでajaxを実装したいことがあります

ポイント1:Drupalでajaxに必要なライブラリをロードし、クライアント側にjquery.form.jsファイルをセット

  • サーバー側でdrupal.ajaxのライブラリをロードする必要があります
  • クライアント側にjquery.form.jsファイルを設置する必要があります
  • この処理はajax処理するページをロード時に行えれば良いです。
    • 例:hook_init()内で処理する
      /**
       * Implements hook_init().
       */
      function YOUR_MODULE_NAME_init()
      {
        drupal_add_js('misc/jquery.form.js');
        drupal_add_library('system','drupal.ajax');
      }
  • クライアント側のブラウザのプロパティでjquery.form.jsがセットされたことの確認ができます

ポイント2:クライアント側のajax起動リンク内にajax対応可否のパラメーター「nojs」とクラス属性「use-ajax」のセット

  • ajaxの起動リンクの作成基本パターン: 
    <a href="text/ajax/nojs/1234" class="use-ajax">ajaxリンク</a>
    • hrefにある「nojs」が決まりの文字
    • hrefにある「1234」はサーバー側に転送したい必要なパラメーター
    • class="use-ajax"はこのリンクがajax用に決める
  • クライアント側のjsで使用しているブラウザがajax対応可能かを判断して、ajax起動リンクに「nojs」のパラメーターを書き換え(利用可能:nojs⇒ajax)てサーバー側に転送
  • サーバー側がajax利用可否よりクライアント側にajax対応有無の結果を返します
    Drupalのajaxフレームワークの利用
  • 上記例のプログラムは以下のようで
    /**
     * Implements hook_init().
     */
    function test_module_init()
    {
      drupal_add_js('misc/jquery.form.js');
      drupal_add_library('system','drupal.ajax');
    }
    
    /**
     *  Implementation of hook_menu()
     */
    function test_module_menu() {
      $items['test/ajax/%/%']=array(     // URLの2,3番目がクライアント側で生成
          'page callback' => 'ajax_node_response',
          'page arguments' => array(2,3),   // URLの2,3番目の引数をコールバック関数に渡す
          'access callback' => 'user_access',
          'access arguments' => array('access content'),
          'type' => MENU_CALLBACK,
      );
      return $items;
    }
    
    function ajax_node_response($type="ajax", $nid=0){
      $node = node_load( $nid, NULL, false );
      $vnode = node_view($node);
      $output = theme('node', $vnode);
      if( $type="ajax" ){
        $commands=array();
        $commands[]=ajax_command_replace( '#block-system-main','<section id="block-system-main">'.$output.'</section>' ) ;
        $page = array(
          '#type' => 'ajax',
          '#commands' => $commands,
        );
        ajax_deliver( $page ) ;   // ajax対応ブラウザの結果
      } else {
        $output = '<div id="content">'.$output.'</div>';  // ajax非対応ブラウザの結果
        return $output;
      }
    }
    

ポイント3:クライアント側で実行させたい部分はajax_commandを使用します

  • クライアント側で処理結果をどこに入り替えはajax_command_replaceで指定します
  • 結果の挿入、入れ替え、削除、css処理などがいろいろあります。詳細は本家のajax_command一覧を参考してください

 

drupal
Views

やりたいこと:モジュール(VBO)の各処理(Operation)に独自(カスタム)オプションを追加したい

  • 前回モジュール(VBO)にたいして処理(Operation)オプション追加を紹介しました
    •  Drupalのモジュール(VBO)の一括処理後にページ遷移させる方法
    • このオプションは全VBOに対して作成したものですが、すべての処理に影響を与えています
  • 各種処理(Operation)に対してどのようにオプションを追加するか前回の課題として残っています
  • 今回はこの課題を解決に新しいカスタムモジュール(vbo_redirect_option)を作成して、紹介します
    モジュールVBOの各種処理に独自のオプション追加

hook_formとCtoolsのdepent systemより各オペレーションに独自のオプションを追加

  • VBOのオペレーション設定フォームがカスタマイズとして開放していないです(前回も説明した)
  • ここで、Drupalのhook_formでVBOのオペレーション設定画面を特定して、カスタムオプション追加することになりました
    function vbo_redirect_option_form_alter(&$form, &$form_state, $form_id)
    {
        if( isset($form_state['id']) && $form_state['id'] === "views_bulk_operations"){
    
            foreach( $form_state['input']['options']['vbo_operations'] as $key => $operation) {
                if( $operation['redirect_check'] && strlen( trim($operation['redirect_url']))>0 ) {
                    variable_set( $key, $operation['redirect_url'] );
                } else {
                    if( !empty( variable_get($key) ) ) variable_del( $key ) ;
                }
            }
    
    
            foreach( $form['options']['vbo_operations'] as $key => &$operation ){
                if( !is_array($operation) ) continue ;
    
                $redirect_url = variable_get($key);
                $dep_key = "edit-options-vbo-operations-" . str_replace("_", "-", str_replace("::","",$key) ) ;
    
                $operation['redirect_check'] = array(
                    '#type' => 'checkbox',
                    '#title' => t('Redirect page to after operation'),
                    '#default_value' =>  $redirect_url ? 1 : 0 ,
                    '#dependency' => array(    // Ctoolsのdependent systemに依存
                        $dep_key."-selected" => array(1),
                    ),
                );
                $operation['redirect_url'] = array(
                    '#type' => 'textfield',
                    '#title' => t('Provide label'),
                    '#title_display' => 'invisible',
                    '#default_value' => empty($redirect_url) ? "" : $redirect_url,
                    '#dependency' => array(    // Ctoolsのdependent systemに依存
                        $dep_key."-selected" => array(1),
                        $dep_key . '-redirect-check' => array(1),
                    ),
                    '#dependency_count' => 2,
                );
            }
        }
    }
    • 設定フォームにチェックボックスをチェックしたら、画面遷移URL入力フィールドが現れるダイナミックフォームはモジュール(Ctools)のdependent systemを利用しています

処理(Operation)確認ステップをスキップがあるかないかを確認してhook_views_bulk_operations_form_alter()実装でオプションの設定を行う

  • VBOの処理(Operation)が確認ステップがあるかないかは2種類あります(この二種類をの処理プロセスが違うのでしっかりテストする必要がある)
  • hook_views_bulk_operations_form_alter()を実装して、各処理ステップにカスタマイズを行います
    function vbo_redirect_option_views_bulk_operations_form_alter(&$form, &$form_state, $vbo)
    {
        // collect all operations that has contained redirect_rul
        $redirect_arr = array();
        foreach( $vbo->options['vbo_operations'] as $key => $operation ) {
            if( !empty( variable_get($key) ) ){
                $redirect_arr[$key] = $key ;
            }
        }
    
        // add redirect step to #submit element
        if(isset($form['select'])) {
    
            // this is the form start step
            foreach( $form['select'] as $key => &$element ){
                if( isset($redirect_arr[$key]) ){
                    // we check if there is any operation has redirect_url
                    $element['#submit'][] = 'vbo_redirect_after_operation';
                    // only one is enough, we will detect witch one in the callback function
                    break;
                }
            }
    
            // do operation with confirmation step
            // this is the confirmation step
        } else if( !$form_state['operation']->getAdminOption('skip_confirmation') ) {
            $form['actions']['submit']['#submit'][] = "vbo_redirect_after_operation_with_confirmation";
            $form_state['redirect_to_after_operation'] = $form_state['operation']->getAdminOption('redirect_url');
        }
    
    }
    
    
    /**
     * callback function that has called by operation
     * this is the form start step, we don't know if it has confirmation step or not
     * @param $form
     * @param $form_state
     */
    function vbo_redirect_after_operation(&$form, &$form_state){
        // the are multiple element can be operated
        // the right one that has be sent to this step
        // we need get redirect_url if the it has
        if( isset($form_state['operation']) ){
            // get redirect_url by operation_id
            $redirec=variable_get($form_state['operation']->operationId) ;
            if( !empty($redirec) ){
                if( $form_state['operation']->getAdminOption('skip_confirmation') ) {
                    $form_state['redirect'] = $redirec;
                }
            }
        }
    }
    
    /**
     * callback function that has be called by operation with confirmation step
     * @param $form
     * @param $form_state
     */
    function vbo_redirect_after_operation_with_confirmation( $form, &$form_state ){
        // there is only operation that has be sent here with the confirmation step
        if( isset($form_state['redirect_to_after_operation']) ){
            // set redirect_url that should be stored in $form_state
            $form_state['redirect'] = $form_state['redir ect_to_after_operation'];
        }
    }

感想と結論:VBOの処理オプション設定はカスタマイズに開放していないため、各種処理(Operation)のオプションの取得、設定に苦労します

  • VBOの処理オプション設定はユーザーにカスタマイズに開放していないです
  • オペレーションの各ステップに$form、$form_state、$vbo変数から必要な情報を取得したり、セットしたりしました
  • 必要な情報がどこにあるかは不明だし(その時dsm($vbo)などで確認)、特定するまでに、時間がかかりました。
添付 サイズ
vbo_redirect_option.zip (1.77 KB) 1.77 KB
Embedded thumbnail for Drupalのモジュール(VBO)の各種処理(Operation)に独自(カスタムオ)のプションの追加方法
drupal
development
Views

Drupalのモジュール(Rules)で作成した各種アクションセットコンポーネントをモジュールVBOで一括処理

  • 背景:Drupal7.x.56、Views Bulk Operation(VBO)7.x-3.4、Rules7.x-2.10
  • モジュール(Rules)がいろいろなアクションセットの作成ができます
    • データの作成/更新/削除
    • メール送信、フラグを立てる
    • などなど
  • モジュール(VBO)がRulesで作成したアクションコンポーネントの利用ができます
    • Drupalのモジュール(Rules)のアクションコンポーネントでVBOより新規ノード作成とフィールドのコピー
  • 今回の例として、Rulesでメッセージ表示する単純なアクションコンポーネント(show message)を作成して、VBOで一括処理を行います
    Rulesでメッセージ表示コンポーネントをVBOで一括処理

問題点:VBO一括処理後に画面遷移(redirect)はできません

  • VBOで一括処理後に、画面を遷移して処理結果を確認することがあります
  • VBOの設定オプションに、処理後の画面遷移設定がありません
  • ネットで調べてみたが、VBO一括処理後の画面遷移オプション追加パッチがります
    • これは、モジュールVBOに対するパッチです
    • このパッチ適応したら、次回VBOアップグレード時に、ソースのマージ作業が面だと思います
    • できれば、VBOのパッチを使用したくないです

解決:カスタムモジュール(vbo_redirect_option.zip)でVBO処理後の画面遷移オプションの追加

  • モジュール(VBO)の主要部分がクラス(class)構造なので、簡単に画面遷移ロジックを追加することはできません
  • 「Bulk Operation Settings」に処理後の画面遷移オプションを追加します
    • 「Bulk Operation Settings」のオーバーライドができないので、hook_form_alter()でオプションを追加することになりました
      /**
       * Implements hook_form_alter().
       */
      function vbo_redirect_option_form_alter(&$form, &$form_state, $form_id)
      {
        // VBOの処理かのチェック
          if( isset($form_state['id']) && $form_state['id'] === "views_bulk_operations"){
      
         // ここで、画面遷移先の保存処理は少し反則
         //  vbo_settingsに画面遷移先の追加は難しい(クラス構造体内にあるため)
         //  環境変数に画面遷移先(uri)を保存
              if( isset($form_state['input']['options']['vbo_settings'][vbo_redirect_url]) ){
                  variable_set( 'vbo_redirect_url', $form_state['input']['options']['vbo_settings'][vbo_redirect_url] ) ;
              }
      
         // 画面遷移先のテキストフィールドを追加
              $form['options']['vbo_settings']['vbo_redirect_url'] = array(
                  '#type' => 'textfield',
                  '#title' => t('Page to direct to after completion of  batch'),
                  '#description' => t('Redirects to the view when finished the operation'),
                  '#default_value' => variable_get('vbo_redirect_url'),
              );
          }
      }
    • 画面遷移先を入力するテキストフィールドを設定画面に追加
    • 画面遷移先(uri)をvbo_settingsに入れたいですが、クラスの構造体にあるため追加できません。環境変数に保存することにしました。
    • 設定画面を保存("#submit")後に、画面遷移先を保存する処理を行いたいですが、"#submit"にコールバック関数を入れても、呼び出されない現象があって、仕方がなく、hook_form_alter()内で画面遷移先(uri)の保存処理を行いました
      VBOに一括処理後に画面遷移オプションの追加
  • hook_views_bulk_operations_form_alter()を実装して、実際のVBO一括処理後に、画面遷移設定を行います
    /**
     * Implements hook_views_bulk_operations_form_alter().
     */
    function vbo_redirect_option_views_bulk_operations_form_alter(&$form, &$form_state, $vbo)
    {
        $vbo_redirect_url = trim( variable_get('vbo_redirect_url') ) ;
    
        if( isset($vbo_redirect_url) && strlen($vbo_redirect_url) >0 ){
    
            // check if vbo operation skip confirmation
            $skip_confirmation = false ;
            foreach( $vbo->options['vbo_operations'] as $key => $operation ){
                if( $operation['selected'] && $operation['skip_confirmation'] ){
                    if( isset($form['select'][$key]) ) {
                        $form['select'][$key]['#submit'][] = 'vbo_redirect_after_operation';
                        $skip_confirmation = true ;
                    }
                }
            }
    
            // set redirect method when vbo has confirmation step
            if( !$skip_confirmation ){
                $form['actions']['submit']['#submit'][] = 'vbo_redirect_after_operation' ;
            }
        }
    }
    
    // callback function to set redirect url
    function vbo_redirect_after_operation($form, &$form_state){
        $vbo_redirect_url = trim( variable_get('vbo_redirect_url') ) ;
        $form_state['redirect'] = $vbo_redirect_url;
    }
    • VBO一括処理の「確認のステップをスキップ」があるか、ないかを分けて処理します(画面遷移設定場所が違うため)
    • "#submit"に画面遷移処理を追加します
    • 画面遷移処理は$form_state['redirect'] で行います

結論と感想:簡単のカスタモジュールでVBOへの影響はありません。各オペレーション設定に画面遷移オプションを追加したほうよいかもしれない

  • このカスタムモジュールのインストールより、モジュール(VBO)への影響はありません
  • この画面遷移オプションを「Bulk Operation Settings」に追加したので、すべてのオペレーションに適応されます
    • VBOの一括処理内容がいろいろあります(例:オーナー変更、エンティティ内容変更など)
    • これらの処理後に一つの画面遷移先の設定はやや強引的だと思います
  • できれば、「Selected Bulk Operations」にある、選択したオペレーションの設定に画面遷移先の設定をしたほうが柔軟的な対応だと思います(次回の課題)
    画面遷移オプションを各オペレーションに追加すべき
添付 サイズ
vbo_redirect_option.zip (1.19 KB) 1.19 KB
Embedded thumbnail for Drupalのモジュール(VBO)の一括処理後にページ遷移させる方法
drupal
form
ajax

やりたいこと:Drupalのajaxフレームワークを利用して表示している要素を削除

  • Drupalのモジュール(Views)で作成した一覧の要素を選択して削除します
    • 要素を選択して削除するモジュール:Views Bulk Operations
    • 例:Drupalのモジュール(VBO)の各種処理(Operation)に独自(カスタムオ)のプションの追加方法
  • 前提条件:要素削除する確認の必要はありません
  • ajaxで動的に削除するのはやさしいUIとも言えるでしょう(以下のイメージのように削除)
    Drupalのajaxフレームワークより要素を動的に削除

Step1:削除リンクにDrupalのajax使用するクラス:use-ajax を追加

  • Drupalのajaxフレームワークに関する説明は以下の記事をご参考ください
    • Drupalでajaxのフレームワークが簡単に作成できる
  • 削除アイコン付きのリンクは以下のようです
    // 削除エレメントID:123 (例)
    <a href="/delete/element/id/123/nojs" class="use-ajax del-link" id="del-link-123">
           <i class="fa fa-trash-o" aria-hidden="true"></i>
    </a>
    • アンカー(a)に削除するエレメントID(または別の識別パラメーター)を入れる必要はあります
    • アンカーリンクの後ろに「nojs」を追加します(クライアント側のajax作動時に、nojs->ajaxに変換され)
    • アンカーがクリックされると、Drupalのajaxフレームワークが起動され、削除パラメーターをサイト側に渡します

Step2:hook_menuで要素削除のリクエストをキャッチします

  • hook_menuで要素削除のリクエストを受け取り、削除処理を行います
    // 要素削除URLの設定
    $items['delete/element/%/nojs'] = array(
    	'page callback' => 'delete_element',
    	'page arguments' => array( 2, 3 ) ,
    	'access callback' => 'delete_access',
    	'type' => MENU_CALLBACK,
    );
    // ajaxが以下のURLでリクエストをします(クライアント側でnojs->ajaxに変換)
    $items['delete/element/%/ajax'] = array(
    	'delivery callback' => 'ajax_deliver',
    )+$items['delete/element/%/nojs'] ;    // 要素削除定義に遷移
    
  • 要素削除処理ファンクション:delete_element で削除処理、処理結果をクライアント側に返します
    function delete_element ($id, $ajax){
        $is_ajax = $ajax === "ajax" ;  // ajaxと通用のリクエスト両方対応のため
    
        // 要素をDBから削除
        db_delete("element_table")->condition("entity_id", $id)->execute() ;
    
        // 画面要素も削除コマンドを返す
        if( $is_ajax ){
            // ajaxで要素削除後の処理
            $commands = array();
            $commands[] = ajax_command_remove( '#element-123');
            return array(
              '#type'=>"ajax",
              '#commands' => $commands,
            );
        } else {
            // 通常での要素削除後の処理
            drupal_set_message(t('Deleted 1 vocabulary'));
            drupal_goto();
        }
    }

     

Drupalのajaxフレームワークで要素削除

纏め:Drupalのajaxフレームワークを利用すればajax処理が自動的に行います

  • 上記例では、削除リンクにクラス:use-ajax を追加するだけで、ajax関連処理を記述する必要はあります
    • 削除リンクではなく、削除ボタン(button)要素を使用する場合クラス: use-ajax-submit
  • サーバー側では、hook_menuで削除リンクの定義、削除リクエストをキャッチして、削除処理関数を作成します
    • DB上のデータ削除完了後に、クライアント側の要素削除命令(ajax_command_remove)を返せば良いです
  • この一連のajax処理の記述はほどんとありません。簡単、便利です
drupal
development
ajax

やりたいこと:Drupalのプログラムレベルで簡単にajaxを利用してクライアント側でデータ交信をしたいです

  • 環境:Drupal7.54
  • DrupalのFormAPIで簡単にajaxの実装ができます(Drupalのフォーム(FromAPI)でのajaxの実装 )
  • FormAPIだけではなく、Drupalをカスタマイズ時にいろいろなところでajaxを実装したいことがあります

ポイント1:Drupalでajaxに必要なライブラリをロードし、クライアント側にjquery.form.jsファイルをセット

  • サーバー側でdrupal.ajaxのライブラリをロードする必要があります
  • クライアント側にjquery.form.jsファイルを設置する必要があります
  • この処理はajax処理するページをロード時に行えれば良いです。
    • 例:hook_init()内で処理する
      /**
       * Implements hook_init().
       */
      function YOUR_MODULE_NAME_init()
      {
        drupal_add_js('misc/jquery.form.js');
        drupal_add_library('system','drupal.ajax');
      }
  • クライアント側のブラウザのプロパティでjquery.form.jsがセットされたことの確認ができます

ポイント2:クライアント側のajax起動リンク内にajax対応可否のパラメーター「nojs」とクラス属性「use-ajax」のセット

  • ajaxの起動リンクの作成基本パターン: 
    <a href="text/ajax/nojs/1234" class="use-ajax">ajaxリンク</a>
    • hrefにある「nojs」が決まりの文字
    • hrefにある「1234」はサーバー側に転送したい必要なパラメーター
    • class="use-ajax"はこのリンクがajax用に決める
  • クライアント側のjsで使用しているブラウザがajax対応可能かを判断して、ajax起動リンクに「nojs」のパラメーターを書き換え(利用可能:nojs⇒ajax)てサーバー側に転送
  • サーバー側がajax利用可否よりクライアント側にajax対応有無の結果を返します
    Drupalのajaxフレームワークの利用
  • 上記例のプログラムは以下のようで
    /**
     * Implements hook_init().
     */
    function test_module_init()
    {
      drupal_add_js('misc/jquery.form.js');
      drupal_add_library('system','drupal.ajax');
    }
    
    /**
     *  Implementation of hook_menu()
     */
    function test_module_menu() {
      $items['test/ajax/%/%']=array(     // URLの2,3番目がクライアント側で生成
          'page callback' => 'ajax_node_response',
          'page arguments' => array(2,3),   // URLの2,3番目の引数をコールバック関数に渡す
          'access callback' => 'user_access',
          'access arguments' => array('access content'),
          'type' => MENU_CALLBACK,
      );
      return $items;
    }
    
    function ajax_node_response($type="ajax", $nid=0){
      $node = node_load( $nid, NULL, false );
      $vnode = node_view($node);
      $output = theme('node', $vnode);
      if( $type="ajax" ){
        $commands=array();
        $commands[]=ajax_command_replace( '#block-system-main','<section id="block-system-main">'.$output.'</section>' ) ;
        $page = array(
          '#type' => 'ajax',
          '#commands' => $commands,
        );
        ajax_deliver( $page ) ;   // ajax対応ブラウザの結果
      } else {
        $output = '<div id="content">'.$output.'</div>';  // ajax非対応ブラウザの結果
        return $output;
      }
    }
    

ポイント3:クライアント側で実行させたい部分はajax_commandを使用します

  • クライアント側で処理結果をどこに入り替えはajax_command_replaceで指定します
  • 結果の挿入、入れ替え、削除、css処理などがいろいろあります。詳細は本家のajax_command一覧を参考してください

 

drupal
Views

やりたいこと:モジュール(VBO)の各処理(Operation)に独自(カスタム)オプションを追加したい

  • 前回モジュール(VBO)にたいして処理(Operation)オプション追加を紹介しました
    •  Drupalのモジュール(VBO)の一括処理後にページ遷移させる方法
    • このオプションは全VBOに対して作成したものですが、すべての処理に影響を与えています
  • 各種処理(Operation)に対してどのようにオプションを追加するか前回の課題として残っています
  • 今回はこの課題を解決に新しいカスタムモジュール(vbo_redirect_option)を作成して、紹介します
    モジュールVBOの各種処理に独自のオプション追加

hook_formとCtoolsのdepent systemより各オペレーションに独自のオプションを追加

  • VBOのオペレーション設定フォームがカスタマイズとして開放していないです(前回も説明した)
  • ここで、Drupalのhook_formでVBOのオペレーション設定画面を特定して、カスタムオプション追加することになりました
    function vbo_redirect_option_form_alter(&$form, &$form_state, $form_id)
    {
        if( isset($form_state['id']) && $form_state['id'] === "views_bulk_operations"){
    
            foreach( $form_state['input']['options']['vbo_operations'] as $key => $operation) {
                if( $operation['redirect_check'] && strlen( trim($operation['redirect_url']))>0 ) {
                    variable_set( $key, $operation['redirect_url'] );
                } else {
                    if( !empty( variable_get($key) ) ) variable_del( $key ) ;
                }
            }
    
    
            foreach( $form['options']['vbo_operations'] as $key => &$operation ){
                if( !is_array($operation) ) continue ;
    
                $redirect_url = variable_get($key);
                $dep_key = "edit-options-vbo-operations-" . str_replace("_", "-", str_replace("::","",$key) ) ;
    
                $operation['redirect_check'] = array(
                    '#type' => 'checkbox',
                    '#title' => t('Redirect page to after operation'),
                    '#default_value' =>  $redirect_url ? 1 : 0 ,
                    '#dependency' => array(    // Ctoolsのdependent systemに依存
                        $dep_key."-selected" => array(1),
                    ),
                );
                $operation['redirect_url'] = array(
                    '#type' => 'textfield',
                    '#title' => t('Provide label'),
                    '#title_display' => 'invisible',
                    '#default_value' => empty($redirect_url) ? "" : $redirect_url,
                    '#dependency' => array(    // Ctoolsのdependent systemに依存
                        $dep_key."-selected" => array(1),
                        $dep_key . '-redirect-check' => array(1),
                    ),
                    '#dependency_count' => 2,
                );
            }
        }
    }
    • 設定フォームにチェックボックスをチェックしたら、画面遷移URL入力フィールドが現れるダイナミックフォームはモジュール(Ctools)のdependent systemを利用しています

処理(Operation)確認ステップをスキップがあるかないかを確認してhook_views_bulk_operations_form_alter()実装でオプションの設定を行う

  • VBOの処理(Operation)が確認ステップがあるかないかは2種類あります(この二種類をの処理プロセスが違うのでしっかりテストする必要がある)
  • hook_views_bulk_operations_form_alter()を実装して、各処理ステップにカスタマイズを行います
    function vbo_redirect_option_views_bulk_operations_form_alter(&$form, &$form_state, $vbo)
    {
        // collect all operations that has contained redirect_rul
        $redirect_arr = array();
        foreach( $vbo->options['vbo_operations'] as $key => $operation ) {
            if( !empty( variable_get($key) ) ){
                $redirect_arr[$key] = $key ;
            }
        }
    
        // add redirect step to #submit element
        if(isset($form['select'])) {
    
            // this is the form start step
            foreach( $form['select'] as $key => &$element ){
                if( isset($redirect_arr[$key]) ){
                    // we check if there is any operation has redirect_url
                    $element['#submit'][] = 'vbo_redirect_after_operation';
                    // only one is enough, we will detect witch one in the callback function
                    break;
                }
            }
    
            // do operation with confirmation step
            // this is the confirmation step
        } else if( !$form_state['operation']->getAdminOption('skip_confirmation') ) {
            $form['actions']['submit']['#submit'][] = "vbo_redirect_after_operation_with_confirmation";
            $form_state['redirect_to_after_operation'] = $form_state['operation']->getAdminOption('redirect_url');
        }
    
    }
    
    
    /**
     * callback function that has called by operation
     * this is the form start step, we don't know if it has confirmation step or not
     * @param $form
     * @param $form_state
     */
    function vbo_redirect_after_operation(&$form, &$form_state){
        // the are multiple element can be operated
        // the right one that has be sent to this step
        // we need get redirect_url if the it has
        if( isset($form_state['operation']) ){
            // get redirect_url by operation_id
            $redirec=variable_get($form_state['operation']->operationId) ;
            if( !empty($redirec) ){
                if( $form_state['operation']->getAdminOption('skip_confirmation') ) {
                    $form_state['redirect'] = $redirec;
                }
            }
        }
    }
    
    /**
     * callback function that has be called by operation with confirmation step
     * @param $form
     * @param $form_state
     */
    function vbo_redirect_after_operation_with_confirmation( $form, &$form_state ){
        // there is only operation that has be sent here with the confirmation step
        if( isset($form_state['redirect_to_after_operation']) ){
            // set redirect_url that should be stored in $form_state
            $form_state['redirect'] = $form_state['redir ect_to_after_operation'];
        }
    }

感想と結論:VBOの処理オプション設定はカスタマイズに開放していないため、各種処理(Operation)のオプションの取得、設定に苦労します

  • VBOの処理オプション設定はユーザーにカスタマイズに開放していないです
  • オペレーションの各ステップに$form、$form_state、$vbo変数から必要な情報を取得したり、セットしたりしました
  • 必要な情報がどこにあるかは不明だし(その時dsm($vbo)などで確認)、特定するまでに、時間がかかりました。
添付 サイズ
vbo_redirect_option.zip (1.77 KB) 1.77 KB
Embedded thumbnail for Drupalのモジュール(VBO)の各種処理(Operation)に独自(カスタムオ)のプションの追加方法
drupal
development
Views

Drupalのモジュール(Rules)で作成した各種アクションセットコンポーネントをモジュールVBOで一括処理

  • 背景:Drupal7.x.56、Views Bulk Operation(VBO)7.x-3.4、Rules7.x-2.10
  • モジュール(Rules)がいろいろなアクションセットの作成ができます
    • データの作成/更新/削除
    • メール送信、フラグを立てる
    • などなど
  • モジュール(VBO)がRulesで作成したアクションコンポーネントの利用ができます
    • Drupalのモジュール(Rules)のアクションコンポーネントでVBOより新規ノード作成とフィールドのコピー
  • 今回の例として、Rulesでメッセージ表示する単純なアクションコンポーネント(show message)を作成して、VBOで一括処理を行います
    Rulesでメッセージ表示コンポーネントをVBOで一括処理

問題点:VBO一括処理後に画面遷移(redirect)はできません

  • VBOで一括処理後に、画面を遷移して処理結果を確認することがあります
  • VBOの設定オプションに、処理後の画面遷移設定がありません
  • ネットで調べてみたが、VBO一括処理後の画面遷移オプション追加パッチがります
    • これは、モジュールVBOに対するパッチです
    • このパッチ適応したら、次回VBOアップグレード時に、ソースのマージ作業が面だと思います
    • できれば、VBOのパッチを使用したくないです

解決:カスタムモジュール(vbo_redirect_option.zip)でVBO処理後の画面遷移オプションの追加

  • モジュール(VBO)の主要部分がクラス(class)構造なので、簡単に画面遷移ロジックを追加することはできません
  • 「Bulk Operation Settings」に処理後の画面遷移オプションを追加します
    • 「Bulk Operation Settings」のオーバーライドができないので、hook_form_alter()でオプションを追加することになりました
      /**
       * Implements hook_form_alter().
       */
      function vbo_redirect_option_form_alter(&$form, &$form_state, $form_id)
      {
        // VBOの処理かのチェック
          if( isset($form_state['id']) && $form_state['id'] === "views_bulk_operations"){
      
         // ここで、画面遷移先の保存処理は少し反則
         //  vbo_settingsに画面遷移先の追加は難しい(クラス構造体内にあるため)
         //  環境変数に画面遷移先(uri)を保存
              if( isset($form_state['input']['options']['vbo_settings'][vbo_redirect_url]) ){
                  variable_set( 'vbo_redirect_url', $form_state['input']['options']['vbo_settings'][vbo_redirect_url] ) ;
              }
      
         // 画面遷移先のテキストフィールドを追加
              $form['options']['vbo_settings']['vbo_redirect_url'] = array(
                  '#type' => 'textfield',
                  '#title' => t('Page to direct to after completion of  batch'),
                  '#description' => t('Redirects to the view when finished the operation'),
                  '#default_value' => variable_get('vbo_redirect_url'),
              );
          }
      }
    • 画面遷移先を入力するテキストフィールドを設定画面に追加
    • 画面遷移先(uri)をvbo_settingsに入れたいですが、クラスの構造体にあるため追加できません。環境変数に保存することにしました。
    • 設定画面を保存("#submit")後に、画面遷移先を保存する処理を行いたいですが、"#submit"にコールバック関数を入れても、呼び出されない現象があって、仕方がなく、hook_form_alter()内で画面遷移先(uri)の保存処理を行いました
      VBOに一括処理後に画面遷移オプションの追加
  • hook_views_bulk_operations_form_alter()を実装して、実際のVBO一括処理後に、画面遷移設定を行います
    /**
     * Implements hook_views_bulk_operations_form_alter().
     */
    function vbo_redirect_option_views_bulk_operations_form_alter(&$form, &$form_state, $vbo)
    {
        $vbo_redirect_url = trim( variable_get('vbo_redirect_url') ) ;
    
        if( isset($vbo_redirect_url) && strlen($vbo_redirect_url) >0 ){
    
            // check if vbo operation skip confirmation
            $skip_confirmation = false ;
            foreach( $vbo->options['vbo_operations'] as $key => $operation ){
                if( $operation['selected'] && $operation['skip_confirmation'] ){
                    if( isset($form['select'][$key]) ) {
                        $form['select'][$key]['#submit'][] = 'vbo_redirect_after_operation';
                        $skip_confirmation = true ;
                    }
                }
            }
    
            // set redirect method when vbo has confirmation step
            if( !$skip_confirmation ){
                $form['actions']['submit']['#submit'][] = 'vbo_redirect_after_operation' ;
            }
        }
    }
    
    // callback function to set redirect url
    function vbo_redirect_after_operation($form, &$form_state){
        $vbo_redirect_url = trim( variable_get('vbo_redirect_url') ) ;
        $form_state['redirect'] = $vbo_redirect_url;
    }
    • VBO一括処理の「確認のステップをスキップ」があるか、ないかを分けて処理します(画面遷移設定場所が違うため)
    • "#submit"に画面遷移処理を追加します
    • 画面遷移処理は$form_state['redirect'] で行います

結論と感想:簡単のカスタモジュールでVBOへの影響はありません。各オペレーション設定に画面遷移オプションを追加したほうよいかもしれない

  • このカスタムモジュールのインストールより、モジュール(VBO)への影響はありません
  • この画面遷移オプションを「Bulk Operation Settings」に追加したので、すべてのオペレーションに適応されます
    • VBOの一括処理内容がいろいろあります(例:オーナー変更、エンティティ内容変更など)
    • これらの処理後に一つの画面遷移先の設定はやや強引的だと思います
  • できれば、「Selected Bulk Operations」にある、選択したオペレーションの設定に画面遷移先の設定をしたほうが柔軟的な対応だと思います(次回の課題)
    画面遷移オプションを各オペレーションに追加すべき
添付 サイズ
vbo_redirect_option.zip (1.19 KB) 1.19 KB
Embedded thumbnail for Drupalのモジュール(VBO)の一括処理後にページ遷移させる方法
drupal
form
ajax

やりたいこと:Drupalのajaxフレームワークを利用して表示している要素を削除

  • Drupalのモジュール(Views)で作成した一覧の要素を選択して削除します
    • 要素を選択して削除するモジュール:Views Bulk Operations
    • 例:Drupalのモジュール(VBO)の各種処理(Operation)に独自(カスタムオ)のプションの追加方法
  • 前提条件:要素削除する確認の必要はありません
  • ajaxで動的に削除するのはやさしいUIとも言えるでしょう(以下のイメージのように削除)
    Drupalのajaxフレームワークより要素を動的に削除

Step1:削除リンクにDrupalのajax使用するクラス:use-ajax を追加

  • Drupalのajaxフレームワークに関する説明は以下の記事をご参考ください
    • Drupalでajaxのフレームワークが簡単に作成できる
  • 削除アイコン付きのリンクは以下のようです
    // 削除エレメントID:123 (例)
    <a href="/delete/element/id/123/nojs" class="use-ajax del-link" id="del-link-123">
           <i class="fa fa-trash-o" aria-hidden="true"></i>
    </a>
    • アンカー(a)に削除するエレメントID(または別の識別パラメーター)を入れる必要はあります
    • アンカーリンクの後ろに「nojs」を追加します(クライアント側のajax作動時に、nojs->ajaxに変換され)
    • アンカーがクリックされると、Drupalのajaxフレームワークが起動され、削除パラメーターをサイト側に渡します

Step2:hook_menuで要素削除のリクエストをキャッチします

  • hook_menuで要素削除のリクエストを受け取り、削除処理を行います
    // 要素削除URLの設定
    $items['delete/element/%/nojs'] = array(
    	'page callback' => 'delete_element',
    	'page arguments' => array( 2, 3 ) ,
    	'access callback' => 'delete_access',
    	'type' => MENU_CALLBACK,
    );
    // ajaxが以下のURLでリクエストをします(クライアント側でnojs->ajaxに変換)
    $items['delete/element/%/ajax'] = array(
    	'delivery callback' => 'ajax_deliver',
    )+$items['delete/element/%/nojs'] ;    // 要素削除定義に遷移
    
  • 要素削除処理ファンクション:delete_element で削除処理、処理結果をクライアント側に返します
    function delete_element ($id, $ajax){
        $is_ajax = $ajax === "ajax" ;  // ajaxと通用のリクエスト両方対応のため
    
        // 要素をDBから削除
        db_delete("element_table")->condition("entity_id", $id)->execute() ;
    
        // 画面要素も削除コマンドを返す
        if( $is_ajax ){
            // ajaxで要素削除後の処理
            $commands = array();
            $commands[] = ajax_command_remove( '#element-123');
            return array(
              '#type'=>"ajax",
              '#commands' => $commands,
            );
        } else {
            // 通常での要素削除後の処理
            drupal_set_message(t('Deleted 1 vocabulary'));
            drupal_goto();
        }
    }

     

Drupalのajaxフレームワークで要素削除

纏め:Drupalのajaxフレームワークを利用すればajax処理が自動的に行います

  • 上記例では、削除リンクにクラス:use-ajax を追加するだけで、ajax関連処理を記述する必要はあります
    • 削除リンクではなく、削除ボタン(button)要素を使用する場合クラス: use-ajax-submit
  • サーバー側では、hook_menuで削除リンクの定義、削除リクエストをキャッチして、削除処理関数を作成します
    • DB上のデータ削除完了後に、クライアント側の要素削除命令(ajax_command_remove)を返せば良いです
  • この一連のajax処理の記述はほどんとありません。簡単、便利です
drupal
development
ajax

やりたいこと:Drupalのプログラムレベルで簡単にajaxを利用してクライアント側でデータ交信をしたいです

  • 環境:Drupal7.54
  • DrupalのFormAPIで簡単にajaxの実装ができます(Drupalのフォーム(FromAPI)でのajaxの実装 )
  • FormAPIだけではなく、Drupalをカスタマイズ時にいろいろなところでajaxを実装したいことがあります

ポイント1:Drupalでajaxに必要なライブラリをロードし、クライアント側にjquery.form.jsファイルをセット

  • サーバー側でdrupal.ajaxのライブラリをロードする必要があります
  • クライアント側にjquery.form.jsファイルを設置する必要があります
  • この処理はajax処理するページをロード時に行えれば良いです。
    • 例:hook_init()内で処理する
      /**
       * Implements hook_init().
       */
      function YOUR_MODULE_NAME_init()
      {
        drupal_add_js('misc/jquery.form.js');
        drupal_add_library('system','drupal.ajax');
      }
  • クライアント側のブラウザのプロパティでjquery.form.jsがセットされたことの確認ができます

ポイント2:クライアント側のajax起動リンク内にajax対応可否のパラメーター「nojs」とクラス属性「use-ajax」のセット

  • ajaxの起動リンクの作成基本パターン: 
    <a href="text/ajax/nojs/1234" class="use-ajax">ajaxリンク</a>
    • hrefにある「nojs」が決まりの文字
    • hrefにある「1234」はサーバー側に転送したい必要なパラメーター
    • class="use-ajax"はこのリンクがajax用に決める
  • クライアント側のjsで使用しているブラウザがajax対応可能かを判断して、ajax起動リンクに「nojs」のパラメーターを書き換え(利用可能:nojs⇒ajax)てサーバー側に転送
  • サーバー側がajax利用可否よりクライアント側にajax対応有無の結果を返します
    Drupalのajaxフレームワークの利用
  • 上記例のプログラムは以下のようで
    /**
     * Implements hook_init().
     */
    function test_module_init()
    {
      drupal_add_js('misc/jquery.form.js');
      drupal_add_library('system','drupal.ajax');
    }
    
    /**
     *  Implementation of hook_menu()
     */
    function test_module_menu() {
      $items['test/ajax/%/%']=array(     // URLの2,3番目がクライアント側で生成
          'page callback' => 'ajax_node_response',
          'page arguments' => array(2,3),   // URLの2,3番目の引数をコールバック関数に渡す
          'access callback' => 'user_access',
          'access arguments' => array('access content'),
          'type' => MENU_CALLBACK,
      );
      return $items;
    }
    
    function ajax_node_response($type="ajax", $nid=0){
      $node = node_load( $nid, NULL, false );
      $vnode = node_view($node);
      $output = theme('node', $vnode);
      if( $type="ajax" ){
        $commands=array();
        $commands[]=ajax_command_replace( '#block-system-main','<section id="block-system-main">'.$output.'</section>' ) ;
        $page = array(
          '#type' => 'ajax',
          '#commands' => $commands,
        );
        ajax_deliver( $page ) ;   // ajax対応ブラウザの結果
      } else {
        $output = '<div id="content">'.$output.'</div>';  // ajax非対応ブラウザの結果
        return $output;
      }
    }
    

ポイント3:クライアント側で実行させたい部分はajax_commandを使用します

  • クライアント側で処理結果をどこに入り替えはajax_command_replaceで指定します
  • 結果の挿入、入れ替え、削除、css処理などがいろいろあります。詳細は本家のajax_command一覧を参考してください

 

drupal
Views

やりたいこと:モジュール(VBO)の各処理(Operation)に独自(カスタム)オプションを追加したい

  • 前回モジュール(VBO)にたいして処理(Operation)オプション追加を紹介しました
    •  Drupalのモジュール(VBO)の一括処理後にページ遷移させる方法
    • このオプションは全VBOに対して作成したものですが、すべての処理に影響を与えています
  • 各種処理(Operation)に対してどのようにオプションを追加するか前回の課題として残っています
  • 今回はこの課題を解決に新しいカスタムモジュール(vbo_redirect_option)を作成して、紹介します
    モジュールVBOの各種処理に独自のオプション追加

hook_formとCtoolsのdepent systemより各オペレーションに独自のオプションを追加

  • VBOのオペレーション設定フォームがカスタマイズとして開放していないです(前回も説明した)
  • ここで、Drupalのhook_formでVBOのオペレーション設定画面を特定して、カスタムオプション追加することになりました
    function vbo_redirect_option_form_alter(&$form, &$form_state, $form_id)
    {
        if( isset($form_state['id']) && $form_state['id'] === "views_bulk_operations"){
    
            foreach( $form_state['input']['options']['vbo_operations'] as $key => $operation) {
                if( $operation['redirect_check'] && strlen( trim($operation['redirect_url']))>0 ) {
                    variable_set( $key, $operation['redirect_url'] );
                } else {
                    if( !empty( variable_get($key) ) ) variable_del( $key ) ;
                }
            }
    
    
            foreach( $form['options']['vbo_operations'] as $key => &$operation ){
                if( !is_array($operation) ) continue ;
    
                $redirect_url = variable_get($key);
                $dep_key = "edit-options-vbo-operations-" . str_replace("_", "-", str_replace("::","",$key) ) ;
    
                $operation['redirect_check'] = array(
                    '#type' => 'checkbox',
                    '#title' => t('Redirect page to after operation'),
                    '#default_value' =>  $redirect_url ? 1 : 0 ,
                    '#dependency' => array(    // Ctoolsのdependent systemに依存
                        $dep_key."-selected" => array(1),
                    ),
                );
                $operation['redirect_url'] = array(
                    '#type' => 'textfield',
                    '#title' => t('Provide label'),
                    '#title_display' => 'invisible',
                    '#default_value' => empty($redirect_url) ? "" : $redirect_url,
                    '#dependency' => array(    // Ctoolsのdependent systemに依存
                        $dep_key."-selected" => array(1),
                        $dep_key . '-redirect-check' => array(1),
                    ),
                    '#dependency_count' => 2,
                );
            }
        }
    }
    • 設定フォームにチェックボックスをチェックしたら、画面遷移URL入力フィールドが現れるダイナミックフォームはモジュール(Ctools)のdependent systemを利用しています

処理(Operation)確認ステップをスキップがあるかないかを確認してhook_views_bulk_operations_form_alter()実装でオプションの設定を行う

  • VBOの処理(Operation)が確認ステップがあるかないかは2種類あります(この二種類をの処理プロセスが違うのでしっかりテストする必要がある)
  • hook_views_bulk_operations_form_alter()を実装して、各処理ステップにカスタマイズを行います
    function vbo_redirect_option_views_bulk_operations_form_alter(&$form, &$form_state, $vbo)
    {
        // collect all operations that has contained redirect_rul
        $redirect_arr = array();
        foreach( $vbo->options['vbo_operations'] as $key => $operation ) {
            if( !empty( variable_get($key) ) ){
                $redirect_arr[$key] = $key ;
            }
        }
    
        // add redirect step to #submit element
        if(isset($form['select'])) {
    
            // this is the form start step
            foreach( $form['select'] as $key => &$element ){
                if( isset($redirect_arr[$key]) ){
                    // we check if there is any operation has redirect_url
                    $element['#submit'][] = 'vbo_redirect_after_operation';
                    // only one is enough, we will detect witch one in the callback function
                    break;
                }
            }
    
            // do operation with confirmation step
            // this is the confirmation step
        } else if( !$form_state['operation']->getAdminOption('skip_confirmation') ) {
            $form['actions']['submit']['#submit'][] = "vbo_redirect_after_operation_with_confirmation";
            $form_state['redirect_to_after_operation'] = $form_state['operation']->getAdminOption('redirect_url');
        }
    
    }
    
    
    /**
     * callback function that has called by operation
     * this is the form start step, we don't know if it has confirmation step or not
     * @param $form
     * @param $form_state
     */
    function vbo_redirect_after_operation(&$form, &$form_state){
        // the are multiple element can be operated
        // the right one that has be sent to this step
        // we need get redirect_url if the it has
        if( isset($form_state['operation']) ){
            // get redirect_url by operation_id
            $redirec=variable_get($form_state['operation']->operationId) ;
            if( !empty($redirec) ){
                if( $form_state['operation']->getAdminOption('skip_confirmation') ) {
                    $form_state['redirect'] = $redirec;
                }
            }
        }
    }
    
    /**
     * callback function that has be called by operation with confirmation step
     * @param $form
     * @param $form_state
     */
    function vbo_redirect_after_operation_with_confirmation( $form, &$form_state ){
        // there is only operation that has be sent here with the confirmation step
        if( isset($form_state['redirect_to_after_operation']) ){
            // set redirect_url that should be stored in $form_state
            $form_state['redirect'] = $form_state['redir ect_to_after_operation'];
        }
    }

感想と結論:VBOの処理オプション設定はカスタマイズに開放していないため、各種処理(Operation)のオプションの取得、設定に苦労します

  • VBOの処理オプション設定はユーザーにカスタマイズに開放していないです
  • オペレーションの各ステップに$form、$form_state、$vbo変数から必要な情報を取得したり、セットしたりしました
  • 必要な情報がどこにあるかは不明だし(その時dsm($vbo)などで確認)、特定するまでに、時間がかかりました。
添付 サイズ
vbo_redirect_option.zip (1.77 KB) 1.77 KB
Embedded thumbnail for Drupalのモジュール(VBO)の各種処理(Operation)に独自(カスタムオ)のプションの追加方法
drupal
development
Views

Drupalのモジュール(Rules)で作成した各種アクションセットコンポーネントをモジュールVBOで一括処理

  • 背景:Drupal7.x.56、Views Bulk Operation(VBO)7.x-3.4、Rules7.x-2.10
  • モジュール(Rules)がいろいろなアクションセットの作成ができます
    • データの作成/更新/削除
    • メール送信、フラグを立てる
    • などなど
  • モジュール(VBO)がRulesで作成したアクションコンポーネントの利用ができます
    • Drupalのモジュール(Rules)のアクションコンポーネントでVBOより新規ノード作成とフィールドのコピー
  • 今回の例として、Rulesでメッセージ表示する単純なアクションコンポーネント(show message)を作成して、VBOで一括処理を行います
    Rulesでメッセージ表示コンポーネントをVBOで一括処理

問題点:VBO一括処理後に画面遷移(redirect)はできません

  • VBOで一括処理後に、画面を遷移して処理結果を確認することがあります
  • VBOの設定オプションに、処理後の画面遷移設定がありません
  • ネットで調べてみたが、VBO一括処理後の画面遷移オプション追加パッチがります
    • これは、モジュールVBOに対するパッチです
    • このパッチ適応したら、次回VBOアップグレード時に、ソースのマージ作業が面だと思います
    • できれば、VBOのパッチを使用したくないです

解決:カスタムモジュール(vbo_redirect_option.zip)でVBO処理後の画面遷移オプションの追加

  • モジュール(VBO)の主要部分がクラス(class)構造なので、簡単に画面遷移ロジックを追加することはできません
  • 「Bulk Operation Settings」に処理後の画面遷移オプションを追加します
    • 「Bulk Operation Settings」のオーバーライドができないので、hook_form_alter()でオプションを追加することになりました
      /**
       * Implements hook_form_alter().
       */
      function vbo_redirect_option_form_alter(&$form, &$form_state, $form_id)
      {
        // VBOの処理かのチェック
          if( isset($form_state['id']) && $form_state['id'] === "views_bulk_operations"){
      
         // ここで、画面遷移先の保存処理は少し反則
         //  vbo_settingsに画面遷移先の追加は難しい(クラス構造体内にあるため)
         //  環境変数に画面遷移先(uri)を保存
              if( isset($form_state['input']['options']['vbo_settings'][vbo_redirect_url]) ){
                  variable_set( 'vbo_redirect_url', $form_state['input']['options']['vbo_settings'][vbo_redirect_url] ) ;
              }
      
         // 画面遷移先のテキストフィールドを追加
              $form['options']['vbo_settings']['vbo_redirect_url'] = array(
                  '#type' => 'textfield',
                  '#title' => t('Page to direct to after completion of  batch'),
                  '#description' => t('Redirects to the view when finished the operation'),
                  '#default_value' => variable_get('vbo_redirect_url'),
              );
          }
      }
    • 画面遷移先を入力するテキストフィールドを設定画面に追加
    • 画面遷移先(uri)をvbo_settingsに入れたいですが、クラスの構造体にあるため追加できません。環境変数に保存することにしました。
    • 設定画面を保存("#submit")後に、画面遷移先を保存する処理を行いたいですが、"#submit"にコールバック関数を入れても、呼び出されない現象があって、仕方がなく、hook_form_alter()内で画面遷移先(uri)の保存処理を行いました
      VBOに一括処理後に画面遷移オプションの追加
  • hook_views_bulk_operations_form_alter()を実装して、実際のVBO一括処理後に、画面遷移設定を行います
    /**
     * Implements hook_views_bulk_operations_form_alter().
     */
    function vbo_redirect_option_views_bulk_operations_form_alter(&$form, &$form_state, $vbo)
    {
        $vbo_redirect_url = trim( variable_get('vbo_redirect_url') ) ;
    
        if( isset($vbo_redirect_url) && strlen($vbo_redirect_url) >0 ){
    
            // check if vbo operation skip confirmation
            $skip_confirmation = false ;
            foreach( $vbo->options['vbo_operations'] as $key => $operation ){
                if( $operation['selected'] && $operation['skip_confirmation'] ){
                    if( isset($form['select'][$key]) ) {
                        $form['select'][$key]['#submit'][] = 'vbo_redirect_after_operation';
                        $skip_confirmation = true ;
                    }
                }
            }
    
            // set redirect method when vbo has confirmation step
            if( !$skip_confirmation ){
                $form['actions']['submit']['#submit'][] = 'vbo_redirect_after_operation' ;
            }
        }
    }
    
    // callback function to set redirect url
    function vbo_redirect_after_operation($form, &$form_state){
        $vbo_redirect_url = trim( variable_get('vbo_redirect_url') ) ;
        $form_state['redirect'] = $vbo_redirect_url;
    }
    • VBO一括処理の「確認のステップをスキップ」があるか、ないかを分けて処理します(画面遷移設定場所が違うため)
    • "#submit"に画面遷移処理を追加します
    • 画面遷移処理は$form_state['redirect'] で行います

結論と感想:簡単のカスタモジュールでVBOへの影響はありません。各オペレーション設定に画面遷移オプションを追加したほうよいかもしれない

  • このカスタムモジュールのインストールより、モジュール(VBO)への影響はありません
  • この画面遷移オプションを「Bulk Operation Settings」に追加したので、すべてのオペレーションに適応されます
    • VBOの一括処理内容がいろいろあります(例:オーナー変更、エンティティ内容変更など)
    • これらの処理後に一つの画面遷移先の設定はやや強引的だと思います
  • できれば、「Selected Bulk Operations」にある、選択したオペレーションの設定に画面遷移先の設定をしたほうが柔軟的な対応だと思います(次回の課題)
    画面遷移オプションを各オペレーションに追加すべき
添付 サイズ
vbo_redirect_option.zip (1.19 KB) 1.19 KB
Embedded thumbnail for Drupalのモジュール(VBO)の一括処理後にページ遷移させる方法
drupal
form
ajax

やりたいこと:Drupalのajaxフレームワークを利用して表示している要素を削除

  • Drupalのモジュール(Views)で作成した一覧の要素を選択して削除します
    • 要素を選択して削除するモジュール:Views Bulk Operations
    • 例:Drupalのモジュール(VBO)の各種処理(Operation)に独自(カスタムオ)のプションの追加方法
  • 前提条件:要素削除する確認の必要はありません
  • ajaxで動的に削除するのはやさしいUIとも言えるでしょう(以下のイメージのように削除)
    Drupalのajaxフレームワークより要素を動的に削除

Step1:削除リンクにDrupalのajax使用するクラス:use-ajax を追加

  • Drupalのajaxフレームワークに関する説明は以下の記事をご参考ください
    • Drupalでajaxのフレームワークが簡単に作成できる
  • 削除アイコン付きのリンクは以下のようです
    // 削除エレメントID:123 (例)
    <a href="/delete/element/id/123/nojs" class="use-ajax del-link" id="del-link-123">
           <i class="fa fa-trash-o" aria-hidden="true"></i>
    </a>
    • アンカー(a)に削除するエレメントID(または別の識別パラメーター)を入れる必要はあります
    • アンカーリンクの後ろに「nojs」を追加します(クライアント側のajax作動時に、nojs->ajaxに変換され)
    • アンカーがクリックされると、Drupalのajaxフレームワークが起動され、削除パラメーターをサイト側に渡します

Step2:hook_menuで要素削除のリクエストをキャッチします

  • hook_menuで要素削除のリクエストを受け取り、削除処理を行います
    // 要素削除URLの設定
    $items['delete/element/%/nojs'] = array(
    	'page callback' => 'delete_element',
    	'page arguments' => array( 2, 3 ) ,
    	'access callback' => 'delete_access',
    	'type' => MENU_CALLBACK,
    );
    // ajaxが以下のURLでリクエストをします(クライアント側でnojs->ajaxに変換)
    $items['delete/element/%/ajax'] = array(
    	'delivery callback' => 'ajax_deliver',
    )+$items['delete/element/%/nojs'] ;    // 要素削除定義に遷移
    
  • 要素削除処理ファンクション:delete_element で削除処理、処理結果をクライアント側に返します
    function delete_element ($id, $ajax){
        $is_ajax = $ajax === "ajax" ;  // ajaxと通用のリクエスト両方対応のため
    
        // 要素をDBから削除
        db_delete("element_table")->condition("entity_id", $id)->execute() ;
    
        // 画面要素も削除コマンドを返す
        if( $is_ajax ){
            // ajaxで要素削除後の処理
            $commands = array();
            $commands[] = ajax_command_remove( '#element-123');
            return array(
              '#type'=>"ajax",
              '#commands' => $commands,
            );
        } else {
            // 通常での要素削除後の処理
            drupal_set_message(t('Deleted 1 vocabulary'));
            drupal_goto();
        }
    }

     

Drupalのajaxフレームワークで要素削除

纏め:Drupalのajaxフレームワークを利用すればajax処理が自動的に行います

  • 上記例では、削除リンクにクラス:use-ajax を追加するだけで、ajax関連処理を記述する必要はあります
    • 削除リンクではなく、削除ボタン(button)要素を使用する場合クラス: use-ajax-submit
  • サーバー側では、hook_menuで削除リンクの定義、削除リクエストをキャッチして、削除処理関数を作成します
    • DB上のデータ削除完了後に、クライアント側の要素削除命令(ajax_command_remove)を返せば良いです
  • この一連のajax処理の記述はほどんとありません。簡単、便利です
drupal
development
ajax

やりたいこと:Drupalのプログラムレベルで簡単にajaxを利用してクライアント側でデータ交信をしたいです

  • 環境:Drupal7.54
  • DrupalのFormAPIで簡単にajaxの実装ができます(Drupalのフォーム(FromAPI)でのajaxの実装 )
  • FormAPIだけではなく、Drupalをカスタマイズ時にいろいろなところでajaxを実装したいことがあります

ポイント1:Drupalでajaxに必要なライブラリをロードし、クライアント側にjquery.form.jsファイルをセット

  • サーバー側でdrupal.ajaxのライブラリをロードする必要があります
  • クライアント側にjquery.form.jsファイルを設置する必要があります
  • この処理はajax処理するページをロード時に行えれば良いです。
    • 例:hook_init()内で処理する
      /**
       * Implements hook_init().
       */
      function YOUR_MODULE_NAME_init()
      {
        drupal_add_js('misc/jquery.form.js');
        drupal_add_library('system','drupal.ajax');
      }
  • クライアント側のブラウザのプロパティでjquery.form.jsがセットされたことの確認ができます

ポイント2:クライアント側のajax起動リンク内にajax対応可否のパラメーター「nojs」とクラス属性「use-ajax」のセット

  • ajaxの起動リンクの作成基本パターン: 
    <a href="text/ajax/nojs/1234" class="use-ajax">ajaxリンク</a>
    • hrefにある「nojs」が決まりの文字
    • hrefにある「1234」はサーバー側に転送したい必要なパラメーター
    • class="use-ajax"はこのリンクがajax用に決める
  • クライアント側のjsで使用しているブラウザがajax対応可能かを判断して、ajax起動リンクに「nojs」のパラメーターを書き換え(利用可能:nojs⇒ajax)てサーバー側に転送
  • サーバー側がajax利用可否よりクライアント側にajax対応有無の結果を返します
    Drupalのajaxフレームワークの利用
  • 上記例のプログラムは以下のようで
    /**
     * Implements hook_init().
     */
    function test_module_init()
    {
      drupal_add_js('misc/jquery.form.js');
      drupal_add_library('system','drupal.ajax');
    }
    
    /**
     *  Implementation of hook_menu()
     */
    function test_module_menu() {
      $items['test/ajax/%/%']=array(     // URLの2,3番目がクライアント側で生成
          'page callback' => 'ajax_node_response',
          'page arguments' => array(2,3),   // URLの2,3番目の引数をコールバック関数に渡す
          'access callback' => 'user_access',
          'access arguments' => array('access content'),
          'type' => MENU_CALLBACK,
      );
      return $items;
    }
    
    function ajax_node_response($type="ajax", $nid=0){
      $node = node_load( $nid, NULL, false );
      $vnode = node_view($node);
      $output = theme('node', $vnode);
      if( $type="ajax" ){
        $commands=array();
        $commands[]=ajax_command_replace( '#block-system-main','<section id="block-system-main">'.$output.'</section>' ) ;
        $page = array(
          '#type' => 'ajax',
          '#commands' => $commands,
        );
        ajax_deliver( $page ) ;   // ajax対応ブラウザの結果
      } else {
        $output = '<div id="content">'.$output.'</div>';  // ajax非対応ブラウザの結果
        return $output;
      }
    }
    

ポイント3:クライアント側で実行させたい部分はajax_commandを使用します

  • クライアント側で処理結果をどこに入り替えはajax_command_replaceで指定します
  • 結果の挿入、入れ替え、削除、css処理などがいろいろあります。詳細は本家のajax_command一覧を参考してください

 

drupal
Views

やりたいこと:モジュール(VBO)の各処理(Operation)に独自(カスタム)オプションを追加したい

  • 前回モジュール(VBO)にたいして処理(Operation)オプション追加を紹介しました
    •  Drupalのモジュール(VBO)の一括処理後にページ遷移させる方法
    • このオプションは全VBOに対して作成したものですが、すべての処理に影響を与えています
  • 各種処理(Operation)に対してどのようにオプションを追加するか前回の課題として残っています
  • 今回はこの課題を解決に新しいカスタムモジュール(vbo_redirect_option)を作成して、紹介します
    モジュールVBOの各種処理に独自のオプション追加

hook_formとCtoolsのdepent systemより各オペレーションに独自のオプションを追加

  • VBOのオペレーション設定フォームがカスタマイズとして開放していないです(前回も説明した)
  • ここで、Drupalのhook_formでVBOのオペレーション設定画面を特定して、カスタムオプション追加することになりました
    function vbo_redirect_option_form_alter(&$form, &$form_state, $form_id)
    {
        if( isset($form_state['id']) && $form_state['id'] === "views_bulk_operations"){
    
            foreach( $form_state['input']['options']['vbo_operations'] as $key => $operation) {
                if( $operation['redirect_check'] && strlen( trim($operation['redirect_url']))>0 ) {
                    variable_set( $key, $operation['redirect_url'] );
                } else {
                    if( !empty( variable_get($key) ) ) variable_del( $key ) ;
                }
            }
    
    
            foreach( $form['options']['vbo_operations'] as $key => &$operation ){
                if( !is_array($operation) ) continue ;
    
                $redirect_url = variable_get($key);
                $dep_key = "edit-options-vbo-operations-" . str_replace("_", "-", str_replace("::","",$key) ) ;
    
                $operation['redirect_check'] = array(
                    '#type' => 'checkbox',
                    '#title' => t('Redirect page to after operation'),
                    '#default_value' =>  $redirect_url ? 1 : 0 ,
                    '#dependency' => array(    // Ctoolsのdependent systemに依存
                        $dep_key."-selected" => array(1),
                    ),
                );
                $operation['redirect_url'] = array(
                    '#type' => 'textfield',
                    '#title' => t('Provide label'),
                    '#title_display' => 'invisible',
                    '#default_value' => empty($redirect_url) ? "" : $redirect_url,
                    '#dependency' => array(    // Ctoolsのdependent systemに依存
                        $dep_key."-selected" => array(1),
                        $dep_key . '-redirect-check' => array(1),
                    ),
                    '#dependency_count' => 2,
                );
            }
        }
    }
    • 設定フォームにチェックボックスをチェックしたら、画面遷移URL入力フィールドが現れるダイナミックフォームはモジュール(Ctools)のdependent systemを利用しています

処理(Operation)確認ステップをスキップがあるかないかを確認してhook_views_bulk_operations_form_alter()実装でオプションの設定を行う

  • VBOの処理(Operation)が確認ステップがあるかないかは2種類あります(この二種類をの処理プロセスが違うのでしっかりテストする必要がある)
  • hook_views_bulk_operations_form_alter()を実装して、各処理ステップにカスタマイズを行います
    function vbo_redirect_option_views_bulk_operations_form_alter(&$form, &$form_state, $vbo)
    {
        // collect all operations that has contained redirect_rul
        $redirect_arr = array();
        foreach( $vbo->options['vbo_operations'] as $key => $operation ) {
            if( !empty( variable_get($key) ) ){
                $redirect_arr[$key] = $key ;
            }
        }
    
        // add redirect step to #submit element
        if(isset($form['select'])) {
    
            // this is the form start step
            foreach( $form['select'] as $key => &$element ){
                if( isset($redirect_arr[$key]) ){
                    // we check if there is any operation has redirect_url
                    $element['#submit'][] = 'vbo_redirect_after_operation';
                    // only one is enough, we will detect witch one in the callback function
                    break;
                }
            }
    
            // do operation with confirmation step
            // this is the confirmation step
        } else if( !$form_state['operation']->getAdminOption('skip_confirmation') ) {
            $form['actions']['submit']['#submit'][] = "vbo_redirect_after_operation_with_confirmation";
            $form_state['redirect_to_after_operation'] = $form_state['operation']->getAdminOption('redirect_url');
        }
    
    }
    
    
    /**
     * callback function that has called by operation
     * this is the form start step, we don't know if it has confirmation step or not
     * @param $form
     * @param $form_state
     */
    function vbo_redirect_after_operation(&$form, &$form_state){
        // the are multiple element can be operated
        // the right one that has be sent to this step
        // we need get redirect_url if the it has
        if( isset($form_state['operation']) ){
            // get redirect_url by operation_id
            $redirec=variable_get($form_state['operation']->operationId) ;
            if( !empty($redirec) ){
                if( $form_state['operation']->getAdminOption('skip_confirmation') ) {
                    $form_state['redirect'] = $redirec;
                }
            }
        }
    }
    
    /**
     * callback function that has be called by operation with confirmation step
     * @param $form
     * @param $form_state
     */
    function vbo_redirect_after_operation_with_confirmation( $form, &$form_state ){
        // there is only operation that has be sent here with the confirmation step
        if( isset($form_state['redirect_to_after_operation']) ){
            // set redirect_url that should be stored in $form_state
            $form_state['redirect'] = $form_state['redir ect_to_after_operation'];
        }
    }

感想と結論:VBOの処理オプション設定はカスタマイズに開放していないため、各種処理(Operation)のオプションの取得、設定に苦労します

  • VBOの処理オプション設定はユーザーにカスタマイズに開放していないです
  • オペレーションの各ステップに$form、$form_state、$vbo変数から必要な情報を取得したり、セットしたりしました
  • 必要な情報がどこにあるかは不明だし(その時dsm($vbo)などで確認)、特定するまでに、時間がかかりました。
添付 サイズ
vbo_redirect_option.zip (1.77 KB) 1.77 KB
Embedded thumbnail for Drupalのモジュール(VBO)の各種処理(Operation)に独自(カスタムオ)のプションの追加方法
drupal
development
Views

Drupalのモジュール(Rules)で作成した各種アクションセットコンポーネントをモジュールVBOで一括処理

  • 背景:Drupal7.x.56、Views Bulk Operation(VBO)7.x-3.4、Rules7.x-2.10
  • モジュール(Rules)がいろいろなアクションセットの作成ができます
    • データの作成/更新/削除
    • メール送信、フラグを立てる
    • などなど
  • モジュール(VBO)がRulesで作成したアクションコンポーネントの利用ができます
    • Drupalのモジュール(Rules)のアクションコンポーネントでVBOより新規ノード作成とフィールドのコピー
  • 今回の例として、Rulesでメッセージ表示する単純なアクションコンポーネント(show message)を作成して、VBOで一括処理を行います
    Rulesでメッセージ表示コンポーネントをVBOで一括処理

問題点:VBO一括処理後に画面遷移(redirect)はできません

  • VBOで一括処理後に、画面を遷移して処理結果を確認することがあります
  • VBOの設定オプションに、処理後の画面遷移設定がありません
  • ネットで調べてみたが、VBO一括処理後の画面遷移オプション追加パッチがります
    • これは、モジュールVBOに対するパッチです
    • このパッチ適応したら、次回VBOアップグレード時に、ソースのマージ作業が面だと思います
    • できれば、VBOのパッチを使用したくないです

解決:カスタムモジュール(vbo_redirect_option.zip)でVBO処理後の画面遷移オプションの追加

  • モジュール(VBO)の主要部分がクラス(class)構造なので、簡単に画面遷移ロジックを追加することはできません
  • 「Bulk Operation Settings」に処理後の画面遷移オプションを追加します
    • 「Bulk Operation Settings」のオーバーライドができないので、hook_form_alter()でオプションを追加することになりました
      /**
       * Implements hook_form_alter().
       */
      function vbo_redirect_option_form_alter(&$form, &$form_state, $form_id)
      {
        // VBOの処理かのチェック
          if( isset($form_state['id']) && $form_state['id'] === "views_bulk_operations"){
      
         // ここで、画面遷移先の保存処理は少し反則
         //  vbo_settingsに画面遷移先の追加は難しい(クラス構造体内にあるため)
         //  環境変数に画面遷移先(uri)を保存
              if( isset($form_state['input']['options']['vbo_settings'][vbo_redirect_url]) ){
                  variable_set( 'vbo_redirect_url', $form_state['input']['options']['vbo_settings'][vbo_redirect_url] ) ;
              }
      
         // 画面遷移先のテキストフィールドを追加
              $form['options']['vbo_settings']['vbo_redirect_url'] = array(
                  '#type' => 'textfield',
                  '#title' => t('Page to direct to after completion of  batch'),
                  '#description' => t('Redirects to the view when finished the operation'),
                  '#default_value' => variable_get('vbo_redirect_url'),
              );
          }
      }
    • 画面遷移先を入力するテキストフィールドを設定画面に追加
    • 画面遷移先(uri)をvbo_settingsに入れたいですが、クラスの構造体にあるため追加できません。環境変数に保存することにしました。
    • 設定画面を保存("#submit")後に、画面遷移先を保存する処理を行いたいですが、"#submit"にコールバック関数を入れても、呼び出されない現象があって、仕方がなく、hook_form_alter()内で画面遷移先(uri)の保存処理を行いました
      VBOに一括処理後に画面遷移オプションの追加
  • hook_views_bulk_operations_form_alter()を実装して、実際のVBO一括処理後に、画面遷移設定を行います
    /**
     * Implements hook_views_bulk_operations_form_alter().
     */
    function vbo_redirect_option_views_bulk_operations_form_alter(&$form, &$form_state, $vbo)
    {
        $vbo_redirect_url = trim( variable_get('vbo_redirect_url') ) ;
    
        if( isset($vbo_redirect_url) && strlen($vbo_redirect_url) >0 ){
    
            // check if vbo operation skip confirmation
            $skip_confirmation = false ;
            foreach( $vbo->options['vbo_operations'] as $key => $operation ){
                if( $operation['selected'] && $operation['skip_confirmation'] ){
                    if( isset($form['select'][$key]) ) {
                        $form['select'][$key]['#submit'][] = 'vbo_redirect_after_operation';
                        $skip_confirmation = true ;
                    }
                }
            }
    
            // set redirect method when vbo has confirmation step
            if( !$skip_confirmation ){
                $form['actions']['submit']['#submit'][] = 'vbo_redirect_after_operation' ;
            }
        }
    }
    
    // callback function to set redirect url
    function vbo_redirect_after_operation($form, &$form_state){
        $vbo_redirect_url = trim( variable_get('vbo_redirect_url') ) ;
        $form_state['redirect'] = $vbo_redirect_url;
    }
    • VBO一括処理の「確認のステップをスキップ」があるか、ないかを分けて処理します(画面遷移設定場所が違うため)
    • "#submit"に画面遷移処理を追加します
    • 画面遷移処理は$form_state['redirect'] で行います

結論と感想:簡単のカスタモジュールでVBOへの影響はありません。各オペレーション設定に画面遷移オプションを追加したほうよいかもしれない

  • このカスタムモジュールのインストールより、モジュール(VBO)への影響はありません
  • この画面遷移オプションを「Bulk Operation Settings」に追加したので、すべてのオペレーションに適応されます
    • VBOの一括処理内容がいろいろあります(例:オーナー変更、エンティティ内容変更など)
    • これらの処理後に一つの画面遷移先の設定はやや強引的だと思います
  • できれば、「Selected Bulk Operations」にある、選択したオペレーションの設定に画面遷移先の設定をしたほうが柔軟的な対応だと思います(次回の課題)
    画面遷移オプションを各オペレーションに追加すべき
添付 サイズ
vbo_redirect_option.zip (1.19 KB) 1.19 KB
Embedded thumbnail for Drupalのモジュール(VBO)の一括処理後にページ遷移させる方法
drupal
form
ajax

やりたいこと:Drupalのajaxフレームワークを利用して表示している要素を削除

  • Drupalのモジュール(Views)で作成した一覧の要素を選択して削除します
    • 要素を選択して削除するモジュール:Views Bulk Operations
    • 例:Drupalのモジュール(VBO)の各種処理(Operation)に独自(カスタムオ)のプションの追加方法
  • 前提条件:要素削除する確認の必要はありません
  • ajaxで動的に削除するのはやさしいUIとも言えるでしょう(以下のイメージのように削除)
    Drupalのajaxフレームワークより要素を動的に削除

Step1:削除リンクにDrupalのajax使用するクラス:use-ajax を追加

  • Drupalのajaxフレームワークに関する説明は以下の記事をご参考ください
    • Drupalでajaxのフレームワークが簡単に作成できる
  • 削除アイコン付きのリンクは以下のようです
    // 削除エレメントID:123 (例)
    <a href="/delete/element/id/123/nojs" class="use-ajax del-link" id="del-link-123">
           <i class="fa fa-trash-o" aria-hidden="true"></i>
    </a>
    • アンカー(a)に削除するエレメントID(または別の識別パラメーター)を入れる必要はあります
    • アンカーリンクの後ろに「nojs」を追加します(クライアント側のajax作動時に、nojs->ajaxに変換され)
    • アンカーがクリックされると、Drupalのajaxフレームワークが起動され、削除パラメーターをサイト側に渡します

Step2:hook_menuで要素削除のリクエストをキャッチします

  • hook_menuで要素削除のリクエストを受け取り、削除処理を行います
    // 要素削除URLの設定
    $items['delete/element/%/nojs'] = array(
    	'page callback' => 'delete_element',
    	'page arguments' => array( 2, 3 ) ,
    	'access callback' => 'delete_access',
    	'type' => MENU_CALLBACK,
    );
    // ajaxが以下のURLでリクエストをします(クライアント側でnojs->ajaxに変換)
    $items['delete/element/%/ajax'] = array(
    	'delivery callback' => 'ajax_deliver',
    )+$items['delete/element/%/nojs'] ;    // 要素削除定義に遷移
    
  • 要素削除処理ファンクション:delete_element で削除処理、処理結果をクライアント側に返します
    function delete_element ($id, $ajax){
        $is_ajax = $ajax === "ajax" ;  // ajaxと通用のリクエスト両方対応のため
    
        // 要素をDBから削除
        db_delete("element_table")->condition("entity_id", $id)->execute() ;
    
        // 画面要素も削除コマンドを返す
        if( $is_ajax ){
            // ajaxで要素削除後の処理
            $commands = array();
            $commands[] = ajax_command_remove( '#element-123');
            return array(
              '#type'=>"ajax",
              '#commands' => $commands,
            );
        } else {
            // 通常での要素削除後の処理
            drupal_set_message(t('Deleted 1 vocabulary'));
            drupal_goto();
        }
    }

     

Drupalのajaxフレームワークで要素削除

纏め:Drupalのajaxフレームワークを利用すればajax処理が自動的に行います

  • 上記例では、削除リンクにクラス:use-ajax を追加するだけで、ajax関連処理を記述する必要はあります
    • 削除リンクではなく、削除ボタン(button)要素を使用する場合クラス: use-ajax-submit
  • サーバー側では、hook_menuで削除リンクの定義、削除リクエストをキャッチして、削除処理関数を作成します
    • DB上のデータ削除完了後に、クライアント側の要素削除命令(ajax_command_remove)を返せば良いです
  • この一連のajax処理の記述はほどんとありません。簡単、便利です
drupal
development
ajax

やりたいこと:Drupalのプログラムレベルで簡単にajaxを利用してクライアント側でデータ交信をしたいです

  • 環境:Drupal7.54
  • DrupalのFormAPIで簡単にajaxの実装ができます(Drupalのフォーム(FromAPI)でのajaxの実装 )
  • FormAPIだけではなく、Drupalをカスタマイズ時にいろいろなところでajaxを実装したいことがあります

ポイント1:Drupalでajaxに必要なライブラリをロードし、クライアント側にjquery.form.jsファイルをセット

  • サーバー側でdrupal.ajaxのライブラリをロードする必要があります
  • クライアント側にjquery.form.jsファイルを設置する必要があります
  • この処理はajax処理するページをロード時に行えれば良いです。
    • 例:hook_init()内で処理する
      /**
       * Implements hook_init().
       */
      function YOUR_MODULE_NAME_init()
      {
        drupal_add_js('misc/jquery.form.js');
        drupal_add_library('system','drupal.ajax');
      }
  • クライアント側のブラウザのプロパティでjquery.form.jsがセットされたことの確認ができます

ポイント2:クライアント側のajax起動リンク内にajax対応可否のパラメーター「nojs」とクラス属性「use-ajax」のセット

  • ajaxの起動リンクの作成基本パターン: 
    <a href="text/ajax/nojs/1234" class="use-ajax">ajaxリンク</a>
    • hrefにある「nojs」が決まりの文字
    • hrefにある「1234」はサーバー側に転送したい必要なパラメーター
    • class="use-ajax"はこのリンクがajax用に決める
  • クライアント側のjsで使用しているブラウザがajax対応可能かを判断して、ajax起動リンクに「nojs」のパラメーターを書き換え(利用可能:nojs⇒ajax)てサーバー側に転送
  • サーバー側がajax利用可否よりクライアント側にajax対応有無の結果を返します
    Drupalのajaxフレームワークの利用
  • 上記例のプログラムは以下のようで
    /**
     * Implements hook_init().
     */
    function test_module_init()
    {
      drupal_add_js('misc/jquery.form.js');
      drupal_add_library('system','drupal.ajax');
    }
    
    /**
     *  Implementation of hook_menu()
     */
    function test_module_menu() {
      $items['test/ajax/%/%']=array(     // URLの2,3番目がクライアント側で生成
          'page callback' => 'ajax_node_response',
          'page arguments' => array(2,3),   // URLの2,3番目の引数をコールバック関数に渡す
          'access callback' => 'user_access',
          'access arguments' => array('access content'),
          'type' => MENU_CALLBACK,
      );
      return $items;
    }
    
    function ajax_node_response($type="ajax", $nid=0){
      $node = node_load( $nid, NULL, false );
      $vnode = node_view($node);
      $output = theme('node', $vnode);
      if( $type="ajax" ){
        $commands=array();
        $commands[]=ajax_command_replace( '#block-system-main','<section id="block-system-main">'.$output.'</section>' ) ;
        $page = array(
          '#type' => 'ajax',
          '#commands' => $commands,
        );
        ajax_deliver( $page ) ;   // ajax対応ブラウザの結果
      } else {
        $output = '<div id="content">'.$output.'</div>';  // ajax非対応ブラウザの結果
        return $output;
      }
    }
    

ポイント3:クライアント側で実行させたい部分はajax_commandを使用します

  • クライアント側で処理結果をどこに入り替えはajax_command_replaceで指定します
  • 結果の挿入、入れ替え、削除、css処理などがいろいろあります。詳細は本家のajax_command一覧を参考してください

 

drupal
Views

やりたいこと:モジュール(VBO)の各処理(Operation)に独自(カスタム)オプションを追加したい

  • 前回モジュール(VBO)にたいして処理(Operation)オプション追加を紹介しました
    •  Drupalのモジュール(VBO)の一括処理後にページ遷移させる方法
    • このオプションは全VBOに対して作成したものですが、すべての処理に影響を与えています
  • 各種処理(Operation)に対してどのようにオプションを追加するか前回の課題として残っています
  • 今回はこの課題を解決に新しいカスタムモジュール(vbo_redirect_option)を作成して、紹介します
    モジュールVBOの各種処理に独自のオプション追加

hook_formとCtoolsのdepent systemより各オペレーションに独自のオプションを追加

  • VBOのオペレーション設定フォームがカスタマイズとして開放していないです(前回も説明した)
  • ここで、Drupalのhook_formでVBOのオペレーション設定画面を特定して、カスタムオプション追加することになりました
    function vbo_redirect_option_form_alter(&$form, &$form_state, $form_id)
    {
        if( isset($form_state['id']) && $form_state['id'] === "views_bulk_operations"){
    
            foreach( $form_state['input']['options']['vbo_operations'] as $key => $operation) {
                if( $operation['redirect_check'] && strlen( trim($operation['redirect_url']))>0 ) {
                    variable_set( $key, $operation['redirect_url'] );
                } else {
                    if( !empty( variable_get($key) ) ) variable_del( $key ) ;
                }
            }
    
    
            foreach( $form['options']['vbo_operations'] as $key => &$operation ){
                if( !is_array($operation) ) continue ;
    
                $redirect_url = variable_get($key);
                $dep_key = "edit-options-vbo-operations-" . str_replace("_", "-", str_replace("::","",$key) ) ;
    
                $operation['redirect_check'] = array(
                    '#type' => 'checkbox',
                    '#title' => t('Redirect page to after operation'),
                    '#default_value' =>  $redirect_url ? 1 : 0 ,
                    '#dependency' => array(    // Ctoolsのdependent systemに依存
                        $dep_key."-selected" => array(1),
                    ),
                );
                $operation['redirect_url'] = array(
                    '#type' => 'textfield',
                    '#title' => t('Provide label'),
                    '#title_display' => 'invisible',
                    '#default_value' => empty($redirect_url) ? "" : $redirect_url,
                    '#dependency' => array(    // Ctoolsのdependent systemに依存
                        $dep_key."-selected" => array(1),
                        $dep_key . '-redirect-check' => array(1),
                    ),
                    '#dependency_count' => 2,
                );
            }
        }
    }
    • 設定フォームにチェックボックスをチェックしたら、画面遷移URL入力フィールドが現れるダイナミックフォームはモジュール(Ctools)のdependent systemを利用しています

処理(Operation)確認ステップをスキップがあるかないかを確認してhook_views_bulk_operations_form_alter()実装でオプションの設定を行う

  • VBOの処理(Operation)が確認ステップがあるかないかは2種類あります(この二種類をの処理プロセスが違うのでしっかりテストする必要がある)
  • hook_views_bulk_operations_form_alter()を実装して、各処理ステップにカスタマイズを行います
    function vbo_redirect_option_views_bulk_operations_form_alter(&$form, &$form_state, $vbo)
    {
        // collect all operations that has contained redirect_rul
        $redirect_arr = array();
        foreach( $vbo->options['vbo_operations'] as $key => $operation ) {
            if( !empty( variable_get($key) ) ){
                $redirect_arr[$key] = $key ;
            }
        }
    
        // add redirect step to #submit element
        if(isset($form['select'])) {
    
            // this is the form start step
            foreach( $form['select'] as $key => &$element ){
                if( isset($redirect_arr[$key]) ){
                    // we check if there is any operation has redirect_url
                    $element['#submit'][] = 'vbo_redirect_after_operation';
                    // only one is enough, we will detect witch one in the callback function
                    break;
                }
            }
    
            // do operation with confirmation step
            // this is the confirmation step
        } else if( !$form_state['operation']->getAdminOption('skip_confirmation') ) {
            $form['actions']['submit']['#submit'][] = "vbo_redirect_after_operation_with_confirmation";
            $form_state['redirect_to_after_operation'] = $form_state['operation']->getAdminOption('redirect_url');
        }
    
    }
    
    
    /**
     * callback function that has called by operation
     * this is the form start step, we don't know if it has confirmation step or not
     * @param $form
     * @param $form_state
     */
    function vbo_redirect_after_operation(&$form, &$form_state){
        // the are multiple element can be operated
        // the right one that has be sent to this step
        // we need get redirect_url if the it has
        if( isset($form_state['operation']) ){
            // get redirect_url by operation_id
            $redirec=variable_get($form_state['operation']->operationId) ;
            if( !empty($redirec) ){
                if( $form_state['operation']->getAdminOption('skip_confirmation') ) {
                    $form_state['redirect'] = $redirec;
                }
            }
        }
    }
    
    /**
     * callback function that has be called by operation with confirmation step
     * @param $form
     * @param $form_state
     */
    function vbo_redirect_after_operation_with_confirmation( $form, &$form_state ){
        // there is only operation that has be sent here with the confirmation step
        if( isset($form_state['redirect_to_after_operation']) ){
            // set redirect_url that should be stored in $form_state
            $form_state['redirect'] = $form_state['redir ect_to_after_operation'];
        }
    }

感想と結論:VBOの処理オプション設定はカスタマイズに開放していないため、各種処理(Operation)のオプションの取得、設定に苦労します

  • VBOの処理オプション設定はユーザーにカスタマイズに開放していないです
  • オペレーションの各ステップに$form、$form_state、$vbo変数から必要な情報を取得したり、セットしたりしました
  • 必要な情報がどこにあるかは不明だし(その時dsm($vbo)などで確認)、特定するまでに、時間がかかりました。
添付 サイズ
vbo_redirect_option.zip (1.77 KB) 1.77 KB
Embedded thumbnail for Drupalのモジュール(VBO)の各種処理(Operation)に独自(カスタムオ)のプションの追加方法
drupal
development
Views

Drupalのモジュール(Rules)で作成した各種アクションセットコンポーネントをモジュールVBOで一括処理

  • 背景:Drupal7.x.56、Views Bulk Operation(VBO)7.x-3.4、Rules7.x-2.10
  • モジュール(Rules)がいろいろなアクションセットの作成ができます
    • データの作成/更新/削除
    • メール送信、フラグを立てる
    • などなど
  • モジュール(VBO)がRulesで作成したアクションコンポーネントの利用ができます
    • Drupalのモジュール(Rules)のアクションコンポーネントでVBOより新規ノード作成とフィールドのコピー
  • 今回の例として、Rulesでメッセージ表示する単純なアクションコンポーネント(show message)を作成して、VBOで一括処理を行います
    Rulesでメッセージ表示コンポーネントをVBOで一括処理

問題点:VBO一括処理後に画面遷移(redirect)はできません

  • VBOで一括処理後に、画面を遷移して処理結果を確認することがあります
  • VBOの設定オプションに、処理後の画面遷移設定がありません
  • ネットで調べてみたが、VBO一括処理後の画面遷移オプション追加パッチがります
    • これは、モジュールVBOに対するパッチです
    • このパッチ適応したら、次回VBOアップグレード時に、ソースのマージ作業が面だと思います
    • できれば、VBOのパッチを使用したくないです

解決:カスタムモジュール(vbo_redirect_option.zip)でVBO処理後の画面遷移オプションの追加

  • モジュール(VBO)の主要部分がクラス(class)構造なので、簡単に画面遷移ロジックを追加することはできません
  • 「Bulk Operation Settings」に処理後の画面遷移オプションを追加します
    • 「Bulk Operation Settings」のオーバーライドができないので、hook_form_alter()でオプションを追加することになりました
      /**
       * Implements hook_form_alter().
       */
      function vbo_redirect_option_form_alter(&$form, &$form_state, $form_id)
      {
        // VBOの処理かのチェック
          if( isset($form_state['id']) && $form_state['id'] === "views_bulk_operations"){
      
         // ここで、画面遷移先の保存処理は少し反則
         //  vbo_settingsに画面遷移先の追加は難しい(クラス構造体内にあるため)
         //  環境変数に画面遷移先(uri)を保存
              if( isset($form_state['input']['options']['vbo_settings'][vbo_redirect_url]) ){
                  variable_set( 'vbo_redirect_url', $form_state['input']['options']['vbo_settings'][vbo_redirect_url] ) ;
              }
      
         // 画面遷移先のテキストフィールドを追加
              $form['options']['vbo_settings']['vbo_redirect_url'] = array(
                  '#type' => 'textfield',
                  '#title' => t('Page to direct to after completion of  batch'),
                  '#description' => t('Redirects to the view when finished the operation'),
                  '#default_value' => variable_get('vbo_redirect_url'),
              );
          }
      }
    • 画面遷移先を入力するテキストフィールドを設定画面に追加
    • 画面遷移先(uri)をvbo_settingsに入れたいですが、クラスの構造体にあるため追加できません。環境変数に保存することにしました。
    • 設定画面を保存("#submit")後に、画面遷移先を保存する処理を行いたいですが、"#submit"にコールバック関数を入れても、呼び出されない現象があって、仕方がなく、hook_form_alter()内で画面遷移先(uri)の保存処理を行いました
      VBOに一括処理後に画面遷移オプションの追加
  • hook_views_bulk_operations_form_alter()を実装して、実際のVBO一括処理後に、画面遷移設定を行います
    /**
     * Implements hook_views_bulk_operations_form_alter().
     */
    function vbo_redirect_option_views_bulk_operations_form_alter(&$form, &$form_state, $vbo)
    {
        $vbo_redirect_url = trim( variable_get('vbo_redirect_url') ) ;
    
        if( isset($vbo_redirect_url) && strlen($vbo_redirect_url) >0 ){
    
            // check if vbo operation skip confirmation
            $skip_confirmation = false ;
            foreach( $vbo->options['vbo_operations'] as $key => $operation ){
                if( $operation['selected'] && $operation['skip_confirmation'] ){
                    if( isset($form['select'][$key]) ) {
                        $form['select'][$key]['#submit'][] = 'vbo_redirect_after_operation';
                        $skip_confirmation = true ;
                    }
                }
            }
    
            // set redirect method when vbo has confirmation step
            if( !$skip_confirmation ){
                $form['actions']['submit']['#submit'][] = 'vbo_redirect_after_operation' ;
            }
        }
    }
    
    // callback function to set redirect url
    function vbo_redirect_after_operation($form, &$form_state){
        $vbo_redirect_url = trim( variable_get('vbo_redirect_url') ) ;
        $form_state['redirect'] = $vbo_redirect_url;
    }
    • VBO一括処理の「確認のステップをスキップ」があるか、ないかを分けて処理します(画面遷移設定場所が違うため)
    • "#submit"に画面遷移処理を追加します
    • 画面遷移処理は$form_state['redirect'] で行います

結論と感想:簡単のカスタモジュールでVBOへの影響はありません。各オペレーション設定に画面遷移オプションを追加したほうよいかもしれない

  • このカスタムモジュールのインストールより、モジュール(VBO)への影響はありません
  • この画面遷移オプションを「Bulk Operation Settings」に追加したので、すべてのオペレーションに適応されます
    • VBOの一括処理内容がいろいろあります(例:オーナー変更、エンティティ内容変更など)
    • これらの処理後に一つの画面遷移先の設定はやや強引的だと思います
  • できれば、「Selected Bulk Operations」にある、選択したオペレーションの設定に画面遷移先の設定をしたほうが柔軟的な対応だと思います(次回の課題)
    画面遷移オプションを各オペレーションに追加すべき
添付 サイズ
vbo_redirect_option.zip (1.19 KB) 1.19 KB
Embedded thumbnail for Drupalのモジュール(VBO)の一括処理後にページ遷移させる方法
drupal
form
ajax

やりたいこと:Drupalのajaxフレームワークを利用して表示している要素を削除

  • Drupalのモジュール(Views)で作成した一覧の要素を選択して削除します
    • 要素を選択して削除するモジュール:Views Bulk Operations
    • 例:Drupalのモジュール(VBO)の各種処理(Operation)に独自(カスタムオ)のプションの追加方法
  • 前提条件:要素削除する確認の必要はありません
  • ajaxで動的に削除するのはやさしいUIとも言えるでしょう(以下のイメージのように削除)
    Drupalのajaxフレームワークより要素を動的に削除

Step1:削除リンクにDrupalのajax使用するクラス:use-ajax を追加

  • Drupalのajaxフレームワークに関する説明は以下の記事をご参考ください
    • Drupalでajaxのフレームワークが簡単に作成できる
  • 削除アイコン付きのリンクは以下のようです
    // 削除エレメントID:123 (例)
    <a href="/delete/element/id/123/nojs" class="use-ajax del-link" id="del-link-123">
           <i class="fa fa-trash-o" aria-hidden="true"></i>
    </a>
    • アンカー(a)に削除するエレメントID(または別の識別パラメーター)を入れる必要はあります
    • アンカーリンクの後ろに「nojs」を追加します(クライアント側のajax作動時に、nojs->ajaxに変換され)
    • アンカーがクリックされると、Drupalのajaxフレームワークが起動され、削除パラメーターをサイト側に渡します

Step2:hook_menuで要素削除のリクエストをキャッチします

  • hook_menuで要素削除のリクエストを受け取り、削除処理を行います
    // 要素削除URLの設定
    $items['delete/element/%/nojs'] = array(
    	'page callback' => 'delete_element',
    	'page arguments' => array( 2, 3 ) ,
    	'access callback' => 'delete_access',
    	'type' => MENU_CALLBACK,
    );
    // ajaxが以下のURLでリクエストをします(クライアント側でnojs->ajaxに変換)
    $items['delete/element/%/ajax'] = array(
    	'delivery callback' => 'ajax_deliver',
    )+$items['delete/element/%/nojs'] ;    // 要素削除定義に遷移
    
  • 要素削除処理ファンクション:delete_element で削除処理、処理結果をクライアント側に返します
    function delete_element ($id, $ajax){
        $is_ajax = $ajax === "ajax" ;  // ajaxと通用のリクエスト両方対応のため
    
        // 要素をDBから削除
        db_delete("element_table")->condition("entity_id", $id)->execute() ;
    
        // 画面要素も削除コマンドを返す
        if( $is_ajax ){
            // ajaxで要素削除後の処理
            $commands = array();
            $commands[] = ajax_command_remove( '#element-123');
            return array(
              '#type'=>"ajax",
              '#commands' => $commands,
            );
        } else {
            // 通常での要素削除後の処理
            drupal_set_message(t('Deleted 1 vocabulary'));
            drupal_goto();
        }
    }

     

Drupalのajaxフレームワークで要素削除

纏め:Drupalのajaxフレームワークを利用すればajax処理が自動的に行います

  • 上記例では、削除リンクにクラス:use-ajax を追加するだけで、ajax関連処理を記述する必要はあります
    • 削除リンクではなく、削除ボタン(button)要素を使用する場合クラス: use-ajax-submit
  • サーバー側では、hook_menuで削除リンクの定義、削除リクエストをキャッチして、削除処理関数を作成します
    • DB上のデータ削除完了後に、クライアント側の要素削除命令(ajax_command_remove)を返せば良いです
  • この一連のajax処理の記述はほどんとありません。簡単、便利です
drupal
development
ajax

やりたいこと:Drupalのプログラムレベルで簡単にajaxを利用してクライアント側でデータ交信をしたいです

  • 環境:Drupal7.54
  • DrupalのFormAPIで簡単にajaxの実装ができます(Drupalのフォーム(FromAPI)でのajaxの実装 )
  • FormAPIだけではなく、Drupalをカスタマイズ時にいろいろなところでajaxを実装したいことがあります

ポイント1:Drupalでajaxに必要なライブラリをロードし、クライアント側にjquery.form.jsファイルをセット

  • サーバー側でdrupal.ajaxのライブラリをロードする必要があります
  • クライアント側にjquery.form.jsファイルを設置する必要があります
  • この処理はajax処理するページをロード時に行えれば良いです。
    • 例:hook_init()内で処理する
      /**
       * Implements hook_init().
       */
      function YOUR_MODULE_NAME_init()
      {
        drupal_add_js('misc/jquery.form.js');
        drupal_add_library('system','drupal.ajax');
      }
  • クライアント側のブラウザのプロパティでjquery.form.jsがセットされたことの確認ができます

ポイント2:クライアント側のajax起動リンク内にajax対応可否のパラメーター「nojs」とクラス属性「use-ajax」のセット

  • ajaxの起動リンクの作成基本パターン: 
    <a href="text/ajax/nojs/1234" class="use-ajax">ajaxリンク</a>
    • hrefにある「nojs」が決まりの文字
    • hrefにある「1234」はサーバー側に転送したい必要なパラメーター
    • class="use-ajax"はこのリンクがajax用に決める
  • クライアント側のjsで使用しているブラウザがajax対応可能かを判断して、ajax起動リンクに「nojs」のパラメーターを書き換え(利用可能:nojs⇒ajax)てサーバー側に転送
  • サーバー側がajax利用可否よりクライアント側にajax対応有無の結果を返します
    Drupalのajaxフレームワークの利用
  • 上記例のプログラムは以下のようで
    /**
     * Implements hook_init().
     */
    function test_module_init()
    {
      drupal_add_js('misc/jquery.form.js');
      drupal_add_library('system','drupal.ajax');
    }
    
    /**
     *  Implementation of hook_menu()
     */
    function test_module_menu() {
      $items['test/ajax/%/%']=array(     // URLの2,3番目がクライアント側で生成
          'page callback' => 'ajax_node_response',
          'page arguments' => array(2,3),   // URLの2,3番目の引数をコールバック関数に渡す
          'access callback' => 'user_access',
          'access arguments' => array('access content'),
          'type' => MENU_CALLBACK,
      );
      return $items;
    }
    
    function ajax_node_response($type="ajax", $nid=0){
      $node = node_load( $nid, NULL, false );
      $vnode = node_view($node);
      $output = theme('node', $vnode);
      if( $type="ajax" ){
        $commands=array();
        $commands[]=ajax_command_replace( '#block-system-main','<section id="block-system-main">'.$output.'</section>' ) ;
        $page = array(
          '#type' => 'ajax',
          '#commands' => $commands,
        );
        ajax_deliver( $page ) ;   // ajax対応ブラウザの結果
      } else {
        $output = '<div id="content">'.$output.'</div>';  // ajax非対応ブラウザの結果
        return $output;
      }
    }
    

ポイント3:クライアント側で実行させたい部分はajax_commandを使用します

  • クライアント側で処理結果をどこに入り替えはajax_command_replaceで指定します
  • 結果の挿入、入れ替え、削除、css処理などがいろいろあります。詳細は本家のajax_command一覧を参考してください

 

drupal
Views

やりたいこと:モジュール(VBO)の各処理(Operation)に独自(カスタム)オプションを追加したい

  • 前回モジュール(VBO)にたいして処理(Operation)オプション追加を紹介しました
    •  Drupalのモジュール(VBO)の一括処理後にページ遷移させる方法
    • このオプションは全VBOに対して作成したものですが、すべての処理に影響を与えています
  • 各種処理(Operation)に対してどのようにオプションを追加するか前回の課題として残っています
  • 今回はこの課題を解決に新しいカスタムモジュール(vbo_redirect_option)を作成して、紹介します
    モジュールVBOの各種処理に独自のオプション追加

hook_formとCtoolsのdepent systemより各オペレーションに独自のオプションを追加

  • VBOのオペレーション設定フォームがカスタマイズとして開放していないです(前回も説明した)
  • ここで、Drupalのhook_formでVBOのオペレーション設定画面を特定して、カスタムオプション追加することになりました
    function vbo_redirect_option_form_alter(&$form, &$form_state, $form_id)
    {
        if( isset($form_state['id']) && $form_state['id'] === "views_bulk_operations"){
    
            foreach( $form_state['input']['options']['vbo_operations'] as $key => $operation) {
                if( $operation['redirect_check'] && strlen( trim($operation['redirect_url']))>0 ) {
                    variable_set( $key, $operation['redirect_url'] );
                } else {
                    if( !empty( variable_get($key) ) ) variable_del( $key ) ;
                }
            }
    
    
            foreach( $form['options']['vbo_operations'] as $key => &$operation ){
                if( !is_array($operation) ) continue ;
    
                $redirect_url = variable_get($key);
                $dep_key = "edit-options-vbo-operations-" . str_replace("_", "-", str_replace("::","",$key) ) ;
    
                $operation['redirect_check'] = array(
                    '#type' => 'checkbox',
                    '#title' => t('Redirect page to after operation'),
                    '#default_value' =>  $redirect_url ? 1 : 0 ,
                    '#dependency' => array(    // Ctoolsのdependent systemに依存
                        $dep_key."-selected" => array(1),
                    ),
                );
                $operation['redirect_url'] = array(
                    '#type' => 'textfield',
                    '#title' => t('Provide label'),
                    '#title_display' => 'invisible',
                    '#default_value' => empty($redirect_url) ? "" : $redirect_url,
                    '#dependency' => array(    // Ctoolsのdependent systemに依存
                        $dep_key."-selected" => array(1),
                        $dep_key . '-redirect-check' => array(1),
                    ),
                    '#dependency_count' => 2,
                );
            }
        }
    }
    • 設定フォームにチェックボックスをチェックしたら、画面遷移URL入力フィールドが現れるダイナミックフォームはモジュール(Ctools)のdependent systemを利用しています

処理(Operation)確認ステップをスキップがあるかないかを確認してhook_views_bulk_operations_form_alter()実装でオプションの設定を行う

  • VBOの処理(Operation)が確認ステップがあるかないかは2種類あります(この二種類をの処理プロセスが違うのでしっかりテストする必要がある)
  • hook_views_bulk_operations_form_alter()を実装して、各処理ステップにカスタマイズを行います
    function vbo_redirect_option_views_bulk_operations_form_alter(&$form, &$form_state, $vbo)
    {
        // collect all operations that has contained redirect_rul
        $redirect_arr = array();
        foreach( $vbo->options['vbo_operations'] as $key => $operation ) {
            if( !empty( variable_get($key) ) ){
                $redirect_arr[$key] = $key ;
            }
        }
    
        // add redirect step to #submit element
        if(isset($form['select'])) {
    
            // this is the form start step
            foreach( $form['select'] as $key => &$element ){
                if( isset($redirect_arr[$key]) ){
                    // we check if there is any operation has redirect_url
                    $element['#submit'][] = 'vbo_redirect_after_operation';
                    // only one is enough, we will detect witch one in the callback function
                    break;
                }
            }
    
            // do operation with confirmation step
            // this is the confirmation step
        } else if( !$form_state['operation']->getAdminOption('skip_confirmation') ) {
            $form['actions']['submit']['#submit'][] = "vbo_redirect_after_operation_with_confirmation";
            $form_state['redirect_to_after_operation'] = $form_state['operation']->getAdminOption('redirect_url');
        }
    
    }
    
    
    /**
     * callback function that has called by operation
     * this is the form start step, we don't know if it has confirmation step or not
     * @param $form
     * @param $form_state
     */
    function vbo_redirect_after_operation(&$form, &$form_state){
        // the are multiple element can be operated
        // the right one that has be sent to this step
        // we need get redirect_url if the it has
        if( isset($form_state['operation']) ){
            // get redirect_url by operation_id
            $redirec=variable_get($form_state['operation']->operationId) ;
            if( !empty($redirec) ){
                if( $form_state['operation']->getAdminOption('skip_confirmation') ) {
                    $form_state['redirect'] = $redirec;
                }
            }
        }
    }
    
    /**
     * callback function that has be called by operation with confirmation step
     * @param $form
     * @param $form_state
     */
    function vbo_redirect_after_operation_with_confirmation( $form, &$form_state ){
        // there is only operation that has be sent here with the confirmation step
        if( isset($form_state['redirect_to_after_operation']) ){
            // set redirect_url that should be stored in $form_state
            $form_state['redirect'] = $form_state['redir ect_to_after_operation'];
        }
    }

感想と結論:VBOの処理オプション設定はカスタマイズに開放していないため、各種処理(Operation)のオプションの取得、設定に苦労します

  • VBOの処理オプション設定はユーザーにカスタマイズに開放していないです
  • オペレーションの各ステップに$form、$form_state、$vbo変数から必要な情報を取得したり、セットしたりしました
  • 必要な情報がどこにあるかは不明だし(その時dsm($vbo)などで確認)、特定するまでに、時間がかかりました。
添付 サイズ
vbo_redirect_option.zip (1.77 KB) 1.77 KB
Embedded thumbnail for Drupalのモジュール(VBO)の各種処理(Operation)に独自(カスタムオ)のプションの追加方法
drupal
development
Views

Drupalのモジュール(Rules)で作成した各種アクションセットコンポーネントをモジュールVBOで一括処理

  • 背景:Drupal7.x.56、Views Bulk Operation(VBO)7.x-3.4、Rules7.x-2.10
  • モジュール(Rules)がいろいろなアクションセットの作成ができます
    • データの作成/更新/削除
    • メール送信、フラグを立てる
    • などなど
  • モジュール(VBO)がRulesで作成したアクションコンポーネントの利用ができます
    • Drupalのモジュール(Rules)のアクションコンポーネントでVBOより新規ノード作成とフィールドのコピー
  • 今回の例として、Rulesでメッセージ表示する単純なアクションコンポーネント(show message)を作成して、VBOで一括処理を行います
    Rulesでメッセージ表示コンポーネントをVBOで一括処理

問題点:VBO一括処理後に画面遷移(redirect)はできません

  • VBOで一括処理後に、画面を遷移して処理結果を確認することがあります
  • VBOの設定オプションに、処理後の画面遷移設定がありません
  • ネットで調べてみたが、VBO一括処理後の画面遷移オプション追加パッチがります
    • これは、モジュールVBOに対するパッチです
    • このパッチ適応したら、次回VBOアップグレード時に、ソースのマージ作業が面だと思います
    • できれば、VBOのパッチを使用したくないです

解決:カスタムモジュール(vbo_redirect_option.zip)でVBO処理後の画面遷移オプションの追加

  • モジュール(VBO)の主要部分がクラス(class)構造なので、簡単に画面遷移ロジックを追加することはできません
  • 「Bulk Operation Settings」に処理後の画面遷移オプションを追加します
    • 「Bulk Operation Settings」のオーバーライドができないので、hook_form_alter()でオプションを追加することになりました
      /**
       * Implements hook_form_alter().
       */
      function vbo_redirect_option_form_alter(&$form, &$form_state, $form_id)
      {
        // VBOの処理かのチェック
          if( isset($form_state['id']) && $form_state['id'] === "views_bulk_operations"){
      
         // ここで、画面遷移先の保存処理は少し反則
         //  vbo_settingsに画面遷移先の追加は難しい(クラス構造体内にあるため)
         //  環境変数に画面遷移先(uri)を保存
              if( isset($form_state['input']['options']['vbo_settings'][vbo_redirect_url]) ){
                  variable_set( 'vbo_redirect_url', $form_state['input']['options']['vbo_settings'][vbo_redirect_url] ) ;
              }
      
         // 画面遷移先のテキストフィールドを追加
              $form['options']['vbo_settings']['vbo_redirect_url'] = array(
                  '#type' => 'textfield',
                  '#title' => t('Page to direct to after completion of  batch'),
                  '#description' => t('Redirects to the view when finished the operation'),
                  '#default_value' => variable_get('vbo_redirect_url'),
              );
          }
      }
    • 画面遷移先を入力するテキストフィールドを設定画面に追加
    • 画面遷移先(uri)をvbo_settingsに入れたいですが、クラスの構造体にあるため追加できません。環境変数に保存することにしました。
    • 設定画面を保存("#submit")後に、画面遷移先を保存する処理を行いたいですが、"#submit"にコールバック関数を入れても、呼び出されない現象があって、仕方がなく、hook_form_alter()内で画面遷移先(uri)の保存処理を行いました
      VBOに一括処理後に画面遷移オプションの追加
  • hook_views_bulk_operations_form_alter()を実装して、実際のVBO一括処理後に、画面遷移設定を行います
    /**
     * Implements hook_views_bulk_operations_form_alter().
     */
    function vbo_redirect_option_views_bulk_operations_form_alter(&$form, &$form_state, $vbo)
    {
        $vbo_redirect_url = trim( variable_get('vbo_redirect_url') ) ;
    
        if( isset($vbo_redirect_url) && strlen($vbo_redirect_url) >0 ){
    
            // check if vbo operation skip confirmation
            $skip_confirmation = false ;
            foreach( $vbo->options['vbo_operations'] as $key => $operation ){
                if( $operation['selected'] && $operation['skip_confirmation'] ){
                    if( isset($form['select'][$key]) ) {
                        $form['select'][$key]['#submit'][] = 'vbo_redirect_after_operation';
                        $skip_confirmation = true ;
                    }
                }
            }
    
            // set redirect method when vbo has confirmation step
            if( !$skip_confirmation ){
                $form['actions']['submit']['#submit'][] = 'vbo_redirect_after_operation' ;
            }
        }
    }
    
    // callback function to set redirect url
    function vbo_redirect_after_operation($form, &$form_state){
        $vbo_redirect_url = trim( variable_get('vbo_redirect_url') ) ;
        $form_state['redirect'] = $vbo_redirect_url;
    }
    • VBO一括処理の「確認のステップをスキップ」があるか、ないかを分けて処理します(画面遷移設定場所が違うため)
    • "#submit"に画面遷移処理を追加します
    • 画面遷移処理は$form_state['redirect'] で行います

結論と感想:簡単のカスタモジュールでVBOへの影響はありません。各オペレーション設定に画面遷移オプションを追加したほうよいかもしれない

  • このカスタムモジュールのインストールより、モジュール(VBO)への影響はありません
  • この画面遷移オプションを「Bulk Operation Settings」に追加したので、すべてのオペレーションに適応されます
    • VBOの一括処理内容がいろいろあります(例:オーナー変更、エンティティ内容変更など)
    • これらの処理後に一つの画面遷移先の設定はやや強引的だと思います
  • できれば、「Selected Bulk Operations」にある、選択したオペレーションの設定に画面遷移先の設定をしたほうが柔軟的な対応だと思います(次回の課題)
    画面遷移オプションを各オペレーションに追加すべき
添付 サイズ
vbo_redirect_option.zip (1.19 KB) 1.19 KB
Embedded thumbnail for Drupalのモジュール(VBO)の一括処理後にページ遷移させる方法
drupal
form
ajax

やりたいこと:Drupalのajaxフレームワークを利用して表示している要素を削除

  • Drupalのモジュール(Views)で作成した一覧の要素を選択して削除します
    • 要素を選択して削除するモジュール:Views Bulk Operations
    • 例:Drupalのモジュール(VBO)の各種処理(Operation)に独自(カスタムオ)のプションの追加方法
  • 前提条件:要素削除する確認の必要はありません
  • ajaxで動的に削除するのはやさしいUIとも言えるでしょう(以下のイメージのように削除)
    Drupalのajaxフレームワークより要素を動的に削除

Step1:削除リンクにDrupalのajax使用するクラス:use-ajax を追加

  • Drupalのajaxフレームワークに関する説明は以下の記事をご参考ください
    • Drupalでajaxのフレームワークが簡単に作成できる
  • 削除アイコン付きのリンクは以下のようです
    // 削除エレメントID:123 (例)
    <a href="/delete/element/id/123/nojs" class="use-ajax del-link" id="del-link-123">
           <i class="fa fa-trash-o" aria-hidden="true"></i>
    </a>
    • アンカー(a)に削除するエレメントID(または別の識別パラメーター)を入れる必要はあります
    • アンカーリンクの後ろに「nojs」を追加します(クライアント側のajax作動時に、nojs->ajaxに変換され)
    • アンカーがクリックされると、Drupalのajaxフレームワークが起動され、削除パラメーターをサイト側に渡します

Step2:hook_menuで要素削除のリクエストをキャッチします

  • hook_menuで要素削除のリクエストを受け取り、削除処理を行います
    // 要素削除URLの設定
    $items['delete/element/%/nojs'] = array(
    	'page callback' => 'delete_element',
    	'page arguments' => array( 2, 3 ) ,
    	'access callback' => 'delete_access',
    	'type' => MENU_CALLBACK,
    );
    // ajaxが以下のURLでリクエストをします(クライアント側でnojs->ajaxに変換)
    $items['delete/element/%/ajax'] = array(
    	'delivery callback' => 'ajax_deliver',
    )+$items['delete/element/%/nojs'] ;    // 要素削除定義に遷移
    
  • 要素削除処理ファンクション:delete_element で削除処理、処理結果をクライアント側に返します
    function delete_element ($id, $ajax){
        $is_ajax = $ajax === "ajax" ;  // ajaxと通用のリクエスト両方対応のため
    
        // 要素をDBから削除
        db_delete("element_table")->condition("entity_id", $id)->execute() ;
    
        // 画面要素も削除コマンドを返す
        if( $is_ajax ){
            // ajaxで要素削除後の処理
            $commands = array();
            $commands[] = ajax_command_remove( '#element-123');
            return array(
              '#type'=>"ajax",
              '#commands' => $commands,
            );
        } else {
            // 通常での要素削除後の処理
            drupal_set_message(t('Deleted 1 vocabulary'));
            drupal_goto();
        }
    }

     

Drupalのajaxフレームワークで要素削除

纏め:Drupalのajaxフレームワークを利用すればajax処理が自動的に行います

  • 上記例では、削除リンクにクラス:use-ajax を追加するだけで、ajax関連処理を記述する必要はあります
    • 削除リンクではなく、削除ボタン(button)要素を使用する場合クラス: use-ajax-submit
  • サーバー側では、hook_menuで削除リンクの定義、削除リクエストをキャッチして、削除処理関数を作成します
    • DB上のデータ削除完了後に、クライアント側の要素削除命令(ajax_command_remove)を返せば良いです
  • この一連のajax処理の記述はほどんとありません。簡単、便利です
drupal
development
ajax

やりたいこと:Drupalのプログラムレベルで簡単にajaxを利用してクライアント側でデータ交信をしたいです

  • 環境:Drupal7.54
  • DrupalのFormAPIで簡単にajaxの実装ができます(Drupalのフォーム(FromAPI)でのajaxの実装 )
  • FormAPIだけではなく、Drupalをカスタマイズ時にいろいろなところでajaxを実装したいことがあります

ポイント1:Drupalでajaxに必要なライブラリをロードし、クライアント側にjquery.form.jsファイルをセット

  • サーバー側でdrupal.ajaxのライブラリをロードする必要があります
  • クライアント側にjquery.form.jsファイルを設置する必要があります
  • この処理はajax処理するページをロード時に行えれば良いです。
    • 例:hook_init()内で処理する
      /**
       * Implements hook_init().
       */
      function YOUR_MODULE_NAME_init()
      {
        drupal_add_js('misc/jquery.form.js');
        drupal_add_library('system','drupal.ajax');
      }
  • クライアント側のブラウザのプロパティでjquery.form.jsがセットされたことの確認ができます

ポイント2:クライアント側のajax起動リンク内にajax対応可否のパラメーター「nojs」とクラス属性「use-ajax」のセット

  • ajaxの起動リンクの作成基本パターン: 
    <a href="text/ajax/nojs/1234" class="use-ajax">ajaxリンク</a>
    • hrefにある「nojs」が決まりの文字
    • hrefにある「1234」はサーバー側に転送したい必要なパラメーター
    • class="use-ajax"はこのリンクがajax用に決める
  • クライアント側のjsで使用しているブラウザがajax対応可能かを判断して、ajax起動リンクに「nojs」のパラメーターを書き換え(利用可能:nojs⇒ajax)てサーバー側に転送
  • サーバー側がajax利用可否よりクライアント側にajax対応有無の結果を返します
    Drupalのajaxフレームワークの利用
  • 上記例のプログラムは以下のようで
    /**
     * Implements hook_init().
     */
    function test_module_init()
    {
      drupal_add_js('misc/jquery.form.js');
      drupal_add_library('system','drupal.ajax');
    }
    
    /**
     *  Implementation of hook_menu()
     */
    function test_module_menu() {
      $items['test/ajax/%/%']=array(     // URLの2,3番目がクライアント側で生成
          'page callback' => 'ajax_node_response',
          'page arguments' => array(2,3),   // URLの2,3番目の引数をコールバック関数に渡す
          'access callback' => 'user_access',
          'access arguments' => array('access content'),
          'type' => MENU_CALLBACK,
      );
      return $items;
    }
    
    function ajax_node_response($type="ajax", $nid=0){
      $node = node_load( $nid, NULL, false );
      $vnode = node_view($node);
      $output = theme('node', $vnode);
      if( $type="ajax" ){
        $commands=array();
        $commands[]=ajax_command_replace( '#block-system-main','<section id="block-system-main">'.$output.'</section>' ) ;
        $page = array(
          '#type' => 'ajax',
          '#commands' => $commands,
        );
        ajax_deliver( $page ) ;   // ajax対応ブラウザの結果
      } else {
        $output = '<div id="content">'.$output.'</div>';  // ajax非対応ブラウザの結果
        return $output;
      }
    }
    

ポイント3:クライアント側で実行させたい部分はajax_commandを使用します

  • クライアント側で処理結果をどこに入り替えはajax_command_replaceで指定します
  • 結果の挿入、入れ替え、削除、css処理などがいろいろあります。詳細は本家のajax_command一覧を参考してください

 

drupal
Views

やりたいこと:モジュール(VBO)の各処理(Operation)に独自(カスタム)オプションを追加したい

  • 前回モジュール(VBO)にたいして処理(Operation)オプション追加を紹介しました
    •  Drupalのモジュール(VBO)の一括処理後にページ遷移させる方法
    • このオプションは全VBOに対して作成したものですが、すべての処理に影響を与えています
  • 各種処理(Operation)に対してどのようにオプションを追加するか前回の課題として残っています
  • 今回はこの課題を解決に新しいカスタムモジュール(vbo_redirect_option)を作成して、紹介します
    モジュールVBOの各種処理に独自のオプション追加

hook_formとCtoolsのdepent systemより各オペレーションに独自のオプションを追加

  • VBOのオペレーション設定フォームがカスタマイズとして開放していないです(前回も説明した)
  • ここで、Drupalのhook_formでVBOのオペレーション設定画面を特定して、カスタムオプション追加することになりました
    function vbo_redirect_option_form_alter(&$form, &$form_state, $form_id)
    {
        if( isset($form_state['id']) && $form_state['id'] === "views_bulk_operations"){
    
            foreach( $form_state['input']['options']['vbo_operations'] as $key => $operation) {
                if( $operation['redirect_check'] && strlen( trim($operation['redirect_url']))>0 ) {
                    variable_set( $key, $operation['redirect_url'] );
                } else {
                    if( !empty( variable_get($key) ) ) variable_del( $key ) ;
                }
            }
    
    
            foreach( $form['options']['vbo_operations'] as $key => &$operation ){
                if( !is_array($operation) ) continue ;
    
                $redirect_url = variable_get($key);
                $dep_key = "edit-options-vbo-operations-" . str_replace("_", "-", str_replace("::","",$key) ) ;
    
                $operation['redirect_check'] = array(
                    '#type' => 'checkbox',
                    '#title' => t('Redirect page to after operation'),
                    '#default_value' =>  $redirect_url ? 1 : 0 ,
                    '#dependency' => array(    // Ctoolsのdependent systemに依存
                        $dep_key."-selected" => array(1),
                    ),
                );
                $operation['redirect_url'] = array(
                    '#type' => 'textfield',
                    '#title' => t('Provide label'),
                    '#title_display' => 'invisible',
                    '#default_value' => empty($redirect_url) ? "" : $redirect_url,
                    '#dependency' => array(    // Ctoolsのdependent systemに依存
                        $dep_key."-selected" => array(1),
                        $dep_key . '-redirect-check' => array(1),
                    ),
                    '#dependency_count' => 2,
                );
            }
        }
    }
    • 設定フォームにチェックボックスをチェックしたら、画面遷移URL入力フィールドが現れるダイナミックフォームはモジュール(Ctools)のdependent systemを利用しています

処理(Operation)確認ステップをスキップがあるかないかを確認してhook_views_bulk_operations_form_alter()実装でオプションの設定を行う

  • VBOの処理(Operation)が確認ステップがあるかないかは2種類あります(この二種類をの処理プロセスが違うのでしっかりテストする必要がある)
  • hook_views_bulk_operations_form_alter()を実装して、各処理ステップにカスタマイズを行います
    function vbo_redirect_option_views_bulk_operations_form_alter(&$form, &$form_state, $vbo)
    {
        // collect all operations that has contained redirect_rul
        $redirect_arr = array();
        foreach( $vbo->options['vbo_operations'] as $key => $operation ) {
            if( !empty( variable_get($key) ) ){
                $redirect_arr[$key] = $key ;
            }
        }
    
        // add redirect step to #submit element
        if(isset($form['select'])) {
    
            // this is the form start step
            foreach( $form['select'] as $key => &$element ){
                if( isset($redirect_arr[$key]) ){
                    // we check if there is any operation has redirect_url
                    $element['#submit'][] = 'vbo_redirect_after_operation';
                    // only one is enough, we will detect witch one in the callback function
                    break;
                }
            }
    
            // do operation with confirmation step
            // this is the confirmation step
        } else if( !$form_state['operation']->getAdminOption('skip_confirmation') ) {
            $form['actions']['submit']['#submit'][] = "vbo_redirect_after_operation_with_confirmation";
            $form_state['redirect_to_after_operation'] = $form_state['operation']->getAdminOption('redirect_url');
        }
    
    }
    
    
    /**
     * callback function that has called by operation
     * this is the form start step, we don't know if it has confirmation step or not
     * @param $form
     * @param $form_state
     */
    function vbo_redirect_after_operation(&$form, &$form_state){
        // the are multiple element can be operated
        // the right one that has be sent to this step
        // we need get redirect_url if the it has
        if( isset($form_state['operation']) ){
            // get redirect_url by operation_id
            $redirec=variable_get($form_state['operation']->operationId) ;
            if( !empty($redirec) ){
                if( $form_state['operation']->getAdminOption('skip_confirmation') ) {
                    $form_state['redirect'] = $redirec;
                }
            }
        }
    }
    
    /**
     * callback function that has be called by operation with confirmation step
     * @param $form
     * @param $form_state
     */
    function vbo_redirect_after_operation_with_confirmation( $form, &$form_state ){
        // there is only operation that has be sent here with the confirmation step
        if( isset($form_state['redirect_to_after_operation']) ){
            // set redirect_url that should be stored in $form_state
            $form_state['redirect'] = $form_state['redir ect_to_after_operation'];
        }
    }

感想と結論:VBOの処理オプション設定はカスタマイズに開放していないため、各種処理(Operation)のオプションの取得、設定に苦労します

  • VBOの処理オプション設定はユーザーにカスタマイズに開放していないです
  • オペレーションの各ステップに$form、$form_state、$vbo変数から必要な情報を取得したり、セットしたりしました
  • 必要な情報がどこにあるかは不明だし(その時dsm($vbo)などで確認)、特定するまでに、時間がかかりました。
添付 サイズ
vbo_redirect_option.zip (1.77 KB) 1.77 KB
Embedded thumbnail for Drupalのモジュール(VBO)の各種処理(Operation)に独自(カスタムオ)のプションの追加方法
drupal
development
Views

Drupalのモジュール(Rules)で作成した各種アクションセットコンポーネントをモジュールVBOで一括処理

  • 背景:Drupal7.x.56、Views Bulk Operation(VBO)7.x-3.4、Rules7.x-2.10
  • モジュール(Rules)がいろいろなアクションセットの作成ができます
    • データの作成/更新/削除
    • メール送信、フラグを立てる
    • などなど
  • モジュール(VBO)がRulesで作成したアクションコンポーネントの利用ができます
    • Drupalのモジュール(Rules)のアクションコンポーネントでVBOより新規ノード作成とフィールドのコピー
  • 今回の例として、Rulesでメッセージ表示する単純なアクションコンポーネント(show message)を作成して、VBOで一括処理を行います
    Rulesでメッセージ表示コンポーネントをVBOで一括処理

問題点:VBO一括処理後に画面遷移(redirect)はできません

  • VBOで一括処理後に、画面を遷移して処理結果を確認することがあります
  • VBOの設定オプションに、処理後の画面遷移設定がありません
  • ネットで調べてみたが、VBO一括処理後の画面遷移オプション追加パッチがります
    • これは、モジュールVBOに対するパッチです
    • このパッチ適応したら、次回VBOアップグレード時に、ソースのマージ作業が面だと思います
    • できれば、VBOのパッチを使用したくないです

解決:カスタムモジュール(vbo_redirect_option.zip)でVBO処理後の画面遷移オプションの追加

  • モジュール(VBO)の主要部分がクラス(class)構造なので、簡単に画面遷移ロジックを追加することはできません
  • 「Bulk Operation Settings」に処理後の画面遷移オプションを追加します
    • 「Bulk Operation Settings」のオーバーライドができないので、hook_form_alter()でオプションを追加することになりました
      /**
       * Implements hook_form_alter().
       */
      function vbo_redirect_option_form_alter(&$form, &$form_state, $form_id)
      {
        // VBOの処理かのチェック
          if( isset($form_state['id']) && $form_state['id'] === "views_bulk_operations"){
      
         // ここで、画面遷移先の保存処理は少し反則
         //  vbo_settingsに画面遷移先の追加は難しい(クラス構造体内にあるため)
         //  環境変数に画面遷移先(uri)を保存
              if( isset($form_state['input']['options']['vbo_settings'][vbo_redirect_url]) ){
                  variable_set( 'vbo_redirect_url', $form_state['input']['options']['vbo_settings'][vbo_redirect_url] ) ;
              }
      
         // 画面遷移先のテキストフィールドを追加
              $form['options']['vbo_settings']['vbo_redirect_url'] = array(
                  '#type' => 'textfield',
                  '#title' => t('Page to direct to after completion of  batch'),
                  '#description' => t('Redirects to the view when finished the operation'),
                  '#default_value' => variable_get('vbo_redirect_url'),
              );
          }
      }
    • 画面遷移先を入力するテキストフィールドを設定画面に追加
    • 画面遷移先(uri)をvbo_settingsに入れたいですが、クラスの構造体にあるため追加できません。環境変数に保存することにしました。
    • 設定画面を保存("#submit")後に、画面遷移先を保存する処理を行いたいですが、"#submit"にコールバック関数を入れても、呼び出されない現象があって、仕方がなく、hook_form_alter()内で画面遷移先(uri)の保存処理を行いました
      VBOに一括処理後に画面遷移オプションの追加
  • hook_views_bulk_operations_form_alter()を実装して、実際のVBO一括処理後に、画面遷移設定を行います
    /**
     * Implements hook_views_bulk_operations_form_alter().
     */
    function vbo_redirect_option_views_bulk_operations_form_alter(&$form, &$form_state, $vbo)
    {
        $vbo_redirect_url = trim( variable_get('vbo_redirect_url') ) ;
    
        if( isset($vbo_redirect_url) && strlen($vbo_redirect_url) >0 ){
    
            // check if vbo operation skip confirmation
            $skip_confirmation = false ;
            foreach( $vbo->options['vbo_operations'] as $key => $operation ){
                if( $operation['selected'] && $operation['skip_confirmation'] ){
                    if( isset($form['select'][$key]) ) {
                        $form['select'][$key]['#submit'][] = 'vbo_redirect_after_operation';
                        $skip_confirmation = true ;
                    }
                }
            }
    
            // set redirect method when vbo has confirmation step
            if( !$skip_confirmation ){
                $form['actions']['submit']['#submit'][] = 'vbo_redirect_after_operation' ;
            }
        }
    }
    
    // callback function to set redirect url
    function vbo_redirect_after_operation($form, &$form_state){
        $vbo_redirect_url = trim( variable_get('vbo_redirect_url') ) ;
        $form_state['redirect'] = $vbo_redirect_url;
    }
    • VBO一括処理の「確認のステップをスキップ」があるか、ないかを分けて処理します(画面遷移設定場所が違うため)
    • "#submit"に画面遷移処理を追加します
    • 画面遷移処理は$form_state['redirect'] で行います

結論と感想:簡単のカスタモジュールでVBOへの影響はありません。各オペレーション設定に画面遷移オプションを追加したほうよいかもしれない

  • このカスタムモジュールのインストールより、モジュール(VBO)への影響はありません
  • この画面遷移オプションを「Bulk Operation Settings」に追加したので、すべてのオペレーションに適応されます
    • VBOの一括処理内容がいろいろあります(例:オーナー変更、エンティティ内容変更など)
    • これらの処理後に一つの画面遷移先の設定はやや強引的だと思います
  • できれば、「Selected Bulk Operations」にある、選択したオペレーションの設定に画面遷移先の設定をしたほうが柔軟的な対応だと思います(次回の課題)
    画面遷移オプションを各オペレーションに追加すべき
添付 サイズ
vbo_redirect_option.zip (1.19 KB) 1.19 KB
Embedded thumbnail for Drupalのモジュール(VBO)の一括処理後にページ遷移させる方法
drupal
form
ajax

やりたいこと:Drupalのajaxフレームワークを利用して表示している要素を削除

  • Drupalのモジュール(Views)で作成した一覧の要素を選択して削除します
    • 要素を選択して削除するモジュール:Views Bulk Operations
    • 例:Drupalのモジュール(VBO)の各種処理(Operation)に独自(カスタムオ)のプションの追加方法
  • 前提条件:要素削除する確認の必要はありません
  • ajaxで動的に削除するのはやさしいUIとも言えるでしょう(以下のイメージのように削除)
    Drupalのajaxフレームワークより要素を動的に削除

Step1:削除リンクにDrupalのajax使用するクラス:use-ajax を追加

  • Drupalのajaxフレームワークに関する説明は以下の記事をご参考ください
    • Drupalでajaxのフレームワークが簡単に作成できる
  • 削除アイコン付きのリンクは以下のようです
    // 削除エレメントID:123 (例)
    <a href="/delete/element/id/123/nojs" class="use-ajax del-link" id="del-link-123">
           <i class="fa fa-trash-o" aria-hidden="true"></i>
    </a>
    • アンカー(a)に削除するエレメントID(または別の識別パラメーター)を入れる必要はあります
    • アンカーリンクの後ろに「nojs」を追加します(クライアント側のajax作動時に、nojs->ajaxに変換され)
    • アンカーがクリックされると、Drupalのajaxフレームワークが起動され、削除パラメーターをサイト側に渡します

Step2:hook_menuで要素削除のリクエストをキャッチします

  • hook_menuで要素削除のリクエストを受け取り、削除処理を行います
    // 要素削除URLの設定
    $items['delete/element/%/nojs'] = array(
    	'page callback' => 'delete_element',
    	'page arguments' => array( 2, 3 ) ,
    	'access callback' => 'delete_access',
    	'type' => MENU_CALLBACK,
    );
    // ajaxが以下のURLでリクエストをします(クライアント側でnojs->ajaxに変換)
    $items['delete/element/%/ajax'] = array(
    	'delivery callback' => 'ajax_deliver',
    )+$items['delete/element/%/nojs'] ;    // 要素削除定義に遷移
    
  • 要素削除処理ファンクション:delete_element で削除処理、処理結果をクライアント側に返します
    function delete_element ($id, $ajax){
        $is_ajax = $ajax === "ajax" ;  // ajaxと通用のリクエスト両方対応のため
    
        // 要素をDBから削除
        db_delete("element_table")->condition("entity_id", $id)->execute() ;
    
        // 画面要素も削除コマンドを返す
        if( $is_ajax ){
            // ajaxで要素削除後の処理
            $commands = array();
            $commands[] = ajax_command_remove( '#element-123');
            return array(
              '#type'=>"ajax",
              '#commands' => $commands,
            );
        } else {
            // 通常での要素削除後の処理
            drupal_set_message(t('Deleted 1 vocabulary'));
            drupal_goto();
        }
    }

     

Drupalのajaxフレームワークで要素削除

纏め:Drupalのajaxフレームワークを利用すればajax処理が自動的に行います

  • 上記例では、削除リンクにクラス:use-ajax を追加するだけで、ajax関連処理を記述する必要はあります
    • 削除リンクではなく、削除ボタン(button)要素を使用する場合クラス: use-ajax-submit
  • サーバー側では、hook_menuで削除リンクの定義、削除リクエストをキャッチして、削除処理関数を作成します
    • DB上のデータ削除完了後に、クライアント側の要素削除命令(ajax_command_remove)を返せば良いです
  • この一連のajax処理の記述はほどんとありません。簡単、便利です
drupal
development
ajax

やりたいこと:Drupalのプログラムレベルで簡単にajaxを利用してクライアント側でデータ交信をしたいです

  • 環境:Drupal7.54
  • DrupalのFormAPIで簡単にajaxの実装ができます(Drupalのフォーム(FromAPI)でのajaxの実装 )
  • FormAPIだけではなく、Drupalをカスタマイズ時にいろいろなところでajaxを実装したいことがあります

ポイント1:Drupalでajaxに必要なライブラリをロードし、クライアント側にjquery.form.jsファイルをセット

  • サーバー側でdrupal.ajaxのライブラリをロードする必要があります
  • クライアント側にjquery.form.jsファイルを設置する必要があります
  • この処理はajax処理するページをロード時に行えれば良いです。
    • 例:hook_init()内で処理する
      /**
       * Implements hook_init().
       */
      function YOUR_MODULE_NAME_init()
      {
        drupal_add_js('misc/jquery.form.js');
        drupal_add_library('system','drupal.ajax');
      }
  • クライアント側のブラウザのプロパティでjquery.form.jsがセットされたことの確認ができます

ポイント2:クライアント側のajax起動リンク内にajax対応可否のパラメーター「nojs」とクラス属性「use-ajax」のセット

  • ajaxの起動リンクの作成基本パターン: 
    <a href="text/ajax/nojs/1234" class="use-ajax">ajaxリンク</a>
    • hrefにある「nojs」が決まりの文字
    • hrefにある「1234」はサーバー側に転送したい必要なパラメーター
    • class="use-ajax"はこのリンクがajax用に決める
  • クライアント側のjsで使用しているブラウザがajax対応可能かを判断して、ajax起動リンクに「nojs」のパラメーターを書き換え(利用可能:nojs⇒ajax)てサーバー側に転送
  • サーバー側がajax利用可否よりクライアント側にajax対応有無の結果を返します
    Drupalのajaxフレームワークの利用
  • 上記例のプログラムは以下のようで
    /**
     * Implements hook_init().
     */
    function test_module_init()
    {
      drupal_add_js('misc/jquery.form.js');
      drupal_add_library('system','drupal.ajax');
    }
    
    /**
     *  Implementation of hook_menu()
     */
    function test_module_menu() {
      $items['test/ajax/%/%']=array(     // URLの2,3番目がクライアント側で生成
          'page callback' => 'ajax_node_response',
          'page arguments' => array(2,3),   // URLの2,3番目の引数をコールバック関数に渡す
          'access callback' => 'user_access',
          'access arguments' => array('access content'),
          'type' => MENU_CALLBACK,
      );
      return $items;
    }
    
    function ajax_node_response($type="ajax", $nid=0){
      $node = node_load( $nid, NULL, false );
      $vnode = node_view($node);
      $output = theme('node', $vnode);
      if( $type="ajax" ){
        $commands=array();
        $commands[]=ajax_command_replace( '#block-system-main','<section id="block-system-main">'.$output.'</section>' ) ;
        $page = array(
          '#type' => 'ajax',
          '#commands' => $commands,
        );
        ajax_deliver( $page ) ;   // ajax対応ブラウザの結果
      } else {
        $output = '<div id="content">'.$output.'</div>';  // ajax非対応ブラウザの結果
        return $output;
      }
    }
    

ポイント3:クライアント側で実行させたい部分はajax_commandを使用します

  • クライアント側で処理結果をどこに入り替えはajax_command_replaceで指定します
  • 結果の挿入、入れ替え、削除、css処理などがいろいろあります。詳細は本家のajax_command一覧を参考してください

 

drupal
Views

やりたいこと:モジュール(VBO)の各処理(Operation)に独自(カスタム)オプションを追加したい

  • 前回モジュール(VBO)にたいして処理(Operation)オプション追加を紹介しました
    •  Drupalのモジュール(VBO)の一括処理後にページ遷移させる方法
    • このオプションは全VBOに対して作成したものですが、すべての処理に影響を与えています
  • 各種処理(Operation)に対してどのようにオプションを追加するか前回の課題として残っています
  • 今回はこの課題を解決に新しいカスタムモジュール(vbo_redirect_option)を作成して、紹介します
    モジュールVBOの各種処理に独自のオプション追加

hook_formとCtoolsのdepent systemより各オペレーションに独自のオプションを追加

  • VBOのオペレーション設定フォームがカスタマイズとして開放していないです(前回も説明した)
  • ここで、Drupalのhook_formでVBOのオペレーション設定画面を特定して、カスタムオプション追加することになりました
    function vbo_redirect_option_form_alter(&$form, &$form_state, $form_id)
    {
        if( isset($form_state['id']) && $form_state['id'] === "views_bulk_operations"){
    
            foreach( $form_state['input']['options']['vbo_operations'] as $key => $operation) {
                if( $operation['redirect_check'] && strlen( trim($operation['redirect_url']))>0 ) {
                    variable_set( $key, $operation['redirect_url'] );
                } else {
                    if( !empty( variable_get($key) ) ) variable_del( $key ) ;
                }
            }
    
    
            foreach( $form['options']['vbo_operations'] as $key => &$operation ){
                if( !is_array($operation) ) continue ;
    
                $redirect_url = variable_get($key);
                $dep_key = "edit-options-vbo-operations-" . str_replace("_", "-", str_replace("::","",$key) ) ;
    
                $operation['redirect_check'] = array(
                    '#type' => 'checkbox',
                    '#title' => t('Redirect page to after operation'),
                    '#default_value' =>  $redirect_url ? 1 : 0 ,
                    '#dependency' => array(    // Ctoolsのdependent systemに依存
                        $dep_key."-selected" => array(1),
                    ),
                );
                $operation['redirect_url'] = array(
                    '#type' => 'textfield',
                    '#title' => t('Provide label'),
                    '#title_display' => 'invisible',
                    '#default_value' => empty($redirect_url) ? "" : $redirect_url,
                    '#dependency' => array(    // Ctoolsのdependent systemに依存
                        $dep_key."-selected" => array(1),
                        $dep_key . '-redirect-check' => array(1),
                    ),
                    '#dependency_count' => 2,
                );
            }
        }
    }
    • 設定フォームにチェックボックスをチェックしたら、画面遷移URL入力フィールドが現れるダイナミックフォームはモジュール(Ctools)のdependent systemを利用しています

処理(Operation)確認ステップをスキップがあるかないかを確認してhook_views_bulk_operations_form_alter()実装でオプションの設定を行う

  • VBOの処理(Operation)が確認ステップがあるかないかは2種類あります(この二種類をの処理プロセスが違うのでしっかりテストする必要がある)
  • hook_views_bulk_operations_form_alter()を実装して、各処理ステップにカスタマイズを行います
    function vbo_redirect_option_views_bulk_operations_form_alter(&$form, &$form_state, $vbo)
    {
        // collect all operations that has contained redirect_rul
        $redirect_arr = array();
        foreach( $vbo->options['vbo_operations'] as $key => $operation ) {
            if( !empty( variable_get($key) ) ){
                $redirect_arr[$key] = $key ;
            }
        }
    
        // add redirect step to #submit element
        if(isset($form['select'])) {
    
            // this is the form start step
            foreach( $form['select'] as $key => &$element ){
                if( isset($redirect_arr[$key]) ){
                    // we check if there is any operation has redirect_url
                    $element['#submit'][] = 'vbo_redirect_after_operation';
                    // only one is enough, we will detect witch one in the callback function
                    break;
                }
            }
    
            // do operation with confirmation step
            // this is the confirmation step
        } else if( !$form_state['operation']->getAdminOption('skip_confirmation') ) {
            $form['actions']['submit']['#submit'][] = "vbo_redirect_after_operation_with_confirmation";
            $form_state['redirect_to_after_operation'] = $form_state['operation']->getAdminOption('redirect_url');
        }
    
    }
    
    
    /**
     * callback function that has called by operation
     * this is the form start step, we don't know if it has confirmation step or not
     * @param $form
     * @param $form_state
     */
    function vbo_redirect_after_operation(&$form, &$form_state){
        // the are multiple element can be operated
        // the right one that has be sent to this step
        // we need get redirect_url if the it has
        if( isset($form_state['operation']) ){
            // get redirect_url by operation_id
            $redirec=variable_get($form_state['operation']->operationId) ;
            if( !empty($redirec) ){
                if( $form_state['operation']->getAdminOption('skip_confirmation') ) {
                    $form_state['redirect'] = $redirec;
                }
            }
        }
    }
    
    /**
     * callback function that has be called by operation with confirmation step
     * @param $form
     * @param $form_state
     */
    function vbo_redirect_after_operation_with_confirmation( $form, &$form_state ){
        // there is only operation that has be sent here with the confirmation step
        if( isset($form_state['redirect_to_after_operation']) ){
            // set redirect_url that should be stored in $form_state
            $form_state['redirect'] = $form_state['redir ect_to_after_operation'];
        }
    }

感想と結論:VBOの処理オプション設定はカスタマイズに開放していないため、各種処理(Operation)のオプションの取得、設定に苦労します

  • VBOの処理オプション設定はユーザーにカスタマイズに開放していないです
  • オペレーションの各ステップに$form、$form_state、$vbo変数から必要な情報を取得したり、セットしたりしました
  • 必要な情報がどこにあるかは不明だし(その時dsm($vbo)などで確認)、特定するまでに、時間がかかりました。
添付 サイズ
vbo_redirect_option.zip (1.77 KB) 1.77 KB
Embedded thumbnail for Drupalのモジュール(VBO)の各種処理(Operation)に独自(カスタムオ)のプションの追加方法
drupal
development
Views

Drupalのモジュール(Rules)で作成した各種アクションセットコンポーネントをモジュールVBOで一括処理

  • 背景:Drupal7.x.56、Views Bulk Operation(VBO)7.x-3.4、Rules7.x-2.10
  • モジュール(Rules)がいろいろなアクションセットの作成ができます
    • データの作成/更新/削除
    • メール送信、フラグを立てる
    • などなど
  • モジュール(VBO)がRulesで作成したアクションコンポーネントの利用ができます
    • Drupalのモジュール(Rules)のアクションコンポーネントでVBOより新規ノード作成とフィールドのコピー
  • 今回の例として、Rulesでメッセージ表示する単純なアクションコンポーネント(show message)を作成して、VBOで一括処理を行います
    Rulesでメッセージ表示コンポーネントをVBOで一括処理

問題点:VBO一括処理後に画面遷移(redirect)はできません

  • VBOで一括処理後に、画面を遷移して処理結果を確認することがあります
  • VBOの設定オプションに、処理後の画面遷移設定がありません
  • ネットで調べてみたが、VBO一括処理後の画面遷移オプション追加パッチがります
    • これは、モジュールVBOに対するパッチです
    • このパッチ適応したら、次回VBOアップグレード時に、ソースのマージ作業が面だと思います
    • できれば、VBOのパッチを使用したくないです

解決:カスタムモジュール(vbo_redirect_option.zip)でVBO処理後の画面遷移オプションの追加

  • モジュール(VBO)の主要部分がクラス(class)構造なので、簡単に画面遷移ロジックを追加することはできません
  • 「Bulk Operation Settings」に処理後の画面遷移オプションを追加します
    • 「Bulk Operation Settings」のオーバーライドができないので、hook_form_alter()でオプションを追加することになりました
      /**
       * Implements hook_form_alter().
       */
      function vbo_redirect_option_form_alter(&$form, &$form_state, $form_id)
      {
        // VBOの処理かのチェック
          if( isset($form_state['id']) && $form_state['id'] === "views_bulk_operations"){
      
         // ここで、画面遷移先の保存処理は少し反則
         //  vbo_settingsに画面遷移先の追加は難しい(クラス構造体内にあるため)
         //  環境変数に画面遷移先(uri)を保存
              if( isset($form_state['input']['options']['vbo_settings'][vbo_redirect_url]) ){
                  variable_set( 'vbo_redirect_url', $form_state['input']['options']['vbo_settings'][vbo_redirect_url] ) ;
              }
      
         // 画面遷移先のテキストフィールドを追加
              $form['options']['vbo_settings']['vbo_redirect_url'] = array(
                  '#type' => 'textfield',
                  '#title' => t('Page to direct to after completion of  batch'),
                  '#description' => t('Redirects to the view when finished the operation'),
                  '#default_value' => variable_get('vbo_redirect_url'),
              );
          }
      }
    • 画面遷移先を入力するテキストフィールドを設定画面に追加
    • 画面遷移先(uri)をvbo_settingsに入れたいですが、クラスの構造体にあるため追加できません。環境変数に保存することにしました。
    • 設定画面を保存("#submit")後に、画面遷移先を保存する処理を行いたいですが、"#submit"にコールバック関数を入れても、呼び出されない現象があって、仕方がなく、hook_form_alter()内で画面遷移先(uri)の保存処理を行いました
      VBOに一括処理後に画面遷移オプションの追加
  • hook_views_bulk_operations_form_alter()を実装して、実際のVBO一括処理後に、画面遷移設定を行います
    /**
     * Implements hook_views_bulk_operations_form_alter().
     */
    function vbo_redirect_option_views_bulk_operations_form_alter(&$form, &$form_state, $vbo)
    {
        $vbo_redirect_url = trim( variable_get('vbo_redirect_url') ) ;
    
        if( isset($vbo_redirect_url) && strlen($vbo_redirect_url) >0 ){
    
            // check if vbo operation skip confirmation
            $skip_confirmation = false ;
            foreach( $vbo->options['vbo_operations'] as $key => $operation ){
                if( $operation['selected'] && $operation['skip_confirmation'] ){
                    if( isset($form['select'][$key]) ) {
                        $form['select'][$key]['#submit'][] = 'vbo_redirect_after_operation';
                        $skip_confirmation = true ;
                    }
                }
            }
    
            // set redirect method when vbo has confirmation step
            if( !$skip_confirmation ){
                $form['actions']['submit']['#submit'][] = 'vbo_redirect_after_operation' ;
            }
        }
    }
    
    // callback function to set redirect url
    function vbo_redirect_after_operation($form, &$form_state){
        $vbo_redirect_url = trim( variable_get('vbo_redirect_url') ) ;
        $form_state['redirect'] = $vbo_redirect_url;
    }
    • VBO一括処理の「確認のステップをスキップ」があるか、ないかを分けて処理します(画面遷移設定場所が違うため)
    • "#submit"に画面遷移処理を追加します
    • 画面遷移処理は$form_state['redirect'] で行います

結論と感想:簡単のカスタモジュールでVBOへの影響はありません。各オペレーション設定に画面遷移オプションを追加したほうよいかもしれない

  • このカスタムモジュールのインストールより、モジュール(VBO)への影響はありません
  • この画面遷移オプションを「Bulk Operation Settings」に追加したので、すべてのオペレーションに適応されます
    • VBOの一括処理内容がいろいろあります(例:オーナー変更、エンティティ内容変更など)
    • これらの処理後に一つの画面遷移先の設定はやや強引的だと思います
  • できれば、「Selected Bulk Operations」にある、選択したオペレーションの設定に画面遷移先の設定をしたほうが柔軟的な対応だと思います(次回の課題)
    画面遷移オプションを各オペレーションに追加すべき
添付 サイズ
vbo_redirect_option.zip (1.19 KB) 1.19 KB
Embedded thumbnail for Drupalのモジュール(VBO)の一括処理後にページ遷移させる方法
drupal
form
ajax

やりたいこと:Drupalのajaxフレームワークを利用して表示している要素を削除

  • Drupalのモジュール(Views)で作成した一覧の要素を選択して削除します
    • 要素を選択して削除するモジュール:Views Bulk Operations
    • 例:Drupalのモジュール(VBO)の各種処理(Operation)に独自(カスタムオ)のプションの追加方法
  • 前提条件:要素削除する確認の必要はありません
  • ajaxで動的に削除するのはやさしいUIとも言えるでしょう(以下のイメージのように削除)
    Drupalのajaxフレームワークより要素を動的に削除

Step1:削除リンクにDrupalのajax使用するクラス:use-ajax を追加

  • Drupalのajaxフレームワークに関する説明は以下の記事をご参考ください
    • Drupalでajaxのフレームワークが簡単に作成できる
  • 削除アイコン付きのリンクは以下のようです
    // 削除エレメントID:123 (例)
    <a href="/delete/element/id/123/nojs" class="use-ajax del-link" id="del-link-123">
           <i class="fa fa-trash-o" aria-hidden="true"></i>
    </a>
    • アンカー(a)に削除するエレメントID(または別の識別パラメーター)を入れる必要はあります
    • アンカーリンクの後ろに「nojs」を追加します(クライアント側のajax作動時に、nojs->ajaxに変換され)
    • アンカーがクリックされると、Drupalのajaxフレームワークが起動され、削除パラメーターをサイト側に渡します

Step2:hook_menuで要素削除のリクエストをキャッチします

  • hook_menuで要素削除のリクエストを受け取り、削除処理を行います
    // 要素削除URLの設定
    $items['delete/element/%/nojs'] = array(
    	'page callback' => 'delete_element',
    	'page arguments' => array( 2, 3 ) ,
    	'access callback' => 'delete_access',
    	'type' => MENU_CALLBACK,
    );
    // ajaxが以下のURLでリクエストをします(クライアント側でnojs->ajaxに変換)
    $items['delete/element/%/ajax'] = array(
    	'delivery callback' => 'ajax_deliver',
    )+$items['delete/element/%/nojs'] ;    // 要素削除定義に遷移
    
  • 要素削除処理ファンクション:delete_element で削除処理、処理結果をクライアント側に返します
    function delete_element ($id, $ajax){
        $is_ajax = $ajax === "ajax" ;  // ajaxと通用のリクエスト両方対応のため
    
        // 要素をDBから削除
        db_delete("element_table")->condition("entity_id", $id)->execute() ;
    
        // 画面要素も削除コマンドを返す
        if( $is_ajax ){
            // ajaxで要素削除後の処理
            $commands = array();
            $commands[] = ajax_command_remove( '#element-123');
            return array(
              '#type'=>"ajax",
              '#commands' => $commands,
            );
        } else {
            // 通常での要素削除後の処理
            drupal_set_message(t('Deleted 1 vocabulary'));
            drupal_goto();
        }
    }

     

Drupalのajaxフレームワークで要素削除

纏め:Drupalのajaxフレームワークを利用すればajax処理が自動的に行います

  • 上記例では、削除リンクにクラス:use-ajax を追加するだけで、ajax関連処理を記述する必要はあります
    • 削除リンクではなく、削除ボタン(button)要素を使用する場合クラス: use-ajax-submit
  • サーバー側では、hook_menuで削除リンクの定義、削除リクエストをキャッチして、削除処理関数を作成します
    • DB上のデータ削除完了後に、クライアント側の要素削除命令(ajax_command_remove)を返せば良いです
  • この一連のajax処理の記述はほどんとありません。簡単、便利です
drupal
development
ajax

やりたいこと:Drupalのプログラムレベルで簡単にajaxを利用してクライアント側でデータ交信をしたいです

  • 環境:Drupal7.54
  • DrupalのFormAPIで簡単にajaxの実装ができます(Drupalのフォーム(FromAPI)でのajaxの実装 )
  • FormAPIだけではなく、Drupalをカスタマイズ時にいろいろなところでajaxを実装したいことがあります

ポイント1:Drupalでajaxに必要なライブラリをロードし、クライアント側にjquery.form.jsファイルをセット

  • サーバー側でdrupal.ajaxのライブラリをロードする必要があります
  • クライアント側にjquery.form.jsファイルを設置する必要があります
  • この処理はajax処理するページをロード時に行えれば良いです。
    • 例:hook_init()内で処理する
      /**
       * Implements hook_init().
       */
      function YOUR_MODULE_NAME_init()
      {
        drupal_add_js('misc/jquery.form.js');
        drupal_add_library('system','drupal.ajax');
      }
  • クライアント側のブラウザのプロパティでjquery.form.jsがセットされたことの確認ができます

ポイント2:クライアント側のajax起動リンク内にajax対応可否のパラメーター「nojs」とクラス属性「use-ajax」のセット

  • ajaxの起動リンクの作成基本パターン: 
    <a href="text/ajax/nojs/1234" class="use-ajax">ajaxリンク</a>
    • hrefにある「nojs」が決まりの文字
    • hrefにある「1234」はサーバー側に転送したい必要なパラメーター
    • class="use-ajax"はこのリンクがajax用に決める
  • クライアント側のjsで使用しているブラウザがajax対応可能かを判断して、ajax起動リンクに「nojs」のパラメーターを書き換え(利用可能:nojs⇒ajax)てサーバー側に転送
  • サーバー側がajax利用可否よりクライアント側にajax対応有無の結果を返します
    Drupalのajaxフレームワークの利用
  • 上記例のプログラムは以下のようで
    /**
     * Implements hook_init().
     */
    function test_module_init()
    {
      drupal_add_js('misc/jquery.form.js');
      drupal_add_library('system','drupal.ajax');
    }
    
    /**
     *  Implementation of hook_menu()
     */
    function test_module_menu() {
      $items['test/ajax/%/%']=array(     // URLの2,3番目がクライアント側で生成
          'page callback' => 'ajax_node_response',
          'page arguments' => array(2,3),   // URLの2,3番目の引数をコールバック関数に渡す
          'access callback' => 'user_access',
          'access arguments' => array('access content'),
          'type' => MENU_CALLBACK,
      );
      return $items;
    }
    
    function ajax_node_response($type="ajax", $nid=0){
      $node = node_load( $nid, NULL, false );
      $vnode = node_view($node);
      $output = theme('node', $vnode);
      if( $type="ajax" ){
        $commands=array();
        $commands[]=ajax_command_replace( '#block-system-main','<section id="block-system-main">'.$output.'</section>' ) ;
        $page = array(
          '#type' => 'ajax',
          '#commands' => $commands,
        );
        ajax_deliver( $page ) ;   // ajax対応ブラウザの結果
      } else {
        $output = '<div id="content">'.$output.'</div>';  // ajax非対応ブラウザの結果
        return $output;
      }
    }
    

ポイント3:クライアント側で実行させたい部分はajax_commandを使用します

  • クライアント側で処理結果をどこに入り替えはajax_command_replaceで指定します
  • 結果の挿入、入れ替え、削除、css処理などがいろいろあります。詳細は本家のajax_command一覧を参考してください

 

drupal
Views

やりたいこと:モジュール(VBO)の各処理(Operation)に独自(カスタム)オプションを追加したい

  • 前回モジュール(VBO)にたいして処理(Operation)オプション追加を紹介しました
    •  Drupalのモジュール(VBO)の一括処理後にページ遷移させる方法
    • このオプションは全VBOに対して作成したものですが、すべての処理に影響を与えています
  • 各種処理(Operation)に対してどのようにオプションを追加するか前回の課題として残っています
  • 今回はこの課題を解決に新しいカスタムモジュール(vbo_redirect_option)を作成して、紹介します
    モジュールVBOの各種処理に独自のオプション追加

hook_formとCtoolsのdepent systemより各オペレーションに独自のオプションを追加

  • VBOのオペレーション設定フォームがカスタマイズとして開放していないです(前回も説明した)
  • ここで、Drupalのhook_formでVBOのオペレーション設定画面を特定して、カスタムオプション追加することになりました
    function vbo_redirect_option_form_alter(&$form, &$form_state, $form_id)
    {
        if( isset($form_state['id']) && $form_state['id'] === "views_bulk_operations"){
    
            foreach( $form_state['input']['options']['vbo_operations'] as $key => $operation) {
                if( $operation['redirect_check'] && strlen( trim($operation['redirect_url']))>0 ) {
                    variable_set( $key, $operation['redirect_url'] );
                } else {
                    if( !empty( variable_get($key) ) ) variable_del( $key ) ;
                }
            }
    
    
            foreach( $form['options']['vbo_operations'] as $key => &$operation ){
                if( !is_array($operation) ) continue ;
    
                $redirect_url = variable_get($key);
                $dep_key = "edit-options-vbo-operations-" . str_replace("_", "-", str_replace("::","",$key) ) ;
    
                $operation['redirect_check'] = array(
                    '#type' => 'checkbox',
                    '#title' => t('Redirect page to after operation'),
                    '#default_value' =>  $redirect_url ? 1 : 0 ,
                    '#dependency' => array(    // Ctoolsのdependent systemに依存
                        $dep_key."-selected" => array(1),
                    ),
                );
                $operation['redirect_url'] = array(
                    '#type' => 'textfield',
                    '#title' => t('Provide label'),
                    '#title_display' => 'invisible',
                    '#default_value' => empty($redirect_url) ? "" : $redirect_url,
                    '#dependency' => array(    // Ctoolsのdependent systemに依存
                        $dep_key."-selected" => array(1),
                        $dep_key . '-redirect-check' => array(1),
                    ),
                    '#dependency_count' => 2,
                );
            }
        }
    }
    • 設定フォームにチェックボックスをチェックしたら、画面遷移URL入力フィールドが現れるダイナミックフォームはモジュール(Ctools)のdependent systemを利用しています

処理(Operation)確認ステップをスキップがあるかないかを確認してhook_views_bulk_operations_form_alter()実装でオプションの設定を行う

  • VBOの処理(Operation)が確認ステップがあるかないかは2種類あります(この二種類をの処理プロセスが違うのでしっかりテストする必要がある)
  • hook_views_bulk_operations_form_alter()を実装して、各処理ステップにカスタマイズを行います
    function vbo_redirect_option_views_bulk_operations_form_alter(&$form, &$form_state, $vbo)
    {
        // collect all operations that has contained redirect_rul
        $redirect_arr = array();
        foreach( $vbo->options['vbo_operations'] as $key => $operation ) {
            if( !empty( variable_get($key) ) ){
                $redirect_arr[$key] = $key ;
            }
        }
    
        // add redirect step to #submit element
        if(isset($form['select'])) {
    
            // this is the form start step
            foreach( $form['select'] as $key => &$element ){
                if( isset($redirect_arr[$key]) ){
                    // we check if there is any operation has redirect_url
                    $element['#submit'][] = 'vbo_redirect_after_operation';
                    // only one is enough, we will detect witch one in the callback function
                    break;
                }
            }
    
            // do operation with confirmation step
            // this is the confirmation step
        } else if( !$form_state['operation']->getAdminOption('skip_confirmation') ) {
            $form['actions']['submit']['#submit'][] = "vbo_redirect_after_operation_with_confirmation";
            $form_state['redirect_to_after_operation'] = $form_state['operation']->getAdminOption('redirect_url');
        }
    
    }
    
    
    /**
     * callback function that has called by operation
     * this is the form start step, we don't know if it has confirmation step or not
     * @param $form
     * @param $form_state
     */
    function vbo_redirect_after_operation(&$form, &$form_state){
        // the are multiple element can be operated
        // the right one that has be sent to this step
        // we need get redirect_url if the it has
        if( isset($form_state['operation']) ){
            // get redirect_url by operation_id
            $redirec=variable_get($form_state['operation']->operationId) ;
            if( !empty($redirec) ){
                if( $form_state['operation']->getAdminOption('skip_confirmation') ) {
                    $form_state['redirect'] = $redirec;
                }
            }
        }
    }
    
    /**
     * callback function that has be called by operation with confirmation step
     * @param $form
     * @param $form_state
     */
    function vbo_redirect_after_operation_with_confirmation( $form, &$form_state ){
        // there is only operation that has be sent here with the confirmation step
        if( isset($form_state['redirect_to_after_operation']) ){
            // set redirect_url that should be stored in $form_state
            $form_state['redirect'] = $form_state['redir ect_to_after_operation'];
        }
    }

感想と結論:VBOの処理オプション設定はカスタマイズに開放していないため、各種処理(Operation)のオプションの取得、設定に苦労します

  • VBOの処理オプション設定はユーザーにカスタマイズに開放していないです
  • オペレーションの各ステップに$form、$form_state、$vbo変数から必要な情報を取得したり、セットしたりしました
  • 必要な情報がどこにあるかは不明だし(その時dsm($vbo)などで確認)、特定するまでに、時間がかかりました。
添付 サイズ
vbo_redirect_option.zip (1.77 KB) 1.77 KB
Embedded thumbnail for Drupalのモジュール(VBO)の各種処理(Operation)に独自(カスタムオ)のプションの追加方法
drupal
development
Views

Drupalのモジュール(Rules)で作成した各種アクションセットコンポーネントをモジュールVBOで一括処理

  • 背景:Drupal7.x.56、Views Bulk Operation(VBO)7.x-3.4、Rules7.x-2.10
  • モジュール(Rules)がいろいろなアクションセットの作成ができます
    • データの作成/更新/削除
    • メール送信、フラグを立てる
    • などなど
  • モジュール(VBO)がRulesで作成したアクションコンポーネントの利用ができます
    • Drupalのモジュール(Rules)のアクションコンポーネントでVBOより新規ノード作成とフィールドのコピー
  • 今回の例として、Rulesでメッセージ表示する単純なアクションコンポーネント(show message)を作成して、VBOで一括処理を行います
    Rulesでメッセージ表示コンポーネントをVBOで一括処理

問題点:VBO一括処理後に画面遷移(redirect)はできません

  • VBOで一括処理後に、画面を遷移して処理結果を確認することがあります
  • VBOの設定オプションに、処理後の画面遷移設定がありません
  • ネットで調べてみたが、VBO一括処理後の画面遷移オプション追加パッチがります
    • これは、モジュールVBOに対するパッチです
    • このパッチ適応したら、次回VBOアップグレード時に、ソースのマージ作業が面だと思います
    • できれば、VBOのパッチを使用したくないです

解決:カスタムモジュール(vbo_redirect_option.zip)でVBO処理後の画面遷移オプションの追加

  • モジュール(VBO)の主要部分がクラス(class)構造なので、簡単に画面遷移ロジックを追加することはできません
  • 「Bulk Operation Settings」に処理後の画面遷移オプションを追加します
    • 「Bulk Operation Settings」のオーバーライドができないので、hook_form_alter()でオプションを追加することになりました
      /**
       * Implements hook_form_alter().
       */
      function vbo_redirect_option_form_alter(&$form, &$form_state, $form_id)
      {
        // VBOの処理かのチェック
          if( isset($form_state['id']) && $form_state['id'] === "views_bulk_operations"){
      
         // ここで、画面遷移先の保存処理は少し反則
         //  vbo_settingsに画面遷移先の追加は難しい(クラス構造体内にあるため)
         //  環境変数に画面遷移先(uri)を保存
              if( isset($form_state['input']['options']['vbo_settings'][vbo_redirect_url]) ){
                  variable_set( 'vbo_redirect_url', $form_state['input']['options']['vbo_settings'][vbo_redirect_url] ) ;
              }
      
         // 画面遷移先のテキストフィールドを追加
              $form['options']['vbo_settings']['vbo_redirect_url'] = array(
                  '#type' => 'textfield',
                  '#title' => t('Page to direct to after completion of  batch'),
                  '#description' => t('Redirects to the view when finished the operation'),
                  '#default_value' => variable_get('vbo_redirect_url'),
              );
          }
      }
    • 画面遷移先を入力するテキストフィールドを設定画面に追加
    • 画面遷移先(uri)をvbo_settingsに入れたいですが、クラスの構造体にあるため追加できません。環境変数に保存することにしました。
    • 設定画面を保存("#submit")後に、画面遷移先を保存する処理を行いたいですが、"#submit"にコールバック関数を入れても、呼び出されない現象があって、仕方がなく、hook_form_alter()内で画面遷移先(uri)の保存処理を行いました
      VBOに一括処理後に画面遷移オプションの追加
  • hook_views_bulk_operations_form_alter()を実装して、実際のVBO一括処理後に、画面遷移設定を行います
    /**
     * Implements hook_views_bulk_operations_form_alter().
     */
    function vbo_redirect_option_views_bulk_operations_form_alter(&$form, &$form_state, $vbo)
    {
        $vbo_redirect_url = trim( variable_get('vbo_redirect_url') ) ;
    
        if( isset($vbo_redirect_url) && strlen($vbo_redirect_url) >0 ){
    
            // check if vbo operation skip confirmation
            $skip_confirmation = false ;
            foreach( $vbo->options['vbo_operations'] as $key => $operation ){
                if( $operation['selected'] && $operation['skip_confirmation'] ){
                    if( isset($form['select'][$key]) ) {
                        $form['select'][$key]['#submit'][] = 'vbo_redirect_after_operation';
                        $skip_confirmation = true ;
                    }
                }
            }
    
            // set redirect method when vbo has confirmation step
            if( !$skip_confirmation ){
                $form['actions']['submit']['#submit'][] = 'vbo_redirect_after_operation' ;
            }
        }
    }
    
    // callback function to set redirect url
    function vbo_redirect_after_operation($form, &$form_state){
        $vbo_redirect_url = trim( variable_get('vbo_redirect_url') ) ;
        $form_state['redirect'] = $vbo_redirect_url;
    }
    • VBO一括処理の「確認のステップをスキップ」があるか、ないかを分けて処理します(画面遷移設定場所が違うため)
    • "#submit"に画面遷移処理を追加します
    • 画面遷移処理は$form_state['redirect'] で行います

結論と感想:簡単のカスタモジュールでVBOへの影響はありません。各オペレーション設定に画面遷移オプションを追加したほうよいかもしれない

  • このカスタムモジュールのインストールより、モジュール(VBO)への影響はありません
  • この画面遷移オプションを「Bulk Operation Settings」に追加したので、すべてのオペレーションに適応されます
    • VBOの一括処理内容がいろいろあります(例:オーナー変更、エンティティ内容変更など)
    • これらの処理後に一つの画面遷移先の設定はやや強引的だと思います
  • できれば、「Selected Bulk Operations」にある、選択したオペレーションの設定に画面遷移先の設定をしたほうが柔軟的な対応だと思います(次回の課題)
    画面遷移オプションを各オペレーションに追加すべき
添付 サイズ
vbo_redirect_option.zip (1.19 KB) 1.19 KB
Embedded thumbnail for Drupalのモジュール(VBO)の一括処理後にページ遷移させる方法
drupal
form
ajax

やりたいこと:Drupalのajaxフレームワークを利用して表示している要素を削除

  • Drupalのモジュール(Views)で作成した一覧の要素を選択して削除します
    • 要素を選択して削除するモジュール:Views Bulk Operations
    • 例:Drupalのモジュール(VBO)の各種処理(Operation)に独自(カスタムオ)のプションの追加方法
  • 前提条件:要素削除する確認の必要はありません
  • ajaxで動的に削除するのはやさしいUIとも言えるでしょう(以下のイメージのように削除)
    Drupalのajaxフレームワークより要素を動的に削除

Step1:削除リンクにDrupalのajax使用するクラス:use-ajax を追加

  • Drupalのajaxフレームワークに関する説明は以下の記事をご参考ください
    • Drupalでajaxのフレームワークが簡単に作成できる
  • 削除アイコン付きのリンクは以下のようです
    // 削除エレメントID:123 (例)
    <a href="/delete/element/id/123/nojs" class="use-ajax del-link" id="del-link-123">
           <i class="fa fa-trash-o" aria-hidden="true"></i>
    </a>
    • アンカー(a)に削除するエレメントID(または別の識別パラメーター)を入れる必要はあります
    • アンカーリンクの後ろに「nojs」を追加します(クライアント側のajax作動時に、nojs->ajaxに変換され)
    • アンカーがクリックされると、Drupalのajaxフレームワークが起動され、削除パラメーターをサイト側に渡します

Step2:hook_menuで要素削除のリクエストをキャッチします

  • hook_menuで要素削除のリクエストを受け取り、削除処理を行います
    // 要素削除URLの設定
    $items['delete/element/%/nojs'] = array(
    	'page callback' => 'delete_element',
    	'page arguments' => array( 2, 3 ) ,
    	'access callback' => 'delete_access',
    	'type' => MENU_CALLBACK,
    );
    // ajaxが以下のURLでリクエストをします(クライアント側でnojs->ajaxに変換)
    $items['delete/element/%/ajax'] = array(
    	'delivery callback' => 'ajax_deliver',
    )+$items['delete/element/%/nojs'] ;    // 要素削除定義に遷移
    
  • 要素削除処理ファンクション:delete_element で削除処理、処理結果をクライアント側に返します
    function delete_element ($id, $ajax){
        $is_ajax = $ajax === "ajax" ;  // ajaxと通用のリクエスト両方対応のため
    
        // 要素をDBから削除
        db_delete("element_table")->condition("entity_id", $id)->execute() ;
    
        // 画面要素も削除コマンドを返す
        if( $is_ajax ){
            // ajaxで要素削除後の処理
            $commands = array();
            $commands[] = ajax_command_remove( '#element-123');
            return array(
              '#type'=>"ajax",
              '#commands' => $commands,
            );
        } else {
            // 通常での要素削除後の処理
            drupal_set_message(t('Deleted 1 vocabulary'));
            drupal_goto();
        }
    }

     

Drupalのajaxフレームワークで要素削除

纏め:Drupalのajaxフレームワークを利用すればajax処理が自動的に行います

  • 上記例では、削除リンクにクラス:use-ajax を追加するだけで、ajax関連処理を記述する必要はあります
    • 削除リンクではなく、削除ボタン(button)要素を使用する場合クラス: use-ajax-submit
  • サーバー側では、hook_menuで削除リンクの定義、削除リクエストをキャッチして、削除処理関数を作成します
    • DB上のデータ削除完了後に、クライアント側の要素削除命令(ajax_command_remove)を返せば良いです
  • この一連のajax処理の記述はほどんとありません。簡単、便利です
drupal
development
ajax

やりたいこと:Drupalのプログラムレベルで簡単にajaxを利用してクライアント側でデータ交信をしたいです

  • 環境:Drupal7.54
  • DrupalのFormAPIで簡単にajaxの実装ができます(Drupalのフォーム(FromAPI)でのajaxの実装 )
  • FormAPIだけではなく、Drupalをカスタマイズ時にいろいろなところでajaxを実装したいことがあります

ポイント1:Drupalでajaxに必要なライブラリをロードし、クライアント側にjquery.form.jsファイルをセット

  • サーバー側でdrupal.ajaxのライブラリをロードする必要があります
  • クライアント側にjquery.form.jsファイルを設置する必要があります
  • この処理はajax処理するページをロード時に行えれば良いです。
    • 例:hook_init()内で処理する
      /**
       * Implements hook_init().
       */
      function YOUR_MODULE_NAME_init()
      {
        drupal_add_js('misc/jquery.form.js');
        drupal_add_library('system','drupal.ajax');
      }
  • クライアント側のブラウザのプロパティでjquery.form.jsがセットされたことの確認ができます

ポイント2:クライアント側のajax起動リンク内にajax対応可否のパラメーター「nojs」とクラス属性「use-ajax」のセット

  • ajaxの起動リンクの作成基本パターン: 
    <a href="text/ajax/nojs/1234" class="use-ajax">ajaxリンク</a>
    • hrefにある「nojs」が決まりの文字
    • hrefにある「1234」はサーバー側に転送したい必要なパラメーター
    • class="use-ajax"はこのリンクがajax用に決める
  • クライアント側のjsで使用しているブラウザがajax対応可能かを判断して、ajax起動リンクに「nojs」のパラメーターを書き換え(利用可能:nojs⇒ajax)てサーバー側に転送
  • サーバー側がajax利用可否よりクライアント側にajax対応有無の結果を返します
    Drupalのajaxフレームワークの利用
  • 上記例のプログラムは以下のようで
    /**
     * Implements hook_init().
     */
    function test_module_init()
    {
      drupal_add_js('misc/jquery.form.js');
      drupal_add_library('system','drupal.ajax');
    }
    
    /**
     *  Implementation of hook_menu()
     */
    function test_module_menu() {
      $items['test/ajax/%/%']=array(     // URLの2,3番目がクライアント側で生成
          'page callback' => 'ajax_node_response',
          'page arguments' => array(2,3),   // URLの2,3番目の引数をコールバック関数に渡す
          'access callback' => 'user_access',
          'access arguments' => array('access content'),
          'type' => MENU_CALLBACK,
      );
      return $items;
    }
    
    function ajax_node_response($type="ajax", $nid=0){
      $node = node_load( $nid, NULL, false );
      $vnode = node_view($node);
      $output = theme('node', $vnode);
      if( $type="ajax" ){
        $commands=array();
        $commands[]=ajax_command_replace( '#block-system-main','<section id="block-system-main">'.$output.'</section>' ) ;
        $page = array(
          '#type' => 'ajax',
          '#commands' => $commands,
        );
        ajax_deliver( $page ) ;   // ajax対応ブラウザの結果
      } else {
        $output = '<div id="content">'.$output.'</div>';  // ajax非対応ブラウザの結果
        return $output;
      }
    }
    

ポイント3:クライアント側で実行させたい部分はajax_commandを使用します

  • クライアント側で処理結果をどこに入り替えはajax_command_replaceで指定します
  • 結果の挿入、入れ替え、削除、css処理などがいろいろあります。詳細は本家のajax_command一覧を参考してください

 

drupal
Views

やりたいこと:モジュール(VBO)の各処理(Operation)に独自(カスタム)オプションを追加したい

  • 前回モジュール(VBO)にたいして処理(Operation)オプション追加を紹介しました
    •  Drupalのモジュール(VBO)の一括処理後にページ遷移させる方法
    • このオプションは全VBOに対して作成したものですが、すべての処理に影響を与えています
  • 各種処理(Operation)に対してどのようにオプションを追加するか前回の課題として残っています
  • 今回はこの課題を解決に新しいカスタムモジュール(vbo_redirect_option)を作成して、紹介します
    モジュールVBOの各種処理に独自のオプション追加

hook_formとCtoolsのdepent systemより各オペレーションに独自のオプションを追加

  • VBOのオペレーション設定フォームがカスタマイズとして開放していないです(前回も説明した)
  • ここで、Drupalのhook_formでVBOのオペレーション設定画面を特定して、カスタムオプション追加することになりました
    function vbo_redirect_option_form_alter(&$form, &$form_state, $form_id)
    {
        if( isset($form_state['id']) && $form_state['id'] === "views_bulk_operations"){
    
            foreach( $form_state['input']['options']['vbo_operations'] as $key => $operation) {
                if( $operation['redirect_check'] && strlen( trim($operation['redirect_url']))>0 ) {
                    variable_set( $key, $operation['redirect_url'] );
                } else {
                    if( !empty( variable_get($key) ) ) variable_del( $key ) ;
                }
            }
    
    
            foreach( $form['options']['vbo_operations'] as $key => &$operation ){
                if( !is_array($operation) ) continue ;
    
                $redirect_url = variable_get($key);
                $dep_key = "edit-options-vbo-operations-" . str_replace("_", "-", str_replace("::","",$key) ) ;
    
                $operation['redirect_check'] = array(
                    '#type' => 'checkbox',
                    '#title' => t('Redirect page to after operation'),
                    '#default_value' =>  $redirect_url ? 1 : 0 ,
                    '#dependency' => array(    // Ctoolsのdependent systemに依存
                        $dep_key."-selected" => array(1),
                    ),
                );
                $operation['redirect_url'] = array(
                    '#type' => 'textfield',
                    '#title' => t('Provide label'),
                    '#title_display' => 'invisible',
                    '#default_value' => empty($redirect_url) ? "" : $redirect_url,
                    '#dependency' => array(    // Ctoolsのdependent systemに依存
                        $dep_key."-selected" => array(1),
                        $dep_key . '-redirect-check' => array(1),
                    ),
                    '#dependency_count' => 2,
                );
            }
        }
    }
    • 設定フォームにチェックボックスをチェックしたら、画面遷移URL入力フィールドが現れるダイナミックフォームはモジュール(Ctools)のdependent systemを利用しています

処理(Operation)確認ステップをスキップがあるかないかを確認してhook_views_bulk_operations_form_alter()実装でオプションの設定を行う

  • VBOの処理(Operation)が確認ステップがあるかないかは2種類あります(この二種類をの処理プロセスが違うのでしっかりテストする必要がある)
  • hook_views_bulk_operations_form_alter()を実装して、各処理ステップにカスタマイズを行います
    function vbo_redirect_option_views_bulk_operations_form_alter(&$form, &$form_state, $vbo)
    {
        // collect all operations that has contained redirect_rul
        $redirect_arr = array();
        foreach( $vbo->options['vbo_operations'] as $key => $operation ) {
            if( !empty( variable_get($key) ) ){
                $redirect_arr[$key] = $key ;
            }
        }
    
        // add redirect step to #submit element
        if(isset($form['select'])) {
    
            // this is the form start step
            foreach( $form['select'] as $key => &$element ){
                if( isset($redirect_arr[$key]) ){
                    // we check if there is any operation has redirect_url
                    $element['#submit'][] = 'vbo_redirect_after_operation';
                    // only one is enough, we will detect witch one in the callback function
                    break;
                }
            }
    
            // do operation with confirmation step
            // this is the confirmation step
        } else if( !$form_state['operation']->getAdminOption('skip_confirmation') ) {
            $form['actions']['submit']['#submit'][] = "vbo_redirect_after_operation_with_confirmation";
            $form_state['redirect_to_after_operation'] = $form_state['operation']->getAdminOption('redirect_url');
        }
    
    }
    
    
    /**
     * callback function that has called by operation
     * this is the form start step, we don't know if it has confirmation step or not
     * @param $form
     * @param $form_state
     */
    function vbo_redirect_after_operation(&$form, &$form_state){
        // the are multiple element can be operated
        // the right one that has be sent to this step
        // we need get redirect_url if the it has
        if( isset($form_state['operation']) ){
            // get redirect_url by operation_id
            $redirec=variable_get($form_state['operation']->operationId) ;
            if( !empty($redirec) ){
                if( $form_state['operation']->getAdminOption('skip_confirmation') ) {
                    $form_state['redirect'] = $redirec;
                }
            }
        }
    }
    
    /**
     * callback function that has be called by operation with confirmation step
     * @param $form
     * @param $form_state
     */
    function vbo_redirect_after_operation_with_confirmation( $form, &$form_state ){
        // there is only operation that has be sent here with the confirmation step
        if( isset($form_state['redirect_to_after_operation']) ){
            // set redirect_url that should be stored in $form_state
            $form_state['redirect'] = $form_state['redir ect_to_after_operation'];
        }
    }

感想と結論:VBOの処理オプション設定はカスタマイズに開放していないため、各種処理(Operation)のオプションの取得、設定に苦労します

  • VBOの処理オプション設定はユーザーにカスタマイズに開放していないです
  • オペレーションの各ステップに$form、$form_state、$vbo変数から必要な情報を取得したり、セットしたりしました
  • 必要な情報がどこにあるかは不明だし(その時dsm($vbo)などで確認)、特定するまでに、時間がかかりました。
添付 サイズ
vbo_redirect_option.zip (1.77 KB) 1.77 KB
Embedded thumbnail for Drupalのモジュール(VBO)の各種処理(Operation)に独自(カスタムオ)のプションの追加方法
drupal
development
Views

Drupalのモジュール(Rules)で作成した各種アクションセットコンポーネントをモジュールVBOで一括処理

  • 背景:Drupal7.x.56、Views Bulk Operation(VBO)7.x-3.4、Rules7.x-2.10
  • モジュール(Rules)がいろいろなアクションセットの作成ができます
    • データの作成/更新/削除
    • メール送信、フラグを立てる
    • などなど
  • モジュール(VBO)がRulesで作成したアクションコンポーネントの利用ができます
    • Drupalのモジュール(Rules)のアクションコンポーネントでVBOより新規ノード作成とフィールドのコピー
  • 今回の例として、Rulesでメッセージ表示する単純なアクションコンポーネント(show message)を作成して、VBOで一括処理を行います
    Rulesでメッセージ表示コンポーネントをVBOで一括処理

問題点:VBO一括処理後に画面遷移(redirect)はできません

  • VBOで一括処理後に、画面を遷移して処理結果を確認することがあります
  • VBOの設定オプションに、処理後の画面遷移設定がありません
  • ネットで調べてみたが、VBO一括処理後の画面遷移オプション追加パッチがります
    • これは、モジュールVBOに対するパッチです
    • このパッチ適応したら、次回VBOアップグレード時に、ソースのマージ作業が面だと思います
    • できれば、VBOのパッチを使用したくないです

解決:カスタムモジュール(vbo_redirect_option.zip)でVBO処理後の画面遷移オプションの追加

  • モジュール(VBO)の主要部分がクラス(class)構造なので、簡単に画面遷移ロジックを追加することはできません
  • 「Bulk Operation Settings」に処理後の画面遷移オプションを追加します
    • 「Bulk Operation Settings」のオーバーライドができないので、hook_form_alter()でオプションを追加することになりました
      /**
       * Implements hook_form_alter().
       */
      function vbo_redirect_option_form_alter(&$form, &$form_state, $form_id)
      {
        // VBOの処理かのチェック
          if( isset($form_state['id']) && $form_state['id'] === "views_bulk_operations"){
      
         // ここで、画面遷移先の保存処理は少し反則
         //  vbo_settingsに画面遷移先の追加は難しい(クラス構造体内にあるため)
         //  環境変数に画面遷移先(uri)を保存
              if( isset($form_state['input']['options']['vbo_settings'][vbo_redirect_url]) ){
                  variable_set( 'vbo_redirect_url', $form_state['input']['options']['vbo_settings'][vbo_redirect_url] ) ;
              }
      
         // 画面遷移先のテキストフィールドを追加
              $form['options']['vbo_settings']['vbo_redirect_url'] = array(
                  '#type' => 'textfield',
                  '#title' => t('Page to direct to after completion of  batch'),
                  '#description' => t('Redirects to the view when finished the operation'),
                  '#default_value' => variable_get('vbo_redirect_url'),
              );
          }
      }
    • 画面遷移先を入力するテキストフィールドを設定画面に追加
    • 画面遷移先(uri)をvbo_settingsに入れたいですが、クラスの構造体にあるため追加できません。環境変数に保存することにしました。
    • 設定画面を保存("#submit")後に、画面遷移先を保存する処理を行いたいですが、"#submit"にコールバック関数を入れても、呼び出されない現象があって、仕方がなく、hook_form_alter()内で画面遷移先(uri)の保存処理を行いました
      VBOに一括処理後に画面遷移オプションの追加
  • hook_views_bulk_operations_form_alter()を実装して、実際のVBO一括処理後に、画面遷移設定を行います
    /**
     * Implements hook_views_bulk_operations_form_alter().
     */
    function vbo_redirect_option_views_bulk_operations_form_alter(&$form, &$form_state, $vbo)
    {
        $vbo_redirect_url = trim( variable_get('vbo_redirect_url') ) ;
    
        if( isset($vbo_redirect_url) && strlen($vbo_redirect_url) >0 ){
    
            // check if vbo operation skip confirmation
            $skip_confirmation = false ;
            foreach( $vbo->options['vbo_operations'] as $key => $operation ){
                if( $operation['selected'] && $operation['skip_confirmation'] ){
                    if( isset($form['select'][$key]) ) {
                        $form['select'][$key]['#submit'][] = 'vbo_redirect_after_operation';
                        $skip_confirmation = true ;
                    }
                }
            }
    
            // set redirect method when vbo has confirmation step
            if( !$skip_confirmation ){
                $form['actions']['submit']['#submit'][] = 'vbo_redirect_after_operation' ;
            }
        }
    }
    
    // callback function to set redirect url
    function vbo_redirect_after_operation($form, &$form_state){
        $vbo_redirect_url = trim( variable_get('vbo_redirect_url') ) ;
        $form_state['redirect'] = $vbo_redirect_url;
    }
    • VBO一括処理の「確認のステップをスキップ」があるか、ないかを分けて処理します(画面遷移設定場所が違うため)
    • "#submit"に画面遷移処理を追加します
    • 画面遷移処理は$form_state['redirect'] で行います

結論と感想:簡単のカスタモジュールでVBOへの影響はありません。各オペレーション設定に画面遷移オプションを追加したほうよいかもしれない

  • このカスタムモジュールのインストールより、モジュール(VBO)への影響はありません
  • この画面遷移オプションを「Bulk Operation Settings」に追加したので、すべてのオペレーションに適応されます
    • VBOの一括処理内容がいろいろあります(例:オーナー変更、エンティティ内容変更など)
    • これらの処理後に一つの画面遷移先の設定はやや強引的だと思います
  • できれば、「Selected Bulk Operations」にある、選択したオペレーションの設定に画面遷移先の設定をしたほうが柔軟的な対応だと思います(次回の課題)
    画面遷移オプションを各オペレーションに追加すべき
添付 サイズ
vbo_redirect_option.zip (1.19 KB) 1.19 KB
Embedded thumbnail for Drupalのモジュール(VBO)の一括処理後にページ遷移させる方法
drupal
form
ajax

やりたいこと:Drupalのajaxフレームワークを利用して表示している要素を削除

  • Drupalのモジュール(Views)で作成した一覧の要素を選択して削除します
    • 要素を選択して削除するモジュール:Views Bulk Operations
    • 例:Drupalのモジュール(VBO)の各種処理(Operation)に独自(カスタムオ)のプションの追加方法
  • 前提条件:要素削除する確認の必要はありません
  • ajaxで動的に削除するのはやさしいUIとも言えるでしょう(以下のイメージのように削除)
    Drupalのajaxフレームワークより要素を動的に削除

Step1:削除リンクにDrupalのajax使用するクラス:use-ajax を追加

  • Drupalのajaxフレームワークに関する説明は以下の記事をご参考ください
    • Drupalでajaxのフレームワークが簡単に作成できる
  • 削除アイコン付きのリンクは以下のようです
    // 削除エレメントID:123 (例)
    <a href="/delete/element/id/123/nojs" class="use-ajax del-link" id="del-link-123">
           <i class="fa fa-trash-o" aria-hidden="true"></i>
    </a>
    • アンカー(a)に削除するエレメントID(または別の識別パラメーター)を入れる必要はあります
    • アンカーリンクの後ろに「nojs」を追加します(クライアント側のajax作動時に、nojs->ajaxに変換され)
    • アンカーがクリックされると、Drupalのajaxフレームワークが起動され、削除パラメーターをサイト側に渡します

Step2:hook_menuで要素削除のリクエストをキャッチします

  • hook_menuで要素削除のリクエストを受け取り、削除処理を行います
    // 要素削除URLの設定
    $items['delete/element/%/nojs'] = array(
    	'page callback' => 'delete_element',
    	'page arguments' => array( 2, 3 ) ,
    	'access callback' => 'delete_access',
    	'type' => MENU_CALLBACK,
    );
    // ajaxが以下のURLでリクエストをします(クライアント側でnojs->ajaxに変換)
    $items['delete/element/%/ajax'] = array(
    	'delivery callback' => 'ajax_deliver',
    )+$items['delete/element/%/nojs'] ;    // 要素削除定義に遷移
    
  • 要素削除処理ファンクション:delete_element で削除処理、処理結果をクライアント側に返します
    function delete_element ($id, $ajax){
        $is_ajax = $ajax === "ajax" ;  // ajaxと通用のリクエスト両方対応のため
    
        // 要素をDBから削除
        db_delete("element_table")->condition("entity_id", $id)->execute() ;
    
        // 画面要素も削除コマンドを返す
        if( $is_ajax ){
            // ajaxで要素削除後の処理
            $commands = array();
            $commands[] = ajax_command_remove( '#element-123');
            return array(
              '#type'=>"ajax",
              '#commands' => $commands,
            );
        } else {
            // 通常での要素削除後の処理
            drupal_set_message(t('Deleted 1 vocabulary'));
            drupal_goto();
        }
    }

     

Drupalのajaxフレームワークで要素削除

纏め:Drupalのajaxフレームワークを利用すればajax処理が自動的に行います

  • 上記例では、削除リンクにクラス:use-ajax を追加するだけで、ajax関連処理を記述する必要はあります
    • 削除リンクではなく、削除ボタン(button)要素を使用する場合クラス: use-ajax-submit
  • サーバー側では、hook_menuで削除リンクの定義、削除リクエストをキャッチして、削除処理関数を作成します
    • DB上のデータ削除完了後に、クライアント側の要素削除命令(ajax_command_remove)を返せば良いです
  • この一連のajax処理の記述はほどんとありません。簡単、便利です
drupal
development
ajax

やりたいこと:Drupalのプログラムレベルで簡単にajaxを利用してクライアント側でデータ交信をしたいです

  • 環境:Drupal7.54
  • DrupalのFormAPIで簡単にajaxの実装ができます(Drupalのフォーム(FromAPI)でのajaxの実装 )
  • FormAPIだけではなく、Drupalをカスタマイズ時にいろいろなところでajaxを実装したいことがあります

ポイント1:Drupalでajaxに必要なライブラリをロードし、クライアント側にjquery.form.jsファイルをセット

  • サーバー側でdrupal.ajaxのライブラリをロードする必要があります
  • クライアント側にjquery.form.jsファイルを設置する必要があります
  • この処理はajax処理するページをロード時に行えれば良いです。
    • 例:hook_init()内で処理する
      /**
       * Implements hook_init().
       */
      function YOUR_MODULE_NAME_init()
      {
        drupal_add_js('misc/jquery.form.js');
        drupal_add_library('system','drupal.ajax');
      }
  • クライアント側のブラウザのプロパティでjquery.form.jsがセットされたことの確認ができます

ポイント2:クライアント側のajax起動リンク内にajax対応可否のパラメーター「nojs」とクラス属性「use-ajax」のセット

  • ajaxの起動リンクの作成基本パターン: 
    <a href="text/ajax/nojs/1234" class="use-ajax">ajaxリンク</a>
    • hrefにある「nojs」が決まりの文字
    • hrefにある「1234」はサーバー側に転送したい必要なパラメーター
    • class="use-ajax"はこのリンクがajax用に決める
  • クライアント側のjsで使用しているブラウザがajax対応可能かを判断して、ajax起動リンクに「nojs」のパラメーターを書き換え(利用可能:nojs⇒ajax)てサーバー側に転送
  • サーバー側がajax利用可否よりクライアント側にajax対応有無の結果を返します
    Drupalのajaxフレームワークの利用
  • 上記例のプログラムは以下のようで
    /**
     * Implements hook_init().
     */
    function test_module_init()
    {
      drupal_add_js('misc/jquery.form.js');
      drupal_add_library('system','drupal.ajax');
    }
    
    /**
     *  Implementation of hook_menu()
     */
    function test_module_menu() {
      $items['test/ajax/%/%']=array(     // URLの2,3番目がクライアント側で生成
          'page callback' => 'ajax_node_response',
          'page arguments' => array(2,3),   // URLの2,3番目の引数をコールバック関数に渡す
          'access callback' => 'user_access',
          'access arguments' => array('access content'),
          'type' => MENU_CALLBACK,
      );
      return $items;
    }
    
    function ajax_node_response($type="ajax", $nid=0){
      $node = node_load( $nid, NULL, false );
      $vnode = node_view($node);
      $output = theme('node', $vnode);
      if( $type="ajax" ){
        $commands=array();
        $commands[]=ajax_command_replace( '#block-system-main','<section id="block-system-main">'.$output.'</section>' ) ;
        $page = array(
          '#type' => 'ajax',
          '#commands' => $commands,
        );
        ajax_deliver( $page ) ;   // ajax対応ブラウザの結果
      } else {
        $output = '<div id="content">'.$output.'</div>';  // ajax非対応ブラウザの結果
        return $output;
      }
    }
    

ポイント3:クライアント側で実行させたい部分はajax_commandを使用します

  • クライアント側で処理結果をどこに入り替えはajax_command_replaceで指定します
  • 結果の挿入、入れ替え、削除、css処理などがいろいろあります。詳細は本家のajax_command一覧を参考してください

 

drupal
Views

やりたいこと:モジュール(VBO)の各処理(Operation)に独自(カスタム)オプションを追加したい

  • 前回モジュール(VBO)にたいして処理(Operation)オプション追加を紹介しました
    •  Drupalのモジュール(VBO)の一括処理後にページ遷移させる方法
    • このオプションは全VBOに対して作成したものですが、すべての処理に影響を与えています
  • 各種処理(Operation)に対してどのようにオプションを追加するか前回の課題として残っています
  • 今回はこの課題を解決に新しいカスタムモジュール(vbo_redirect_option)を作成して、紹介します
    モジュールVBOの各種処理に独自のオプション追加

hook_formとCtoolsのdepent systemより各オペレーションに独自のオプションを追加

  • VBOのオペレーション設定フォームがカスタマイズとして開放していないです(前回も説明した)
  • ここで、Drupalのhook_formでVBOのオペレーション設定画面を特定して、カスタムオプション追加することになりました
    function vbo_redirect_option_form_alter(&$form, &$form_state, $form_id)
    {
        if( isset($form_state['id']) && $form_state['id'] === "views_bulk_operations"){
    
            foreach( $form_state['input']['options']['vbo_operations'] as $key => $operation) {
                if( $operation['redirect_check'] && strlen( trim($operation['redirect_url']))>0 ) {
                    variable_set( $key, $operation['redirect_url'] );
                } else {
                    if( !empty( variable_get($key) ) ) variable_del( $key ) ;
                }
            }
    
    
            foreach( $form['options']['vbo_operations'] as $key => &$operation ){
                if( !is_array($operation) ) continue ;
    
                $redirect_url = variable_get($key);
                $dep_key = "edit-options-vbo-operations-" . str_replace("_", "-", str_replace("::","",$key) ) ;
    
                $operation['redirect_check'] = array(
                    '#type' => 'checkbox',
                    '#title' => t('Redirect page to after operation'),
                    '#default_value' =>  $redirect_url ? 1 : 0 ,
                    '#dependency' => array(    // Ctoolsのdependent systemに依存
                        $dep_key."-selected" => array(1),
                    ),
                );
                $operation['redirect_url'] = array(
                    '#type' => 'textfield',
                    '#title' => t('Provide label'),
                    '#title_display' => 'invisible',
                    '#default_value' => empty($redirect_url) ? "" : $redirect_url,
                    '#dependency' => array(    // Ctoolsのdependent systemに依存
                        $dep_key."-selected" => array(1),
                        $dep_key . '-redirect-check' => array(1),
                    ),
                    '#dependency_count' => 2,
                );
            }
        }
    }
    • 設定フォームにチェックボックスをチェックしたら、画面遷移URL入力フィールドが現れるダイナミックフォームはモジュール(Ctools)のdependent systemを利用しています

処理(Operation)確認ステップをスキップがあるかないかを確認してhook_views_bulk_operations_form_alter()実装でオプションの設定を行う

  • VBOの処理(Operation)が確認ステップがあるかないかは2種類あります(この二種類をの処理プロセスが違うのでしっかりテストする必要がある)
  • hook_views_bulk_operations_form_alter()を実装して、各処理ステップにカスタマイズを行います
    function vbo_redirect_option_views_bulk_operations_form_alter(&$form, &$form_state, $vbo)
    {
        // collect all operations that has contained redirect_rul
        $redirect_arr = array();
        foreach( $vbo->options['vbo_operations'] as $key => $operation ) {
            if( !empty( variable_get($key) ) ){
                $redirect_arr[$key] = $key ;
            }
        }
    
        // add redirect step to #submit element
        if(isset($form['select'])) {
    
            // this is the form start step
            foreach( $form['select'] as $key => &$element ){
                if( isset($redirect_arr[$key]) ){
                    // we check if there is any operation has redirect_url
                    $element['#submit'][] = 'vbo_redirect_after_operation';
                    // only one is enough, we will detect witch one in the callback function
                    break;
                }
            }
    
            // do operation with confirmation step
            // this is the confirmation step
        } else if( !$form_state['operation']->getAdminOption('skip_confirmation') ) {
            $form['actions']['submit']['#submit'][] = "vbo_redirect_after_operation_with_confirmation";
            $form_state['redirect_to_after_operation'] = $form_state['operation']->getAdminOption('redirect_url');
        }
    
    }
    
    
    /**
     * callback function that has called by operation
     * this is the form start step, we don't know if it has confirmation step or not
     * @param $form
     * @param $form_state
     */
    function vbo_redirect_after_operation(&$form, &$form_state){
        // the are multiple element can be operated
        // the right one that has be sent to this step
        // we need get redirect_url if the it has
        if( isset($form_state['operation']) ){
            // get redirect_url by operation_id
            $redirec=variable_get($form_state['operation']->operationId) ;
            if( !empty($redirec) ){
                if( $form_state['operation']->getAdminOption('skip_confirmation') ) {
                    $form_state['redirect'] = $redirec;
                }
            }
        }
    }
    
    /**
     * callback function that has be called by operation with confirmation step
     * @param $form
     * @param $form_state
     */
    function vbo_redirect_after_operation_with_confirmation( $form, &$form_state ){
        // there is only operation that has be sent here with the confirmation step
        if( isset($form_state['redirect_to_after_operation']) ){
            // set redirect_url that should be stored in $form_state
            $form_state['redirect'] = $form_state['redir ect_to_after_operation'];
        }
    }

感想と結論:VBOの処理オプション設定はカスタマイズに開放していないため、各種処理(Operation)のオプションの取得、設定に苦労します

  • VBOの処理オプション設定はユーザーにカスタマイズに開放していないです
  • オペレーションの各ステップに$form、$form_state、$vbo変数から必要な情報を取得したり、セットしたりしました
  • 必要な情報がどこにあるかは不明だし(その時dsm($vbo)などで確認)、特定するまでに、時間がかかりました。
添付 サイズ
vbo_redirect_option.zip (1.77 KB) 1.77 KB
Embedded thumbnail for Drupalのモジュール(VBO)の各種処理(Operation)に独自(カスタムオ)のプションの追加方法
drupal
development
Views

Drupalのモジュール(Rules)で作成した各種アクションセットコンポーネントをモジュールVBOで一括処理

  • 背景:Drupal7.x.56、Views Bulk Operation(VBO)7.x-3.4、Rules7.x-2.10
  • モジュール(Rules)がいろいろなアクションセットの作成ができます
    • データの作成/更新/削除
    • メール送信、フラグを立てる
    • などなど
  • モジュール(VBO)がRulesで作成したアクションコンポーネントの利用ができます
    • Drupalのモジュール(Rules)のアクションコンポーネントでVBOより新規ノード作成とフィールドのコピー
  • 今回の例として、Rulesでメッセージ表示する単純なアクションコンポーネント(show message)を作成して、VBOで一括処理を行います
    Rulesでメッセージ表示コンポーネントをVBOで一括処理

問題点:VBO一括処理後に画面遷移(redirect)はできません

  • VBOで一括処理後に、画面を遷移して処理結果を確認することがあります
  • VBOの設定オプションに、処理後の画面遷移設定がありません
  • ネットで調べてみたが、VBO一括処理後の画面遷移オプション追加パッチがります
    • これは、モジュールVBOに対するパッチです
    • このパッチ適応したら、次回VBOアップグレード時に、ソースのマージ作業が面だと思います
    • できれば、VBOのパッチを使用したくないです

解決:カスタムモジュール(vbo_redirect_option.zip)でVBO処理後の画面遷移オプションの追加

  • モジュール(VBO)の主要部分がクラス(class)構造なので、簡単に画面遷移ロジックを追加することはできません
  • 「Bulk Operation Settings」に処理後の画面遷移オプションを追加します
    • 「Bulk Operation Settings」のオーバーライドができないので、hook_form_alter()でオプションを追加することになりました
      /**
       * Implements hook_form_alter().
       */
      function vbo_redirect_option_form_alter(&$form, &$form_state, $form_id)
      {
        // VBOの処理かのチェック
          if( isset($form_state['id']) && $form_state['id'] === "views_bulk_operations"){
      
         // ここで、画面遷移先の保存処理は少し反則
         //  vbo_settingsに画面遷移先の追加は難しい(クラス構造体内にあるため)
         //  環境変数に画面遷移先(uri)を保存
              if( isset($form_state['input']['options']['vbo_settings'][vbo_redirect_url]) ){
                  variable_set( 'vbo_redirect_url', $form_state['input']['options']['vbo_settings'][vbo_redirect_url] ) ;
              }
      
         // 画面遷移先のテキストフィールドを追加
              $form['options']['vbo_settings']['vbo_redirect_url'] = array(
                  '#type' => 'textfield',
                  '#title' => t('Page to direct to after completion of  batch'),
                  '#description' => t('Redirects to the view when finished the operation'),
                  '#default_value' => variable_get('vbo_redirect_url'),
              );
          }
      }
    • 画面遷移先を入力するテキストフィールドを設定画面に追加
    • 画面遷移先(uri)をvbo_settingsに入れたいですが、クラスの構造体にあるため追加できません。環境変数に保存することにしました。
    • 設定画面を保存("#submit")後に、画面遷移先を保存する処理を行いたいですが、"#submit"にコールバック関数を入れても、呼び出されない現象があって、仕方がなく、hook_form_alter()内で画面遷移先(uri)の保存処理を行いました
      VBOに一括処理後に画面遷移オプションの追加
  • hook_views_bulk_operations_form_alter()を実装して、実際のVBO一括処理後に、画面遷移設定を行います
    /**
     * Implements hook_views_bulk_operations_form_alter().
     */
    function vbo_redirect_option_views_bulk_operations_form_alter(&$form, &$form_state, $vbo)
    {
        $vbo_redirect_url = trim( variable_get('vbo_redirect_url') ) ;
    
        if( isset($vbo_redirect_url) && strlen($vbo_redirect_url) >0 ){
    
            // check if vbo operation skip confirmation
            $skip_confirmation = false ;
            foreach( $vbo->options['vbo_operations'] as $key => $operation ){
                if( $operation['selected'] && $operation['skip_confirmation'] ){
                    if( isset($form['select'][$key]) ) {
                        $form['select'][$key]['#submit'][] = 'vbo_redirect_after_operation';
                        $skip_confirmation = true ;
                    }
                }
            }
    
            // set redirect method when vbo has confirmation step
            if( !$skip_confirmation ){
                $form['actions']['submit']['#submit'][] = 'vbo_redirect_after_operation' ;
            }
        }
    }
    
    // callback function to set redirect url
    function vbo_redirect_after_operation($form, &$form_state){
        $vbo_redirect_url = trim( variable_get('vbo_redirect_url') ) ;
        $form_state['redirect'] = $vbo_redirect_url;
    }
    • VBO一括処理の「確認のステップをスキップ」があるか、ないかを分けて処理します(画面遷移設定場所が違うため)
    • "#submit"に画面遷移処理を追加します
    • 画面遷移処理は$form_state['redirect'] で行います

結論と感想:簡単のカスタモジュールでVBOへの影響はありません。各オペレーション設定に画面遷移オプションを追加したほうよいかもしれない

  • このカスタムモジュールのインストールより、モジュール(VBO)への影響はありません
  • この画面遷移オプションを「Bulk Operation Settings」に追加したので、すべてのオペレーションに適応されます
    • VBOの一括処理内容がいろいろあります(例:オーナー変更、エンティティ内容変更など)
    • これらの処理後に一つの画面遷移先の設定はやや強引的だと思います
  • できれば、「Selected Bulk Operations」にある、選択したオペレーションの設定に画面遷移先の設定をしたほうが柔軟的な対応だと思います(次回の課題)
    画面遷移オプションを各オペレーションに追加すべき
添付 サイズ
vbo_redirect_option.zip (1.19 KB) 1.19 KB
Embedded thumbnail for Drupalのモジュール(VBO)の一括処理後にページ遷移させる方法
drupal
form
ajax

やりたいこと:Drupalのajaxフレームワークを利用して表示している要素を削除

  • Drupalのモジュール(Views)で作成した一覧の要素を選択して削除します
    • 要素を選択して削除するモジュール:Views Bulk Operations
    • 例:Drupalのモジュール(VBO)の各種処理(Operation)に独自(カスタムオ)のプションの追加方法
  • 前提条件:要素削除する確認の必要はありません
  • ajaxで動的に削除するのはやさしいUIとも言えるでしょう(以下のイメージのように削除)
    Drupalのajaxフレームワークより要素を動的に削除

Step1:削除リンクにDrupalのajax使用するクラス:use-ajax を追加

  • Drupalのajaxフレームワークに関する説明は以下の記事をご参考ください
    • Drupalでajaxのフレームワークが簡単に作成できる
  • 削除アイコン付きのリンクは以下のようです
    // 削除エレメントID:123 (例)
    <a href="/delete/element/id/123/nojs" class="use-ajax del-link" id="del-link-123">
           <i class="fa fa-trash-o" aria-hidden="true"></i>
    </a>
    • アンカー(a)に削除するエレメントID(または別の識別パラメーター)を入れる必要はあります
    • アンカーリンクの後ろに「nojs」を追加します(クライアント側のajax作動時に、nojs->ajaxに変換され)
    • アンカーがクリックされると、Drupalのajaxフレームワークが起動され、削除パラメーターをサイト側に渡します

Step2:hook_menuで要素削除のリクエストをキャッチします

  • hook_menuで要素削除のリクエストを受け取り、削除処理を行います
    // 要素削除URLの設定
    $items['delete/element/%/nojs'] = array(
    	'page callback' => 'delete_element',
    	'page arguments' => array( 2, 3 ) ,
    	'access callback' => 'delete_access',
    	'type' => MENU_CALLBACK,
    );
    // ajaxが以下のURLでリクエストをします(クライアント側でnojs->ajaxに変換)
    $items['delete/element/%/ajax'] = array(
    	'delivery callback' => 'ajax_deliver',
    )+$items['delete/element/%/nojs'] ;    // 要素削除定義に遷移
    
  • 要素削除処理ファンクション:delete_element で削除処理、処理結果をクライアント側に返します
    function delete_element ($id, $ajax){
        $is_ajax = $ajax === "ajax" ;  // ajaxと通用のリクエスト両方対応のため
    
        // 要素をDBから削除
        db_delete("element_table")->condition("entity_id", $id)->execute() ;
    
        // 画面要素も削除コマンドを返す
        if( $is_ajax ){
            // ajaxで要素削除後の処理
            $commands = array();
            $commands[] = ajax_command_remove( '#element-123');
            return array(
              '#type'=>"ajax",
              '#commands' => $commands,
            );
        } else {
            // 通常での要素削除後の処理
            drupal_set_message(t('Deleted 1 vocabulary'));
            drupal_goto();
        }
    }

     

Drupalのajaxフレームワークで要素削除

纏め:Drupalのajaxフレームワークを利用すればajax処理が自動的に行います

  • 上記例では、削除リンクにクラス:use-ajax を追加するだけで、ajax関連処理を記述する必要はあります
    • 削除リンクではなく、削除ボタン(button)要素を使用する場合クラス: use-ajax-submit
  • サーバー側では、hook_menuで削除リンクの定義、削除リクエストをキャッチして、削除処理関数を作成します
    • DB上のデータ削除完了後に、クライアント側の要素削除命令(ajax_command_remove)を返せば良いです
  • この一連のajax処理の記述はほどんとありません。簡単、便利です
drupal
development
ajax

やりたいこと:Drupalのプログラムレベルで簡単にajaxを利用してクライアント側でデータ交信をしたいです

  • 環境:Drupal7.54
  • DrupalのFormAPIで簡単にajaxの実装ができます(Drupalのフォーム(FromAPI)でのajaxの実装 )
  • FormAPIだけではなく、Drupalをカスタマイズ時にいろいろなところでajaxを実装したいことがあります

ポイント1:Drupalでajaxに必要なライブラリをロードし、クライアント側にjquery.form.jsファイルをセット

  • サーバー側でdrupal.ajaxのライブラリをロードする必要があります
  • クライアント側にjquery.form.jsファイルを設置する必要があります
  • この処理はajax処理するページをロード時に行えれば良いです。
    • 例:hook_init()内で処理する
      /**
       * Implements hook_init().
       */
      function YOUR_MODULE_NAME_init()
      {
        drupal_add_js('misc/jquery.form.js');
        drupal_add_library('system','drupal.ajax');
      }
  • クライアント側のブラウザのプロパティでjquery.form.jsがセットされたことの確認ができます

ポイント2:クライアント側のajax起動リンク内にajax対応可否のパラメーター「nojs」とクラス属性「use-ajax」のセット

  • ajaxの起動リンクの作成基本パターン: 
    <a href="text/ajax/nojs/1234" class="use-ajax">ajaxリンク</a>
    • hrefにある「nojs」が決まりの文字
    • hrefにある「1234」はサーバー側に転送したい必要なパラメーター
    • class="use-ajax"はこのリンクがajax用に決める
  • クライアント側のjsで使用しているブラウザがajax対応可能かを判断して、ajax起動リンクに「nojs」のパラメーターを書き換え(利用可能:nojs⇒ajax)てサーバー側に転送
  • サーバー側がajax利用可否よりクライアント側にajax対応有無の結果を返します
    Drupalのajaxフレームワークの利用
  • 上記例のプログラムは以下のようで
    /**
     * Implements hook_init().
     */
    function test_module_init()
    {
      drupal_add_js('misc/jquery.form.js');
      drupal_add_library('system','drupal.ajax');
    }
    
    /**
     *  Implementation of hook_menu()
     */
    function test_module_menu() {
      $items['test/ajax/%/%']=array(     // URLの2,3番目がクライアント側で生成
          'page callback' => 'ajax_node_response',
          'page arguments' => array(2,3),   // URLの2,3番目の引数をコールバック関数に渡す
          'access callback' => 'user_access',
          'access arguments' => array('access content'),
          'type' => MENU_CALLBACK,
      );
      return $items;
    }
    
    function ajax_node_response($type="ajax", $nid=0){
      $node = node_load( $nid, NULL, false );
      $vnode = node_view($node);
      $output = theme('node', $vnode);
      if( $type="ajax" ){
        $commands=array();
        $commands[]=ajax_command_replace( '#block-system-main','<section id="block-system-main">'.$output.'</section>' ) ;
        $page = array(
          '#type' => 'ajax',
          '#commands' => $commands,
        );
        ajax_deliver( $page ) ;   // ajax対応ブラウザの結果
      } else {
        $output = '<div id="content">'.$output.'</div>';  // ajax非対応ブラウザの結果
        return $output;
      }
    }
    

ポイント3:クライアント側で実行させたい部分はajax_commandを使用します

  • クライアント側で処理結果をどこに入り替えはajax_command_replaceで指定します
  • 結果の挿入、入れ替え、削除、css処理などがいろいろあります。詳細は本家のajax_command一覧を参考してください

 

drupal
Views

やりたいこと:モジュール(VBO)の各処理(Operation)に独自(カスタム)オプションを追加したい

  • 前回モジュール(VBO)にたいして処理(Operation)オプション追加を紹介しました
    •  Drupalのモジュール(VBO)の一括処理後にページ遷移させる方法
    • このオプションは全VBOに対して作成したものですが、すべての処理に影響を与えています
  • 各種処理(Operation)に対してどのようにオプションを追加するか前回の課題として残っています
  • 今回はこの課題を解決に新しいカスタムモジュール(vbo_redirect_option)を作成して、紹介します
    モジュールVBOの各種処理に独自のオプション追加

hook_formとCtoolsのdepent systemより各オペレーションに独自のオプションを追加

  • VBOのオペレーション設定フォームがカスタマイズとして開放していないです(前回も説明した)
  • ここで、Drupalのhook_formでVBOのオペレーション設定画面を特定して、カスタムオプション追加することになりました
    function vbo_redirect_option_form_alter(&$form, &$form_state, $form_id)
    {
        if( isset($form_state['id']) && $form_state['id'] === "views_bulk_operations"){
    
            foreach( $form_state['input']['options']['vbo_operations'] as $key => $operation) {
                if( $operation['redirect_check'] && strlen( trim($operation['redirect_url']))>0 ) {
                    variable_set( $key, $operation['redirect_url'] );
                } else {
                    if( !empty( variable_get($key) ) ) variable_del( $key ) ;
                }
            }
    
    
            foreach( $form['options']['vbo_operations'] as $key => &$operation ){
                if( !is_array($operation) ) continue ;
    
                $redirect_url = variable_get($key);
                $dep_key = "edit-options-vbo-operations-" . str_replace("_", "-", str_replace("::","",$key) ) ;
    
                $operation['redirect_check'] = array(
                    '#type' => 'checkbox',
                    '#title' => t('Redirect page to after operation'),
                    '#default_value' =>  $redirect_url ? 1 : 0 ,
                    '#dependency' => array(    // Ctoolsのdependent systemに依存
                        $dep_key."-selected" => array(1),
                    ),
                );
                $operation['redirect_url'] = array(
                    '#type' => 'textfield',
                    '#title' => t('Provide label'),
                    '#title_display' => 'invisible',
                    '#default_value' => empty($redirect_url) ? "" : $redirect_url,
                    '#dependency' => array(    // Ctoolsのdependent systemに依存
                        $dep_key."-selected" => array(1),
                        $dep_key . '-redirect-check' => array(1),
                    ),
                    '#dependency_count' => 2,
                );
            }
        }
    }
    • 設定フォームにチェックボックスをチェックしたら、画面遷移URL入力フィールドが現れるダイナミックフォームはモジュール(Ctools)のdependent systemを利用しています

処理(Operation)確認ステップをスキップがあるかないかを確認してhook_views_bulk_operations_form_alter()実装でオプションの設定を行う

  • VBOの処理(Operation)が確認ステップがあるかないかは2種類あります(この二種類をの処理プロセスが違うのでしっかりテストする必要がある)
  • hook_views_bulk_operations_form_alter()を実装して、各処理ステップにカスタマイズを行います
    function vbo_redirect_option_views_bulk_operations_form_alter(&$form, &$form_state, $vbo)
    {
        // collect all operations that has contained redirect_rul
        $redirect_arr = array();
        foreach( $vbo->options['vbo_operations'] as $key => $operation ) {
            if( !empty( variable_get($key) ) ){
                $redirect_arr[$key] = $key ;
            }
        }
    
        // add redirect step to #submit element
        if(isset($form['select'])) {
    
            // this is the form start step
            foreach( $form['select'] as $key => &$element ){
                if( isset($redirect_arr[$key]) ){
                    // we check if there is any operation has redirect_url
                    $element['#submit'][] = 'vbo_redirect_after_operation';
                    // only one is enough, we will detect witch one in the callback function
                    break;
                }
            }
    
            // do operation with confirmation step
            // this is the confirmation step
        } else if( !$form_state['operation']->getAdminOption('skip_confirmation') ) {
            $form['actions']['submit']['#submit'][] = "vbo_redirect_after_operation_with_confirmation";
            $form_state['redirect_to_after_operation'] = $form_state['operation']->getAdminOption('redirect_url');
        }
    
    }
    
    
    /**
     * callback function that has called by operation
     * this is the form start step, we don't know if it has confirmation step or not
     * @param $form
     * @param $form_state
     */
    function vbo_redirect_after_operation(&$form, &$form_state){
        // the are multiple element can be operated
        // the right one that has be sent to this step
        // we need get redirect_url if the it has
        if( isset($form_state['operation']) ){
            // get redirect_url by operation_id
            $redirec=variable_get($form_state['operation']->operationId) ;
            if( !empty($redirec) ){
                if( $form_state['operation']->getAdminOption('skip_confirmation') ) {
                    $form_state['redirect'] = $redirec;
                }
            }
        }
    }
    
    /**
     * callback function that has be called by operation with confirmation step
     * @param $form
     * @param $form_state
     */
    function vbo_redirect_after_operation_with_confirmation( $form, &$form_state ){
        // there is only operation that has be sent here with the confirmation step
        if( isset($form_state['redirect_to_after_operation']) ){
            // set redirect_url that should be stored in $form_state
            $form_state['redirect'] = $form_state['redir ect_to_after_operation'];
        }
    }

感想と結論:VBOの処理オプション設定はカスタマイズに開放していないため、各種処理(Operation)のオプションの取得、設定に苦労します

  • VBOの処理オプション設定はユーザーにカスタマイズに開放していないです
  • オペレーションの各ステップに$form、$form_state、$vbo変数から必要な情報を取得したり、セットしたりしました
  • 必要な情報がどこにあるかは不明だし(その時dsm($vbo)などで確認)、特定するまでに、時間がかかりました。
添付 サイズ
vbo_redirect_option.zip (1.77 KB) 1.77 KB
Embedded thumbnail for Drupalのモジュール(VBO)の各種処理(Operation)に独自(カスタムオ)のプションの追加方法
drupal
development
Views

Drupalのモジュール(Rules)で作成した各種アクションセットコンポーネントをモジュールVBOで一括処理

  • 背景:Drupal7.x.56、Views Bulk Operation(VBO)7.x-3.4、Rules7.x-2.10
  • モジュール(Rules)がいろいろなアクションセットの作成ができます
    • データの作成/更新/削除
    • メール送信、フラグを立てる
    • などなど
  • モジュール(VBO)がRulesで作成したアクションコンポーネントの利用ができます
    • Drupalのモジュール(Rules)のアクションコンポーネントでVBOより新規ノード作成とフィールドのコピー
  • 今回の例として、Rulesでメッセージ表示する単純なアクションコンポーネント(show message)を作成して、VBOで一括処理を行います
    Rulesでメッセージ表示コンポーネントをVBOで一括処理

問題点:VBO一括処理後に画面遷移(redirect)はできません

  • VBOで一括処理後に、画面を遷移して処理結果を確認することがあります
  • VBOの設定オプションに、処理後の画面遷移設定がありません
  • ネットで調べてみたが、VBO一括処理後の画面遷移オプション追加パッチがります
    • これは、モジュールVBOに対するパッチです
    • このパッチ適応したら、次回VBOアップグレード時に、ソースのマージ作業が面だと思います
    • できれば、VBOのパッチを使用したくないです

解決:カスタムモジュール(vbo_redirect_option.zip)でVBO処理後の画面遷移オプションの追加

  • モジュール(VBO)の主要部分がクラス(class)構造なので、簡単に画面遷移ロジックを追加することはできません
  • 「Bulk Operation Settings」に処理後の画面遷移オプションを追加します
    • 「Bulk Operation Settings」のオーバーライドができないので、hook_form_alter()でオプションを追加することになりました
      /**
       * Implements hook_form_alter().
       */
      function vbo_redirect_option_form_alter(&$form, &$form_state, $form_id)
      {
        // VBOの処理かのチェック
          if( isset($form_state['id']) && $form_state['id'] === "views_bulk_operations"){
      
         // ここで、画面遷移先の保存処理は少し反則
         //  vbo_settingsに画面遷移先の追加は難しい(クラス構造体内にあるため)
         //  環境変数に画面遷移先(uri)を保存
              if( isset($form_state['input']['options']['vbo_settings'][vbo_redirect_url]) ){
                  variable_set( 'vbo_redirect_url', $form_state['input']['options']['vbo_settings'][vbo_redirect_url] ) ;
              }
      
         // 画面遷移先のテキストフィールドを追加
              $form['options']['vbo_settings']['vbo_redirect_url'] = array(
                  '#type' => 'textfield',
                  '#title' => t('Page to direct to after completion of  batch'),
                  '#description' => t('Redirects to the view when finished the operation'),
                  '#default_value' => variable_get('vbo_redirect_url'),
              );
          }
      }
    • 画面遷移先を入力するテキストフィールドを設定画面に追加
    • 画面遷移先(uri)をvbo_settingsに入れたいですが、クラスの構造体にあるため追加できません。環境変数に保存することにしました。
    • 設定画面を保存("#submit")後に、画面遷移先を保存する処理を行いたいですが、"#submit"にコールバック関数を入れても、呼び出されない現象があって、仕方がなく、hook_form_alter()内で画面遷移先(uri)の保存処理を行いました
      VBOに一括処理後に画面遷移オプションの追加
  • hook_views_bulk_operations_form_alter()を実装して、実際のVBO一括処理後に、画面遷移設定を行います
    /**
     * Implements hook_views_bulk_operations_form_alter().
     */
    function vbo_redirect_option_views_bulk_operations_form_alter(&$form, &$form_state, $vbo)
    {
        $vbo_redirect_url = trim( variable_get('vbo_redirect_url') ) ;
    
        if( isset($vbo_redirect_url) && strlen($vbo_redirect_url) >0 ){
    
            // check if vbo operation skip confirmation
            $skip_confirmation = false ;
            foreach( $vbo->options['vbo_operations'] as $key => $operation ){
                if( $operation['selected'] && $operation['skip_confirmation'] ){
                    if( isset($form['select'][$key]) ) {
                        $form['select'][$key]['#submit'][] = 'vbo_redirect_after_operation';
                        $skip_confirmation = true ;
                    }
                }
            }
    
            // set redirect method when vbo has confirmation step
            if( !$skip_confirmation ){
                $form['actions']['submit']['#submit'][] = 'vbo_redirect_after_operation' ;
            }
        }
    }
    
    // callback function to set redirect url
    function vbo_redirect_after_operation($form, &$form_state){
        $vbo_redirect_url = trim( variable_get('vbo_redirect_url') ) ;
        $form_state['redirect'] = $vbo_redirect_url;
    }
    • VBO一括処理の「確認のステップをスキップ」があるか、ないかを分けて処理します(画面遷移設定場所が違うため)
    • "#submit"に画面遷移処理を追加します
    • 画面遷移処理は$form_state['redirect'] で行います

結論と感想:簡単のカスタモジュールでVBOへの影響はありません。各オペレーション設定に画面遷移オプションを追加したほうよいかもしれない

  • このカスタムモジュールのインストールより、モジュール(VBO)への影響はありません
  • この画面遷移オプションを「Bulk Operation Settings」に追加したので、すべてのオペレーションに適応されます
    • VBOの一括処理内容がいろいろあります(例:オーナー変更、エンティティ内容変更など)
    • これらの処理後に一つの画面遷移先の設定はやや強引的だと思います
  • できれば、「Selected Bulk Operations」にある、選択したオペレーションの設定に画面遷移先の設定をしたほうが柔軟的な対応だと思います(次回の課題)
    画面遷移オプションを各オペレーションに追加すべき
添付 サイズ
vbo_redirect_option.zip (1.19 KB) 1.19 KB
Embedded thumbnail for Drupalのモジュール(VBO)の一括処理後にページ遷移させる方法
drupal
form
ajax

やりたいこと:Drupalのajaxフレームワークを利用して表示している要素を削除

  • Drupalのモジュール(Views)で作成した一覧の要素を選択して削除します
    • 要素を選択して削除するモジュール:Views Bulk Operations
    • 例:Drupalのモジュール(VBO)の各種処理(Operation)に独自(カスタムオ)のプションの追加方法
  • 前提条件:要素削除する確認の必要はありません
  • ajaxで動的に削除するのはやさしいUIとも言えるでしょう(以下のイメージのように削除)
    Drupalのajaxフレームワークより要素を動的に削除

Step1:削除リンクにDrupalのajax使用するクラス:use-ajax を追加

  • Drupalのajaxフレームワークに関する説明は以下の記事をご参考ください
    • Drupalでajaxのフレームワークが簡単に作成できる
  • 削除アイコン付きのリンクは以下のようです
    // 削除エレメントID:123 (例)
    <a href="/delete/element/id/123/nojs" class="use-ajax del-link" id="del-link-123">
           <i class="fa fa-trash-o" aria-hidden="true"></i>
    </a>
    • アンカー(a)に削除するエレメントID(または別の識別パラメーター)を入れる必要はあります
    • アンカーリンクの後ろに「nojs」を追加します(クライアント側のajax作動時に、nojs->ajaxに変換され)
    • アンカーがクリックされると、Drupalのajaxフレームワークが起動され、削除パラメーターをサイト側に渡します

Step2:hook_menuで要素削除のリクエストをキャッチします

  • hook_menuで要素削除のリクエストを受け取り、削除処理を行います
    // 要素削除URLの設定
    $items['delete/element/%/nojs'] = array(
    	'page callback' => 'delete_element',
    	'page arguments' => array( 2, 3 ) ,
    	'access callback' => 'delete_access',
    	'type' => MENU_CALLBACK,
    );
    // ajaxが以下のURLでリクエストをします(クライアント側でnojs->ajaxに変換)
    $items['delete/element/%/ajax'] = array(
    	'delivery callback' => 'ajax_deliver',
    )+$items['delete/element/%/nojs'] ;    // 要素削除定義に遷移
    
  • 要素削除処理ファンクション:delete_element で削除処理、処理結果をクライアント側に返します
    function delete_element ($id, $ajax){
        $is_ajax = $ajax === "ajax" ;  // ajaxと通用のリクエスト両方対応のため
    
        // 要素をDBから削除
        db_delete("element_table")->condition("entity_id", $id)->execute() ;
    
        // 画面要素も削除コマンドを返す
        if( $is_ajax ){
            // ajaxで要素削除後の処理
            $commands = array();
            $commands[] = ajax_command_remove( '#element-123');
            return array(
              '#type'=>"ajax",
              '#commands' => $commands,
            );
        } else {
            // 通常での要素削除後の処理
            drupal_set_message(t('Deleted 1 vocabulary'));
            drupal_goto();
        }
    }

     

Drupalのajaxフレームワークで要素削除

纏め:Drupalのajaxフレームワークを利用すればajax処理が自動的に行います

  • 上記例では、削除リンクにクラス:use-ajax を追加するだけで、ajax関連処理を記述する必要はあります
    • 削除リンクではなく、削除ボタン(button)要素を使用する場合クラス: use-ajax-submit
  • サーバー側では、hook_menuで削除リンクの定義、削除リクエストをキャッチして、削除処理関数を作成します
    • DB上のデータ削除完了後に、クライアント側の要素削除命令(ajax_command_remove)を返せば良いです
  • この一連のajax処理の記述はほどんとありません。簡単、便利です
drupal
development
ajax

やりたいこと:Drupalのプログラムレベルで簡単にajaxを利用してクライアント側でデータ交信をしたいです

  • 環境:Drupal7.54
  • DrupalのFormAPIで簡単にajaxの実装ができます(Drupalのフォーム(FromAPI)でのajaxの実装 )
  • FormAPIだけではなく、Drupalをカスタマイズ時にいろいろなところでajaxを実装したいことがあります

ポイント1:Drupalでajaxに必要なライブラリをロードし、クライアント側にjquery.form.jsファイルをセット

  • サーバー側でdrupal.ajaxのライブラリをロードする必要があります
  • クライアント側にjquery.form.jsファイルを設置する必要があります
  • この処理はajax処理するページをロード時に行えれば良いです。
    • 例:hook_init()内で処理する
      /**
       * Implements hook_init().
       */
      function YOUR_MODULE_NAME_init()
      {
        drupal_add_js('misc/jquery.form.js');
        drupal_add_library('system','drupal.ajax');
      }
  • クライアント側のブラウザのプロパティでjquery.form.jsがセットされたことの確認ができます

ポイント2:クライアント側のajax起動リンク内にajax対応可否のパラメーター「nojs」とクラス属性「use-ajax」のセット

  • ajaxの起動リンクの作成基本パターン: 
    <a href="text/ajax/nojs/1234" class="use-ajax">ajaxリンク</a>
    • hrefにある「nojs」が決まりの文字
    • hrefにある「1234」はサーバー側に転送したい必要なパラメーター
    • class="use-ajax"はこのリンクがajax用に決める
  • クライアント側のjsで使用しているブラウザがajax対応可能かを判断して、ajax起動リンクに「nojs」のパラメーターを書き換え(利用可能:nojs⇒ajax)てサーバー側に転送
  • サーバー側がajax利用可否よりクライアント側にajax対応有無の結果を返します
    Drupalのajaxフレームワークの利用
  • 上記例のプログラムは以下のようで
    /**
     * Implements hook_init().
     */
    function test_module_init()
    {
      drupal_add_js('misc/jquery.form.js');
      drupal_add_library('system','drupal.ajax');
    }
    
    /**
     *  Implementation of hook_menu()
     */
    function test_module_menu() {
      $items['test/ajax/%/%']=array(     // URLの2,3番目がクライアント側で生成
          'page callback' => 'ajax_node_response',
          'page arguments' => array(2,3),   // URLの2,3番目の引数をコールバック関数に渡す
          'access callback' => 'user_access',
          'access arguments' => array('access content'),
          'type' => MENU_CALLBACK,
      );
      return $items;
    }
    
    function ajax_node_response($type="ajax", $nid=0){
      $node = node_load( $nid, NULL, false );
      $vnode = node_view($node);
      $output = theme('node', $vnode);
      if( $type="ajax" ){
        $commands=array();
        $commands[]=ajax_command_replace( '#block-system-main','<section id="block-system-main">'.$output.'</section>' ) ;
        $page = array(
          '#type' => 'ajax',
          '#commands' => $commands,
        );
        ajax_deliver( $page ) ;   // ajax対応ブラウザの結果
      } else {
        $output = '<div id="content">'.$output.'</div>';  // ajax非対応ブラウザの結果
        return $output;
      }
    }
    

ポイント3:クライアント側で実行させたい部分はajax_commandを使用します

  • クライアント側で処理結果をどこに入り替えはajax_command_replaceで指定します
  • 結果の挿入、入れ替え、削除、css処理などがいろいろあります。詳細は本家のajax_command一覧を参考してください

 

drupal
Views

やりたいこと:モジュール(VBO)の各処理(Operation)に独自(カスタム)オプションを追加したい

  • 前回モジュール(VBO)にたいして処理(Operation)オプション追加を紹介しました
    •  Drupalのモジュール(VBO)の一括処理後にページ遷移させる方法
    • このオプションは全VBOに対して作成したものですが、すべての処理に影響を与えています
  • 各種処理(Operation)に対してどのようにオプションを追加するか前回の課題として残っています
  • 今回はこの課題を解決に新しいカスタムモジュール(vbo_redirect_option)を作成して、紹介します
    モジュールVBOの各種処理に独自のオプション追加

hook_formとCtoolsのdepent systemより各オペレーションに独自のオプションを追加

  • VBOのオペレーション設定フォームがカスタマイズとして開放していないです(前回も説明した)
  • ここで、Drupalのhook_formでVBOのオペレーション設定画面を特定して、カスタムオプション追加することになりました
    function vbo_redirect_option_form_alter(&$form, &$form_state, $form_id)
    {
        if( isset($form_state['id']) && $form_state['id'] === "views_bulk_operations"){
    
            foreach( $form_state['input']['options']['vbo_operations'] as $key => $operation) {
                if( $operation['redirect_check'] && strlen( trim($operation['redirect_url']))>0 ) {
                    variable_set( $key, $operation['redirect_url'] );
                } else {
                    if( !empty( variable_get($key) ) ) variable_del( $key ) ;
                }
            }
    
    
            foreach( $form['options']['vbo_operations'] as $key => &$operation ){
                if( !is_array($operation) ) continue ;
    
                $redirect_url = variable_get($key);
                $dep_key = "edit-options-vbo-operations-" . str_replace("_", "-", str_replace("::","",$key) ) ;
    
                $operation['redirect_check'] = array(
                    '#type' => 'checkbox',
                    '#title' => t('Redirect page to after operation'),
                    '#default_value' =>  $redirect_url ? 1 : 0 ,
                    '#dependency' => array(    // Ctoolsのdependent systemに依存
                        $dep_key."-selected" => array(1),
                    ),
                );
                $operation['redirect_url'] = array(
                    '#type' => 'textfield',
                    '#title' => t('Provide label'),
                    '#title_display' => 'invisible',
                    '#default_value' => empty($redirect_url) ? "" : $redirect_url,
                    '#dependency' => array(    // Ctoolsのdependent systemに依存
                        $dep_key."-selected" => array(1),
                        $dep_key . '-redirect-check' => array(1),
                    ),
                    '#dependency_count' => 2,
                );
            }
        }
    }
    • 設定フォームにチェックボックスをチェックしたら、画面遷移URL入力フィールドが現れるダイナミックフォームはモジュール(Ctools)のdependent systemを利用しています

処理(Operation)確認ステップをスキップがあるかないかを確認してhook_views_bulk_operations_form_alter()実装でオプションの設定を行う

  • VBOの処理(Operation)が確認ステップがあるかないかは2種類あります(この二種類をの処理プロセスが違うのでしっかりテストする必要がある)
  • hook_views_bulk_operations_form_alter()を実装して、各処理ステップにカスタマイズを行います
    function vbo_redirect_option_views_bulk_operations_form_alter(&$form, &$form_state, $vbo)
    {
        // collect all operations that has contained redirect_rul
        $redirect_arr = array();
        foreach( $vbo->options['vbo_operations'] as $key => $operation ) {
            if( !empty( variable_get($key) ) ){
                $redirect_arr[$key] = $key ;
            }
        }
    
        // add redirect step to #submit element
        if(isset($form['select'])) {
    
            // this is the form start step
            foreach( $form['select'] as $key => &$element ){
                if( isset($redirect_arr[$key]) ){
                    // we check if there is any operation has redirect_url
                    $element['#submit'][] = 'vbo_redirect_after_operation';
                    // only one is enough, we will detect witch one in the callback function
                    break;
                }
            }
    
            // do operation with confirmation step
            // this is the confirmation step
        } else if( !$form_state['operation']->getAdminOption('skip_confirmation') ) {
            $form['actions']['submit']['#submit'][] = "vbo_redirect_after_operation_with_confirmation";
            $form_state['redirect_to_after_operation'] = $form_state['operation']->getAdminOption('redirect_url');
        }
    
    }
    
    
    /**
     * callback function that has called by operation
     * this is the form start step, we don't know if it has confirmation step or not
     * @param $form
     * @param $form_state
     */
    function vbo_redirect_after_operation(&$form, &$form_state){
        // the are multiple element can be operated
        // the right one that has be sent to this step
        // we need get redirect_url if the it has
        if( isset($form_state['operation']) ){
            // get redirect_url by operation_id
            $redirec=variable_get($form_state['operation']->operationId) ;
            if( !empty($redirec) ){
                if( $form_state['operation']->getAdminOption('skip_confirmation') ) {
                    $form_state['redirect'] = $redirec;
                }
            }
        }
    }
    
    /**
     * callback function that has be called by operation with confirmation step
     * @param $form
     * @param $form_state
     */
    function vbo_redirect_after_operation_with_confirmation( $form, &$form_state ){
        // there is only operation that has be sent here with the confirmation step
        if( isset($form_state['redirect_to_after_operation']) ){
            // set redirect_url that should be stored in $form_state
            $form_state['redirect'] = $form_state['redir ect_to_after_operation'];
        }
    }

感想と結論:VBOの処理オプション設定はカスタマイズに開放していないため、各種処理(Operation)のオプションの取得、設定に苦労します

  • VBOの処理オプション設定はユーザーにカスタマイズに開放していないです
  • オペレーションの各ステップに$form、$form_state、$vbo変数から必要な情報を取得したり、セットしたりしました
  • 必要な情報がどこにあるかは不明だし(その時dsm($vbo)などで確認)、特定するまでに、時間がかかりました。
添付 サイズ
vbo_redirect_option.zip (1.77 KB) 1.77 KB
Embedded thumbnail for Drupalのモジュール(VBO)の各種処理(Operation)に独自(カスタムオ)のプションの追加方法
drupal
development
Views

Drupalのモジュール(Rules)で作成した各種アクションセットコンポーネントをモジュールVBOで一括処理

  • 背景:Drupal7.x.56、Views Bulk Operation(VBO)7.x-3.4、Rules7.x-2.10
  • モジュール(Rules)がいろいろなアクションセットの作成ができます
    • データの作成/更新/削除
    • メール送信、フラグを立てる
    • などなど
  • モジュール(VBO)がRulesで作成したアクションコンポーネントの利用ができます
    • Drupalのモジュール(Rules)のアクションコンポーネントでVBOより新規ノード作成とフィールドのコピー
  • 今回の例として、Rulesでメッセージ表示する単純なアクションコンポーネント(show message)を作成して、VBOで一括処理を行います
    Rulesでメッセージ表示コンポーネントをVBOで一括処理

問題点:VBO一括処理後に画面遷移(redirect)はできません

  • VBOで一括処理後に、画面を遷移して処理結果を確認することがあります
  • VBOの設定オプションに、処理後の画面遷移設定がありません
  • ネットで調べてみたが、VBO一括処理後の画面遷移オプション追加パッチがります
    • これは、モジュールVBOに対するパッチです
    • このパッチ適応したら、次回VBOアップグレード時に、ソースのマージ作業が面だと思います
    • できれば、VBOのパッチを使用したくないです

解決:カスタムモジュール(vbo_redirect_option.zip)でVBO処理後の画面遷移オプションの追加

  • モジュール(VBO)の主要部分がクラス(class)構造なので、簡単に画面遷移ロジックを追加することはできません
  • 「Bulk Operation Settings」に処理後の画面遷移オプションを追加します
    • 「Bulk Operation Settings」のオーバーライドができないので、hook_form_alter()でオプションを追加することになりました
      /**
       * Implements hook_form_alter().
       */
      function vbo_redirect_option_form_alter(&$form, &$form_state, $form_id)
      {
        // VBOの処理かのチェック
          if( isset($form_state['id']) && $form_state['id'] === "views_bulk_operations"){
      
         // ここで、画面遷移先の保存処理は少し反則
         //  vbo_settingsに画面遷移先の追加は難しい(クラス構造体内にあるため)
         //  環境変数に画面遷移先(uri)を保存
              if( isset($form_state['input']['options']['vbo_settings'][vbo_redirect_url]) ){
                  variable_set( 'vbo_redirect_url', $form_state['input']['options']['vbo_settings'][vbo_redirect_url] ) ;
              }
      
         // 画面遷移先のテキストフィールドを追加
              $form['options']['vbo_settings']['vbo_redirect_url'] = array(
                  '#type' => 'textfield',
                  '#title' => t('Page to direct to after completion of  batch'),
                  '#description' => t('Redirects to the view when finished the operation'),
                  '#default_value' => variable_get('vbo_redirect_url'),
              );
          }
      }
    • 画面遷移先を入力するテキストフィールドを設定画面に追加
    • 画面遷移先(uri)をvbo_settingsに入れたいですが、クラスの構造体にあるため追加できません。環境変数に保存することにしました。
    • 設定画面を保存("#submit")後に、画面遷移先を保存する処理を行いたいですが、"#submit"にコールバック関数を入れても、呼び出されない現象があって、仕方がなく、hook_form_alter()内で画面遷移先(uri)の保存処理を行いました
      VBOに一括処理後に画面遷移オプションの追加
  • hook_views_bulk_operations_form_alter()を実装して、実際のVBO一括処理後に、画面遷移設定を行います
    /**
     * Implements hook_views_bulk_operations_form_alter().
     */
    function vbo_redirect_option_views_bulk_operations_form_alter(&$form, &$form_state, $vbo)
    {
        $vbo_redirect_url = trim( variable_get('vbo_redirect_url') ) ;
    
        if( isset($vbo_redirect_url) && strlen($vbo_redirect_url) >0 ){
    
            // check if vbo operation skip confirmation
            $skip_confirmation = false ;
            foreach( $vbo->options['vbo_operations'] as $key => $operation ){
                if( $operation['selected'] && $operation['skip_confirmation'] ){
                    if( isset($form['select'][$key]) ) {
                        $form['select'][$key]['#submit'][] = 'vbo_redirect_after_operation';
                        $skip_confirmation = true ;
                    }
                }
            }
    
            // set redirect method when vbo has confirmation step
            if( !$skip_confirmation ){
                $form['actions']['submit']['#submit'][] = 'vbo_redirect_after_operation' ;
            }
        }
    }
    
    // callback function to set redirect url
    function vbo_redirect_after_operation($form, &$form_state){
        $vbo_redirect_url = trim( variable_get('vbo_redirect_url') ) ;
        $form_state['redirect'] = $vbo_redirect_url;
    }
    • VBO一括処理の「確認のステップをスキップ」があるか、ないかを分けて処理します(画面遷移設定場所が違うため)
    • "#submit"に画面遷移処理を追加します
    • 画面遷移処理は$form_state['redirect'] で行います

結論と感想:簡単のカスタモジュールでVBOへの影響はありません。各オペレーション設定に画面遷移オプションを追加したほうよいかもしれない

  • このカスタムモジュールのインストールより、モジュール(VBO)への影響はありません
  • この画面遷移オプションを「Bulk Operation Settings」に追加したので、すべてのオペレーションに適応されます
    • VBOの一括処理内容がいろいろあります(例:オーナー変更、エンティティ内容変更など)
    • これらの処理後に一つの画面遷移先の設定はやや強引的だと思います
  • できれば、「Selected Bulk Operations」にある、選択したオペレーションの設定に画面遷移先の設定をしたほうが柔軟的な対応だと思います(次回の課題)
    画面遷移オプションを各オペレーションに追加すべき
添付 サイズ
vbo_redirect_option.zip (1.19 KB) 1.19 KB
Embedded thumbnail for Drupalのモジュール(VBO)の一括処理後にページ遷移させる方法
drupal
form
ajax

やりたいこと:Drupalのajaxフレームワークを利用して表示している要素を削除

  • Drupalのモジュール(Views)で作成した一覧の要素を選択して削除します
    • 要素を選択して削除するモジュール:Views Bulk Operations
    • 例:Drupalのモジュール(VBO)の各種処理(Operation)に独自(カスタムオ)のプションの追加方法
  • 前提条件:要素削除する確認の必要はありません
  • ajaxで動的に削除するのはやさしいUIとも言えるでしょう(以下のイメージのように削除)
    Drupalのajaxフレームワークより要素を動的に削除

Step1:削除リンクにDrupalのajax使用するクラス:use-ajax を追加

  • Drupalのajaxフレームワークに関する説明は以下の記事をご参考ください
    • Drupalでajaxのフレームワークが簡単に作成できる
  • 削除アイコン付きのリンクは以下のようです
    // 削除エレメントID:123 (例)
    <a href="/delete/element/id/123/nojs" class="use-ajax del-link" id="del-link-123">
           <i class="fa fa-trash-o" aria-hidden="true"></i>
    </a>
    • アンカー(a)に削除するエレメントID(または別の識別パラメーター)を入れる必要はあります
    • アンカーリンクの後ろに「nojs」を追加します(クライアント側のajax作動時に、nojs->ajaxに変換され)
    • アンカーがクリックされると、Drupalのajaxフレームワークが起動され、削除パラメーターをサイト側に渡します

Step2:hook_menuで要素削除のリクエストをキャッチします

  • hook_menuで要素削除のリクエストを受け取り、削除処理を行います
    // 要素削除URLの設定
    $items['delete/element/%/nojs'] = array(
    	'page callback' => 'delete_element',
    	'page arguments' => array( 2, 3 ) ,
    	'access callback' => 'delete_access',
    	'type' => MENU_CALLBACK,
    );
    // ajaxが以下のURLでリクエストをします(クライアント側でnojs->ajaxに変換)
    $items['delete/element/%/ajax'] = array(
    	'delivery callback' => 'ajax_deliver',
    )+$items['delete/element/%/nojs'] ;    // 要素削除定義に遷移
    
  • 要素削除処理ファンクション:delete_element で削除処理、処理結果をクライアント側に返します
    function delete_element ($id, $ajax){
        $is_ajax = $ajax === "ajax" ;  // ajaxと通用のリクエスト両方対応のため
    
        // 要素をDBから削除
        db_delete("element_table")->condition("entity_id", $id)->execute() ;
    
        // 画面要素も削除コマンドを返す
        if( $is_ajax ){
            // ajaxで要素削除後の処理
            $commands = array();
            $commands[] = ajax_command_remove( '#element-123');
            return array(
              '#type'=>"ajax",
              '#commands' => $commands,
            );
        } else {
            // 通常での要素削除後の処理
            drupal_set_message(t('Deleted 1 vocabulary'));
            drupal_goto();
        }
    }

     

Drupalのajaxフレームワークで要素削除

纏め:Drupalのajaxフレームワークを利用すればajax処理が自動的に行います

  • 上記例では、削除リンクにクラス:use-ajax を追加するだけで、ajax関連処理を記述する必要はあります
    • 削除リンクではなく、削除ボタン(button)要素を使用する場合クラス: use-ajax-submit
  • サーバー側では、hook_menuで削除リンクの定義、削除リクエストをキャッチして、削除処理関数を作成します
    • DB上のデータ削除完了後に、クライアント側の要素削除命令(ajax_command_remove)を返せば良いです
  • この一連のajax処理の記述はほどんとありません。簡単、便利です
drupal
development
ajax

やりたいこと:Drupalのプログラムレベルで簡単にajaxを利用してクライアント側でデータ交信をしたいです

  • 環境:Drupal7.54
  • DrupalのFormAPIで簡単にajaxの実装ができます(Drupalのフォーム(FromAPI)でのajaxの実装 )
  • FormAPIだけではなく、Drupalをカスタマイズ時にいろいろなところでajaxを実装したいことがあります

ポイント1:Drupalでajaxに必要なライブラリをロードし、クライアント側にjquery.form.jsファイルをセット

  • サーバー側でdrupal.ajaxのライブラリをロードする必要があります
  • クライアント側にjquery.form.jsファイルを設置する必要があります
  • この処理はajax処理するページをロード時に行えれば良いです。
    • 例:hook_init()内で処理する
      /**
       * Implements hook_init().
       */
      function YOUR_MODULE_NAME_init()
      {
        drupal_add_js('misc/jquery.form.js');
        drupal_add_library('system','drupal.ajax');
      }
  • クライアント側のブラウザのプロパティでjquery.form.jsがセットされたことの確認ができます

ポイント2:クライアント側のajax起動リンク内にajax対応可否のパラメーター「nojs」とクラス属性「use-ajax」のセット

  • ajaxの起動リンクの作成基本パターン: 
    <a href="text/ajax/nojs/1234" class="use-ajax">ajaxリンク</a>
    • hrefにある「nojs」が決まりの文字
    • hrefにある「1234」はサーバー側に転送したい必要なパラメーター
    • class="use-ajax"はこのリンクがajax用に決める
  • クライアント側のjsで使用しているブラウザがajax対応可能かを判断して、ajax起動リンクに「nojs」のパラメーターを書き換え(利用可能:nojs⇒ajax)てサーバー側に転送
  • サーバー側がajax利用可否よりクライアント側にajax対応有無の結果を返します
    Drupalのajaxフレームワークの利用
  • 上記例のプログラムは以下のようで
    /**
     * Implements hook_init().
     */
    function test_module_init()
    {
      drupal_add_js('misc/jquery.form.js');
      drupal_add_library('system','drupal.ajax');
    }
    
    /**
     *  Implementation of hook_menu()
     */
    function test_module_menu() {
      $items['test/ajax/%/%']=array(     // URLの2,3番目がクライアント側で生成
          'page callback' => 'ajax_node_response',
          'page arguments' => array(2,3),   // URLの2,3番目の引数をコールバック関数に渡す
          'access callback' => 'user_access',
          'access arguments' => array('access content'),
          'type' => MENU_CALLBACK,
      );
      return $items;
    }
    
    function ajax_node_response($type="ajax", $nid=0){
      $node = node_load( $nid, NULL, false );
      $vnode = node_view($node);
      $output = theme('node', $vnode);
      if( $type="ajax" ){
        $commands=array();
        $commands[]=ajax_command_replace( '#block-system-main','<section id="block-system-main">'.$output.'</section>' ) ;
        $page = array(
          '#type' => 'ajax',
          '#commands' => $commands,
        );
        ajax_deliver( $page ) ;   // ajax対応ブラウザの結果
      } else {
        $output = '<div id="content">'.$output.'</div>';  // ajax非対応ブラウザの結果
        return $output;
      }
    }
    

ポイント3:クライアント側で実行させたい部分はajax_commandを使用します

  • クライアント側で処理結果をどこに入り替えはajax_command_replaceで指定します
  • 結果の挿入、入れ替え、削除、css処理などがいろいろあります。詳細は本家のajax_command一覧を参考してください

 

drupal
Views

やりたいこと:モジュール(VBO)の各処理(Operation)に独自(カスタム)オプションを追加したい

  • 前回モジュール(VBO)にたいして処理(Operation)オプション追加を紹介しました
    •  Drupalのモジュール(VBO)の一括処理後にページ遷移させる方法
    • このオプションは全VBOに対して作成したものですが、すべての処理に影響を与えています
  • 各種処理(Operation)に対してどのようにオプションを追加するか前回の課題として残っています
  • 今回はこの課題を解決に新しいカスタムモジュール(vbo_redirect_option)を作成して、紹介します
    モジュールVBOの各種処理に独自のオプション追加

hook_formとCtoolsのdepent systemより各オペレーションに独自のオプションを追加

  • VBOのオペレーション設定フォームがカスタマイズとして開放していないです(前回も説明した)
  • ここで、Drupalのhook_formでVBOのオペレーション設定画面を特定して、カスタムオプション追加することになりました
    function vbo_redirect_option_form_alter(&$form, &$form_state, $form_id)
    {
        if( isset($form_state['id']) && $form_state['id'] === "views_bulk_operations"){
    
            foreach( $form_state['input']['options']['vbo_operations'] as $key => $operation) {
                if( $operation['redirect_check'] && strlen( trim($operation['redirect_url']))>0 ) {
                    variable_set( $key, $operation['redirect_url'] );
                } else {
                    if( !empty( variable_get($key) ) ) variable_del( $key ) ;
                }
            }
    
    
            foreach( $form['options']['vbo_operations'] as $key => &$operation ){
                if( !is_array($operation) ) continue ;
    
                $redirect_url = variable_get($key);
                $dep_key = "edit-options-vbo-operations-" . str_replace("_", "-", str_replace("::","",$key) ) ;
    
                $operation['redirect_check'] = array(
                    '#type' => 'checkbox',
                    '#title' => t('Redirect page to after operation'),
                    '#default_value' =>  $redirect_url ? 1 : 0 ,
                    '#dependency' => array(    // Ctoolsのdependent systemに依存
                        $dep_key."-selected" => array(1),
                    ),
                );
                $operation['redirect_url'] = array(
                    '#type' => 'textfield',
                    '#title' => t('Provide label'),
                    '#title_display' => 'invisible',
                    '#default_value' => empty($redirect_url) ? "" : $redirect_url,
                    '#dependency' => array(    // Ctoolsのdependent systemに依存
                        $dep_key."-selected" => array(1),
                        $dep_key . '-redirect-check' => array(1),
                    ),
                    '#dependency_count' => 2,
                );
            }
        }
    }
    • 設定フォームにチェックボックスをチェックしたら、画面遷移URL入力フィールドが現れるダイナミックフォームはモジュール(Ctools)のdependent systemを利用しています

処理(Operation)確認ステップをスキップがあるかないかを確認してhook_views_bulk_operations_form_alter()実装でオプションの設定を行う

  • VBOの処理(Operation)が確認ステップがあるかないかは2種類あります(この二種類をの処理プロセスが違うのでしっかりテストする必要がある)
  • hook_views_bulk_operations_form_alter()を実装して、各処理ステップにカスタマイズを行います
    function vbo_redirect_option_views_bulk_operations_form_alter(&$form, &$form_state, $vbo)
    {
        // collect all operations that has contained redirect_rul
        $redirect_arr = array();
        foreach( $vbo->options['vbo_operations'] as $key => $operation ) {
            if( !empty( variable_get($key) ) ){
                $redirect_arr[$key] = $key ;
            }
        }
    
        // add redirect step to #submit element
        if(isset($form['select'])) {
    
            // this is the form start step
            foreach( $form['select'] as $key => &$element ){
                if( isset($redirect_arr[$key]) ){
                    // we check if there is any operation has redirect_url
                    $element['#submit'][] = 'vbo_redirect_after_operation';
                    // only one is enough, we will detect witch one in the callback function
                    break;
                }
            }
    
            // do operation with confirmation step
            // this is the confirmation step
        } else if( !$form_state['operation']->getAdminOption('skip_confirmation') ) {
            $form['actions']['submit']['#submit'][] = "vbo_redirect_after_operation_with_confirmation";
            $form_state['redirect_to_after_operation'] = $form_state['operation']->getAdminOption('redirect_url');
        }
    
    }
    
    
    /**
     * callback function that has called by operation
     * this is the form start step, we don't know if it has confirmation step or not
     * @param $form
     * @param $form_state
     */
    function vbo_redirect_after_operation(&$form, &$form_state){
        // the are multiple element can be operated
        // the right one that has be sent to this step
        // we need get redirect_url if the it has
        if( isset($form_state['operation']) ){
            // get redirect_url by operation_id
            $redirec=variable_get($form_state['operation']->operationId) ;
            if( !empty($redirec) ){
                if( $form_state['operation']->getAdminOption('skip_confirmation') ) {
                    $form_state['redirect'] = $redirec;
                }
            }
        }
    }
    
    /**
     * callback function that has be called by operation with confirmation step
     * @param $form
     * @param $form_state
     */
    function vbo_redirect_after_operation_with_confirmation( $form, &$form_state ){
        // there is only operation that has be sent here with the confirmation step
        if( isset($form_state['redirect_to_after_operation']) ){
            // set redirect_url that should be stored in $form_state
            $form_state['redirect'] = $form_state['redir ect_to_after_operation'];
        }
    }

感想と結論:VBOの処理オプション設定はカスタマイズに開放していないため、各種処理(Operation)のオプションの取得、設定に苦労します

  • VBOの処理オプション設定はユーザーにカスタマイズに開放していないです
  • オペレーションの各ステップに$form、$form_state、$vbo変数から必要な情報を取得したり、セットしたりしました
  • 必要な情報がどこにあるかは不明だし(その時dsm($vbo)などで確認)、特定するまでに、時間がかかりました。
添付 サイズ
vbo_redirect_option.zip (1.77 KB) 1.77 KB
Embedded thumbnail for Drupalのモジュール(VBO)の各種処理(Operation)に独自(カスタムオ)のプションの追加方法
drupal
development
Views

Drupalのモジュール(Rules)で作成した各種アクションセットコンポーネントをモジュールVBOで一括処理

  • 背景:Drupal7.x.56、Views Bulk Operation(VBO)7.x-3.4、Rules7.x-2.10
  • モジュール(Rules)がいろいろなアクションセットの作成ができます
    • データの作成/更新/削除
    • メール送信、フラグを立てる
    • などなど
  • モジュール(VBO)がRulesで作成したアクションコンポーネントの利用ができます
    • Drupalのモジュール(Rules)のアクションコンポーネントでVBOより新規ノード作成とフィールドのコピー
  • 今回の例として、Rulesでメッセージ表示する単純なアクションコンポーネント(show message)を作成して、VBOで一括処理を行います
    Rulesでメッセージ表示コンポーネントをVBOで一括処理

問題点:VBO一括処理後に画面遷移(redirect)はできません

  • VBOで一括処理後に、画面を遷移して処理結果を確認することがあります
  • VBOの設定オプションに、処理後の画面遷移設定がありません
  • ネットで調べてみたが、VBO一括処理後の画面遷移オプション追加パッチがります
    • これは、モジュールVBOに対するパッチです
    • このパッチ適応したら、次回VBOアップグレード時に、ソースのマージ作業が面だと思います
    • できれば、VBOのパッチを使用したくないです

解決:カスタムモジュール(vbo_redirect_option.zip)でVBO処理後の画面遷移オプションの追加

  • モジュール(VBO)の主要部分がクラス(class)構造なので、簡単に画面遷移ロジックを追加することはできません
  • 「Bulk Operation Settings」に処理後の画面遷移オプションを追加します
    • 「Bulk Operation Settings」のオーバーライドができないので、hook_form_alter()でオプションを追加することになりました
      /**
       * Implements hook_form_alter().
       */
      function vbo_redirect_option_form_alter(&$form, &$form_state, $form_id)
      {
        // VBOの処理かのチェック
          if( isset($form_state['id']) && $form_state['id'] === "views_bulk_operations"){
      
         // ここで、画面遷移先の保存処理は少し反則
         //  vbo_settingsに画面遷移先の追加は難しい(クラス構造体内にあるため)
         //  環境変数に画面遷移先(uri)を保存
              if( isset($form_state['input']['options']['vbo_settings'][vbo_redirect_url]) ){
                  variable_set( 'vbo_redirect_url', $form_state['input']['options']['vbo_settings'][vbo_redirect_url] ) ;
              }
      
         // 画面遷移先のテキストフィールドを追加
              $form['options']['vbo_settings']['vbo_redirect_url'] = array(
                  '#type' => 'textfield',
                  '#title' => t('Page to direct to after completion of  batch'),
                  '#description' => t('Redirects to the view when finished the operation'),
                  '#default_value' => variable_get('vbo_redirect_url'),
              );
          }
      }
    • 画面遷移先を入力するテキストフィールドを設定画面に追加
    • 画面遷移先(uri)をvbo_settingsに入れたいですが、クラスの構造体にあるため追加できません。環境変数に保存することにしました。
    • 設定画面を保存("#submit")後に、画面遷移先を保存する処理を行いたいですが、"#submit"にコールバック関数を入れても、呼び出されない現象があって、仕方がなく、hook_form_alter()内で画面遷移先(uri)の保存処理を行いました
      VBOに一括処理後に画面遷移オプションの追加
  • hook_views_bulk_operations_form_alter()を実装して、実際のVBO一括処理後に、画面遷移設定を行います
    /**
     * Implements hook_views_bulk_operations_form_alter().
     */
    function vbo_redirect_option_views_bulk_operations_form_alter(&$form, &$form_state, $vbo)
    {
        $vbo_redirect_url = trim( variable_get('vbo_redirect_url') ) ;
    
        if( isset($vbo_redirect_url) && strlen($vbo_redirect_url) >0 ){
    
            // check if vbo operation skip confirmation
            $skip_confirmation = false ;
            foreach( $vbo->options['vbo_operations'] as $key => $operation ){
                if( $operation['selected'] && $operation['skip_confirmation'] ){
                    if( isset($form['select'][$key]) ) {
                        $form['select'][$key]['#submit'][] = 'vbo_redirect_after_operation';
                        $skip_confirmation = true ;
                    }
                }
            }
    
            // set redirect method when vbo has confirmation step
            if( !$skip_confirmation ){
                $form['actions']['submit']['#submit'][] = 'vbo_redirect_after_operation' ;
            }
        }
    }
    
    // callback function to set redirect url
    function vbo_redirect_after_operation($form, &$form_state){
        $vbo_redirect_url = trim( variable_get('vbo_redirect_url') ) ;
        $form_state['redirect'] = $vbo_redirect_url;
    }
    • VBO一括処理の「確認のステップをスキップ」があるか、ないかを分けて処理します(画面遷移設定場所が違うため)
    • "#submit"に画面遷移処理を追加します
    • 画面遷移処理は$form_state['redirect'] で行います

結論と感想:簡単のカスタモジュールでVBOへの影響はありません。各オペレーション設定に画面遷移オプションを追加したほうよいかもしれない

  • このカスタムモジュールのインストールより、モジュール(VBO)への影響はありません
  • この画面遷移オプションを「Bulk Operation Settings」に追加したので、すべてのオペレーションに適応されます
    • VBOの一括処理内容がいろいろあります(例:オーナー変更、エンティティ内容変更など)
    • これらの処理後に一つの画面遷移先の設定はやや強引的だと思います
  • できれば、「Selected Bulk Operations」にある、選択したオペレーションの設定に画面遷移先の設定をしたほうが柔軟的な対応だと思います(次回の課題)
    画面遷移オプションを各オペレーションに追加すべき
添付 サイズ
vbo_redirect_option.zip (1.19 KB) 1.19 KB
Embedded thumbnail for Drupalのモジュール(VBO)の一括処理後にページ遷移させる方法
drupal
form
ajax

やりたいこと:Drupalのajaxフレームワークを利用して表示している要素を削除

  • Drupalのモジュール(Views)で作成した一覧の要素を選択して削除します
    • 要素を選択して削除するモジュール:Views Bulk Operations
    • 例:Drupalのモジュール(VBO)の各種処理(Operation)に独自(カスタムオ)のプションの追加方法
  • 前提条件:要素削除する確認の必要はありません
  • ajaxで動的に削除するのはやさしいUIとも言えるでしょう(以下のイメージのように削除)
    Drupalのajaxフレームワークより要素を動的に削除

Step1:削除リンクにDrupalのajax使用するクラス:use-ajax を追加

  • Drupalのajaxフレームワークに関する説明は以下の記事をご参考ください
    • Drupalでajaxのフレームワークが簡単に作成できる
  • 削除アイコン付きのリンクは以下のようです
    // 削除エレメントID:123 (例)
    <a href="/delete/element/id/123/nojs" class="use-ajax del-link" id="del-link-123">
           <i class="fa fa-trash-o" aria-hidden="true"></i>
    </a>
    • アンカー(a)に削除するエレメントID(または別の識別パラメーター)を入れる必要はあります
    • アンカーリンクの後ろに「nojs」を追加します(クライアント側のajax作動時に、nojs->ajaxに変換され)
    • アンカーがクリックされると、Drupalのajaxフレームワークが起動され、削除パラメーターをサイト側に渡します

Step2:hook_menuで要素削除のリクエストをキャッチします

  • hook_menuで要素削除のリクエストを受け取り、削除処理を行います
    // 要素削除URLの設定
    $items['delete/element/%/nojs'] = array(
    	'page callback' => 'delete_element',
    	'page arguments' => array( 2, 3 ) ,
    	'access callback' => 'delete_access',
    	'type' => MENU_CALLBACK,
    );
    // ajaxが以下のURLでリクエストをします(クライアント側でnojs->ajaxに変換)
    $items['delete/element/%/ajax'] = array(
    	'delivery callback' => 'ajax_deliver',
    )+$items['delete/element/%/nojs'] ;    // 要素削除定義に遷移
    
  • 要素削除処理ファンクション:delete_element で削除処理、処理結果をクライアント側に返します
    function delete_element ($id, $ajax){
        $is_ajax = $ajax === "ajax" ;  // ajaxと通用のリクエスト両方対応のため
    
        // 要素をDBから削除
        db_delete("element_table")->condition("entity_id", $id)->execute() ;
    
        // 画面要素も削除コマンドを返す
        if( $is_ajax ){
            // ajaxで要素削除後の処理
            $commands = array();
            $commands[] = ajax_command_remove( '#element-123');
            return array(
              '#type'=>"ajax",
              '#commands' => $commands,
            );
        } else {
            // 通常での要素削除後の処理
            drupal_set_message(t('Deleted 1 vocabulary'));
            drupal_goto();
        }
    }

     

Drupalのajaxフレームワークで要素削除

纏め:Drupalのajaxフレームワークを利用すればajax処理が自動的に行います

  • 上記例では、削除リンクにクラス:use-ajax を追加するだけで、ajax関連処理を記述する必要はあります
    • 削除リンクではなく、削除ボタン(button)要素を使用する場合クラス: use-ajax-submit
  • サーバー側では、hook_menuで削除リンクの定義、削除リクエストをキャッチして、削除処理関数を作成します
    • DB上のデータ削除完了後に、クライアント側の要素削除命令(ajax_command_remove)を返せば良いです
  • この一連のajax処理の記述はほどんとありません。簡単、便利です
drupal
form
ajax

Drupalのajaxフレームワークにあるajax_command_invokeがユーザーが自分的にしたjavascriptのカスタムコマンドの呼び出しができます

  • Drupalのajaxフレームワークに、クライアント側のUI要素追加、更新、削除、cssなどの処理コマンドが数多くあります
    • コマンドの説明:https://api.drupal.org/api/drupal/includes%21ajax.inc/group/ajax_comman…
  • ajaxコマンド:ajax_command_invoke があります。このコマンドがユーザー自分作成したjavascriptの呼び出しができます
  • 例: クライアント側で要素削除時に、自作にjavascriptで要素をゆっくり消していく動画効果を再現します
    ajaxで要素作成動画

方法1:jQueryのカスタム関数で定義します

  • jQueryのカスタム関数を利用して、上記動画効果のjavascriptを作成して、Drupalのajax_command_invokeより呼びされます
    jQuery でカスタム関数の作成
  • Drupalのajax_command_invokeでカスタム関数にパラメターを渡して、実行させます
    // サーバ側でカスタム関数(removeElement)にパラメータを渡して実行させる
    $commands = array();
    $commands[] = ajax_command_invoke( null,
                                       'removeElement', 
                                        array("#del-div-".$entity->entity_id) );
    return array(  '#type'=>"ajax",  '#commands' => $commands,);
    
    // クライアント側で実行されるカスタム関数(removeElement)
    jQuery.fn.removeElement = function(ele_id) {
        jQuery( ele_id )
            .css({'opacity':0, 'transition': 'all 1s' })   // cssで要素の透明度をゼロにする
            .delay(1000).queue(function(){jQuery( ele_id ).remove()} ) ; // 1秒後に要素の削除
    };
    

     

方法2:Drupalのajaxフレームワーク(Drupal.ajax.prototype.commands)にカスタム関数をバインドします

  • DrupalのajaxフレームワークにjQueryのようにカスタム関数の追加ができます
  • パラメータの引き渡しはjQueryのカスタム関数と違います
    • jQueryのカスタム関数にパラメーターを配列に渡します
    • Drupal.ajax.prototype.commandsにパラメータを個別に渡します
  • 上記の例では同じようにDrupal.ajax.prototype.commandsで実現します
    // サーバ側でカスタム関数(removeElement)にパラメータを渡して実行させる 
    $commands = array(); 
    $commands[] = array( 'command' => 'removeElement', 
                                        'ele_id' => "#del-div-".$entity->entity_id) ); 
    return array( '#type'=>"ajax", '#commands' => $commands,); 
    
    // クライアント側のカスタム関数(removeElement)の実行
    Drupal.ajax.prototype.commands.removeElement = 
    function(ajax, response, status) {
        jQuery( response.ele_id )
            .css({'opacity':0, 'transition': 'all 1s' })
            .delay(1000).queue(function(){jQuery( response.ele_id ).remove()}) ;
    }

     

  • 同じ結果となります

 

drupal
form
ajax

やりたいこと:Drupalのajaxフレームワークを利用して表示している要素を削除

  • Drupalのモジュール(Views)で作成した一覧の要素を選択して削除します
    • 要素を選択して削除するモジュール:Views Bulk Operations
    • 例:Drupalのモジュール(VBO)の各種処理(Operation)に独自(カスタムオ)のプションの追加方法
  • 前提条件:要素削除する確認の必要はありません
  • ajaxで動的に削除するのはやさしいUIとも言えるでしょう(以下のイメージのように削除)
    Drupalのajaxフレームワークより要素を動的に削除

Step1:削除リンクにDrupalのajax使用するクラス:use-ajax を追加

  • Drupalのajaxフレームワークに関する説明は以下の記事をご参考ください
    • Drupalでajaxのフレームワークが簡単に作成できる
  • 削除アイコン付きのリンクは以下のようです
    // 削除エレメントID:123 (例)
    <a href="/delete/element/id/123/nojs" class="use-ajax del-link" id="del-link-123">
           <i class="fa fa-trash-o" aria-hidden="true"></i>
    </a>
    • アンカー(a)に削除するエレメントID(または別の識別パラメーター)を入れる必要はあります
    • アンカーリンクの後ろに「nojs」を追加します(クライアント側のajax作動時に、nojs->ajaxに変換され)
    • アンカーがクリックされると、Drupalのajaxフレームワークが起動され、削除パラメーターをサイト側に渡します

Step2:hook_menuで要素削除のリクエストをキャッチします

  • hook_menuで要素削除のリクエストを受け取り、削除処理を行います
    // 要素削除URLの設定
    $items['delete/element/%/nojs'] = array(
    	'page callback' => 'delete_element',
    	'page arguments' => array( 2, 3 ) ,
    	'access callback' => 'delete_access',
    	'type' => MENU_CALLBACK,
    );
    // ajaxが以下のURLでリクエストをします(クライアント側でnojs->ajaxに変換)
    $items['delete/element/%/ajax'] = array(
    	'delivery callback' => 'ajax_deliver',
    )+$items['delete/element/%/nojs'] ;    // 要素削除定義に遷移
    
  • 要素削除処理ファンクション:delete_element で削除処理、処理結果をクライアント側に返します
    function delete_element ($id, $ajax){
        $is_ajax = $ajax === "ajax" ;  // ajaxと通用のリクエスト両方対応のため
    
        // 要素をDBから削除
        db_delete("element_table")->condition("entity_id", $id)->execute() ;
    
        // 画面要素も削除コマンドを返す
        if( $is_ajax ){
            // ajaxで要素削除後の処理
            $commands = array();
            $commands[] = ajax_command_remove( '#element-123');
            return array(
              '#type'=>"ajax",
              '#commands' => $commands,
            );
        } else {
            // 通常での要素削除後の処理
            drupal_set_message(t('Deleted 1 vocabulary'));
            drupal_goto();
        }
    }

     

Drupalのajaxフレームワークで要素削除

纏め:Drupalのajaxフレームワークを利用すればajax処理が自動的に行います

  • 上記例では、削除リンクにクラス:use-ajax を追加するだけで、ajax関連処理を記述する必要はあります
    • 削除リンクではなく、削除ボタン(button)要素を使用する場合クラス: use-ajax-submit
  • サーバー側では、hook_menuで削除リンクの定義、削除リクエストをキャッチして、削除処理関数を作成します
    • DB上のデータ削除完了後に、クライアント側の要素削除命令(ajax_command_remove)を返せば良いです
  • この一連のajax処理の記述はほどんとありません。簡単、便利です
drupal
form
ajax

Drupalのajaxフレームワークにあるajax_command_invokeがユーザーが自分的にしたjavascriptのカスタムコマンドの呼び出しができます

  • Drupalのajaxフレームワークに、クライアント側のUI要素追加、更新、削除、cssなどの処理コマンドが数多くあります
    • コマンドの説明:https://api.drupal.org/api/drupal/includes%21ajax.inc/group/ajax_comman…
  • ajaxコマンド:ajax_command_invoke があります。このコマンドがユーザー自分作成したjavascriptの呼び出しができます
  • 例: クライアント側で要素削除時に、自作にjavascriptで要素をゆっくり消していく動画効果を再現します
    ajaxで要素作成動画

方法1:jQueryのカスタム関数で定義します

  • jQueryのカスタム関数を利用して、上記動画効果のjavascriptを作成して、Drupalのajax_command_invokeより呼びされます
    jQuery でカスタム関数の作成
  • Drupalのajax_command_invokeでカスタム関数にパラメターを渡して、実行させます
    // サーバ側でカスタム関数(removeElement)にパラメータを渡して実行させる
    $commands = array();
    $commands[] = ajax_command_invoke( null,
                                       'removeElement', 
                                        array("#del-div-".$entity->entity_id) );
    return array(  '#type'=>"ajax",  '#commands' => $commands,);
    
    // クライアント側で実行されるカスタム関数(removeElement)
    jQuery.fn.removeElement = function(ele_id) {
        jQuery( ele_id )
            .css({'opacity':0, 'transition': 'all 1s' })   // cssで要素の透明度をゼロにする
            .delay(1000).queue(function(){jQuery( ele_id ).remove()} ) ; // 1秒後に要素の削除
    };
    

     

方法2:Drupalのajaxフレームワーク(Drupal.ajax.prototype.commands)にカスタム関数をバインドします

  • DrupalのajaxフレームワークにjQueryのようにカスタム関数の追加ができます
  • パラメータの引き渡しはjQueryのカスタム関数と違います
    • jQueryのカスタム関数にパラメーターを配列に渡します
    • Drupal.ajax.prototype.commandsにパラメータを個別に渡します
  • 上記の例では同じようにDrupal.ajax.prototype.commandsで実現します
    // サーバ側でカスタム関数(removeElement)にパラメータを渡して実行させる 
    $commands = array(); 
    $commands[] = array( 'command' => 'removeElement', 
                                        'ele_id' => "#del-div-".$entity->entity_id) ); 
    return array( '#type'=>"ajax", '#commands' => $commands,); 
    
    // クライアント側のカスタム関数(removeElement)の実行
    Drupal.ajax.prototype.commands.removeElement = 
    function(ajax, response, status) {
        jQuery( response.ele_id )
            .css({'opacity':0, 'transition': 'all 1s' })
            .delay(1000).queue(function(){jQuery( response.ele_id ).remove()}) ;
    }

     

  • 同じ結果となります

 

drupal
form
ajax

やりたいこと:Drupalのajaxフレームワークを利用して表示している要素を削除

  • Drupalのモジュール(Views)で作成した一覧の要素を選択して削除します
    • 要素を選択して削除するモジュール:Views Bulk Operations
    • 例:Drupalのモジュール(VBO)の各種処理(Operation)に独自(カスタムオ)のプションの追加方法
  • 前提条件:要素削除する確認の必要はありません
  • ajaxで動的に削除するのはやさしいUIとも言えるでしょう(以下のイメージのように削除)
    Drupalのajaxフレームワークより要素を動的に削除

Step1:削除リンクにDrupalのajax使用するクラス:use-ajax を追加

  • Drupalのajaxフレームワークに関する説明は以下の記事をご参考ください
    • Drupalでajaxのフレームワークが簡単に作成できる
  • 削除アイコン付きのリンクは以下のようです
    // 削除エレメントID:123 (例)
    <a href="/delete/element/id/123/nojs" class="use-ajax del-link" id="del-link-123">
           <i class="fa fa-trash-o" aria-hidden="true"></i>
    </a>
    • アンカー(a)に削除するエレメントID(または別の識別パラメーター)を入れる必要はあります
    • アンカーリンクの後ろに「nojs」を追加します(クライアント側のajax作動時に、nojs->ajaxに変換され)
    • アンカーがクリックされると、Drupalのajaxフレームワークが起動され、削除パラメーターをサイト側に渡します

Step2:hook_menuで要素削除のリクエストをキャッチします

  • hook_menuで要素削除のリクエストを受け取り、削除処理を行います
    // 要素削除URLの設定
    $items['delete/element/%/nojs'] = array(
    	'page callback' => 'delete_element',
    	'page arguments' => array( 2, 3 ) ,
    	'access callback' => 'delete_access',
    	'type' => MENU_CALLBACK,
    );
    // ajaxが以下のURLでリクエストをします(クライアント側でnojs->ajaxに変換)
    $items['delete/element/%/ajax'] = array(
    	'delivery callback' => 'ajax_deliver',
    )+$items['delete/element/%/nojs'] ;    // 要素削除定義に遷移
    
  • 要素削除処理ファンクション:delete_element で削除処理、処理結果をクライアント側に返します
    function delete_element ($id, $ajax){
        $is_ajax = $ajax === "ajax" ;  // ajaxと通用のリクエスト両方対応のため
    
        // 要素をDBから削除
        db_delete("element_table")->condition("entity_id", $id)->execute() ;
    
        // 画面要素も削除コマンドを返す
        if( $is_ajax ){
            // ajaxで要素削除後の処理
            $commands = array();
            $commands[] = ajax_command_remove( '#element-123');
            return array(
              '#type'=>"ajax",
              '#commands' => $commands,
            );
        } else {
            // 通常での要素削除後の処理
            drupal_set_message(t('Deleted 1 vocabulary'));
            drupal_goto();
        }
    }

     

Drupalのajaxフレームワークで要素削除

纏め:Drupalのajaxフレームワークを利用すればajax処理が自動的に行います

  • 上記例では、削除リンクにクラス:use-ajax を追加するだけで、ajax関連処理を記述する必要はあります
    • 削除リンクではなく、削除ボタン(button)要素を使用する場合クラス: use-ajax-submit
  • サーバー側では、hook_menuで削除リンクの定義、削除リクエストをキャッチして、削除処理関数を作成します
    • DB上のデータ削除完了後に、クライアント側の要素削除命令(ajax_command_remove)を返せば良いです
  • この一連のajax処理の記述はほどんとありません。簡単、便利です
drupal
form
ajax

Drupalのajaxフレームワークにあるajax_command_invokeがユーザーが自分的にしたjavascriptのカスタムコマンドの呼び出しができます

  • Drupalのajaxフレームワークに、クライアント側のUI要素追加、更新、削除、cssなどの処理コマンドが数多くあります
    • コマンドの説明:https://api.drupal.org/api/drupal/includes%21ajax.inc/group/ajax_comman…
  • ajaxコマンド:ajax_command_invoke があります。このコマンドがユーザー自分作成したjavascriptの呼び出しができます
  • 例: クライアント側で要素削除時に、自作にjavascriptで要素をゆっくり消していく動画効果を再現します
    ajaxで要素作成動画

方法1:jQueryのカスタム関数で定義します

  • jQueryのカスタム関数を利用して、上記動画効果のjavascriptを作成して、Drupalのajax_command_invokeより呼びされます
    jQuery でカスタム関数の作成
  • Drupalのajax_command_invokeでカスタム関数にパラメターを渡して、実行させます
    // サーバ側でカスタム関数(removeElement)にパラメータを渡して実行させる
    $commands = array();
    $commands[] = ajax_command_invoke( null,
                                       'removeElement', 
                                        array("#del-div-".$entity->entity_id) );
    return array(  '#type'=>"ajax",  '#commands' => $commands,);
    
    // クライアント側で実行されるカスタム関数(removeElement)
    jQuery.fn.removeElement = function(ele_id) {
        jQuery( ele_id )
            .css({'opacity':0, 'transition': 'all 1s' })   // cssで要素の透明度をゼロにする
            .delay(1000).queue(function(){jQuery( ele_id ).remove()} ) ; // 1秒後に要素の削除
    };
    

     

方法2:Drupalのajaxフレームワーク(Drupal.ajax.prototype.commands)にカスタム関数をバインドします

  • DrupalのajaxフレームワークにjQueryのようにカスタム関数の追加ができます
  • パラメータの引き渡しはjQueryのカスタム関数と違います
    • jQueryのカスタム関数にパラメーターを配列に渡します
    • Drupal.ajax.prototype.commandsにパラメータを個別に渡します
  • 上記の例では同じようにDrupal.ajax.prototype.commandsで実現します
    // サーバ側でカスタム関数(removeElement)にパラメータを渡して実行させる 
    $commands = array(); 
    $commands[] = array( 'command' => 'removeElement', 
                                        'ele_id' => "#del-div-".$entity->entity_id) ); 
    return array( '#type'=>"ajax", '#commands' => $commands,); 
    
    // クライアント側のカスタム関数(removeElement)の実行
    Drupal.ajax.prototype.commands.removeElement = 
    function(ajax, response, status) {
        jQuery( response.ele_id )
            .css({'opacity':0, 'transition': 'all 1s' })
            .delay(1000).queue(function(){jQuery( response.ele_id ).remove()}) ;
    }

     

  • 同じ結果となります

 

drupal
form
ajax

やりたいこと:Drupalのajaxフレームワークを利用して表示している要素を削除

  • Drupalのモジュール(Views)で作成した一覧の要素を選択して削除します
    • 要素を選択して削除するモジュール:Views Bulk Operations
    • 例:Drupalのモジュール(VBO)の各種処理(Operation)に独自(カスタムオ)のプションの追加方法
  • 前提条件:要素削除する確認の必要はありません
  • ajaxで動的に削除するのはやさしいUIとも言えるでしょう(以下のイメージのように削除)
    Drupalのajaxフレームワークより要素を動的に削除

Step1:削除リンクにDrupalのajax使用するクラス:use-ajax を追加

  • Drupalのajaxフレームワークに関する説明は以下の記事をご参考ください
    • Drupalでajaxのフレームワークが簡単に作成できる
  • 削除アイコン付きのリンクは以下のようです
    // 削除エレメントID:123 (例)
    <a href="/delete/element/id/123/nojs" class="use-ajax del-link" id="del-link-123">
           <i class="fa fa-trash-o" aria-hidden="true"></i>
    </a>
    • アンカー(a)に削除するエレメントID(または別の識別パラメーター)を入れる必要はあります
    • アンカーリンクの後ろに「nojs」を追加します(クライアント側のajax作動時に、nojs->ajaxに変換され)
    • アンカーがクリックされると、Drupalのajaxフレームワークが起動され、削除パラメーターをサイト側に渡します

Step2:hook_menuで要素削除のリクエストをキャッチします

  • hook_menuで要素削除のリクエストを受け取り、削除処理を行います
    // 要素削除URLの設定
    $items['delete/element/%/nojs'] = array(
    	'page callback' => 'delete_element',
    	'page arguments' => array( 2, 3 ) ,
    	'access callback' => 'delete_access',
    	'type' => MENU_CALLBACK,
    );
    // ajaxが以下のURLでリクエストをします(クライアント側でnojs->ajaxに変換)
    $items['delete/element/%/ajax'] = array(
    	'delivery callback' => 'ajax_deliver',
    )+$items['delete/element/%/nojs'] ;    // 要素削除定義に遷移
    
  • 要素削除処理ファンクション:delete_element で削除処理、処理結果をクライアント側に返します
    function delete_element ($id, $ajax){
        $is_ajax = $ajax === "ajax" ;  // ajaxと通用のリクエスト両方対応のため
    
        // 要素をDBから削除
        db_delete("element_table")->condition("entity_id", $id)->execute() ;
    
        // 画面要素も削除コマンドを返す
        if( $is_ajax ){
            // ajaxで要素削除後の処理
            $commands = array();
            $commands[] = ajax_command_remove( '#element-123');
            return array(
              '#type'=>"ajax",
              '#commands' => $commands,
            );
        } else {
            // 通常での要素削除後の処理
            drupal_set_message(t('Deleted 1 vocabulary'));
            drupal_goto();
        }
    }

     

Drupalのajaxフレームワークで要素削除

纏め:Drupalのajaxフレームワークを利用すればajax処理が自動的に行います

  • 上記例では、削除リンクにクラス:use-ajax を追加するだけで、ajax関連処理を記述する必要はあります
    • 削除リンクではなく、削除ボタン(button)要素を使用する場合クラス: use-ajax-submit
  • サーバー側では、hook_menuで削除リンクの定義、削除リクエストをキャッチして、削除処理関数を作成します
    • DB上のデータ削除完了後に、クライアント側の要素削除命令(ajax_command_remove)を返せば良いです
  • この一連のajax処理の記述はほどんとありません。簡単、便利です
drupal
form
ajax

Drupalのajaxフレームワークにあるajax_command_invokeがユーザーが自分的にしたjavascriptのカスタムコマンドの呼び出しができます

  • Drupalのajaxフレームワークに、クライアント側のUI要素追加、更新、削除、cssなどの処理コマンドが数多くあります
    • コマンドの説明:https://api.drupal.org/api/drupal/includes%21ajax.inc/group/ajax_comman…
  • ajaxコマンド:ajax_command_invoke があります。このコマンドがユーザー自分作成したjavascriptの呼び出しができます
  • 例: クライアント側で要素削除時に、自作にjavascriptで要素をゆっくり消していく動画効果を再現します
    ajaxで要素作成動画

方法1:jQueryのカスタム関数で定義します

  • jQueryのカスタム関数を利用して、上記動画効果のjavascriptを作成して、Drupalのajax_command_invokeより呼びされます
    jQuery でカスタム関数の作成
  • Drupalのajax_command_invokeでカスタム関数にパラメターを渡して、実行させます
    // サーバ側でカスタム関数(removeElement)にパラメータを渡して実行させる
    $commands = array();
    $commands[] = ajax_command_invoke( null,
                                       'removeElement', 
                                        array("#del-div-".$entity->entity_id) );
    return array(  '#type'=>"ajax",  '#commands' => $commands,);
    
    // クライアント側で実行されるカスタム関数(removeElement)
    jQuery.fn.removeElement = function(ele_id) {
        jQuery( ele_id )
            .css({'opacity':0, 'transition': 'all 1s' })   // cssで要素の透明度をゼロにする
            .delay(1000).queue(function(){jQuery( ele_id ).remove()} ) ; // 1秒後に要素の削除
    };
    

     

方法2:Drupalのajaxフレームワーク(Drupal.ajax.prototype.commands)にカスタム関数をバインドします

  • DrupalのajaxフレームワークにjQueryのようにカスタム関数の追加ができます
  • パラメータの引き渡しはjQueryのカスタム関数と違います
    • jQueryのカスタム関数にパラメーターを配列に渡します
    • Drupal.ajax.prototype.commandsにパラメータを個別に渡します
  • 上記の例では同じようにDrupal.ajax.prototype.commandsで実現します
    // サーバ側でカスタム関数(removeElement)にパラメータを渡して実行させる 
    $commands = array(); 
    $commands[] = array( 'command' => 'removeElement', 
                                        'ele_id' => "#del-div-".$entity->entity_id) ); 
    return array( '#type'=>"ajax", '#commands' => $commands,); 
    
    // クライアント側のカスタム関数(removeElement)の実行
    Drupal.ajax.prototype.commands.removeElement = 
    function(ajax, response, status) {
        jQuery( response.ele_id )
            .css({'opacity':0, 'transition': 'all 1s' })
            .delay(1000).queue(function(){jQuery( response.ele_id ).remove()}) ;
    }

     

  • 同じ結果となります

 

drupal
form
ajax

やりたいこと:Drupalのajaxフレームワークを利用して表示している要素を削除

  • Drupalのモジュール(Views)で作成した一覧の要素を選択して削除します
    • 要素を選択して削除するモジュール:Views Bulk Operations
    • 例:Drupalのモジュール(VBO)の各種処理(Operation)に独自(カスタムオ)のプションの追加方法
  • 前提条件:要素削除する確認の必要はありません
  • ajaxで動的に削除するのはやさしいUIとも言えるでしょう(以下のイメージのように削除)
    Drupalのajaxフレームワークより要素を動的に削除

Step1:削除リンクにDrupalのajax使用するクラス:use-ajax を追加

  • Drupalのajaxフレームワークに関する説明は以下の記事をご参考ください
    • Drupalでajaxのフレームワークが簡単に作成できる
  • 削除アイコン付きのリンクは以下のようです
    // 削除エレメントID:123 (例)
    <a href="/delete/element/id/123/nojs" class="use-ajax del-link" id="del-link-123">
           <i class="fa fa-trash-o" aria-hidden="true"></i>
    </a>
    • アンカー(a)に削除するエレメントID(または別の識別パラメーター)を入れる必要はあります
    • アンカーリンクの後ろに「nojs」を追加します(クライアント側のajax作動時に、nojs->ajaxに変換され)
    • アンカーがクリックされると、Drupalのajaxフレームワークが起動され、削除パラメーターをサイト側に渡します

Step2:hook_menuで要素削除のリクエストをキャッチします

  • hook_menuで要素削除のリクエストを受け取り、削除処理を行います
    // 要素削除URLの設定
    $items['delete/element/%/nojs'] = array(
    	'page callback' => 'delete_element',
    	'page arguments' => array( 2, 3 ) ,
    	'access callback' => 'delete_access',
    	'type' => MENU_CALLBACK,
    );
    // ajaxが以下のURLでリクエストをします(クライアント側でnojs->ajaxに変換)
    $items['delete/element/%/ajax'] = array(
    	'delivery callback' => 'ajax_deliver',
    )+$items['delete/element/%/nojs'] ;    // 要素削除定義に遷移
    
  • 要素削除処理ファンクション:delete_element で削除処理、処理結果をクライアント側に返します
    function delete_element ($id, $ajax){
        $is_ajax = $ajax === "ajax" ;  // ajaxと通用のリクエスト両方対応のため
    
        // 要素をDBから削除
        db_delete("element_table")->condition("entity_id", $id)->execute() ;
    
        // 画面要素も削除コマンドを返す
        if( $is_ajax ){
            // ajaxで要素削除後の処理
            $commands = array();
            $commands[] = ajax_command_remove( '#element-123');
            return array(
              '#type'=>"ajax",
              '#commands' => $commands,
            );
        } else {
            // 通常での要素削除後の処理
            drupal_set_message(t('Deleted 1 vocabulary'));
            drupal_goto();
        }
    }

     

Drupalのajaxフレームワークで要素削除

纏め:Drupalのajaxフレームワークを利用すればajax処理が自動的に行います

  • 上記例では、削除リンクにクラス:use-ajax を追加するだけで、ajax関連処理を記述する必要はあります
    • 削除リンクではなく、削除ボタン(button)要素を使用する場合クラス: use-ajax-submit
  • サーバー側では、hook_menuで削除リンクの定義、削除リクエストをキャッチして、削除処理関数を作成します
    • DB上のデータ削除完了後に、クライアント側の要素削除命令(ajax_command_remove)を返せば良いです
  • この一連のajax処理の記述はほどんとありません。簡単、便利です
drupal
form
ajax

Drupalのajaxフレームワークにあるajax_command_invokeがユーザーが自分的にしたjavascriptのカスタムコマンドの呼び出しができます

  • Drupalのajaxフレームワークに、クライアント側のUI要素追加、更新、削除、cssなどの処理コマンドが数多くあります
    • コマンドの説明:https://api.drupal.org/api/drupal/includes%21ajax.inc/group/ajax_comman…
  • ajaxコマンド:ajax_command_invoke があります。このコマンドがユーザー自分作成したjavascriptの呼び出しができます
  • 例: クライアント側で要素削除時に、自作にjavascriptで要素をゆっくり消していく動画効果を再現します
    ajaxで要素作成動画

方法1:jQueryのカスタム関数で定義します

  • jQueryのカスタム関数を利用して、上記動画効果のjavascriptを作成して、Drupalのajax_command_invokeより呼びされます
    jQuery でカスタム関数の作成
  • Drupalのajax_command_invokeでカスタム関数にパラメターを渡して、実行させます
    // サーバ側でカスタム関数(removeElement)にパラメータを渡して実行させる
    $commands = array();
    $commands[] = ajax_command_invoke( null,
                                       'removeElement', 
                                        array("#del-div-".$entity->entity_id) );
    return array(  '#type'=>"ajax",  '#commands' => $commands,);
    
    // クライアント側で実行されるカスタム関数(removeElement)
    jQuery.fn.removeElement = function(ele_id) {
        jQuery( ele_id )
            .css({'opacity':0, 'transition': 'all 1s' })   // cssで要素の透明度をゼロにする
            .delay(1000).queue(function(){jQuery( ele_id ).remove()} ) ; // 1秒後に要素の削除
    };
    

     

方法2:Drupalのajaxフレームワーク(Drupal.ajax.prototype.commands)にカスタム関数をバインドします

  • DrupalのajaxフレームワークにjQueryのようにカスタム関数の追加ができます
  • パラメータの引き渡しはjQueryのカスタム関数と違います
    • jQueryのカスタム関数にパラメーターを配列に渡します
    • Drupal.ajax.prototype.commandsにパラメータを個別に渡します
  • 上記の例では同じようにDrupal.ajax.prototype.commandsで実現します
    // サーバ側でカスタム関数(removeElement)にパラメータを渡して実行させる 
    $commands = array(); 
    $commands[] = array( 'command' => 'removeElement', 
                                        'ele_id' => "#del-div-".$entity->entity_id) ); 
    return array( '#type'=>"ajax", '#commands' => $commands,); 
    
    // クライアント側のカスタム関数(removeElement)の実行
    Drupal.ajax.prototype.commands.removeElement = 
    function(ajax, response, status) {
        jQuery( response.ele_id )
            .css({'opacity':0, 'transition': 'all 1s' })
            .delay(1000).queue(function(){jQuery( response.ele_id ).remove()}) ;
    }

     

  • 同じ結果となります

 

drupal
form
ajax

やりたいこと:Drupalのajaxフレームワークを利用して表示している要素を削除

  • Drupalのモジュール(Views)で作成した一覧の要素を選択して削除します
    • 要素を選択して削除するモジュール:Views Bulk Operations
    • 例:Drupalのモジュール(VBO)の各種処理(Operation)に独自(カスタムオ)のプションの追加方法
  • 前提条件:要素削除する確認の必要はありません
  • ajaxで動的に削除するのはやさしいUIとも言えるでしょう(以下のイメージのように削除)
    Drupalのajaxフレームワークより要素を動的に削除

Step1:削除リンクにDrupalのajax使用するクラス:use-ajax を追加

  • Drupalのajaxフレームワークに関する説明は以下の記事をご参考ください
    • Drupalでajaxのフレームワークが簡単に作成できる
  • 削除アイコン付きのリンクは以下のようです
    // 削除エレメントID:123 (例)
    <a href="/delete/element/id/123/nojs" class="use-ajax del-link" id="del-link-123">
           <i class="fa fa-trash-o" aria-hidden="true"></i>
    </a>
    • アンカー(a)に削除するエレメントID(または別の識別パラメーター)を入れる必要はあります
    • アンカーリンクの後ろに「nojs」を追加します(クライアント側のajax作動時に、nojs->ajaxに変換され)
    • アンカーがクリックされると、Drupalのajaxフレームワークが起動され、削除パラメーターをサイト側に渡します

Step2:hook_menuで要素削除のリクエストをキャッチします

  • hook_menuで要素削除のリクエストを受け取り、削除処理を行います
    // 要素削除URLの設定
    $items['delete/element/%/nojs'] = array(
    	'page callback' => 'delete_element',
    	'page arguments' => array( 2, 3 ) ,
    	'access callback' => 'delete_access',
    	'type' => MENU_CALLBACK,
    );
    // ajaxが以下のURLでリクエストをします(クライアント側でnojs->ajaxに変換)
    $items['delete/element/%/ajax'] = array(
    	'delivery callback' => 'ajax_deliver',
    )+$items['delete/element/%/nojs'] ;    // 要素削除定義に遷移
    
  • 要素削除処理ファンクション:delete_element で削除処理、処理結果をクライアント側に返します
    function delete_element ($id, $ajax){
        $is_ajax = $ajax === "ajax" ;  // ajaxと通用のリクエスト両方対応のため
    
        // 要素をDBから削除
        db_delete("element_table")->condition("entity_id", $id)->execute() ;
    
        // 画面要素も削除コマンドを返す
        if( $is_ajax ){
            // ajaxで要素削除後の処理
            $commands = array();
            $commands[] = ajax_command_remove( '#element-123');
            return array(
              '#type'=>"ajax",
              '#commands' => $commands,
            );
        } else {
            // 通常での要素削除後の処理
            drupal_set_message(t('Deleted 1 vocabulary'));
            drupal_goto();
        }
    }

     

Drupalのajaxフレームワークで要素削除

纏め:Drupalのajaxフレームワークを利用すればajax処理が自動的に行います

  • 上記例では、削除リンクにクラス:use-ajax を追加するだけで、ajax関連処理を記述する必要はあります
    • 削除リンクではなく、削除ボタン(button)要素を使用する場合クラス: use-ajax-submit
  • サーバー側では、hook_menuで削除リンクの定義、削除リクエストをキャッチして、削除処理関数を作成します
    • DB上のデータ削除完了後に、クライアント側の要素削除命令(ajax_command_remove)を返せば良いです
  • この一連のajax処理の記述はほどんとありません。簡単、便利です
drupal
form
ajax

Drupalのajaxフレームワークにあるajax_command_invokeがユーザーが自分的にしたjavascriptのカスタムコマンドの呼び出しができます

  • Drupalのajaxフレームワークに、クライアント側のUI要素追加、更新、削除、cssなどの処理コマンドが数多くあります
    • コマンドの説明:https://api.drupal.org/api/drupal/includes%21ajax.inc/group/ajax_comman…
  • ajaxコマンド:ajax_command_invoke があります。このコマンドがユーザー自分作成したjavascriptの呼び出しができます
  • 例: クライアント側で要素削除時に、自作にjavascriptで要素をゆっくり消していく動画効果を再現します
    ajaxで要素作成動画

方法1:jQueryのカスタム関数で定義します

  • jQueryのカスタム関数を利用して、上記動画効果のjavascriptを作成して、Drupalのajax_command_invokeより呼びされます
    jQuery でカスタム関数の作成
  • Drupalのajax_command_invokeでカスタム関数にパラメターを渡して、実行させます
    // サーバ側でカスタム関数(removeElement)にパラメータを渡して実行させる
    $commands = array();
    $commands[] = ajax_command_invoke( null,
                                       'removeElement', 
                                        array("#del-div-".$entity->entity_id) );
    return array(  '#type'=>"ajax",  '#commands' => $commands,);
    
    // クライアント側で実行されるカスタム関数(removeElement)
    jQuery.fn.removeElement = function(ele_id) {
        jQuery( ele_id )
            .css({'opacity':0, 'transition': 'all 1s' })   // cssで要素の透明度をゼロにする
            .delay(1000).queue(function(){jQuery( ele_id ).remove()} ) ; // 1秒後に要素の削除
    };
    

     

方法2:Drupalのajaxフレームワーク(Drupal.ajax.prototype.commands)にカスタム関数をバインドします

  • DrupalのajaxフレームワークにjQueryのようにカスタム関数の追加ができます
  • パラメータの引き渡しはjQueryのカスタム関数と違います
    • jQueryのカスタム関数にパラメーターを配列に渡します
    • Drupal.ajax.prototype.commandsにパラメータを個別に渡します
  • 上記の例では同じようにDrupal.ajax.prototype.commandsで実現します
    // サーバ側でカスタム関数(removeElement)にパラメータを渡して実行させる 
    $commands = array(); 
    $commands[] = array( 'command' => 'removeElement', 
                                        'ele_id' => "#del-div-".$entity->entity_id) ); 
    return array( '#type'=>"ajax", '#commands' => $commands,); 
    
    // クライアント側のカスタム関数(removeElement)の実行
    Drupal.ajax.prototype.commands.removeElement = 
    function(ajax, response, status) {
        jQuery( response.ele_id )
            .css({'opacity':0, 'transition': 'all 1s' })
            .delay(1000).queue(function(){jQuery( response.ele_id ).remove()}) ;
    }

     

  • 同じ結果となります

 

drupal
form
ajax

やりたいこと:Drupalのajaxフレームワークを利用して表示している要素を削除

  • Drupalのモジュール(Views)で作成した一覧の要素を選択して削除します
    • 要素を選択して削除するモジュール:Views Bulk Operations
    • 例:Drupalのモジュール(VBO)の各種処理(Operation)に独自(カスタムオ)のプションの追加方法
  • 前提条件:要素削除する確認の必要はありません
  • ajaxで動的に削除するのはやさしいUIとも言えるでしょう(以下のイメージのように削除)
    Drupalのajaxフレームワークより要素を動的に削除

Step1:削除リンクにDrupalのajax使用するクラス:use-ajax を追加

  • Drupalのajaxフレームワークに関する説明は以下の記事をご参考ください
    • Drupalでajaxのフレームワークが簡単に作成できる
  • 削除アイコン付きのリンクは以下のようです
    // 削除エレメントID:123 (例)
    <a href="/delete/element/id/123/nojs" class="use-ajax del-link" id="del-link-123">
           <i class="fa fa-trash-o" aria-hidden="true"></i>
    </a>
    • アンカー(a)に削除するエレメントID(または別の識別パラメーター)を入れる必要はあります
    • アンカーリンクの後ろに「nojs」を追加します(クライアント側のajax作動時に、nojs->ajaxに変換され)
    • アンカーがクリックされると、Drupalのajaxフレームワークが起動され、削除パラメーターをサイト側に渡します

Step2:hook_menuで要素削除のリクエストをキャッチします

  • hook_menuで要素削除のリクエストを受け取り、削除処理を行います
    // 要素削除URLの設定
    $items['delete/element/%/nojs'] = array(
    	'page callback' => 'delete_element',
    	'page arguments' => array( 2, 3 ) ,
    	'access callback' => 'delete_access',
    	'type' => MENU_CALLBACK,
    );
    // ajaxが以下のURLでリクエストをします(クライアント側でnojs->ajaxに変換)
    $items['delete/element/%/ajax'] = array(
    	'delivery callback' => 'ajax_deliver',
    )+$items['delete/element/%/nojs'] ;    // 要素削除定義に遷移
    
  • 要素削除処理ファンクション:delete_element で削除処理、処理結果をクライアント側に返します
    function delete_element ($id, $ajax){
        $is_ajax = $ajax === "ajax" ;  // ajaxと通用のリクエスト両方対応のため
    
        // 要素をDBから削除
        db_delete("element_table")->condition("entity_id", $id)->execute() ;
    
        // 画面要素も削除コマンドを返す
        if( $is_ajax ){
            // ajaxで要素削除後の処理
            $commands = array();
            $commands[] = ajax_command_remove( '#element-123');
            return array(
              '#type'=>"ajax",
              '#commands' => $commands,
            );
        } else {
            // 通常での要素削除後の処理
            drupal_set_message(t('Deleted 1 vocabulary'));
            drupal_goto();
        }
    }

     

Drupalのajaxフレームワークで要素削除

纏め:Drupalのajaxフレームワークを利用すればajax処理が自動的に行います

  • 上記例では、削除リンクにクラス:use-ajax を追加するだけで、ajax関連処理を記述する必要はあります
    • 削除リンクではなく、削除ボタン(button)要素を使用する場合クラス: use-ajax-submit
  • サーバー側では、hook_menuで削除リンクの定義、削除リクエストをキャッチして、削除処理関数を作成します
    • DB上のデータ削除完了後に、クライアント側の要素削除命令(ajax_command_remove)を返せば良いです
  • この一連のajax処理の記述はほどんとありません。簡単、便利です
drupal
form
ajax

Drupalのajaxフレームワークにあるajax_command_invokeがユーザーが自分的にしたjavascriptのカスタムコマンドの呼び出しができます

  • Drupalのajaxフレームワークに、クライアント側のUI要素追加、更新、削除、cssなどの処理コマンドが数多くあります
    • コマンドの説明:https://api.drupal.org/api/drupal/includes%21ajax.inc/group/ajax_comman…
  • ajaxコマンド:ajax_command_invoke があります。このコマンドがユーザー自分作成したjavascriptの呼び出しができます
  • 例: クライアント側で要素削除時に、自作にjavascriptで要素をゆっくり消していく動画効果を再現します
    ajaxで要素作成動画

方法1:jQueryのカスタム関数で定義します

  • jQueryのカスタム関数を利用して、上記動画効果のjavascriptを作成して、Drupalのajax_command_invokeより呼びされます
    jQuery でカスタム関数の作成
  • Drupalのajax_command_invokeでカスタム関数にパラメターを渡して、実行させます
    // サーバ側でカスタム関数(removeElement)にパラメータを渡して実行させる
    $commands = array();
    $commands[] = ajax_command_invoke( null,
                                       'removeElement', 
                                        array("#del-div-".$entity->entity_id) );
    return array(  '#type'=>"ajax",  '#commands' => $commands,);
    
    // クライアント側で実行されるカスタム関数(removeElement)
    jQuery.fn.removeElement = function(ele_id) {
        jQuery( ele_id )
            .css({'opacity':0, 'transition': 'all 1s' })   // cssで要素の透明度をゼロにする
            .delay(1000).queue(function(){jQuery( ele_id ).remove()} ) ; // 1秒後に要素の削除
    };
    

     

方法2:Drupalのajaxフレームワーク(Drupal.ajax.prototype.commands)にカスタム関数をバインドします

  • DrupalのajaxフレームワークにjQueryのようにカスタム関数の追加ができます
  • パラメータの引き渡しはjQueryのカスタム関数と違います
    • jQueryのカスタム関数にパラメーターを配列に渡します
    • Drupal.ajax.prototype.commandsにパラメータを個別に渡します
  • 上記の例では同じようにDrupal.ajax.prototype.commandsで実現します
    // サーバ側でカスタム関数(removeElement)にパラメータを渡して実行させる 
    $commands = array(); 
    $commands[] = array( 'command' => 'removeElement', 
                                        'ele_id' => "#del-div-".$entity->entity_id) ); 
    return array( '#type'=>"ajax", '#commands' => $commands,); 
    
    // クライアント側のカスタム関数(removeElement)の実行
    Drupal.ajax.prototype.commands.removeElement = 
    function(ajax, response, status) {
        jQuery( response.ele_id )
            .css({'opacity':0, 'transition': 'all 1s' })
            .delay(1000).queue(function(){jQuery( response.ele_id ).remove()}) ;
    }

     

  • 同じ結果となります

 

drupal
form
ajax

やりたいこと:Drupalのajaxフレームワークを利用して表示している要素を削除

  • Drupalのモジュール(Views)で作成した一覧の要素を選択して削除します
    • 要素を選択して削除するモジュール:Views Bulk Operations
    • 例:Drupalのモジュール(VBO)の各種処理(Operation)に独自(カスタムオ)のプションの追加方法
  • 前提条件:要素削除する確認の必要はありません
  • ajaxで動的に削除するのはやさしいUIとも言えるでしょう(以下のイメージのように削除)
    Drupalのajaxフレームワークより要素を動的に削除

Step1:削除リンクにDrupalのajax使用するクラス:use-ajax を追加

  • Drupalのajaxフレームワークに関する説明は以下の記事をご参考ください
    • Drupalでajaxのフレームワークが簡単に作成できる
  • 削除アイコン付きのリンクは以下のようです
    // 削除エレメントID:123 (例)
    <a href="/delete/element/id/123/nojs" class="use-ajax del-link" id="del-link-123">
           <i class="fa fa-trash-o" aria-hidden="true"></i>
    </a>
    • アンカー(a)に削除するエレメントID(または別の識別パラメーター)を入れる必要はあります
    • アンカーリンクの後ろに「nojs」を追加します(クライアント側のajax作動時に、nojs->ajaxに変換され)
    • アンカーがクリックされると、Drupalのajaxフレームワークが起動され、削除パラメーターをサイト側に渡します

Step2:hook_menuで要素削除のリクエストをキャッチします

  • hook_menuで要素削除のリクエストを受け取り、削除処理を行います
    // 要素削除URLの設定
    $items['delete/element/%/nojs'] = array(
    	'page callback' => 'delete_element',
    	'page arguments' => array( 2, 3 ) ,
    	'access callback' => 'delete_access',
    	'type' => MENU_CALLBACK,
    );
    // ajaxが以下のURLでリクエストをします(クライアント側でnojs->ajaxに変換)
    $items['delete/element/%/ajax'] = array(
    	'delivery callback' => 'ajax_deliver',
    )+$items['delete/element/%/nojs'] ;    // 要素削除定義に遷移
    
  • 要素削除処理ファンクション:delete_element で削除処理、処理結果をクライアント側に返します
    function delete_element ($id, $ajax){
        $is_ajax = $ajax === "ajax" ;  // ajaxと通用のリクエスト両方対応のため
    
        // 要素をDBから削除
        db_delete("element_table")->condition("entity_id", $id)->execute() ;
    
        // 画面要素も削除コマンドを返す
        if( $is_ajax ){
            // ajaxで要素削除後の処理
            $commands = array();
            $commands[] = ajax_command_remove( '#element-123');
            return array(
              '#type'=>"ajax",
              '#commands' => $commands,
            );
        } else {
            // 通常での要素削除後の処理
            drupal_set_message(t('Deleted 1 vocabulary'));
            drupal_goto();
        }
    }

     

Drupalのajaxフレームワークで要素削除

纏め:Drupalのajaxフレームワークを利用すればajax処理が自動的に行います

  • 上記例では、削除リンクにクラス:use-ajax を追加するだけで、ajax関連処理を記述する必要はあります
    • 削除リンクではなく、削除ボタン(button)要素を使用する場合クラス: use-ajax-submit
  • サーバー側では、hook_menuで削除リンクの定義、削除リクエストをキャッチして、削除処理関数を作成します
    • DB上のデータ削除完了後に、クライアント側の要素削除命令(ajax_command_remove)を返せば良いです
  • この一連のajax処理の記述はほどんとありません。簡単、便利です
drupal
form
ajax

Drupalのajaxフレームワークにあるajax_command_invokeがユーザーが自分的にしたjavascriptのカスタムコマンドの呼び出しができます

  • Drupalのajaxフレームワークに、クライアント側のUI要素追加、更新、削除、cssなどの処理コマンドが数多くあります
    • コマンドの説明:https://api.drupal.org/api/drupal/includes%21ajax.inc/group/ajax_comman…
  • ajaxコマンド:ajax_command_invoke があります。このコマンドがユーザー自分作成したjavascriptの呼び出しができます
  • 例: クライアント側で要素削除時に、自作にjavascriptで要素をゆっくり消していく動画効果を再現します
    ajaxで要素作成動画

方法1:jQueryのカスタム関数で定義します

  • jQueryのカスタム関数を利用して、上記動画効果のjavascriptを作成して、Drupalのajax_command_invokeより呼びされます
    jQuery でカスタム関数の作成
  • Drupalのajax_command_invokeでカスタム関数にパラメターを渡して、実行させます
    // サーバ側でカスタム関数(removeElement)にパラメータを渡して実行させる
    $commands = array();
    $commands[] = ajax_command_invoke( null,
                                       'removeElement', 
                                        array("#del-div-".$entity->entity_id) );
    return array(  '#type'=>"ajax",  '#commands' => $commands,);
    
    // クライアント側で実行されるカスタム関数(removeElement)
    jQuery.fn.removeElement = function(ele_id) {
        jQuery( ele_id )
            .css({'opacity':0, 'transition': 'all 1s' })   // cssで要素の透明度をゼロにする
            .delay(1000).queue(function(){jQuery( ele_id ).remove()} ) ; // 1秒後に要素の削除
    };
    

     

方法2:Drupalのajaxフレームワーク(Drupal.ajax.prototype.commands)にカスタム関数をバインドします

  • DrupalのajaxフレームワークにjQueryのようにカスタム関数の追加ができます
  • パラメータの引き渡しはjQueryのカスタム関数と違います
    • jQueryのカスタム関数にパラメーターを配列に渡します
    • Drupal.ajax.prototype.commandsにパラメータを個別に渡します
  • 上記の例では同じようにDrupal.ajax.prototype.commandsで実現します
    // サーバ側でカスタム関数(removeElement)にパラメータを渡して実行させる 
    $commands = array(); 
    $commands[] = array( 'command' => 'removeElement', 
                                        'ele_id' => "#del-div-".$entity->entity_id) ); 
    return array( '#type'=>"ajax", '#commands' => $commands,); 
    
    // クライアント側のカスタム関数(removeElement)の実行
    Drupal.ajax.prototype.commands.removeElement = 
    function(ajax, response, status) {
        jQuery( response.ele_id )
            .css({'opacity':0, 'transition': 'all 1s' })
            .delay(1000).queue(function(){jQuery( response.ele_id ).remove()}) ;
    }

     

  • 同じ結果となります

 

drupal
form
ajax

やりたいこと:Drupalのajaxフレームワークを利用して表示している要素を削除

  • Drupalのモジュール(Views)で作成した一覧の要素を選択して削除します
    • 要素を選択して削除するモジュール:Views Bulk Operations
    • 例:Drupalのモジュール(VBO)の各種処理(Operation)に独自(カスタムオ)のプションの追加方法
  • 前提条件:要素削除する確認の必要はありません
  • ajaxで動的に削除するのはやさしいUIとも言えるでしょう(以下のイメージのように削除)
    Drupalのajaxフレームワークより要素を動的に削除

Step1:削除リンクにDrupalのajax使用するクラス:use-ajax を追加

  • Drupalのajaxフレームワークに関する説明は以下の記事をご参考ください
    • Drupalでajaxのフレームワークが簡単に作成できる
  • 削除アイコン付きのリンクは以下のようです
    // 削除エレメントID:123 (例)
    <a href="/delete/element/id/123/nojs" class="use-ajax del-link" id="del-link-123">
           <i class="fa fa-trash-o" aria-hidden="true"></i>
    </a>
    • アンカー(a)に削除するエレメントID(または別の識別パラメーター)を入れる必要はあります
    • アンカーリンクの後ろに「nojs」を追加します(クライアント側のajax作動時に、nojs->ajaxに変換され)
    • アンカーがクリックされると、Drupalのajaxフレームワークが起動され、削除パラメーターをサイト側に渡します

Step2:hook_menuで要素削除のリクエストをキャッチします

  • hook_menuで要素削除のリクエストを受け取り、削除処理を行います
    // 要素削除URLの設定
    $items['delete/element/%/nojs'] = array(
    	'page callback' => 'delete_element',
    	'page arguments' => array( 2, 3 ) ,
    	'access callback' => 'delete_access',
    	'type' => MENU_CALLBACK,
    );
    // ajaxが以下のURLでリクエストをします(クライアント側でnojs->ajaxに変換)
    $items['delete/element/%/ajax'] = array(
    	'delivery callback' => 'ajax_deliver',
    )+$items['delete/element/%/nojs'] ;    // 要素削除定義に遷移
    
  • 要素削除処理ファンクション:delete_element で削除処理、処理結果をクライアント側に返します
    function delete_element ($id, $ajax){
        $is_ajax = $ajax === "ajax" ;  // ajaxと通用のリクエスト両方対応のため
    
        // 要素をDBから削除
        db_delete("element_table")->condition("entity_id", $id)->execute() ;
    
        // 画面要素も削除コマンドを返す
        if( $is_ajax ){
            // ajaxで要素削除後の処理
            $commands = array();
            $commands[] = ajax_command_remove( '#element-123');
            return array(
              '#type'=>"ajax",
              '#commands' => $commands,
            );
        } else {
            // 通常での要素削除後の処理
            drupal_set_message(t('Deleted 1 vocabulary'));
            drupal_goto();
        }
    }

     

Drupalのajaxフレームワークで要素削除

纏め:Drupalのajaxフレームワークを利用すればajax処理が自動的に行います

  • 上記例では、削除リンクにクラス:use-ajax を追加するだけで、ajax関連処理を記述する必要はあります
    • 削除リンクではなく、削除ボタン(button)要素を使用する場合クラス: use-ajax-submit
  • サーバー側では、hook_menuで削除リンクの定義、削除リクエストをキャッチして、削除処理関数を作成します
    • DB上のデータ削除完了後に、クライアント側の要素削除命令(ajax_command_remove)を返せば良いです
  • この一連のajax処理の記述はほどんとありません。簡単、便利です
drupal
form
ajax

Drupalのajaxフレームワークにあるajax_command_invokeがユーザーが自分的にしたjavascriptのカスタムコマンドの呼び出しができます

  • Drupalのajaxフレームワークに、クライアント側のUI要素追加、更新、削除、cssなどの処理コマンドが数多くあります
    • コマンドの説明:https://api.drupal.org/api/drupal/includes%21ajax.inc/group/ajax_comman…
  • ajaxコマンド:ajax_command_invoke があります。このコマンドがユーザー自分作成したjavascriptの呼び出しができます
  • 例: クライアント側で要素削除時に、自作にjavascriptで要素をゆっくり消していく動画効果を再現します
    ajaxで要素作成動画

方法1:jQueryのカスタム関数で定義します

  • jQueryのカスタム関数を利用して、上記動画効果のjavascriptを作成して、Drupalのajax_command_invokeより呼びされます
    jQuery でカスタム関数の作成
  • Drupalのajax_command_invokeでカスタム関数にパラメターを渡して、実行させます
    // サーバ側でカスタム関数(removeElement)にパラメータを渡して実行させる
    $commands = array();
    $commands[] = ajax_command_invoke( null,
                                       'removeElement', 
                                        array("#del-div-".$entity->entity_id) );
    return array(  '#type'=>"ajax",  '#commands' => $commands,);
    
    // クライアント側で実行されるカスタム関数(removeElement)
    jQuery.fn.removeElement = function(ele_id) {
        jQuery( ele_id )
            .css({'opacity':0, 'transition': 'all 1s' })   // cssで要素の透明度をゼロにする
            .delay(1000).queue(function(){jQuery( ele_id ).remove()} ) ; // 1秒後に要素の削除
    };
    

     

方法2:Drupalのajaxフレームワーク(Drupal.ajax.prototype.commands)にカスタム関数をバインドします

  • DrupalのajaxフレームワークにjQueryのようにカスタム関数の追加ができます
  • パラメータの引き渡しはjQueryのカスタム関数と違います
    • jQueryのカスタム関数にパラメーターを配列に渡します
    • Drupal.ajax.prototype.commandsにパラメータを個別に渡します
  • 上記の例では同じようにDrupal.ajax.prototype.commandsで実現します
    // サーバ側でカスタム関数(removeElement)にパラメータを渡して実行させる 
    $commands = array(); 
    $commands[] = array( 'command' => 'removeElement', 
                                        'ele_id' => "#del-div-".$entity->entity_id) ); 
    return array( '#type'=>"ajax", '#commands' => $commands,); 
    
    // クライアント側のカスタム関数(removeElement)の実行
    Drupal.ajax.prototype.commands.removeElement = 
    function(ajax, response, status) {
        jQuery( response.ele_id )
            .css({'opacity':0, 'transition': 'all 1s' })
            .delay(1000).queue(function(){jQuery( response.ele_id ).remove()}) ;
    }

     

  • 同じ結果となります

 

drupal
form
ajax

やりたいこと:Drupalのajaxフレームワークを利用して表示している要素を削除

  • Drupalのモジュール(Views)で作成した一覧の要素を選択して削除します
    • 要素を選択して削除するモジュール:Views Bulk Operations
    • 例:Drupalのモジュール(VBO)の各種処理(Operation)に独自(カスタムオ)のプションの追加方法
  • 前提条件:要素削除する確認の必要はありません
  • ajaxで動的に削除するのはやさしいUIとも言えるでしょう(以下のイメージのように削除)
    Drupalのajaxフレームワークより要素を動的に削除

Step1:削除リンクにDrupalのajax使用するクラス:use-ajax を追加

  • Drupalのajaxフレームワークに関する説明は以下の記事をご参考ください
    • Drupalでajaxのフレームワークが簡単に作成できる
  • 削除アイコン付きのリンクは以下のようです
    // 削除エレメントID:123 (例)
    <a href="/delete/element/id/123/nojs" class="use-ajax del-link" id="del-link-123">
           <i class="fa fa-trash-o" aria-hidden="true"></i>
    </a>
    • アンカー(a)に削除するエレメントID(または別の識別パラメーター)を入れる必要はあります
    • アンカーリンクの後ろに「nojs」を追加します(クライアント側のajax作動時に、nojs->ajaxに変換され)
    • アンカーがクリックされると、Drupalのajaxフレームワークが起動され、削除パラメーターをサイト側に渡します

Step2:hook_menuで要素削除のリクエストをキャッチします

  • hook_menuで要素削除のリクエストを受け取り、削除処理を行います
    // 要素削除URLの設定
    $items['delete/element/%/nojs'] = array(
    	'page callback' => 'delete_element',
    	'page arguments' => array( 2, 3 ) ,
    	'access callback' => 'delete_access',
    	'type' => MENU_CALLBACK,
    );
    // ajaxが以下のURLでリクエストをします(クライアント側でnojs->ajaxに変換)
    $items['delete/element/%/ajax'] = array(
    	'delivery callback' => 'ajax_deliver',
    )+$items['delete/element/%/nojs'] ;    // 要素削除定義に遷移
    
  • 要素削除処理ファンクション:delete_element で削除処理、処理結果をクライアント側に返します
    function delete_element ($id, $ajax){
        $is_ajax = $ajax === "ajax" ;  // ajaxと通用のリクエスト両方対応のため
    
        // 要素をDBから削除
        db_delete("element_table")->condition("entity_id", $id)->execute() ;
    
        // 画面要素も削除コマンドを返す
        if( $is_ajax ){
            // ajaxで要素削除後の処理
            $commands = array();
            $commands[] = ajax_command_remove( '#element-123');
            return array(
              '#type'=>"ajax",
              '#commands' => $commands,
            );
        } else {
            // 通常での要素削除後の処理
            drupal_set_message(t('Deleted 1 vocabulary'));
            drupal_goto();
        }
    }

     

Drupalのajaxフレームワークで要素削除

纏め:Drupalのajaxフレームワークを利用すればajax処理が自動的に行います

  • 上記例では、削除リンクにクラス:use-ajax を追加するだけで、ajax関連処理を記述する必要はあります
    • 削除リンクではなく、削除ボタン(button)要素を使用する場合クラス: use-ajax-submit
  • サーバー側では、hook_menuで削除リンクの定義、削除リクエストをキャッチして、削除処理関数を作成します
    • DB上のデータ削除完了後に、クライアント側の要素削除命令(ajax_command_remove)を返せば良いです
  • この一連のajax処理の記述はほどんとありません。簡単、便利です
drupal
form
ajax

Drupalのajaxフレームワークにあるajax_command_invokeがユーザーが自分的にしたjavascriptのカスタムコマンドの呼び出しができます

  • Drupalのajaxフレームワークに、クライアント側のUI要素追加、更新、削除、cssなどの処理コマンドが数多くあります
    • コマンドの説明:https://api.drupal.org/api/drupal/includes%21ajax.inc/group/ajax_comman…
  • ajaxコマンド:ajax_command_invoke があります。このコマンドがユーザー自分作成したjavascriptの呼び出しができます
  • 例: クライアント側で要素削除時に、自作にjavascriptで要素をゆっくり消していく動画効果を再現します
    ajaxで要素作成動画

方法1:jQueryのカスタム関数で定義します

  • jQueryのカスタム関数を利用して、上記動画効果のjavascriptを作成して、Drupalのajax_command_invokeより呼びされます
    jQuery でカスタム関数の作成
  • Drupalのajax_command_invokeでカスタム関数にパラメターを渡して、実行させます
    // サーバ側でカスタム関数(removeElement)にパラメータを渡して実行させる
    $commands = array();
    $commands[] = ajax_command_invoke( null,
                                       'removeElement', 
                                        array("#del-div-".$entity->entity_id) );
    return array(  '#type'=>"ajax",  '#commands' => $commands,);
    
    // クライアント側で実行されるカスタム関数(removeElement)
    jQuery.fn.removeElement = function(ele_id) {
        jQuery( ele_id )
            .css({'opacity':0, 'transition': 'all 1s' })   // cssで要素の透明度をゼロにする
            .delay(1000).queue(function(){jQuery( ele_id ).remove()} ) ; // 1秒後に要素の削除
    };
    

     

方法2:Drupalのajaxフレームワーク(Drupal.ajax.prototype.commands)にカスタム関数をバインドします

  • DrupalのajaxフレームワークにjQueryのようにカスタム関数の追加ができます
  • パラメータの引き渡しはjQueryのカスタム関数と違います
    • jQueryのカスタム関数にパラメーターを配列に渡します
    • Drupal.ajax.prototype.commandsにパラメータを個別に渡します
  • 上記の例では同じようにDrupal.ajax.prototype.commandsで実現します
    // サーバ側でカスタム関数(removeElement)にパラメータを渡して実行させる 
    $commands = array(); 
    $commands[] = array( 'command' => 'removeElement', 
                                        'ele_id' => "#del-div-".$entity->entity_id) ); 
    return array( '#type'=>"ajax", '#commands' => $commands,); 
    
    // クライアント側のカスタム関数(removeElement)の実行
    Drupal.ajax.prototype.commands.removeElement = 
    function(ajax, response, status) {
        jQuery( response.ele_id )
            .css({'opacity':0, 'transition': 'all 1s' })
            .delay(1000).queue(function(){jQuery( response.ele_id ).remove()}) ;
    }

     

  • 同じ結果となります

 

drupal
form
ajax

やりたいこと:Drupalのajaxフレームワークを利用して表示している要素を削除

  • Drupalのモジュール(Views)で作成した一覧の要素を選択して削除します
    • 要素を選択して削除するモジュール:Views Bulk Operations
    • 例:Drupalのモジュール(VBO)の各種処理(Operation)に独自(カスタムオ)のプションの追加方法
  • 前提条件:要素削除する確認の必要はありません
  • ajaxで動的に削除するのはやさしいUIとも言えるでしょう(以下のイメージのように削除)
    Drupalのajaxフレームワークより要素を動的に削除

Step1:削除リンクにDrupalのajax使用するクラス:use-ajax を追加

  • Drupalのajaxフレームワークに関する説明は以下の記事をご参考ください
    • Drupalでajaxのフレームワークが簡単に作成できる
  • 削除アイコン付きのリンクは以下のようです
    // 削除エレメントID:123 (例)
    <a href="/delete/element/id/123/nojs" class="use-ajax del-link" id="del-link-123">
           <i class="fa fa-trash-o" aria-hidden="true"></i>
    </a>
    • アンカー(a)に削除するエレメントID(または別の識別パラメーター)を入れる必要はあります
    • アンカーリンクの後ろに「nojs」を追加します(クライアント側のajax作動時に、nojs->ajaxに変換され)
    • アンカーがクリックされると、Drupalのajaxフレームワークが起動され、削除パラメーターをサイト側に渡します

Step2:hook_menuで要素削除のリクエストをキャッチします

  • hook_menuで要素削除のリクエストを受け取り、削除処理を行います
    // 要素削除URLの設定
    $items['delete/element/%/nojs'] = array(
    	'page callback' => 'delete_element',
    	'page arguments' => array( 2, 3 ) ,
    	'access callback' => 'delete_access',
    	'type' => MENU_CALLBACK,
    );
    // ajaxが以下のURLでリクエストをします(クライアント側でnojs->ajaxに変換)
    $items['delete/element/%/ajax'] = array(
    	'delivery callback' => 'ajax_deliver',
    )+$items['delete/element/%/nojs'] ;    // 要素削除定義に遷移
    
  • 要素削除処理ファンクション:delete_element で削除処理、処理結果をクライアント側に返します
    function delete_element ($id, $ajax){
        $is_ajax = $ajax === "ajax" ;  // ajaxと通用のリクエスト両方対応のため
    
        // 要素をDBから削除
        db_delete("element_table")->condition("entity_id", $id)->execute() ;
    
        // 画面要素も削除コマンドを返す
        if( $is_ajax ){
            // ajaxで要素削除後の処理
            $commands = array();
            $commands[] = ajax_command_remove( '#element-123');
            return array(
              '#type'=>"ajax",
              '#commands' => $commands,
            );
        } else {
            // 通常での要素削除後の処理
            drupal_set_message(t('Deleted 1 vocabulary'));
            drupal_goto();
        }
    }

     

Drupalのajaxフレームワークで要素削除

纏め:Drupalのajaxフレームワークを利用すればajax処理が自動的に行います

  • 上記例では、削除リンクにクラス:use-ajax を追加するだけで、ajax関連処理を記述する必要はあります
    • 削除リンクではなく、削除ボタン(button)要素を使用する場合クラス: use-ajax-submit
  • サーバー側では、hook_menuで削除リンクの定義、削除リクエストをキャッチして、削除処理関数を作成します
    • DB上のデータ削除完了後に、クライアント側の要素削除命令(ajax_command_remove)を返せば良いです
  • この一連のajax処理の記述はほどんとありません。簡単、便利です
drupal
form
ajax

Drupalのajaxフレームワークにあるajax_command_invokeがユーザーが自分的にしたjavascriptのカスタムコマンドの呼び出しができます

  • Drupalのajaxフレームワークに、クライアント側のUI要素追加、更新、削除、cssなどの処理コマンドが数多くあります
    • コマンドの説明:https://api.drupal.org/api/drupal/includes%21ajax.inc/group/ajax_comman…
  • ajaxコマンド:ajax_command_invoke があります。このコマンドがユーザー自分作成したjavascriptの呼び出しができます
  • 例: クライアント側で要素削除時に、自作にjavascriptで要素をゆっくり消していく動画効果を再現します
    ajaxで要素作成動画

方法1:jQueryのカスタム関数で定義します

  • jQueryのカスタム関数を利用して、上記動画効果のjavascriptを作成して、Drupalのajax_command_invokeより呼びされます
    jQuery でカスタム関数の作成
  • Drupalのajax_command_invokeでカスタム関数にパラメターを渡して、実行させます
    // サーバ側でカスタム関数(removeElement)にパラメータを渡して実行させる
    $commands = array();
    $commands[] = ajax_command_invoke( null,
                                       'removeElement', 
                                        array("#del-div-".$entity->entity_id) );
    return array(  '#type'=>"ajax",  '#commands' => $commands,);
    
    // クライアント側で実行されるカスタム関数(removeElement)
    jQuery.fn.removeElement = function(ele_id) {
        jQuery( ele_id )
            .css({'opacity':0, 'transition': 'all 1s' })   // cssで要素の透明度をゼロにする
            .delay(1000).queue(function(){jQuery( ele_id ).remove()} ) ; // 1秒後に要素の削除
    };
    

     

方法2:Drupalのajaxフレームワーク(Drupal.ajax.prototype.commands)にカスタム関数をバインドします

  • DrupalのajaxフレームワークにjQueryのようにカスタム関数の追加ができます
  • パラメータの引き渡しはjQueryのカスタム関数と違います
    • jQueryのカスタム関数にパラメーターを配列に渡します
    • Drupal.ajax.prototype.commandsにパラメータを個別に渡します
  • 上記の例では同じようにDrupal.ajax.prototype.commandsで実現します
    // サーバ側でカスタム関数(removeElement)にパラメータを渡して実行させる 
    $commands = array(); 
    $commands[] = array( 'command' => 'removeElement', 
                                        'ele_id' => "#del-div-".$entity->entity_id) ); 
    return array( '#type'=>"ajax", '#commands' => $commands,); 
    
    // クライアント側のカスタム関数(removeElement)の実行
    Drupal.ajax.prototype.commands.removeElement = 
    function(ajax, response, status) {
        jQuery( response.ele_id )
            .css({'opacity':0, 'transition': 'all 1s' })
            .delay(1000).queue(function(){jQuery( response.ele_id ).remove()}) ;
    }

     

  • 同じ結果となります

 

drupal
form
ajax

やりたいこと:Drupalのajaxフレームワークを利用して表示している要素を削除

  • Drupalのモジュール(Views)で作成した一覧の要素を選択して削除します
    • 要素を選択して削除するモジュール:Views Bulk Operations
    • 例:Drupalのモジュール(VBO)の各種処理(Operation)に独自(カスタムオ)のプションの追加方法
  • 前提条件:要素削除する確認の必要はありません
  • ajaxで動的に削除するのはやさしいUIとも言えるでしょう(以下のイメージのように削除)
    Drupalのajaxフレームワークより要素を動的に削除

Step1:削除リンクにDrupalのajax使用するクラス:use-ajax を追加

  • Drupalのajaxフレームワークに関する説明は以下の記事をご参考ください
    • Drupalでajaxのフレームワークが簡単に作成できる
  • 削除アイコン付きのリンクは以下のようです
    // 削除エレメントID:123 (例)
    <a href="/delete/element/id/123/nojs" class="use-ajax del-link" id="del-link-123">
           <i class="fa fa-trash-o" aria-hidden="true"></i>
    </a>
    • アンカー(a)に削除するエレメントID(または別の識別パラメーター)を入れる必要はあります
    • アンカーリンクの後ろに「nojs」を追加します(クライアント側のajax作動時に、nojs->ajaxに変換され)
    • アンカーがクリックされると、Drupalのajaxフレームワークが起動され、削除パラメーターをサイト側に渡します

Step2:hook_menuで要素削除のリクエストをキャッチします

  • hook_menuで要素削除のリクエストを受け取り、削除処理を行います
    // 要素削除URLの設定
    $items['delete/element/%/nojs'] = array(
    	'page callback' => 'delete_element',
    	'page arguments' => array( 2, 3 ) ,
    	'access callback' => 'delete_access',
    	'type' => MENU_CALLBACK,
    );
    // ajaxが以下のURLでリクエストをします(クライアント側でnojs->ajaxに変換)
    $items['delete/element/%/ajax'] = array(
    	'delivery callback' => 'ajax_deliver',
    )+$items['delete/element/%/nojs'] ;    // 要素削除定義に遷移
    
  • 要素削除処理ファンクション:delete_element で削除処理、処理結果をクライアント側に返します
    function delete_element ($id, $ajax){
        $is_ajax = $ajax === "ajax" ;  // ajaxと通用のリクエスト両方対応のため
    
        // 要素をDBから削除
        db_delete("element_table")->condition("entity_id", $id)->execute() ;
    
        // 画面要素も削除コマンドを返す
        if( $is_ajax ){
            // ajaxで要素削除後の処理
            $commands = array();
            $commands[] = ajax_command_remove( '#element-123');
            return array(
              '#type'=>"ajax",
              '#commands' => $commands,
            );
        } else {
            // 通常での要素削除後の処理
            drupal_set_message(t('Deleted 1 vocabulary'));
            drupal_goto();
        }
    }

     

Drupalのajaxフレームワークで要素削除

纏め:Drupalのajaxフレームワークを利用すればajax処理が自動的に行います

  • 上記例では、削除リンクにクラス:use-ajax を追加するだけで、ajax関連処理を記述する必要はあります
    • 削除リンクではなく、削除ボタン(button)要素を使用する場合クラス: use-ajax-submit
  • サーバー側では、hook_menuで削除リンクの定義、削除リクエストをキャッチして、削除処理関数を作成します
    • DB上のデータ削除完了後に、クライアント側の要素削除命令(ajax_command_remove)を返せば良いです
  • この一連のajax処理の記述はほどんとありません。簡単、便利です
drupal
form
ajax

Drupalのajaxフレームワークにあるajax_command_invokeがユーザーが自分的にしたjavascriptのカスタムコマンドの呼び出しができます

  • Drupalのajaxフレームワークに、クライアント側のUI要素追加、更新、削除、cssなどの処理コマンドが数多くあります
    • コマンドの説明:https://api.drupal.org/api/drupal/includes%21ajax.inc/group/ajax_comman…
  • ajaxコマンド:ajax_command_invoke があります。このコマンドがユーザー自分作成したjavascriptの呼び出しができます
  • 例: クライアント側で要素削除時に、自作にjavascriptで要素をゆっくり消していく動画効果を再現します
    ajaxで要素作成動画

方法1:jQueryのカスタム関数で定義します

  • jQueryのカスタム関数を利用して、上記動画効果のjavascriptを作成して、Drupalのajax_command_invokeより呼びされます
    jQuery でカスタム関数の作成
  • Drupalのajax_command_invokeでカスタム関数にパラメターを渡して、実行させます
    // サーバ側でカスタム関数(removeElement)にパラメータを渡して実行させる
    $commands = array();
    $commands[] = ajax_command_invoke( null,
                                       'removeElement', 
                                        array("#del-div-".$entity->entity_id) );
    return array(  '#type'=>"ajax",  '#commands' => $commands,);
    
    // クライアント側で実行されるカスタム関数(removeElement)
    jQuery.fn.removeElement = function(ele_id) {
        jQuery( ele_id )
            .css({'opacity':0, 'transition': 'all 1s' })   // cssで要素の透明度をゼロにする
            .delay(1000).queue(function(){jQuery( ele_id ).remove()} ) ; // 1秒後に要素の削除
    };
    

     

方法2:Drupalのajaxフレームワーク(Drupal.ajax.prototype.commands)にカスタム関数をバインドします

  • DrupalのajaxフレームワークにjQueryのようにカスタム関数の追加ができます
  • パラメータの引き渡しはjQueryのカスタム関数と違います
    • jQueryのカスタム関数にパラメーターを配列に渡します
    • Drupal.ajax.prototype.commandsにパラメータを個別に渡します
  • 上記の例では同じようにDrupal.ajax.prototype.commandsで実現します
    // サーバ側でカスタム関数(removeElement)にパラメータを渡して実行させる 
    $commands = array(); 
    $commands[] = array( 'command' => 'removeElement', 
                                        'ele_id' => "#del-div-".$entity->entity_id) ); 
    return array( '#type'=>"ajax", '#commands' => $commands,); 
    
    // クライアント側のカスタム関数(removeElement)の実行
    Drupal.ajax.prototype.commands.removeElement = 
    function(ajax, response, status) {
        jQuery( response.ele_id )
            .css({'opacity':0, 'transition': 'all 1s' })
            .delay(1000).queue(function(){jQuery( response.ele_id ).remove()}) ;
    }

     

  • 同じ結果となります

 

drupal
form
ajax

やりたいこと:Drupalのajaxフレームワークを利用して表示している要素を削除

  • Drupalのモジュール(Views)で作成した一覧の要素を選択して削除します
    • 要素を選択して削除するモジュール:Views Bulk Operations
    • 例:Drupalのモジュール(VBO)の各種処理(Operation)に独自(カスタムオ)のプションの追加方法
  • 前提条件:要素削除する確認の必要はありません
  • ajaxで動的に削除するのはやさしいUIとも言えるでしょう(以下のイメージのように削除)
    Drupalのajaxフレームワークより要素を動的に削除

Step1:削除リンクにDrupalのajax使用するクラス:use-ajax を追加

  • Drupalのajaxフレームワークに関する説明は以下の記事をご参考ください
    • Drupalでajaxのフレームワークが簡単に作成できる
  • 削除アイコン付きのリンクは以下のようです
    // 削除エレメントID:123 (例)
    <a href="/delete/element/id/123/nojs" class="use-ajax del-link" id="del-link-123">
           <i class="fa fa-trash-o" aria-hidden="true"></i>
    </a>
    • アンカー(a)に削除するエレメントID(または別の識別パラメーター)を入れる必要はあります
    • アンカーリンクの後ろに「nojs」を追加します(クライアント側のajax作動時に、nojs->ajaxに変換され)
    • アンカーがクリックされると、Drupalのajaxフレームワークが起動され、削除パラメーターをサイト側に渡します

Step2:hook_menuで要素削除のリクエストをキャッチします

  • hook_menuで要素削除のリクエストを受け取り、削除処理を行います
    // 要素削除URLの設定
    $items['delete/element/%/nojs'] = array(
    	'page callback' => 'delete_element',
    	'page arguments' => array( 2, 3 ) ,
    	'access callback' => 'delete_access',
    	'type' => MENU_CALLBACK,
    );
    // ajaxが以下のURLでリクエストをします(クライアント側でnojs->ajaxに変換)
    $items['delete/element/%/ajax'] = array(
    	'delivery callback' => 'ajax_deliver',
    )+$items['delete/element/%/nojs'] ;    // 要素削除定義に遷移
    
  • 要素削除処理ファンクション:delete_element で削除処理、処理結果をクライアント側に返します
    function delete_element ($id, $ajax){
        $is_ajax = $ajax === "ajax" ;  // ajaxと通用のリクエスト両方対応のため
    
        // 要素をDBから削除
        db_delete("element_table")->condition("entity_id", $id)->execute() ;
    
        // 画面要素も削除コマンドを返す
        if( $is_ajax ){
            // ajaxで要素削除後の処理
            $commands = array();
            $commands[] = ajax_command_remove( '#element-123');
            return array(
              '#type'=>"ajax",
              '#commands' => $commands,
            );
        } else {
            // 通常での要素削除後の処理
            drupal_set_message(t('Deleted 1 vocabulary'));
            drupal_goto();
        }
    }

     

Drupalのajaxフレームワークで要素削除

纏め:Drupalのajaxフレームワークを利用すればajax処理が自動的に行います

  • 上記例では、削除リンクにクラス:use-ajax を追加するだけで、ajax関連処理を記述する必要はあります
    • 削除リンクではなく、削除ボタン(button)要素を使用する場合クラス: use-ajax-submit
  • サーバー側では、hook_menuで削除リンクの定義、削除リクエストをキャッチして、削除処理関数を作成します
    • DB上のデータ削除完了後に、クライアント側の要素削除命令(ajax_command_remove)を返せば良いです
  • この一連のajax処理の記述はほどんとありません。簡単、便利です
drupal
form
ajax

Drupalのajaxフレームワークにあるajax_command_invokeがユーザーが自分的にしたjavascriptのカスタムコマンドの呼び出しができます

  • Drupalのajaxフレームワークに、クライアント側のUI要素追加、更新、削除、cssなどの処理コマンドが数多くあります
    • コマンドの説明:https://api.drupal.org/api/drupal/includes%21ajax.inc/group/ajax_comman…
  • ajaxコマンド:ajax_command_invoke があります。このコマンドがユーザー自分作成したjavascriptの呼び出しができます
  • 例: クライアント側で要素削除時に、自作にjavascriptで要素をゆっくり消していく動画効果を再現します
    ajaxで要素作成動画

方法1:jQueryのカスタム関数で定義します

  • jQueryのカスタム関数を利用して、上記動画効果のjavascriptを作成して、Drupalのajax_command_invokeより呼びされます
    jQuery でカスタム関数の作成
  • Drupalのajax_command_invokeでカスタム関数にパラメターを渡して、実行させます
    // サーバ側でカスタム関数(removeElement)にパラメータを渡して実行させる
    $commands = array();
    $commands[] = ajax_command_invoke( null,
                                       'removeElement', 
                                        array("#del-div-".$entity->entity_id) );
    return array(  '#type'=>"ajax",  '#commands' => $commands,);
    
    // クライアント側で実行されるカスタム関数(removeElement)
    jQuery.fn.removeElement = function(ele_id) {
        jQuery( ele_id )
            .css({'opacity':0, 'transition': 'all 1s' })   // cssで要素の透明度をゼロにする
            .delay(1000).queue(function(){jQuery( ele_id ).remove()} ) ; // 1秒後に要素の削除
    };
    

     

方法2:Drupalのajaxフレームワーク(Drupal.ajax.prototype.commands)にカスタム関数をバインドします

  • DrupalのajaxフレームワークにjQueryのようにカスタム関数の追加ができます
  • パラメータの引き渡しはjQueryのカスタム関数と違います
    • jQueryのカスタム関数にパラメーターを配列に渡します
    • Drupal.ajax.prototype.commandsにパラメータを個別に渡します
  • 上記の例では同じようにDrupal.ajax.prototype.commandsで実現します
    // サーバ側でカスタム関数(removeElement)にパラメータを渡して実行させる 
    $commands = array(); 
    $commands[] = array( 'command' => 'removeElement', 
                                        'ele_id' => "#del-div-".$entity->entity_id) ); 
    return array( '#type'=>"ajax", '#commands' => $commands,); 
    
    // クライアント側のカスタム関数(removeElement)の実行
    Drupal.ajax.prototype.commands.removeElement = 
    function(ajax, response, status) {
        jQuery( response.ele_id )
            .css({'opacity':0, 'transition': 'all 1s' })
            .delay(1000).queue(function(){jQuery( response.ele_id ).remove()}) ;
    }

     

  • 同じ結果となります

 

drupal
form
ajax

やりたいこと:Drupalのajaxフレームワークを利用して表示している要素を削除

  • Drupalのモジュール(Views)で作成した一覧の要素を選択して削除します
    • 要素を選択して削除するモジュール:Views Bulk Operations
    • 例:Drupalのモジュール(VBO)の各種処理(Operation)に独自(カスタムオ)のプションの追加方法
  • 前提条件:要素削除する確認の必要はありません
  • ajaxで動的に削除するのはやさしいUIとも言えるでしょう(以下のイメージのように削除)
    Drupalのajaxフレームワークより要素を動的に削除

Step1:削除リンクにDrupalのajax使用するクラス:use-ajax を追加

  • Drupalのajaxフレームワークに関する説明は以下の記事をご参考ください
    • Drupalでajaxのフレームワークが簡単に作成できる
  • 削除アイコン付きのリンクは以下のようです
    // 削除エレメントID:123 (例)
    <a href="/delete/element/id/123/nojs" class="use-ajax del-link" id="del-link-123">
           <i class="fa fa-trash-o" aria-hidden="true"></i>
    </a>
    • アンカー(a)に削除するエレメントID(または別の識別パラメーター)を入れる必要はあります
    • アンカーリンクの後ろに「nojs」を追加します(クライアント側のajax作動時に、nojs->ajaxに変換され)
    • アンカーがクリックされると、Drupalのajaxフレームワークが起動され、削除パラメーターをサイト側に渡します

Step2:hook_menuで要素削除のリクエストをキャッチします

  • hook_menuで要素削除のリクエストを受け取り、削除処理を行います
    // 要素削除URLの設定
    $items['delete/element/%/nojs'] = array(
    	'page callback' => 'delete_element',
    	'page arguments' => array( 2, 3 ) ,
    	'access callback' => 'delete_access',
    	'type' => MENU_CALLBACK,
    );
    // ajaxが以下のURLでリクエストをします(クライアント側でnojs->ajaxに変換)
    $items['delete/element/%/ajax'] = array(
    	'delivery callback' => 'ajax_deliver',
    )+$items['delete/element/%/nojs'] ;    // 要素削除定義に遷移
    
  • 要素削除処理ファンクション:delete_element で削除処理、処理結果をクライアント側に返します
    function delete_element ($id, $ajax){
        $is_ajax = $ajax === "ajax" ;  // ajaxと通用のリクエスト両方対応のため
    
        // 要素をDBから削除
        db_delete("element_table")->condition("entity_id", $id)->execute() ;
    
        // 画面要素も削除コマンドを返す
        if( $is_ajax ){
            // ajaxで要素削除後の処理
            $commands = array();
            $commands[] = ajax_command_remove( '#element-123');
            return array(
              '#type'=>"ajax",
              '#commands' => $commands,
            );
        } else {
            // 通常での要素削除後の処理
            drupal_set_message(t('Deleted 1 vocabulary'));
            drupal_goto();
        }
    }

     

Drupalのajaxフレームワークで要素削除

纏め:Drupalのajaxフレームワークを利用すればajax処理が自動的に行います

  • 上記例では、削除リンクにクラス:use-ajax を追加するだけで、ajax関連処理を記述する必要はあります
    • 削除リンクではなく、削除ボタン(button)要素を使用する場合クラス: use-ajax-submit
  • サーバー側では、hook_menuで削除リンクの定義、削除リクエストをキャッチして、削除処理関数を作成します
    • DB上のデータ削除完了後に、クライアント側の要素削除命令(ajax_command_remove)を返せば良いです
  • この一連のajax処理の記述はほどんとありません。簡単、便利です
drupal
form
ajax

Drupalのajaxフレームワークにあるajax_command_invokeがユーザーが自分的にしたjavascriptのカスタムコマンドの呼び出しができます

  • Drupalのajaxフレームワークに、クライアント側のUI要素追加、更新、削除、cssなどの処理コマンドが数多くあります
    • コマンドの説明:https://api.drupal.org/api/drupal/includes%21ajax.inc/group/ajax_comman…
  • ajaxコマンド:ajax_command_invoke があります。このコマンドがユーザー自分作成したjavascriptの呼び出しができます
  • 例: クライアント側で要素削除時に、自作にjavascriptで要素をゆっくり消していく動画効果を再現します
    ajaxで要素作成動画

方法1:jQueryのカスタム関数で定義します

  • jQueryのカスタム関数を利用して、上記動画効果のjavascriptを作成して、Drupalのajax_command_invokeより呼びされます
    jQuery でカスタム関数の作成
  • Drupalのajax_command_invokeでカスタム関数にパラメターを渡して、実行させます
    // サーバ側でカスタム関数(removeElement)にパラメータを渡して実行させる
    $commands = array();
    $commands[] = ajax_command_invoke( null,
                                       'removeElement', 
                                        array("#del-div-".$entity->entity_id) );
    return array(  '#type'=>"ajax",  '#commands' => $commands,);
    
    // クライアント側で実行されるカスタム関数(removeElement)
    jQuery.fn.removeElement = function(ele_id) {
        jQuery( ele_id )
            .css({'opacity':0, 'transition': 'all 1s' })   // cssで要素の透明度をゼロにする
            .delay(1000).queue(function(){jQuery( ele_id ).remove()} ) ; // 1秒後に要素の削除
    };
    

     

方法2:Drupalのajaxフレームワーク(Drupal.ajax.prototype.commands)にカスタム関数をバインドします

  • DrupalのajaxフレームワークにjQueryのようにカスタム関数の追加ができます
  • パラメータの引き渡しはjQueryのカスタム関数と違います
    • jQueryのカスタム関数にパラメーターを配列に渡します
    • Drupal.ajax.prototype.commandsにパラメータを個別に渡します
  • 上記の例では同じようにDrupal.ajax.prototype.commandsで実現します
    // サーバ側でカスタム関数(removeElement)にパラメータを渡して実行させる 
    $commands = array(); 
    $commands[] = array( 'command' => 'removeElement', 
                                        'ele_id' => "#del-div-".$entity->entity_id) ); 
    return array( '#type'=>"ajax", '#commands' => $commands,); 
    
    // クライアント側のカスタム関数(removeElement)の実行
    Drupal.ajax.prototype.commands.removeElement = 
    function(ajax, response, status) {
        jQuery( response.ele_id )
            .css({'opacity':0, 'transition': 'all 1s' })
            .delay(1000).queue(function(){jQuery( response.ele_id ).remove()}) ;
    }

     

  • 同じ結果となります

 

drupal
form
ajax

やりたいこと:Drupalのajaxフレームワークを利用して表示している要素を削除

  • Drupalのモジュール(Views)で作成した一覧の要素を選択して削除します
    • 要素を選択して削除するモジュール:Views Bulk Operations
    • 例:Drupalのモジュール(VBO)の各種処理(Operation)に独自(カスタムオ)のプションの追加方法
  • 前提条件:要素削除する確認の必要はありません
  • ajaxで動的に削除するのはやさしいUIとも言えるでしょう(以下のイメージのように削除)
    Drupalのajaxフレームワークより要素を動的に削除

Step1:削除リンクにDrupalのajax使用するクラス:use-ajax を追加

  • Drupalのajaxフレームワークに関する説明は以下の記事をご参考ください
    • Drupalでajaxのフレームワークが簡単に作成できる
  • 削除アイコン付きのリンクは以下のようです
    // 削除エレメントID:123 (例)
    <a href="/delete/element/id/123/nojs" class="use-ajax del-link" id="del-link-123">
           <i class="fa fa-trash-o" aria-hidden="true"></i>
    </a>
    • アンカー(a)に削除するエレメントID(または別の識別パラメーター)を入れる必要はあります
    • アンカーリンクの後ろに「nojs」を追加します(クライアント側のajax作動時に、nojs->ajaxに変換され)
    • アンカーがクリックされると、Drupalのajaxフレームワークが起動され、削除パラメーターをサイト側に渡します

Step2:hook_menuで要素削除のリクエストをキャッチします

  • hook_menuで要素削除のリクエストを受け取り、削除処理を行います
    // 要素削除URLの設定
    $items['delete/element/%/nojs'] = array(
    	'page callback' => 'delete_element',
    	'page arguments' => array( 2, 3 ) ,
    	'access callback' => 'delete_access',
    	'type' => MENU_CALLBACK,
    );
    // ajaxが以下のURLでリクエストをします(クライアント側でnojs->ajaxに変換)
    $items['delete/element/%/ajax'] = array(
    	'delivery callback' => 'ajax_deliver',
    )+$items['delete/element/%/nojs'] ;    // 要素削除定義に遷移
    
  • 要素削除処理ファンクション:delete_element で削除処理、処理結果をクライアント側に返します
    function delete_element ($id, $ajax){
        $is_ajax = $ajax === "ajax" ;  // ajaxと通用のリクエスト両方対応のため
    
        // 要素をDBから削除
        db_delete("element_table")->condition("entity_id", $id)->execute() ;
    
        // 画面要素も削除コマンドを返す
        if( $is_ajax ){
            // ajaxで要素削除後の処理
            $commands = array();
            $commands[] = ajax_command_remove( '#element-123');
            return array(
              '#type'=>"ajax",
              '#commands' => $commands,
            );
        } else {
            // 通常での要素削除後の処理
            drupal_set_message(t('Deleted 1 vocabulary'));
            drupal_goto();
        }
    }

     

Drupalのajaxフレームワークで要素削除

纏め:Drupalのajaxフレームワークを利用すればajax処理が自動的に行います

  • 上記例では、削除リンクにクラス:use-ajax を追加するだけで、ajax関連処理を記述する必要はあります
    • 削除リンクではなく、削除ボタン(button)要素を使用する場合クラス: use-ajax-submit
  • サーバー側では、hook_menuで削除リンクの定義、削除リクエストをキャッチして、削除処理関数を作成します
    • DB上のデータ削除完了後に、クライアント側の要素削除命令(ajax_command_remove)を返せば良いです
  • この一連のajax処理の記述はほどんとありません。簡単、便利です
drupal
form
ajax

Drupalのajaxフレームワークにあるajax_command_invokeがユーザーが自分的にしたjavascriptのカスタムコマンドの呼び出しができます

  • Drupalのajaxフレームワークに、クライアント側のUI要素追加、更新、削除、cssなどの処理コマンドが数多くあります
    • コマンドの説明:https://api.drupal.org/api/drupal/includes%21ajax.inc/group/ajax_comman…
  • ajaxコマンド:ajax_command_invoke があります。このコマンドがユーザー自分作成したjavascriptの呼び出しができます
  • 例: クライアント側で要素削除時に、自作にjavascriptで要素をゆっくり消していく動画効果を再現します
    ajaxで要素作成動画

方法1:jQueryのカスタム関数で定義します

  • jQueryのカスタム関数を利用して、上記動画効果のjavascriptを作成して、Drupalのajax_command_invokeより呼びされます
    jQuery でカスタム関数の作成
  • Drupalのajax_command_invokeでカスタム関数にパラメターを渡して、実行させます
    // サーバ側でカスタム関数(removeElement)にパラメータを渡して実行させる
    $commands = array();
    $commands[] = ajax_command_invoke( null,
                                       'removeElement', 
                                        array("#del-div-".$entity->entity_id) );
    return array(  '#type'=>"ajax",  '#commands' => $commands,);
    
    // クライアント側で実行されるカスタム関数(removeElement)
    jQuery.fn.removeElement = function(ele_id) {
        jQuery( ele_id )
            .css({'opacity':0, 'transition': 'all 1s' })   // cssで要素の透明度をゼロにする
            .delay(1000).queue(function(){jQuery( ele_id ).remove()} ) ; // 1秒後に要素の削除
    };
    

     

方法2:Drupalのajaxフレームワーク(Drupal.ajax.prototype.commands)にカスタム関数をバインドします

  • DrupalのajaxフレームワークにjQueryのようにカスタム関数の追加ができます
  • パラメータの引き渡しはjQueryのカスタム関数と違います
    • jQueryのカスタム関数にパラメーターを配列に渡します
    • Drupal.ajax.prototype.commandsにパラメータを個別に渡します
  • 上記の例では同じようにDrupal.ajax.prototype.commandsで実現します
    // サーバ側でカスタム関数(removeElement)にパラメータを渡して実行させる 
    $commands = array(); 
    $commands[] = array( 'command' => 'removeElement', 
                                        'ele_id' => "#del-div-".$entity->entity_id) ); 
    return array( '#type'=>"ajax", '#commands' => $commands,); 
    
    // クライアント側のカスタム関数(removeElement)の実行
    Drupal.ajax.prototype.commands.removeElement = 
    function(ajax, response, status) {
        jQuery( response.ele_id )
            .css({'opacity':0, 'transition': 'all 1s' })
            .delay(1000).queue(function(){jQuery( response.ele_id ).remove()}) ;
    }

     

  • 同じ結果となります

 

drupal
form
ajax

やりたいこと:Drupalのajaxフレームワークを利用して表示している要素を削除

  • Drupalのモジュール(Views)で作成した一覧の要素を選択して削除します
    • 要素を選択して削除するモジュール:Views Bulk Operations
    • 例:Drupalのモジュール(VBO)の各種処理(Operation)に独自(カスタムオ)のプションの追加方法
  • 前提条件:要素削除する確認の必要はありません
  • ajaxで動的に削除するのはやさしいUIとも言えるでしょう(以下のイメージのように削除)
    Drupalのajaxフレームワークより要素を動的に削除

Step1:削除リンクにDrupalのajax使用するクラス:use-ajax を追加

  • Drupalのajaxフレームワークに関する説明は以下の記事をご参考ください
    • Drupalでajaxのフレームワークが簡単に作成できる
  • 削除アイコン付きのリンクは以下のようです
    // 削除エレメントID:123 (例)
    <a href="/delete/element/id/123/nojs" class="use-ajax del-link" id="del-link-123">
           <i class="fa fa-trash-o" aria-hidden="true"></i>
    </a>
    • アンカー(a)に削除するエレメントID(または別の識別パラメーター)を入れる必要はあります
    • アンカーリンクの後ろに「nojs」を追加します(クライアント側のajax作動時に、nojs->ajaxに変換され)
    • アンカーがクリックされると、Drupalのajaxフレームワークが起動され、削除パラメーターをサイト側に渡します

Step2:hook_menuで要素削除のリクエストをキャッチします

  • hook_menuで要素削除のリクエストを受け取り、削除処理を行います
    // 要素削除URLの設定
    $items['delete/element/%/nojs'] = array(
    	'page callback' => 'delete_element',
    	'page arguments' => array( 2, 3 ) ,
    	'access callback' => 'delete_access',
    	'type' => MENU_CALLBACK,
    );
    // ajaxが以下のURLでリクエストをします(クライアント側でnojs->ajaxに変換)
    $items['delete/element/%/ajax'] = array(
    	'delivery callback' => 'ajax_deliver',
    )+$items['delete/element/%/nojs'] ;    // 要素削除定義に遷移
    
  • 要素削除処理ファンクション:delete_element で削除処理、処理結果をクライアント側に返します
    function delete_element ($id, $ajax){
        $is_ajax = $ajax === "ajax" ;  // ajaxと通用のリクエスト両方対応のため
    
        // 要素をDBから削除
        db_delete("element_table")->condition("entity_id", $id)->execute() ;
    
        // 画面要素も削除コマンドを返す
        if( $is_ajax ){
            // ajaxで要素削除後の処理
            $commands = array();
            $commands[] = ajax_command_remove( '#element-123');
            return array(
              '#type'=>"ajax",
              '#commands' => $commands,
            );
        } else {
            // 通常での要素削除後の処理
            drupal_set_message(t('Deleted 1 vocabulary'));
            drupal_goto();
        }
    }

     

Drupalのajaxフレームワークで要素削除

纏め:Drupalのajaxフレームワークを利用すればajax処理が自動的に行います

  • 上記例では、削除リンクにクラス:use-ajax を追加するだけで、ajax関連処理を記述する必要はあります
    • 削除リンクではなく、削除ボタン(button)要素を使用する場合クラス: use-ajax-submit
  • サーバー側では、hook_menuで削除リンクの定義、削除リクエストをキャッチして、削除処理関数を作成します
    • DB上のデータ削除完了後に、クライアント側の要素削除命令(ajax_command_remove)を返せば良いです
  • この一連のajax処理の記述はほどんとありません。簡単、便利です
drupal
form
ajax

Drupalのajaxフレームワークにあるajax_command_invokeがユーザーが自分的にしたjavascriptのカスタムコマンドの呼び出しができます

  • Drupalのajaxフレームワークに、クライアント側のUI要素追加、更新、削除、cssなどの処理コマンドが数多くあります
    • コマンドの説明:https://api.drupal.org/api/drupal/includes%21ajax.inc/group/ajax_comman…
  • ajaxコマンド:ajax_command_invoke があります。このコマンドがユーザー自分作成したjavascriptの呼び出しができます
  • 例: クライアント側で要素削除時に、自作にjavascriptで要素をゆっくり消していく動画効果を再現します
    ajaxで要素作成動画

方法1:jQueryのカスタム関数で定義します

  • jQueryのカスタム関数を利用して、上記動画効果のjavascriptを作成して、Drupalのajax_command_invokeより呼びされます
    jQuery でカスタム関数の作成
  • Drupalのajax_command_invokeでカスタム関数にパラメターを渡して、実行させます
    // サーバ側でカスタム関数(removeElement)にパラメータを渡して実行させる
    $commands = array();
    $commands[] = ajax_command_invoke( null,
                                       'removeElement', 
                                        array("#del-div-".$entity->entity_id) );
    return array(  '#type'=>"ajax",  '#commands' => $commands,);
    
    // クライアント側で実行されるカスタム関数(removeElement)
    jQuery.fn.removeElement = function(ele_id) {
        jQuery( ele_id )
            .css({'opacity':0, 'transition': 'all 1s' })   // cssで要素の透明度をゼロにする
            .delay(1000).queue(function(){jQuery( ele_id ).remove()} ) ; // 1秒後に要素の削除
    };
    

     

方法2:Drupalのajaxフレームワーク(Drupal.ajax.prototype.commands)にカスタム関数をバインドします

  • DrupalのajaxフレームワークにjQueryのようにカスタム関数の追加ができます
  • パラメータの引き渡しはjQueryのカスタム関数と違います
    • jQueryのカスタム関数にパラメーターを配列に渡します
    • Drupal.ajax.prototype.commandsにパラメータを個別に渡します
  • 上記の例では同じようにDrupal.ajax.prototype.commandsで実現します
    // サーバ側でカスタム関数(removeElement)にパラメータを渡して実行させる 
    $commands = array(); 
    $commands[] = array( 'command' => 'removeElement', 
                                        'ele_id' => "#del-div-".$entity->entity_id) ); 
    return array( '#type'=>"ajax", '#commands' => $commands,); 
    
    // クライアント側のカスタム関数(removeElement)の実行
    Drupal.ajax.prototype.commands.removeElement = 
    function(ajax, response, status) {
        jQuery( response.ele_id )
            .css({'opacity':0, 'transition': 'all 1s' })
            .delay(1000).queue(function(){jQuery( response.ele_id ).remove()}) ;
    }

     

  • 同じ結果となります

 

drupal
form
ajax

やりたいこと:Drupalのajaxフレームワークを利用して表示している要素を削除

  • Drupalのモジュール(Views)で作成した一覧の要素を選択して削除します
    • 要素を選択して削除するモジュール:Views Bulk Operations
    • 例:Drupalのモジュール(VBO)の各種処理(Operation)に独自(カスタムオ)のプションの追加方法
  • 前提条件:要素削除する確認の必要はありません
  • ajaxで動的に削除するのはやさしいUIとも言えるでしょう(以下のイメージのように削除)
    Drupalのajaxフレームワークより要素を動的に削除

Step1:削除リンクにDrupalのajax使用するクラス:use-ajax を追加

  • Drupalのajaxフレームワークに関する説明は以下の記事をご参考ください
    • Drupalでajaxのフレームワークが簡単に作成できる
  • 削除アイコン付きのリンクは以下のようです
    // 削除エレメントID:123 (例)
    <a href="/delete/element/id/123/nojs" class="use-ajax del-link" id="del-link-123">
           <i class="fa fa-trash-o" aria-hidden="true"></i>
    </a>
    • アンカー(a)に削除するエレメントID(または別の識別パラメーター)を入れる必要はあります
    • アンカーリンクの後ろに「nojs」を追加します(クライアント側のajax作動時に、nojs->ajaxに変換され)
    • アンカーがクリックされると、Drupalのajaxフレームワークが起動され、削除パラメーターをサイト側に渡します

Step2:hook_menuで要素削除のリクエストをキャッチします

  • hook_menuで要素削除のリクエストを受け取り、削除処理を行います
    // 要素削除URLの設定
    $items['delete/element/%/nojs'] = array(
    	'page callback' => 'delete_element',
    	'page arguments' => array( 2, 3 ) ,
    	'access callback' => 'delete_access',
    	'type' => MENU_CALLBACK,
    );
    // ajaxが以下のURLでリクエストをします(クライアント側でnojs->ajaxに変換)
    $items['delete/element/%/ajax'] = array(
    	'delivery callback' => 'ajax_deliver',
    )+$items['delete/element/%/nojs'] ;    // 要素削除定義に遷移
    
  • 要素削除処理ファンクション:delete_element で削除処理、処理結果をクライアント側に返します
    function delete_element ($id, $ajax){
        $is_ajax = $ajax === "ajax" ;  // ajaxと通用のリクエスト両方対応のため
    
        // 要素をDBから削除
        db_delete("element_table")->condition("entity_id", $id)->execute() ;
    
        // 画面要素も削除コマンドを返す
        if( $is_ajax ){
            // ajaxで要素削除後の処理
            $commands = array();
            $commands[] = ajax_command_remove( '#element-123');
            return array(
              '#type'=>"ajax",
              '#commands' => $commands,
            );
        } else {
            // 通常での要素削除後の処理
            drupal_set_message(t('Deleted 1 vocabulary'));
            drupal_goto();
        }
    }

     

Drupalのajaxフレームワークで要素削除

纏め:Drupalのajaxフレームワークを利用すればajax処理が自動的に行います

  • 上記例では、削除リンクにクラス:use-ajax を追加するだけで、ajax関連処理を記述する必要はあります
    • 削除リンクではなく、削除ボタン(button)要素を使用する場合クラス: use-ajax-submit
  • サーバー側では、hook_menuで削除リンクの定義、削除リクエストをキャッチして、削除処理関数を作成します
    • DB上のデータ削除完了後に、クライアント側の要素削除命令(ajax_command_remove)を返せば良いです
  • この一連のajax処理の記述はほどんとありません。簡単、便利です
drupal
form
ajax

Drupalのajaxフレームワークにあるajax_command_invokeがユーザーが自分的にしたjavascriptのカスタムコマンドの呼び出しができます

  • Drupalのajaxフレームワークに、クライアント側のUI要素追加、更新、削除、cssなどの処理コマンドが数多くあります
    • コマンドの説明:https://api.drupal.org/api/drupal/includes%21ajax.inc/group/ajax_comman…
  • ajaxコマンド:ajax_command_invoke があります。このコマンドがユーザー自分作成したjavascriptの呼び出しができます
  • 例: クライアント側で要素削除時に、自作にjavascriptで要素をゆっくり消していく動画効果を再現します
    ajaxで要素作成動画

方法1:jQueryのカスタム関数で定義します

  • jQueryのカスタム関数を利用して、上記動画効果のjavascriptを作成して、Drupalのajax_command_invokeより呼びされます
    jQuery でカスタム関数の作成
  • Drupalのajax_command_invokeでカスタム関数にパラメターを渡して、実行させます
    // サーバ側でカスタム関数(removeElement)にパラメータを渡して実行させる
    $commands = array();
    $commands[] = ajax_command_invoke( null,
                                       'removeElement', 
                                        array("#del-div-".$entity->entity_id) );
    return array(  '#type'=>"ajax",  '#commands' => $commands,);
    
    // クライアント側で実行されるカスタム関数(removeElement)
    jQuery.fn.removeElement = function(ele_id) {
        jQuery( ele_id )
            .css({'opacity':0, 'transition': 'all 1s' })   // cssで要素の透明度をゼロにする
            .delay(1000).queue(function(){jQuery( ele_id ).remove()} ) ; // 1秒後に要素の削除
    };
    

     

方法2:Drupalのajaxフレームワーク(Drupal.ajax.prototype.commands)にカスタム関数をバインドします

  • DrupalのajaxフレームワークにjQueryのようにカスタム関数の追加ができます
  • パラメータの引き渡しはjQueryのカスタム関数と違います
    • jQueryのカスタム関数にパラメーターを配列に渡します
    • Drupal.ajax.prototype.commandsにパラメータを個別に渡します
  • 上記の例では同じようにDrupal.ajax.prototype.commandsで実現します
    // サーバ側でカスタム関数(removeElement)にパラメータを渡して実行させる 
    $commands = array(); 
    $commands[] = array( 'command' => 'removeElement', 
                                        'ele_id' => "#del-div-".$entity->entity_id) ); 
    return array( '#type'=>"ajax", '#commands' => $commands,); 
    
    // クライアント側のカスタム関数(removeElement)の実行
    Drupal.ajax.prototype.commands.removeElement = 
    function(ajax, response, status) {
        jQuery( response.ele_id )
            .css({'opacity':0, 'transition': 'all 1s' })
            .delay(1000).queue(function(){jQuery( response.ele_id ).remove()}) ;
    }

     

  • 同じ結果となります

 

drupal
form
ajax

やりたいこと:Drupalのajaxフレームワークを利用して表示している要素を削除

  • Drupalのモジュール(Views)で作成した一覧の要素を選択して削除します
    • 要素を選択して削除するモジュール:Views Bulk Operations
    • 例:Drupalのモジュール(VBO)の各種処理(Operation)に独自(カスタムオ)のプションの追加方法
  • 前提条件:要素削除する確認の必要はありません
  • ajaxで動的に削除するのはやさしいUIとも言えるでしょう(以下のイメージのように削除)
    Drupalのajaxフレームワークより要素を動的に削除

Step1:削除リンクにDrupalのajax使用するクラス:use-ajax を追加

  • Drupalのajaxフレームワークに関する説明は以下の記事をご参考ください
    • Drupalでajaxのフレームワークが簡単に作成できる
  • 削除アイコン付きのリンクは以下のようです
    // 削除エレメントID:123 (例)
    <a href="/delete/element/id/123/nojs" class="use-ajax del-link" id="del-link-123">
           <i class="fa fa-trash-o" aria-hidden="true"></i>
    </a>
    • アンカー(a)に削除するエレメントID(または別の識別パラメーター)を入れる必要はあります
    • アンカーリンクの後ろに「nojs」を追加します(クライアント側のajax作動時に、nojs->ajaxに変換され)
    • アンカーがクリックされると、Drupalのajaxフレームワークが起動され、削除パラメーターをサイト側に渡します

Step2:hook_menuで要素削除のリクエストをキャッチします

  • hook_menuで要素削除のリクエストを受け取り、削除処理を行います
    // 要素削除URLの設定
    $items['delete/element/%/nojs'] = array(
    	'page callback' => 'delete_element',
    	'page arguments' => array( 2, 3 ) ,
    	'access callback' => 'delete_access',
    	'type' => MENU_CALLBACK,
    );
    // ajaxが以下のURLでリクエストをします(クライアント側でnojs->ajaxに変換)
    $items['delete/element/%/ajax'] = array(
    	'delivery callback' => 'ajax_deliver',
    )+$items['delete/element/%/nojs'] ;    // 要素削除定義に遷移
    
  • 要素削除処理ファンクション:delete_element で削除処理、処理結果をクライアント側に返します
    function delete_element ($id, $ajax){
        $is_ajax = $ajax === "ajax" ;  // ajaxと通用のリクエスト両方対応のため
    
        // 要素をDBから削除
        db_delete("element_table")->condition("entity_id", $id)->execute() ;
    
        // 画面要素も削除コマンドを返す
        if( $is_ajax ){
            // ajaxで要素削除後の処理
            $commands = array();
            $commands[] = ajax_command_remove( '#element-123');
            return array(
              '#type'=>"ajax",
              '#commands' => $commands,
            );
        } else {
            // 通常での要素削除後の処理
            drupal_set_message(t('Deleted 1 vocabulary'));
            drupal_goto();
        }
    }

     

Drupalのajaxフレームワークで要素削除

纏め:Drupalのajaxフレームワークを利用すればajax処理が自動的に行います

  • 上記例では、削除リンクにクラス:use-ajax を追加するだけで、ajax関連処理を記述する必要はあります
    • 削除リンクではなく、削除ボタン(button)要素を使用する場合クラス: use-ajax-submit
  • サーバー側では、hook_menuで削除リンクの定義、削除リクエストをキャッチして、削除処理関数を作成します
    • DB上のデータ削除完了後に、クライアント側の要素削除命令(ajax_command_remove)を返せば良いです
  • この一連のajax処理の記述はほどんとありません。簡単、便利です
drupal
form
ajax

Drupalのajaxフレームワークにあるajax_command_invokeがユーザーが自分的にしたjavascriptのカスタムコマンドの呼び出しができます

  • Drupalのajaxフレームワークに、クライアント側のUI要素追加、更新、削除、cssなどの処理コマンドが数多くあります
    • コマンドの説明:https://api.drupal.org/api/drupal/includes%21ajax.inc/group/ajax_comman…
  • ajaxコマンド:ajax_command_invoke があります。このコマンドがユーザー自分作成したjavascriptの呼び出しができます
  • 例: クライアント側で要素削除時に、自作にjavascriptで要素をゆっくり消していく動画効果を再現します
    ajaxで要素作成動画

方法1:jQueryのカスタム関数で定義します

  • jQueryのカスタム関数を利用して、上記動画効果のjavascriptを作成して、Drupalのajax_command_invokeより呼びされます
    jQuery でカスタム関数の作成
  • Drupalのajax_command_invokeでカスタム関数にパラメターを渡して、実行させます
    // サーバ側でカスタム関数(removeElement)にパラメータを渡して実行させる
    $commands = array();
    $commands[] = ajax_command_invoke( null,
                                       'removeElement', 
                                        array("#del-div-".$entity->entity_id) );
    return array(  '#type'=>"ajax",  '#commands' => $commands,);
    
    // クライアント側で実行されるカスタム関数(removeElement)
    jQuery.fn.removeElement = function(ele_id) {
        jQuery( ele_id )
            .css({'opacity':0, 'transition': 'all 1s' })   // cssで要素の透明度をゼロにする
            .delay(1000).queue(function(){jQuery( ele_id ).remove()} ) ; // 1秒後に要素の削除
    };
    

     

方法2:Drupalのajaxフレームワーク(Drupal.ajax.prototype.commands)にカスタム関数をバインドします

  • DrupalのajaxフレームワークにjQueryのようにカスタム関数の追加ができます
  • パラメータの引き渡しはjQueryのカスタム関数と違います
    • jQueryのカスタム関数にパラメーターを配列に渡します
    • Drupal.ajax.prototype.commandsにパラメータを個別に渡します
  • 上記の例では同じようにDrupal.ajax.prototype.commandsで実現します
    // サーバ側でカスタム関数(removeElement)にパラメータを渡して実行させる 
    $commands = array(); 
    $commands[] = array( 'command' => 'removeElement', 
                                        'ele_id' => "#del-div-".$entity->entity_id) ); 
    return array( '#type'=>"ajax", '#commands' => $commands,); 
    
    // クライアント側のカスタム関数(removeElement)の実行
    Drupal.ajax.prototype.commands.removeElement = 
    function(ajax, response, status) {
        jQuery( response.ele_id )
            .css({'opacity':0, 'transition': 'all 1s' })
            .delay(1000).queue(function(){jQuery( response.ele_id ).remove()}) ;
    }

     

  • 同じ結果となります

 

drupal
form
ajax

やりたいこと:Drupalのajaxフレームワークを利用して表示している要素を削除

  • Drupalのモジュール(Views)で作成した一覧の要素を選択して削除します
    • 要素を選択して削除するモジュール:Views Bulk Operations
    • 例:Drupalのモジュール(VBO)の各種処理(Operation)に独自(カスタムオ)のプションの追加方法
  • 前提条件:要素削除する確認の必要はありません
  • ajaxで動的に削除するのはやさしいUIとも言えるでしょう(以下のイメージのように削除)
    Drupalのajaxフレームワークより要素を動的に削除

Step1:削除リンクにDrupalのajax使用するクラス:use-ajax を追加

  • Drupalのajaxフレームワークに関する説明は以下の記事をご参考ください
    • Drupalでajaxのフレームワークが簡単に作成できる
  • 削除アイコン付きのリンクは以下のようです
    // 削除エレメントID:123 (例)
    <a href="/delete/element/id/123/nojs" class="use-ajax del-link" id="del-link-123">
           <i class="fa fa-trash-o" aria-hidden="true"></i>
    </a>
    • アンカー(a)に削除するエレメントID(または別の識別パラメーター)を入れる必要はあります
    • アンカーリンクの後ろに「nojs」を追加します(クライアント側のajax作動時に、nojs->ajaxに変換され)
    • アンカーがクリックされると、Drupalのajaxフレームワークが起動され、削除パラメーターをサイト側に渡します

Step2:hook_menuで要素削除のリクエストをキャッチします

  • hook_menuで要素削除のリクエストを受け取り、削除処理を行います
    // 要素削除URLの設定
    $items['delete/element/%/nojs'] = array(
    	'page callback' => 'delete_element',
    	'page arguments' => array( 2, 3 ) ,
    	'access callback' => 'delete_access',
    	'type' => MENU_CALLBACK,
    );
    // ajaxが以下のURLでリクエストをします(クライアント側でnojs->ajaxに変換)
    $items['delete/element/%/ajax'] = array(
    	'delivery callback' => 'ajax_deliver',
    )+$items['delete/element/%/nojs'] ;    // 要素削除定義に遷移
    
  • 要素削除処理ファンクション:delete_element で削除処理、処理結果をクライアント側に返します
    function delete_element ($id, $ajax){
        $is_ajax = $ajax === "ajax" ;  // ajaxと通用のリクエスト両方対応のため
    
        // 要素をDBから削除
        db_delete("element_table")->condition("entity_id", $id)->execute() ;
    
        // 画面要素も削除コマンドを返す
        if( $is_ajax ){
            // ajaxで要素削除後の処理
            $commands = array();
            $commands[] = ajax_command_remove( '#element-123');
            return array(
              '#type'=>"ajax",
              '#commands' => $commands,
            );
        } else {
            // 通常での要素削除後の処理
            drupal_set_message(t('Deleted 1 vocabulary'));
            drupal_goto();
        }
    }

     

Drupalのajaxフレームワークで要素削除

纏め:Drupalのajaxフレームワークを利用すればajax処理が自動的に行います

  • 上記例では、削除リンクにクラス:use-ajax を追加するだけで、ajax関連処理を記述する必要はあります
    • 削除リンクではなく、削除ボタン(button)要素を使用する場合クラス: use-ajax-submit
  • サーバー側では、hook_menuで削除リンクの定義、削除リクエストをキャッチして、削除処理関数を作成します
    • DB上のデータ削除完了後に、クライアント側の要素削除命令(ajax_command_remove)を返せば良いです
  • この一連のajax処理の記述はほどんとありません。簡単、便利です
drupal
form
ajax

Drupalのajaxフレームワークにあるajax_command_invokeがユーザーが自分的にしたjavascriptのカスタムコマンドの呼び出しができます

  • Drupalのajaxフレームワークに、クライアント側のUI要素追加、更新、削除、cssなどの処理コマンドが数多くあります
    • コマンドの説明:https://api.drupal.org/api/drupal/includes%21ajax.inc/group/ajax_comman…
  • ajaxコマンド:ajax_command_invoke があります。このコマンドがユーザー自分作成したjavascriptの呼び出しができます
  • 例: クライアント側で要素削除時に、自作にjavascriptで要素をゆっくり消していく動画効果を再現します
    ajaxで要素作成動画

方法1:jQueryのカスタム関数で定義します

  • jQueryのカスタム関数を利用して、上記動画効果のjavascriptを作成して、Drupalのajax_command_invokeより呼びされます
    jQuery でカスタム関数の作成
  • Drupalのajax_command_invokeでカスタム関数にパラメターを渡して、実行させます
    // サーバ側でカスタム関数(removeElement)にパラメータを渡して実行させる
    $commands = array();
    $commands[] = ajax_command_invoke( null,
                                       'removeElement', 
                                        array("#del-div-".$entity->entity_id) );
    return array(  '#type'=>"ajax",  '#commands' => $commands,);
    
    // クライアント側で実行されるカスタム関数(removeElement)
    jQuery.fn.removeElement = function(ele_id) {
        jQuery( ele_id )
            .css({'opacity':0, 'transition': 'all 1s' })   // cssで要素の透明度をゼロにする
            .delay(1000).queue(function(){jQuery( ele_id ).remove()} ) ; // 1秒後に要素の削除
    };
    

     

方法2:Drupalのajaxフレームワーク(Drupal.ajax.prototype.commands)にカスタム関数をバインドします

  • DrupalのajaxフレームワークにjQueryのようにカスタム関数の追加ができます
  • パラメータの引き渡しはjQueryのカスタム関数と違います
    • jQueryのカスタム関数にパラメーターを配列に渡します
    • Drupal.ajax.prototype.commandsにパラメータを個別に渡します
  • 上記の例では同じようにDrupal.ajax.prototype.commandsで実現します
    // サーバ側でカスタム関数(removeElement)にパラメータを渡して実行させる 
    $commands = array(); 
    $commands[] = array( 'command' => 'removeElement', 
                                        'ele_id' => "#del-div-".$entity->entity_id) ); 
    return array( '#type'=>"ajax", '#commands' => $commands,); 
    
    // クライアント側のカスタム関数(removeElement)の実行
    Drupal.ajax.prototype.commands.removeElement = 
    function(ajax, response, status) {
        jQuery( response.ele_id )
            .css({'opacity':0, 'transition': 'all 1s' })
            .delay(1000).queue(function(){jQuery( response.ele_id ).remove()}) ;
    }

     

  • 同じ結果となります

 

drupal
form
ajax

やりたいこと:Drupalのajaxフレームワークを利用して表示している要素を削除

  • Drupalのモジュール(Views)で作成した一覧の要素を選択して削除します
    • 要素を選択して削除するモジュール:Views Bulk Operations
    • 例:Drupalのモジュール(VBO)の各種処理(Operation)に独自(カスタムオ)のプションの追加方法
  • 前提条件:要素削除する確認の必要はありません
  • ajaxで動的に削除するのはやさしいUIとも言えるでしょう(以下のイメージのように削除)
    Drupalのajaxフレームワークより要素を動的に削除

Step1:削除リンクにDrupalのajax使用するクラス:use-ajax を追加

  • Drupalのajaxフレームワークに関する説明は以下の記事をご参考ください
    • Drupalでajaxのフレームワークが簡単に作成できる
  • 削除アイコン付きのリンクは以下のようです
    // 削除エレメントID:123 (例)
    <a href="/delete/element/id/123/nojs" class="use-ajax del-link" id="del-link-123">
           <i class="fa fa-trash-o" aria-hidden="true"></i>
    </a>
    • アンカー(a)に削除するエレメントID(または別の識別パラメーター)を入れる必要はあります
    • アンカーリンクの後ろに「nojs」を追加します(クライアント側のajax作動時に、nojs->ajaxに変換され)
    • アンカーがクリックされると、Drupalのajaxフレームワークが起動され、削除パラメーターをサイト側に渡します

Step2:hook_menuで要素削除のリクエストをキャッチします

  • hook_menuで要素削除のリクエストを受け取り、削除処理を行います
    // 要素削除URLの設定
    $items['delete/element/%/nojs'] = array(
    	'page callback' => 'delete_element',
    	'page arguments' => array( 2, 3 ) ,
    	'access callback' => 'delete_access',
    	'type' => MENU_CALLBACK,
    );
    // ajaxが以下のURLでリクエストをします(クライアント側でnojs->ajaxに変換)
    $items['delete/element/%/ajax'] = array(
    	'delivery callback' => 'ajax_deliver',
    )+$items['delete/element/%/nojs'] ;    // 要素削除定義に遷移
    
  • 要素削除処理ファンクション:delete_element で削除処理、処理結果をクライアント側に返します
    function delete_element ($id, $ajax){
        $is_ajax = $ajax === "ajax" ;  // ajaxと通用のリクエスト両方対応のため
    
        // 要素をDBから削除
        db_delete("element_table")->condition("entity_id", $id)->execute() ;
    
        // 画面要素も削除コマンドを返す
        if( $is_ajax ){
            // ajaxで要素削除後の処理
            $commands = array();
            $commands[] = ajax_command_remove( '#element-123');
            return array(
              '#type'=>"ajax",
              '#commands' => $commands,
            );
        } else {
            // 通常での要素削除後の処理
            drupal_set_message(t('Deleted 1 vocabulary'));
            drupal_goto();
        }
    }

     

Drupalのajaxフレームワークで要素削除

纏め:Drupalのajaxフレームワークを利用すればajax処理が自動的に行います

  • 上記例では、削除リンクにクラス:use-ajax を追加するだけで、ajax関連処理を記述する必要はあります
    • 削除リンクではなく、削除ボタン(button)要素を使用する場合クラス: use-ajax-submit
  • サーバー側では、hook_menuで削除リンクの定義、削除リクエストをキャッチして、削除処理関数を作成します
    • DB上のデータ削除完了後に、クライアント側の要素削除命令(ajax_command_remove)を返せば良いです
  • この一連のajax処理の記述はほどんとありません。簡単、便利です
drupal
form
ajax

Drupalのajaxフレームワークにあるajax_command_invokeがユーザーが自分的にしたjavascriptのカスタムコマンドの呼び出しができます

  • Drupalのajaxフレームワークに、クライアント側のUI要素追加、更新、削除、cssなどの処理コマンドが数多くあります
    • コマンドの説明:https://api.drupal.org/api/drupal/includes%21ajax.inc/group/ajax_comman…
  • ajaxコマンド:ajax_command_invoke があります。このコマンドがユーザー自分作成したjavascriptの呼び出しができます
  • 例: クライアント側で要素削除時に、自作にjavascriptで要素をゆっくり消していく動画効果を再現します
    ajaxで要素作成動画

方法1:jQueryのカスタム関数で定義します

  • jQueryのカスタム関数を利用して、上記動画効果のjavascriptを作成して、Drupalのajax_command_invokeより呼びされます
    jQuery でカスタム関数の作成
  • Drupalのajax_command_invokeでカスタム関数にパラメターを渡して、実行させます
    // サーバ側でカスタム関数(removeElement)にパラメータを渡して実行させる
    $commands = array();
    $commands[] = ajax_command_invoke( null,
                                       'removeElement', 
                                        array("#del-div-".$entity->entity_id) );
    return array(  '#type'=>"ajax",  '#commands' => $commands,);
    
    // クライアント側で実行されるカスタム関数(removeElement)
    jQuery.fn.removeElement = function(ele_id) {
        jQuery( ele_id )
            .css({'opacity':0, 'transition': 'all 1s' })   // cssで要素の透明度をゼロにする
            .delay(1000).queue(function(){jQuery( ele_id ).remove()} ) ; // 1秒後に要素の削除
    };
    

     

方法2:Drupalのajaxフレームワーク(Drupal.ajax.prototype.commands)にカスタム関数をバインドします

  • DrupalのajaxフレームワークにjQueryのようにカスタム関数の追加ができます
  • パラメータの引き渡しはjQueryのカスタム関数と違います
    • jQueryのカスタム関数にパラメーターを配列に渡します
    • Drupal.ajax.prototype.commandsにパラメータを個別に渡します
  • 上記の例では同じようにDrupal.ajax.prototype.commandsで実現します
    // サーバ側でカスタム関数(removeElement)にパラメータを渡して実行させる 
    $commands = array(); 
    $commands[] = array( 'command' => 'removeElement', 
                                        'ele_id' => "#del-div-".$entity->entity_id) ); 
    return array( '#type'=>"ajax", '#commands' => $commands,); 
    
    // クライアント側のカスタム関数(removeElement)の実行
    Drupal.ajax.prototype.commands.removeElement = 
    function(ajax, response, status) {
        jQuery( response.ele_id )
            .css({'opacity':0, 'transition': 'all 1s' })
            .delay(1000).queue(function(){jQuery( response.ele_id ).remove()}) ;
    }

     

  • 同じ結果となります

 

drupal
form
ajax

やりたいこと:Drupalのajaxフレームワークを利用して表示している要素を削除

  • Drupalのモジュール(Views)で作成した一覧の要素を選択して削除します
    • 要素を選択して削除するモジュール:Views Bulk Operations
    • 例:Drupalのモジュール(VBO)の各種処理(Operation)に独自(カスタムオ)のプションの追加方法
  • 前提条件:要素削除する確認の必要はありません
  • ajaxで動的に削除するのはやさしいUIとも言えるでしょう(以下のイメージのように削除)
    Drupalのajaxフレームワークより要素を動的に削除

Step1:削除リンクにDrupalのajax使用するクラス:use-ajax を追加

  • Drupalのajaxフレームワークに関する説明は以下の記事をご参考ください
    • Drupalでajaxのフレームワークが簡単に作成できる
  • 削除アイコン付きのリンクは以下のようです
    // 削除エレメントID:123 (例)
    <a href="/delete/element/id/123/nojs" class="use-ajax del-link" id="del-link-123">
           <i class="fa fa-trash-o" aria-hidden="true"></i>
    </a>
    • アンカー(a)に削除するエレメントID(または別の識別パラメーター)を入れる必要はあります
    • アンカーリンクの後ろに「nojs」を追加します(クライアント側のajax作動時に、nojs->ajaxに変換され)
    • アンカーがクリックされると、Drupalのajaxフレームワークが起動され、削除パラメーターをサイト側に渡します

Step2:hook_menuで要素削除のリクエストをキャッチします

  • hook_menuで要素削除のリクエストを受け取り、削除処理を行います
    // 要素削除URLの設定
    $items['delete/element/%/nojs'] = array(
    	'page callback' => 'delete_element',
    	'page arguments' => array( 2, 3 ) ,
    	'access callback' => 'delete_access',
    	'type' => MENU_CALLBACK,
    );
    // ajaxが以下のURLでリクエストをします(クライアント側でnojs->ajaxに変換)
    $items['delete/element/%/ajax'] = array(
    	'delivery callback' => 'ajax_deliver',
    )+$items['delete/element/%/nojs'] ;    // 要素削除定義に遷移
    
  • 要素削除処理ファンクション:delete_element で削除処理、処理結果をクライアント側に返します
    function delete_element ($id, $ajax){
        $is_ajax = $ajax === "ajax" ;  // ajaxと通用のリクエスト両方対応のため
    
        // 要素をDBから削除
        db_delete("element_table")->condition("entity_id", $id)->execute() ;
    
        // 画面要素も削除コマンドを返す
        if( $is_ajax ){
            // ajaxで要素削除後の処理
            $commands = array();
            $commands[] = ajax_command_remove( '#element-123');
            return array(
              '#type'=>"ajax",
              '#commands' => $commands,
            );
        } else {
            // 通常での要素削除後の処理
            drupal_set_message(t('Deleted 1 vocabulary'));
            drupal_goto();
        }
    }

     

Drupalのajaxフレームワークで要素削除

纏め:Drupalのajaxフレームワークを利用すればajax処理が自動的に行います

  • 上記例では、削除リンクにクラス:use-ajax を追加するだけで、ajax関連処理を記述する必要はあります
    • 削除リンクではなく、削除ボタン(button)要素を使用する場合クラス: use-ajax-submit
  • サーバー側では、hook_menuで削除リンクの定義、削除リクエストをキャッチして、削除処理関数を作成します
    • DB上のデータ削除完了後に、クライアント側の要素削除命令(ajax_command_remove)を返せば良いです
  • この一連のajax処理の記述はほどんとありません。簡単、便利です
ホーム

古松

検索

Article Category

  • apache(7)
  • css(19)
  • drupal(295)
  • Electron(4)
  • html(34)
  • javascript(27)
  • laravel(4)
  • linux(5)
  • macOS(2)
  • mysql(13)
  • php(19)
  • python(4)
  • SEO(12)
  • video(72)
  • Visual Studio Code(4)
  • windows(13)
  • wordpress(32)