Posts tagged app

OpenPNE テンプレートのカスタマイズ

2

OpenPNE は Smarty を使用していますが、そのテンプレートを修正したい場合、直接オリジナルのテンプレートを編集するのではなくカスタマイズ用のテンプレートを作成して修正することができます。

ディレクトリは下記になります。
オリジナルのテンプレート
/openpne/webapp/modules/pc/templates/
カスタマイズ用のテンプレート
/openpne/webapp_ext/modules/pc/templates/

/openpne/webapp_ext/modules/pc/templates/ ディレクトリは最初からはないので作成します。
次にカスタマイズしたいテンプレートをオリジナルのテンプレートディレクトリからカスタマイズ用のディレクトリにコピーします。

次に /openpne/config.php の
define('USE_EXT_DIR', false);

define('USE_EXT_DIR', true)
に変更すれば、カスタマイズ用ディレクトリにテンプレートが存在すればそちらを優先して使用されます。

カスタマイズ失敗してもカスタマイズ用のテンプレートを削除すればオリジナルのテンプレートが使用されますので、便利ですね。
この /openpne/webapp_ext/ ディレクトリはテンプレート以外でも webapp ディレクトリのファイルを上書きできます。

optionタグを選択不可にする disabled 属性を IE6 でも有効にする方法

0

optionタグを選択不可にする disabled 属性で紹介したように option タグに disabled 属性を指定することにより選択不可にすることができるのですが、IE6 では選択できてしまいます。

JavaScript で解決する方法です。

Select, Option, Disabled And The JavaScript Solution

上記の参考サイトに詳しくやり方が書かれていますので、簡単に手順だけ紹介。

  • 参考サイトの「Implementing」にある download リンクより JavaScript コード(select-option-disabled-emulation.js)をダウンロード
  • select-option-disabled-emulation.js を適当な場所に保存
  • html 内で select-option-disabled-emulation.js を読み込む
  • 選択不可にしたい option タグに disabled 属性を指定する

DHTML で解決する方法です。

これは上記参考サイトの補足で紹介されていたサイトです。
apptaro’s blog: Emulating Disabled Options in IE with DHTML Behaviors

こちらも上記URL に詳しいやり方が書かかれていますので、簡単にご紹介。

  • 参考サイトの中央よりやや下にある Download よりファイル一式をダウンロード
  • 適当な場所に css, htc ファイルを保存
  • html で上記 css を読み込む
  • 選択不可にしたい option タグに disabled 属性を指定する

これで IE6 でも option タグの disabled 属性が使えるようになりました。

optionタグを選択不可にする disabled 属性

2

フォーム画面を動的に表示してある条件のときにはラジオボタンなどを disabled にしたりします。
今回もあるフォームを作成していて在庫が0のときに select タグで表示する項目を選択できないようにしたかったので調べてみたところ、option タグにも disabled 属性がありました。

そこで下記のようにしてみたところ

<form action="">
<select>
<option>オプション1</option>
<option disabled="disabled">オプション2</option>
<option>オプション3</option>
<option>オプション4</option>
</select>
<input type="submit">
</form>

option-desiabled

うまく選択不可になりました。
ところが Firefox では OK だったのですが、IE6では選択可能に。。。

調べてみると
Disable Option’s In A Select (Dropdown) Element ? Post Archive ? www.lattimore.id.au

It never ceases to amaze me how a browser like IE6, managed to not implement something as trivial as an attribute like disabled. The IE team managed to implement it against the <select> element, but some how overlooked the <option> element. They implement the readonly attribute against the appropriate elements – yet some how the disabled attribute managed to be overlooked when they implemented it. More surprising is that, since the HTML4.01 specification came out in late 1999, IE has been updated and upgraded for various things literally hundreds of times. Why hasn’t this made it into an update? You’d begin to think that Microsoft aren’t aware of it, however the thought of that just seems too far fetched.

どうも IE6 のバグのようです。

CakePHP cakeError で日本語メッセージを表示できない

0

ビューに直接メッセージを日本語で書けば表示できるのですが、
動的にメッセージを変えたいような場合に、

$params = array( array('message'=>'エラーです') );
$this->cakeError('foo', $params);

とし cakeError に日本語のメッセージをパラメータとして渡しても表示できません。
原因は /cake/libs/error.php のコンストラクタで

$clean = new Sanitize();
$messages = $clean->paranoid($messages, $allow);

となっていて、パラメータをサニタイズしていて半角英数字以外は削除されてしまいます。
ちなみに Sanitize::paranoid メソッドは
/cake/libs/sanitize.php

function paranoid($string, $allowed = array()) {
    $allow = null;
    if (!empty($allowed)) {
        foreach($allowed as $value) {
            $allow .= "\\$value";
        }
    }

    if (is_array($string)) {
        foreach($string as $key => $clean) {
            $cleaned[$key] = preg_replace("/[^{$allow}a-zA-Z0-9]/", "", $clean);        }
    } else {
        $cleaned = preg_replace("/[^{$allow}a-zA-Z0-9]/", "", $string);
    }
    return $cleaned;
}

