[jquery-ui][cakephp]SortableでSerializeできないのは設定のミスではないか?

jQueryのSortableでハマったのでメモ。

http://stackoverflow.com/questions/965083/jquery-sortable-list-wont-serialize-why

$("#foo").sortable("serialize");

でシリアライズした値が取得できなかったのですが、これは各ドラッグしたい項目ごとにidに_(アンダースコア)付きの名称を設定しないといけないんだそうです。

例:tableタグのtr(行)単位でsortableを使いたい場合

<tr id="category_<?php e($category['Category']['id']);?>">

のようにしておく。

 
jQuery:

<script type="text/javascript">
$(function() {
$("#sortable").sortable({
update : function () { 
var order = $('#sortable').sortable("serialize");
$.post(url,order,function(theResponse){$('#sortable').html(theResponse);});
});
$("#sortable").disableSelection();
});
</script>

php:
foreach($this->params['form']['category'] as $position => $id):
$this->Category->id = $id;
$this->Category->saveField('sort_order',$position);
endforeach;

な感じでアップデートできます。
 
#やっぱり、QAサイトってニーズ大きいですね。。。

[cakephp]多言語展開CMS

グローバル化の影響なのか、多言語展開CMSの需要が伸びています。

n-style;でも複数の事例を扱うようになってきました。CakePHPはけっこう前からi18n対応していました。php4で動作しかつi18n対応のフレームワークは、数年前はCakePHPしかなかったように思います。

手順としては、

  1. アプリケーションを普通に作成。メッセージは
    __(‘english message’);
    のようにしておき、英語で記述すること。
    動的に変化させる必要のある部分はsprintfなどを用いて記述するとよい。
  2. コンソールから
    cake i18n -app /path/to/your/app
    とコマンドを叩いて、 英語のメッセージ文を抽出する。
  3. poeditを使って翻訳する。
  4. 翻訳後、書き出しを行う。
  5. 日本語の翻訳ファイルを
    /app/locale/jpn/LC_MESSAGES/default.po
    に配置する。

ざっと上記のような感じになります。

プログラマーとしては、メッセージの作り方、UIの作り方に注意すればよいと思います。

テンプレートの読み込み分けとか、画像ファイルの読み込み分けなども必要になってきますよね。

意外と、画像の中にテキストが含まれるもの—例えば、ボタンのグラフィック、スローガン入りバナーなど—を「多言語仕様」で作るのを忘れる、なんていうことが起きます。
別途デザイナーさんがいらっしゃるようなプロジェクトでは要検討事項になるでしょう。

Webアプリケーションの多言語展開をお考えでしたら、どうぞn-style;にご用命ください。

 

[cakephp]Windows Apache + PHP5.2.11 + SQLServer2005

DB接続で文字化けし、UTF-8でのデータ取得でハマったのでメモ。

データをUTF-8で取得するには、SQL Server Driver for PHP 1.1をインストールする必要があり、バージョンの整合性の関係上SQL Server 2008 Native Clientをインストール。(SQLServer自体は2005だけど、下位互換ありのためこちらを使用する)。

SQL Server Driver for PHP 1.1をダウンロードすると、複数のdllがあるので、phpのバージョンとVisual C(コンパイラのバージョンが影響しているのか?不明。。。)を合うようにマニュアルのマトリックスから選択。

選択したdllをphp/extに入れておき、php.iniのextensionコーナーに記述。

このサイトにあるスクリプトを参考にする。

 

<?php

uses('model' . DS . 'datasources' . DS . 'dbo' . DS . 'dbo_mssql');

class DboSqlsrv extends DboMssql {

    var $description = "SQL Server 2005 Driver for PHP";

    var $_baseConfig = array(
        'persistent' => true,
        'host' => 'localhost',
        'login' => 'root',
        'password' => '',
        'database' => 'cake',
    );

    function __construct($config)
    {
        if (!function_exists('sqlsrv_connect')) {
            trigger_error($this->description  . " is not installed, cannot continue.", E_USER_ERROR);
        }
        return DboSource::__construct($config);
    }

    function connect()
    {
        $this->connection = sqlsrv_connect($this->config['host'], array(
            'Database' => $this->config['database'],
            'ConnectionPooling' => $this->config['persistent'] ? 1 : 0,
            'UID' => $this->config['login'],
            'PWD' => $this->config['password'],
        ));
        $this->connected = false;
        if ($this->connection !== false){// && sqlsrv_query($this->connection, 'USE ' . $this->config['database'])) {
            $this->connected = true;
        }
    }

    function disconnect()
    {
        @sqlsrv_free_stmt($this->results);
        $this->connected = !@sqlsrv_close($this->connection);
        return !$this->connected;
    }

    function _execute($sql)
    {
        return sqlsrv_query($this->connection, $sql);
    }

    function begin(&$model)
    {
        if (parent::begin($model)) {
            if (sqlsrv_begin_transaction($this->connection)) {
                $this->_transactionStarted = true;
                return true;
            }
        }
        return false;
    }

    function commit(&$model)
    {
        if (parent::commit($model)) {
            $this->_transactionStarted = false;
            return sqlsrv_commit($this->connection);
        }
        return false;
    }

    function rollback(&$model)
    {
        if (parent::rollback($model)) {
            return sqlsrv_rollback($this->connection);
        }
        return false;
    }

    function lastError()
    {
        if (($errors = sqlsrv_errors()) != null) {
            $msg = '';
            foreach($errors as $e) {
                $msg .= "SQLSTATE: " . $e['SQLSTATE'] . "  ";
                $msg .= "CODE: " . $e['code'] . "  ";
                $msg .= "MESSAGE: " . $e['message'] . "    ";
                break;
            }
            return $msg;
        }
        return null;
    }

    function lastAffected()
    {
        if ($this->_result) {
            $cnt = sqlsrv_rows_affected($this->_result);
            if ($cnt < 0) $cnt = 0;
            return $cnt;
        }
        return null;
    }

    function lastNumRows()
    {
        if (is_resource($this->_result)) {
            $cnt = -1;
            $stmt = sqlsrv_query($this->connection, 'SELECT @@ROWCOUNT AS cnt');
            if (sqlsrv_fetch($stmt)) {
                $cnt = sqlsrv_get_field($stmt, 0);
            }
            return $cnt;
        }
        return null;
    }

    function resultSet(&$results)
    {
        $this->results =& $results;
        $this->map = array();
        $meta = sqlsrv_field_metadata($results);
        $num_fields = count($meta);
        $index = 0;
        $j = 0;

        while ($j < $num_fields) {
            $column = $meta[$j]['Name'];
            if (strpos($column, '__')) {
                if (isset($this->__fieldMappings[$column]) && strpos($this->__fieldMappings[$column], '.')) {
                    $map = explode('.', $this->__fieldMappings[$column]);
                } elseif (isset($this->__fieldMappings[$column])) {
                    $map = array(0, $this->__fieldMappings[$column]);
                } else {
                    $map = array(0, $column);
                }
                $this->map[$index++] = $map;
            } else {
                $this->map[$index++] = array(0, $column);
            }
            $j++;
        }
    }

    function fetchResult()
    {
         if (sqlsrv_fetch($this->results)) {
            $resultRow = array();
            foreach (sqlsrv_field_metadata($this->results) as $index => $field) {
                list($table, $column) = $this->map[$index];
                $resultRow[$table][$column] = sqlsrv_get_field($this->results, $index);
            }
            return $resultRow;
        } else {
            return false;
        }
    }

}
?>  

 

[MySQL]トランザクション

トランザクションを有効にするには、InnoDBにする必要がある。
デフォルトはMyISAM。

[cakephp] CakePHPカンファレンス東京!

CakePHPのカンファレンスが開催されるようです。

待ちに待った感がありまして、7日はPCに張り付いて申込しました。

http://events.php.gr.jp/events/show/55

楽しみです。久々の東京・・・

[cakephp1.2.x.x][php]CakePHPで作成したアプリケーションの文字コード

 CakePHPで作成したアプリケーションを、Shift-JISで表示させたいときには。。。

DB:mysqlをUTF8で作成。

.htaccess:以下のように設定しました。

php_flag  output_buffering              On

php_value output_handler                mb_output_handler

php_value default_charset               Shift_JIS

php_value mbstring.language             japanese

php_flag  mbstring.encoding_translation On

php_value mbstring.http_input           auto

php_value mbstring.http_output          SJIS

php_value mbstring.internal_encoding    UTF-8

php_value mbstring.substitute_character none

 

[実験][SimplePie][RSS]複数のRSSを取得して表示する

SimplePieの実験で作ってみました。

こちら

サーバーサイドでphpを実行し、Javascriptの形式で返却、といってもdocument.writeの嵐です。

ちょっと重いかな。。。キャッシュしている間は早いです。

配置するサーバによって、faviconが表示できたりできなかったりするなぞの現象あり。要調査。

[cakephp][1.2.x.x]キャッシュ

■キャッシュを使うには:

var $helpers = array(‘Cache’);

ヘルパーにCacheを設定

 

■$cacheActionで、アクション単位でキャッシュを指定

var $cacheAction = array(‘display’ => ’1 hour’);

 

adminルーティングを使用したアプリケーションで、キャッシュを使用した途端にログインできなくなってしまったので、原因を調査していたところ、ログイン画面もキャッシュされていたことが原因と判明。特定のアクションではキャッシュしない設定に変更することで回避できました。

 

[cakephp][ajax][jQuery]ファイルアップロード

 http://cakephp.jp/modules/newbb/viewtopic.php?post_id=1870&topic_id=965&forum=12

 

[cakephp][1.2.x.x]URLで言語を切り替える方法

routes.php
$bits = explode('/', $_GET['url']);
foreach($bits as $strUrl){
    if($strUrl === 'ja' || $strUrl === 'en'){
        Configure::write('Config.language', $strUrl);
	Router::connect(&quot;/$strUrl/admin/:controller/:action/*&quot;, 
                array(
                    'controller' => ':controller',
                    'prefix' => 'admin',
                    'action' => ':action'
                )
                );
        break;
    }
}