のようになっています。半角英数字と $allow で許可した文字以外は削除されます。

前回の投稿「cakeError でエラー処理」のように自分で cakeError 処理を書いた場合には /app/error.php でコンストラクタを上書きして問題の部分をコメントアウトすることにより、日本語を表示することができるようになります。

/cake/libs/error.php の __construct メソッドを丸ごと /app/error.php にコピペして
parent::__construct();
$messages = $clean->paranoid($messages, $allow);の2行をコメントアウト

こうすることにより日本語を表示することができるようになりました。

※サニタイズ処理をコメントアウトしていますので、その点は十分に注意が必要です。

CakePHP cakeError でエラー処理

1

CakePHP でエラー処理をさせるのに cakeError を使ってみました。
致命的なエラーのときに、メールを送信したりログを記録したりするのに使えるかと思います。

/app/error.php を作成

class AppError extends ErrorHandler
{
    function foo($params){
        // ここにエラー処理を書く

        // $params を展開
        extract($params);

        // view のディレクトリを指定
        $this->controller->viewPath='errors';

        $this->controller->set('message', $message);
        $this->controller->render('foo');
        exit();
    }
}

エラー用のビューを app/views/errors/foo.thtml に作成

呼び出し方は第1引数にメソッド名、第2引数にメソッドに渡すパラメータ

$params = array( array('message'=>'Error!') );
$this->cakeError('foo', $params);

$params の指定方法にちょっとだけ注意が必要です。

PEAR::Pager ページ番号を PATH_INFO で渡す

3

ページング処理を行ってくれる PEAR::Pager 、かなり便利です。
通常は
index.php?pageID=2
のようにしてページ番号を渡すのですがこれをPATH_INFO で渡すには下記のようにオプションパラメータを指定します。

$params = array(
...
'path' => 'http://localhost/foo/',
'fileName' => '%d',
'append' => false,
cuurentPage => 現在のページ
);

ポイント

append = false なら fileName の %d にpageID を埋め込む。
currentPage を指定しないと Pager が現在のページが分からない。

fileName

'path' => 'http://localhost/',
'fileName' => 'foo/%d'

なども可能。append=false なら fileName の %d にpageID を埋め込むということ。

現在のページを取得するには

$path_info = explode("/", $_SERVER['PATH_INFO']);
if (isset($path_info[1]) {
    $currentPage = $path_info[1];
} else {
    $currentPage = 1;
}

PATH_INFO が使用できるか

サーバによっては PATH_INFO が使用できない。
使用できるかは $_SERVER["PATH_INFO"] が存在するかどうか。
ただし、http://localhost/index.php では $_SERVER["PATH_INFO"] には値はセットされないので、 http://localhost/index.php/1 などのようにして $_SERVER["PATH_INFO"] が設定されているか調べる。

PEAR::Page マニュアル

CakePHP コントローラのメソッドをURLから実行させない

0

コントローラにアクション以外のメソッドを書かないのが一番いいのかもしれません。
ただ、どうしても書きたいという場合にはメソッド名にアンダーバー “_” を付けるとURLからアクセスできなくなります。

試しに posts_controller.php_foo というメソッド名を作り /posts/_foo/ にアクセスしてみると
Private Method in PostsController
You are seeing this error because the private class method _foo should not be accessed directly.

とプライベートメソッドなのでアクセスできませんよというエラーメッセージが出力されました。

しかしこのメッセージってあまりよくないのではと思い、試しに DEBUG=0 とデバッグモードを本番環境用にしたところ、

Not found
The requested address posts/_foo/ was not found on this server.

となりました。やはり考えてますよねそれくらい。

ちなみにエラーメッセージは
/cake/libs/view/templates/errors/
にエラーの種類によって15のテンプレートが用意されています。
自分で Not found などのエラーを修正したい場合は
/cake/libs/view/templates/errors/error404.thtml

/app/views/errors/error404.thtml
にコピーして修正すればそちらのテンプレートが使用されます。

CakePHP の日本語マニュアルに書かれている

メンバ関数を protected にして見えるようにするには、コントローラアクション名を ‘-’ ではじめてください。(訳注:将来の仕様???)
メンバ関数を private にするためには、コントローラアクション名を ‘–’ ではじめてください。(訳注:将来の仕様???)

というのはこれのことなのかな?
ただ、”_” ではなく “-” になっている。(英語のマニュアルも同様に “-” でした。)

CakePHP 日本語マニュアル
C.4. コントローラ(Controllers)

CakePHP マニュアル(英語)
CakePHP Manual

CakePHP ヘルパーの出力を echo を使わずに出力する方法

2

※この投稿の方法はバージョン1.1 までしか使用できないようです。1.2 のソースを確認したところ、$html->input の$return パラメータはなくなっていました。/app/config/core.php に AUTO_OUTPUT という定数もなくなっていました。ご注意ください。

Cakephp のヘルパーを使用していて
<?php echo $html->input('Model/filed', array()); ?>と書くところを
<?php $html->input('Model/field', array()); ?>と echo を使用せずに出力するには
/app/config/core.php
AUTO_OUTPUT = true;にすれば、自動的に出力するようになります。

私はつい echo を書き忘れてしまうので助かります。

ヘルパーのメソッドの $return パラメータを true にするとこの AUTO_OUTPUT を無効にすることもできます。
ただ、各メソッドによって、$return パラメータの位置がバラバラなので、書くときにはヘルパーのソースを確認する必要があるかと思います。

ちなにみに input の場合は
<?php $html->input('Model/field', array(), true); ?>とすると自動出力を抑止できますので、上記は何も表示されなくなります。

CakePHP 日本語マニュアル
10章 ヘルパー

CakePHP アソシエーションのまとめ(4)

0

まとめ(1) では1対1のアソシエーション hasOne でしたが、
今回は1対多のアソシエーション hasMany です。

例えば、一人のユーザに複数のコメント投稿があるような場合です。
データベースは

CREATE TABLE users(
    id int unsigned auto_increment primary key,
    nickname varchar(30) NOT NULL,
    created datetime default NULL,
    modified datetime default NULL
);

CREATE TABLE posts(
    id int unsigned auto_increment primary key,
    user_id int unsigned unique,
    comment text,
    created datetime default NULL,
    modified datetime default NULL
);

のような場合、アソシエーションの定義は下記のようになります。

< ?php
class User extends AppModel
{
    var $name = 'User';
    var $hasMany = array('Post' =>
                    array('className' => 'Post',
                          'conditions' => '',
                          'order' => '',
                          'foreignKey' => 'user_id',
                          'dependent' => true,
                          'exclusive' => false,
                          'finderQuery' => ''
                    )
                  );
}
?>

これで、
$this->User->findById($id);
とすると下記のようにデータを取得できます。

Array
(
    [User] => Array
        (
            [id] => 1
            [nickname] => boze
        )
    [Post] => Array
        (
            [0] => Array
                (
                    [id] => 1
                    [user_id] => 1
                    [comment] => コメント1です
                )
            [1] => Array
                (
                    [id] => 1
                    [user_id] => 1
                    [comment] => コメント2です
                )
            ....
        )
);

また、hasOne などと同様に CakePHP の命名規約に従っていれば、foreignKey は指定しなくても大丈夫ですので、最低限
var $hasMany = array('Post');
でもアソシエーションを定義できます。

また、hasMany で指定する配列の意味は下記の通りです。

className
関連付けたいモデルのクラス名

conditions
hasMany で取得したいデータの条件を指定する。 SQL の条件文。

order
関連するモデルのデータの並び順。SQL の ORDER 句の指定方法。
Post.created DESC
テーブル名をカラム名の前に付けないと、User.created と区別できません。

limit
Cake が取り出す関連モデルのデータの最大数。
‘limit’ => 5 のように数字で指定。

foreignKey
関連しているモデルを指している外部キーの名前。
Cake の命名規約に従っている場合は省略可能。従っていない場合はここで指定する。

dependent
true に設定すると、モデルのデータの削除時に関連しているモデル側のデータも削除される。

exclusive
true に設定すると、関連しているすべてのオブジェクトが一つの SQL ステートメントで削除される。

finderQuery
アソシエーションを取り出すために、完全な SQL ステートメントを指定する。

CakePHP 日本語マニュアル
6.4. アソシエーション

CakePHP アソシエーションのまとめ(3)

1

今回は belongsTo です。
CakePHP アソシエーションのまとめ(1) で hasOne をやりましたが、belongsTo はその逆です。

まとめ(1) で使用したテーブルで説明すると、Profile モデルにUser モデルを関連付けるのが belongsTo になります。

profile.php

<?php
class Profile extends AppModel {
    var $name = 'Profile';
    var $belongsTo = array('User' =>
                        array('className'  => 'User',
                              'conditions' => '',
                              'order'      => '',
                              'foreignKey' => 'user_id'
                        )
                      );
}
?>

配列のそれぞれの意味は CakePHP アソシエーションのまとめ(2) に説明があります。

これで、
$this->profile->findById($id);
とかすると、Profile モデルの該当するID のデータ内容とそのProfile モデルの元の User モデルのデータが取得できます。

もちろん、CakePHP の命名規則に従っていれば、

profile.php

<?php
class Profile extends AppModel {
    var $name = 'Profile';
    var $belongsTo = array('User');
}

?>

でもいけます。

6.4. アソシエーション

Go to Top